Hello,

I send a new version of the patch simplified. It is based on current master 
(9d806c51c25a23d64df607c8d7a88089745f963a).

Brief explanation:
This adds a new method for the dnsmasq ubus object 'leases', when calling this 
method it will return an ubus data structure with all the available leases 
stored.

Apart from this, the DHCP options from the request packet are saved into a 
linked list to be sent in "dhcp.ack" event and in the 'leases' method.

Perhaps some of these changes could be shared or refactored for other features 
that exist in dnsmasq (HAVE_SCRIPT, DBUS...).

Best Regards,
Eduardo.




From: Eduardo AGUILAR <eduardo.aguilar_...@softathome.com>
Sent: Monday, June 21, 2021 8:56 AM
To: dnsmasq-discuss@lists.thekelleys.org.uk 
<dnsmasq-discuss@lists.thekelleys.org.uk>
Subject: Re: [Dnsmasq-discuss] [PATCH] Expose more lease data through ubus 
 
Hi Petr,

Thanks for the review.

The patch adds a method that can be called through ubus "dnsmasq.leases()" 
which iterates the leases linked list and shows the available information on 
them. Then also extend the information in existing ubus events when a DHCP 
packet is processed. I will add more information on the patch commit commentary 
perhaps.

You are right regarding the ACK options, perhaps I can derive the data in other 
way.

Regarding the location of the ubus_event_bcast calls I also thought of 
implementing as you propose, but currently it is called inside the log_packet 
call. Perhaps getting the ubus_event_bcast out will simplify the patch too.

I was also wondering that the variable "extradata" may be used for the same 
purpose, and if so, maybe it would make sense to remake the patch using that 
variable instead.

I will make these changes and submit a new patch based on master.

Best Regards,
Eduardo.

From: Dnsmasq-discuss <dnsmasq-discuss-boun...@lists.thekelleys.org.uk> on 
behalf of Petr Menšík <pemen...@redhat.com>
Sent: Tuesday, June 15, 2021 4:26 PM
To: dnsmasq-discuss@lists.thekelleys.org.uk 
<dnsmasq-discuss@lists.thekelleys.org.uk>
Subject: Re: [Dnsmasq-discuss] [PATCH] Expose more lease data through ubus 
 
Hi Eduardo,
can you rebase it to master branch?
Do you have any readme or summary, how that feature would be used?
My first note is it adds HAVE_UBUS define to lease structure, but it seems more 
or less unrelated to ubus itself. I could imagine similar mechanism might be 
interesting also for d-bus interface eventually.
Why does it log ACK options? Can they be different for known host? I think 
logging network tag would help, but otherwise sent options should be constant 
according to configuration. Should it store those flags again?
First problem is it always allocates extra info for the lease. I think it 
should try it only when --enable-ubus is used in configuration. I would move 
separate net member into ubus_extra_info structure. And move its defintion 
outside lease structure, use in struct lease {} just:
struct ubus_extra_info *ubus_extra_info;
I would use functions to free and reset ubus_extra_info inside ubus.c. It might 
not need to know structure definition of ubus_extra_info. Avoid complex 
ubus_delete_options() and free in lease.c, move it to function called 
ubus_free_extra_info(lease->ubus_extra_info);
Move implementation details to ubus, since those details are only used there. I 
don't like extending log_packet by lease, just because only 3 types are logged 
with details.
Why is used (string ? string : NULL) ?? use just string. It is either non-NULL 
or NULL anyway. I don't like assigning xid in packet_log function. It should 
only log, not change the records also. Is DHCPREQUEST handled by if's, but not 
supplied with lease intentional? I would expect options from request to be the 
most important to log.
I would use it like this, since it should not log every message:
log_packet("DHCPREQUEST", ...);
#ifdef HAVE_UBUS
      ubus_event_bcast("dhcp.request", daemon->namebuff, 
inet_ntoa(&mess->yiaddr), NULL, iface_name, lease);
#endif
Just might thoughts after quick patch review.
Cheers,
Petr
On 6/11/21 11:59 AM, Eduardo AGUILAR wrote:
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.


 
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss
From e072cbf028e54437dfb3996e42147cbc9bded9de Mon Sep 17 00:00:00 2001
From: Eduardo Aguilar <eduardo.aguilar_...@softathome.com>
Date: Fri, 2 Jul 2021 18:55:40 +0200
Subject: [PATCH] ubus: expose more lease data

