Hi everyone,

I tried emailing Simon directly but he seems absent.

I send a patch we are using at Soft at Home to retrieve more information about 
leases using ubus. We would like to have this upstreamed if possible.

We are maintaining these changes at 
https://gitlab.com/soft.at.home/forks/dnsmasq/-/tree/v2.85_ubus_patch

Please let me know about any feedback you may have.

Best Regards,
Eduardo.
From 22edbc5e3f2b1be22fc802784bc71488714adf82 Mon Sep 17 00:00:00 2001
From: Eduardo Aguilar <eduardo.aguilar_...@softathome.com>
Date: Tue, 1 Jun 2021 14:12:47 +0200
Subject: [PATCH] ubus: expose more lease data

* Add dnsmasq networkid to the events.
* Expose DHCPREQUEST and DHCPACK options.

Signed-off-by: Eduardo Aguilar <eduardo.aguilar_...@softathome.com>
---
 src/dnsmasq.h |  21 ++++-
 src/lease.c   |  17 +++++
 src/rfc2131.c |  94 +++++++++++++++--------
 src/ubus.c    | 208 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 304 insertions(+), 36 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 1e21005..5fb86d8 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -277,6 +277,8 @@ struct event_desc {
 #define option_var(x) (daemon->options[(x) / OPTION_BITS])
 #define option_val(x) ((1u) << ((x) % OPTION_BITS))
 #define option_bool(x) (option_var(x) & option_val(x))
+#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
+#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
 
 /* extra flags for my_syslog, we use facilities since they are known 
    not to occupy the same bits as priorities, no matter how syslog.h is set up. 
@@ -757,6 +759,20 @@ struct dhcp_lease {
     struct slaac_address *next;
   } *slaac_address;
   int vendorclass_count;
+#endif
+#ifdef HAVE_UBUS
+  const char* net;
+  struct ubus_extra_info {
+    u32   xid;
+    struct reply_option {
+      struct reply_option* next;
+      unsigned char tag;
+      unsigned char* raw_option_data;
+      size_t raw_option_length;
+      char* option_name;
+      char* option_value;
+    } *request_options, *reply_options;
+  } *ubus_extra_info;
 #endif
   struct dhcp_lease *next;
 };
@@ -1424,6 +1440,7 @@ char *host_from_dns(struct in_addr addr);
 
 /* lease.c */
 #ifdef HAVE_DHCP
+struct dhcp_lease* lease_getfirst(void);
 void lease_update_file(time_t now);
 void lease_update_dns(int force);
 void lease_init(time_t now);
@@ -1516,7 +1533,9 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
 void ubus_init(void);
 void set_ubus_listeners(void);
 void check_ubus_listeners(void);
-void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
+void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface, struct dhcp_lease *lease);
+struct reply_option* ubus_parse_options(unsigned char *start);
+void ubus_delete_options(struct reply_option* list);
 #endif
 
 /* ipset.c */
diff --git a/src/lease.c b/src/lease.c
index 7c5599c..3c24765 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -21,6 +21,10 @@
 static struct dhcp_lease *leases = NULL, *old_leases = NULL;
 static int dns_dirty, file_dirty, leases_left;
 
+struct dhcp_lease* lease_getfirst(void) {
+    return leases;
+}
+
 static int read_leases(time_t now, FILE *leasestream)
 {
   unsigned long ei;
@@ -789,6 +793,10 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
     {
       lease->addr = addr;
       daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
+#ifdef HAVE_UBUS
+      lease->net = NULL;
+      lease->ubus_extra_info = calloc(1, sizeof(struct ubus_extra_info));
+#endif
     }
   
   return lease;
@@ -1103,6 +1111,15 @@ int do_script_run(time_t now)
 	      tmp = slaac->next;
 	      free(slaac);
 	    }
+#endif
+#ifdef HAVE_UBUS
+      lease->net = NULL;
+      if(lease->ubus_extra_info) {
+        ubus_delete_options(lease->ubus_extra_info->reply_options);
+        ubus_delete_options(lease->ubus_extra_info->request_options);
+        free(lease->ubus_extra_info);
+        lease->ubus_extra_info = NULL;
+      }
 #endif
 	  kill_name(lease);
 #ifdef HAVE_SCRIPT
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 3f50755..bc5a599 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -18,9 +18,6 @@
 
 #ifdef HAVE_DHCP
 
