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