* Add dnsmasq networkid to the events.
* Expose DHCPREQUEST options.
* 'leases' ubus method to retrieve the list of leases.

The purpose of the patch is to be able to synchronize with leases
from dnsmasq using ubus only. The ubus 'leases' method can be called
once and then subscribe to the events based on the dhcp packets
received.

The ubus events remain as they were, just add the parameter of the
networkid to identify the pool to which they belong in the config,
and the requested dhcp options from the client.

Signed-off-by: Eduardo Aguilar <eduardo.aguilar_...@softathome.com>
---
 src/dnsmasq.h |  23 +++++-
 src/lease.c   |  10 +++
 src/rfc2131.c |  84 ++++++++++++---------
 src/ubus.c    | 202 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 284 insertions(+), 35 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 939e41e..8a4f183 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -280,6 +280,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. 
@@ -807,6 +809,9 @@ struct dhcp_lease {
     struct slaac_address *next;
   } *slaac_address;
   int vendorclass_count;
+#endif
+#ifdef HAVE_UBUS
+  struct ubus_extra_info *ubus_extra_info;
 #endif
   struct dhcp_lease *next;
 };
@@ -1473,6 +1478,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);
@@ -1562,14 +1568,29 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
 
 /* ubus.c */
 #ifdef HAVE_UBUS
+struct ubus_extra_info {
+  const char* net;
+  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;
+};
 char *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);
 #  ifdef HAVE_CONNTRACK
 void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name);
 void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *pattern, const char *ip, u32 ttl);
 #  endif
+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);
+void ubus_free_extrainfo(struct ubus_extra_info* extra);
 #endif
 
 /* ipset.c */
diff --git a/src/lease.c b/src/lease.c
index b56647d..93c7bea 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,9 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
     {
       lease->addr = addr;
       daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
+#ifdef HAVE_UBUS
+      lease->ubus_extra_info = calloc(1, sizeof(struct ubus_extra_info));
+#endif
     }
   
   return lease;
@@ -1103,6 +1110,9 @@ int do_script_run(time_t now)
 	      tmp = slaac->next;
 	      free(slaac);
 	    }
+#endif
+#ifdef HAVE_UBUS
+      ubus_free_extrainfo(lease->ubus_extra_info);
 #endif
 	  kill_name(lease);
 #ifdef HAVE_SCRIPT
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 0baa602..a6ae3ba 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,17 @@ 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->ubus_extra_info) {
+        lease->ubus_extra_info->net = context->netid.net;
+        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 +1500,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 +1511,21 @@ 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->ubus_extra_info) {
+         lease->ubus_extra_info->net = context->netid.net;
+       }
+#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 +1552,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 +1585,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 +1686,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 +1706,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 +1715,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 +1723,11 @@ 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, interface, lease);
+    else if (!strcmp(type, "DHCPRELEASE"))
+        ubus_event_bcast("dhcp.release", daemon->namebuff, (addr ? inet_ntoa(a) : NULL), string, interface, lease);
 #endif
 }
 
@@ -1718,7 +1736,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 4d63006..aceb8b3 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -52,11 +52,18 @@ static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct u
 					      struct ubus_request_data *req, const char *method,
 					      struct blob_attr *msg);
 #endif
+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),
 #ifdef HAVE_CONNTRACK
   UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
 #endif
@@ -173,6 +180,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)
@@ -307,7 +337,108 @@ fail:
 }
 #endif
 
-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->ubus_extra_info) {
+          if (lease->ubus_extra_info->net)
+            blobmsg_add_string(&b, "net", lease->ubus_extra_info->net);
+
+          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;
@@ -324,7 +455,25 @@ 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->ubus_extra_info) {
+      if (lease->ubus_extra_info->net)
+        blobmsg_add_string(&b, "net", lease->ubus_extra_info->net);
   
+      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->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));
@@ -369,4 +518,55 @@ void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, co
 #endif
 
 
+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;
+}
+
+void ubus_free_extrainfo(struct ubus_extra_info* extra) {
+    extra->net = NULL;
+    ubus_delete_options(extra->request_options);
+    free(extra);
+    extra = 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