-#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
-#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
-
 #ifdef HAVE_SCRIPT
 static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
 #endif
@@ -33,8 +30,8 @@ static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
 			      int opt, const char *string, int null_term);
 static struct in_addr option_addr(unsigned char *opt);
 static unsigned int option_uint(unsigned char *opt, int offset, int size);
-static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
-		       int mac_len, char *interface, char *string, char *err, u32 xid);
+static void log_packet(char *type, void *addr, unsigned char *ext_mac,
+                       int mac_len, char *interface, char *string, char *err, u32 xid, struct dhcp_lease *lease);
 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
 static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
 static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
@@ -655,7 +652,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	}
       
       daemon->metrics[METRIC_BOOTP]++;
-      log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
+      log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid, NULL);
       
       return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
     }
@@ -912,7 +909,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	  opt71.next = daemon->dhcp_opts;
 	  do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
 	  
-	  log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
+	  log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid, NULL);
+
 	  log_tags(tagif_netid, ntohl(mess->xid));
 	  return dhcp_packet_size(mess, agent_id, real_end);	  
 	}
@@ -987,7 +985,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		    do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
 	    
 		  daemon->metrics[METRIC_PXE]++;
-		  log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
+		  log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid, NULL);
+
 		  log_tags(tagif_netid, ntohl(mess->xid));
 		  if (!ignore)
 		    apply_delay(mess->xid, recvtime, tagif_netid);
@@ -1022,7 +1021,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	return 0;
       
       daemon->metrics[METRIC_DHCPDECLINE]++;
-      log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
+      log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid, NULL);
       
       if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
 	lease_prune(lease, now);
@@ -1048,15 +1047,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	  !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
 	  option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
 	return 0;
-      
+
+      log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid, lease);
+
       if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
 	lease_prune(lease, now);
       else
 	message = _("unknown lease");
 
       daemon->metrics[METRIC_DHCPRELEASE]++;
-      log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
-	
       return 0;
       
     case DHCPDISCOVER:
@@ -1122,7 +1121,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	}
       
       daemon->metrics[METRIC_DHCPDISCOVER]++;
-      log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); 
+      log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid, NULL);
 
       if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
 	return 0;
@@ -1143,7 +1142,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	}
       
       daemon->metrics[METRIC_DHCPOFFER]++;
-      log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
+      log_packet("DHCPOFFER",  &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid, NULL);
       
       time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
       clear_packet(mess, end);
@@ -1156,7 +1155,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
       
       return dhcp_packet_size(mess, agent_id, real_end);
 	
-
     case DHCPREQUEST:
       if (ignore || have_config(config, CONFIG_DISABLE))
 	return 0;
@@ -1183,7 +1181,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		  for (; context; context = context->current)
 		    if (context->local.s_addr == option_addr(opt).s_addr)
 		      break;
-		  
+
 		  if (!context)
 		    {
 		      /* Handle very strange configs where clients have more than one route to the server.
@@ -1256,8 +1254,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	}
 
       daemon->metrics[METRIC_DHCPREQUEST]++;
-      log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
-      
+      log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid, NULL);
+
     rapid_commit:
       if (!message)
 	{
@@ -1330,7 +1328,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
       if (message)
 	{
 	  daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++;
-	  log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
+	  log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid, NULL);
 
 	  /* rapid commit case: lease allocate failed but don't send DHCPNAK */
 	  if (rapid_commit)
@@ -1359,7 +1357,19 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	    }
 
 	  log_tags(tagif_netid, ntohl(mess->xid));
-	  
+
+#ifdef HAVE_UBUS
+      if(lease) {
+        lease->net = context->netid.net;
+        if(lease->ubus_extra_info) {
+          if(lease->ubus_extra_info->request_options) {
+            ubus_delete_options(lease->ubus_extra_info->request_options);
+          }
+          lease->ubus_extra_info->request_options = ubus_parse_options(&mess->options[0] + sizeof(u32));
+        }
+      }
+#endif
+
 	  if (do_classes)
 	    {
 	      /* pick up INIT-REBOOT events. */
@@ -1492,7 +1502,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 	    override = lease->override;
 
 	  daemon->metrics[METRIC_DHCPACK]++;
-	  log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  
 
 	  clear_packet(mess, end);
 	  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
@@ -1504,14 +1513,27 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
 	}
 
-      return dhcp_packet_size(mess, agent_id, real_end); 
+       size_t result = dhcp_packet_size(mess, agent_id, real_end);
+#ifdef HAVE_UBUS
+       if(lease) {
+         lease->net = context->netid.net;
+         if (lease->ubus_extra_info) {
+           if(lease->ubus_extra_info->reply_options) {
+             ubus_delete_options(lease->ubus_extra_info->reply_options);
+           }
+           lease->ubus_extra_info->reply_options = ubus_parse_options(&mess->options[0] + sizeof(u32));
+         }
+       }
+#endif
+       log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid, lease);
+       return result;
       
     case DHCPINFORM:
       if (ignore || have_config(config, CONFIG_DISABLE))
 	message = _("ignored");
       
       daemon->metrics[METRIC_DHCPINFORM]++;
-      log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
+      log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid, NULL);
      
       if (message || mess->ciaddr.s_addr == 0)
 	return 0;
@@ -1538,7 +1560,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
       log_tags(tagif_netid, ntohl(mess->xid));
       
       daemon->metrics[METRIC_DHCPACK]++;
-      log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
+      log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid, lease);
       
       if (lease)
 	{
@@ -1571,6 +1593,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
 		 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
       
       *is_inform = 1; /* handle reply differently */
+
       return dhcp_packet_size(mess, agent_id, real_end); 
     }
   
@@ -1671,9 +1694,11 @@ static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
 }
 #endif
 
-static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
-		       int mac_len, char *interface, char *string, char *err, u32 xid)
+static void log_packet(char *type, void *addr, unsigned char *ext_mac,
+		       int mac_len, char *interface, char *string, char *err, u32 xid,
+			   struct dhcp_lease* lease)
 {
+  (void)lease;
   struct in_addr a;
  
   if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
@@ -1689,7 +1714,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
      my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
 	       ntohl(xid), 
 	       type,
-	       interface, 
+	       interface,
 	       addr ? inet_ntoa(a) : "",
 	       addr ? " " : "",
 	       daemon->namebuff,
@@ -1698,7 +1723,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
   else
     my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
 	      type,
-	      interface, 
+	      interface,
 	      addr ? inet_ntoa(a) : "",
 	      addr ? " " : "",
 	      daemon->namebuff,
@@ -1706,10 +1731,13 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
 	      err ? err : "");
 
 #ifdef HAVE_UBUS
-	if (!strcmp(type, "DHCPACK"))
-		ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
-	else if (!strcmp(type, "DHCPRELEASE"))
-		ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
+    if (lease && lease->ubus_extra_info) lease->ubus_extra_info->xid = xid;
+    if (!strcmp(type, "DHCPACK"))
+        ubus_event_bcast("dhcp.ack", daemon->namebuff, (addr ? inet_ntoa(a) : NULL), (string ? string : NULL), interface, lease);
+    else if (!strcmp(type, "DHCPRELEASE"))
+        ubus_event_bcast("dhcp.release", daemon->namebuff, (addr ? inet_ntoa(a) : NULL), (string ? string : NULL), interface, lease);
+    else if (!strcmp(type, "DHCPREQUEST"))
+        ubus_event_bcast("dhcp.request", daemon->namebuff, (addr ? inet_ntoa(a) : NULL), (string ? string : NULL), interface, lease);
 #endif
 }
 
@@ -1718,7 +1746,7 @@ static void log_options(unsigned char *start, u32 xid)
   while (*start != OPTION_END)
     {
       char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
-      
+
       my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s  %s", 
 		ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
       start += start[1] + 2;
diff --git a/src/ubus.c b/src/ubus.c
index 33c2783..0ebb873 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -28,10 +28,18 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
 			       struct ubus_request_data *req, const char *method,
 			       struct blob_attr *msg);
 
+static int ubus_handle_leases(struct ubus_context *ctx, struct ubus_object *obj,
+                   struct ubus_request_data *req, const char *method,
+                   struct blob_attr *msg);
+
 static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
 
+struct reply_option* ubus_parse_options(unsigned char *start);
+void ubus_delete_options(struct reply_option* list);
+
 static const struct ubus_method ubus_object_methods[] = {
   UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
+  UBUS_METHOD_NOARG("leases", ubus_handle_leases),
 };
 
 static struct ubus_object_type ubus_object_type =
@@ -160,6 +168,29 @@ void check_ubus_listeners()
     }
 }
 
+static void ubus_fill_options(struct reply_option *list) {
+  char buf[256];
+  struct reply_option *itt = list;
+  while (itt) {
+      void* option = blobmsg_open_table(&b, itt->option_name);
+      blobmsg_add_u32(&b, "tag", itt->tag);
+      blobmsg_add_string(&b, "value", itt->option_value);
+      if (itt->raw_option_data) {
+          char* p = buf;
+          *p = 0;
+          size_t len = itt->raw_option_length <= sizeof(buf) ? itt->raw_option_length : sizeof(buf);
+          for (size_t i = 0; i < len; ++i) {
+              unsigned char v = itt->raw_option_data[i];
+              sprintf(p, "%02x", (int)v);
+              p += 2;
+          }
+          blobmsg_add_string(&b, "raw", buf);
+      }
+      blobmsg_close_table(&b, option);
+      itt = itt->next;
+  }
+}
+
 static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
 			       struct ubus_request_data *req, const char *method,
 			       struct blob_attr *msg)
@@ -178,7 +209,113 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
   return ubus_send_reply(ctx, req, b.head);
 }
 
-void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
+static int ubus_handle_leases(struct ubus_context *ctx, struct ubus_object *obj,
+                              struct ubus_request_data *req, const char *method,
+                              struct blob_attr *msg) {
+    (void)obj;
+    (void)method;
+    (void)msg;
+
+    struct dhcp_lease *lease = lease_getfirst();
+    char name[64];
+    int index = 0;
+    char str[INET6_ADDRSTRLEN];
+    const char* s;
+    char* p;
+    char buf[64];
+
+    blob_buf_init(&b, 0);
+    void* leases = blobmsg_open_array(&b, "leases");
+
+    while (lease) {
+        sprintf(name, "lease%d", index);
+        void* entry = blobmsg_open_table(&b, name);
+
+        if (lease->hostname) {
+            blobmsg_add_string(&b, "hostname", lease->hostname);
+        }
+        if (lease->fqdn) {
+            blobmsg_add_string(&b, "FQDN", lease->fqdn);
+        }
+
+        s = inet_ntop(AF_INET, &lease->addr, str, sizeof(str));
+        if (s) blobmsg_add_string(&b, "ipv4", str);
+
+        if (lease->override.s_addr) {
+            s = inet_ntop(AF_INET, &lease->override, str, sizeof(str));
+            if (s) blobmsg_add_string(&b, "override", str);
+        }
+
+        if (lease->giaddr.s_addr) {
+            s = inet_ntop(AF_INET, &lease->giaddr, str, sizeof(str));
+            if (s) blobmsg_add_string(&b, "giaddr", str);
+        }
+
+        strftime(buf, sizeof(buf), "%FT%TZ", gmtime(&lease->expires));
+        blobmsg_add_string(&b, "expires", buf);
+
+        if (indextoname(daemon->dhcpfd, lease->last_interface, buf)) {
+            blobmsg_add_string(&b, "last_interface", buf);
+        }
+
+        if (indextoname(daemon->dhcpfd, lease->new_interface, buf)) {
+            blobmsg_add_string(&b, "new_interface", buf);
+            blobmsg_add_u32(&b, "new_prefix_length", lease->new_prefixlen);
+        }
+
+        switch (lease->hwaddr_type) {
+            case ARPHRD_NETROM: s = "KA9Q NET/ROM Pseudo"; break;
+            case ARPHRD_ETHER: s = "Ethernet"; break;
+            case ARPHRD_EETHER: s = "Experimental Ethernet"; break;
+            case ARPHRD_AX25: s = "AX.25 Level 2"; break;
+            case ARPHRD_PRONET: s = "PROnet token ring"; break;
+            case ARPHRD_CHAOS: s = "Chaosnet"; break;
+            case ARPHRD_IEEE802: s = "IEEE 802.2 Ethernet/TR/TB"; break;
+            case ARPHRD_ARCNET: s = "ARCnet"; break;
+            case ARPHRD_APPLETLK: s = "APPLEtalk"; break;
+            case ARPHRD_DLCI: s = "Frame Relay DLCI"; break;
+            case ARPHRD_ATM: s = "ATM"; break;
+            case ARPHRD_METRICOM: s = "Metricom STRIP"; break;
+            case ARPHRD_IEEE1394: s = "IEEE 1394 IPv4"; break;
+            case ARPHRD_EUI64: s = "EUI-64"; break;
+            case ARPHRD_INFINIBAND: s = "InfiniBand"; break;
+            default: s= "Unknown";
+        }
+        blobmsg_add_string(&b, "hwaddr_type", s);
+        p = buf;
+        for (int i = 0; i < lease->hwaddr_len; ++i, p += 2) {
+            if (i >= (int)( sizeof(buf) / 2 )) break;
+            sprintf(p, "%02X", lease->hwaddr[i]);
+        }
+        blobmsg_add_string(&b, "hwaddr", buf);
+
+        if (lease->net)
+          blobmsg_add_string(&b, "net", lease->net);
+
+        if (lease->ubus_extra_info) {
+          if(lease->ubus_extra_info->reply_options) {
+            void* table = blobmsg_open_table(&b, "options_ack");
+            ubus_fill_options(lease->ubus_extra_info->reply_options);
+            blobmsg_close_table(&b, table);
+          }
+          if(lease->ubus_extra_info->request_options) {
+            void* table = blobmsg_open_table(&b, "options_request");
+            ubus_fill_options(lease->ubus_extra_info->request_options);
+            blobmsg_close_table(&b, table);
+          }
+        }
+
+        blobmsg_close_table(&b, entry);
+        ++index;
+        lease = lease->next;
+    }
+
+    blobmsg_close_array(&b, leases);
+    ubus_send_reply(ctx, req, b.head);
+    return 0;
+}
+
+void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface, struct dhcp_lease* lease)
 {
   struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
   int ret;
@@ -195,11 +332,78 @@ void ubus_event_bcast(const char *type, const char *mac, const char *ip, const c
     blobmsg_add_string(&b, "name", name);
   if (interface)
     blobmsg_add_string(&b, "interface", interface);
-  
+  if (lease) {
+      if (lease->net)
+        blobmsg_add_string(&b, "net", lease->net);
+
+      if (lease->ubus_extra_info) {
+        char sxid[9];
+        sprintf(sxid, "%08X", lease->ubus_extra_info->xid);
+        blobmsg_add_string(&b, "xid", sxid);
+
+        if(!strcmp(type, "dhcp.ack")) {
+          if(lease->ubus_extra_info->reply_options) {
+            void* table = blobmsg_open_table(&b, "options_ack");
+            ubus_fill_options(lease->ubus_extra_info->reply_options);
+            blobmsg_close_table(&b, table);
+          }
+          if(lease->ubus_extra_info->request_options) {
+            void* table = blobmsg_open_table(&b, "options_request");
+            ubus_fill_options(lease->ubus_extra_info->request_options);
+            blobmsg_close_table(&b, table);
+          }
+        }
+      }
+  }
+
   ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
   if (!ret)
     my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
 }
 
 
+struct reply_option* ubus_parse_options(unsigned char *start) {
+
+    struct reply_option* elem = NULL;
+    unsigned char* ptr = start;
+    while (*ptr != OPTION_END) {
+        char *optname = option_string(AF_INET, ptr[0],
+                          option_ptr(ptr, 0), option_len(ptr), daemon->namebuff, MAXDNAME);
+        struct reply_option* new_element = calloc(1, sizeof(struct reply_option));
+
+        if (new_element) {
+          new_element->next = elem;
+          elem = new_element;
+          new_element->tag = ptr[0];
+          if (option_ptr(ptr, 0)) {
+            new_element->raw_option_data = malloc(option_len(ptr));
+            if (new_element->raw_option_data) {
+                memcpy(new_element->raw_option_data, option_ptr(ptr, 0), option_len(ptr));
+                new_element->raw_option_length = option_len(ptr);
+            }
+          }
+          if (optname) new_element->option_name = strdup(optname);
+          if (daemon->namebuff) new_element->option_value = strdup(daemon->namebuff);
+        } else {
+          break;
+        }
+
+        ptr += ptr[1] + 2;
+    }
+    return elem;
+}
+
+void ubus_delete_options(struct reply_option* list) {
+    struct reply_option* itt = list;
+    while (itt) {
+        struct reply_option* next = itt->next;
+        free(itt->raw_option_data);
+        free(itt->option_name);
+        free(itt->option_value);
+        free(itt);
+        itt = next;
+    }
+    list = NULL;
+}
+
 #endif /* HAVE_UBUS */
-- 
2.30.1

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to