For our usage, we need to have more informations sent over D-Bus such as the interface name, the vendor class identifier and the lease expiration time.
To achieve this, we add a new D-Bus signal "DhcpLeaseNotification" which exports the requested informations as a dictionnary. It also has the advantage to be flexible if someone wants to add a new entry in the future. Note: in order to get leases extradata be populated, we enabled this feature if D-Bus is enabled in configuration file (this was enabled in the past only if a script was ran on leases updates). Here is an example of the obtained result with a Python3 program: ''' Define our D-Bus callback ''' def cb(action, ipaddr, hwaddr, hostname, info): print(f'Action: {action}') print(f'IP: {ipaddr}') print(f'Hostname: {hostname}') for k in info: print(f'{k}: {info.get(k)}') ''' Connect to signal DhcpLeaseNotification on interface uk.org.thekelleys.dnsmasq ''' DNSMasq.listen('DhcpLeaseNotification', callback=cb) ''' Run GLib loop ''' GLib.MainLoop().run() ''' When DNSMasq receives a DHCP request, here is the result: ''' Action: 3 IP: 192.168.1.100 Hostname: Nucleus.nucle.us interface: br-mgmt vendor_class: LaGrosseBiche expiration: 1575667431 Signed-off-by: Victorien Molle <victorien.mo...@wifirst.fr> Signed-off-by: Florent Fourcot <florent.four...@wifirst.fr> --- dbus/DBus-interface | 9 ++++ src/dbus.c | 108 ++++++++++++++++++++++++++++++++++++++++++++ src/rfc2131.c | 2 +- 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/dbus/DBus-interface b/dbus/DBus-interface index 954c5b9..ed42551 100644 --- a/dbus/DBus-interface +++ b/dbus/DBus-interface @@ -273,14 +273,23 @@ DhcpLeaseAdded --------------- This signal is emitted when a DHCP lease for a given IP address is created. +This will also trigger the DhcpLeaseNotification signal. DhcpLeaseDeleted ---------------- This signal is emitted when a DHCP lease for a given IP address is deleted. +This will also trigger the DhcpLeaseNotification signal. DhcpLeaseUpdated ---------------- This signal is emitted when a DHCP lease for a given IP address is updated. +This will also trigger the DhcpLeaseNotification signal. + +DhcpLeaseNotification +--------------------- + +This signal is emitted when a DHCP lease action is triggered. It exports, +as a dictionnary, more informations than the other signals. diff --git a/src/dbus.c b/src/dbus.c index c0ce903..01cf3ea 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -70,6 +70,13 @@ const char* introspection_xml_template = " <arg name=\"hwaddr\" type=\"s\"/>\n" " <arg name=\"hostname\" type=\"s\"/>\n" " </signal>\n" +" <signal name=\"DhcpLeaseNotification\">\n" +" <arg name=\"notification_type\" type=\"i\"/>\n" +" <arg name=\"ipaddr\" type=\"s\"/>\n" +" <arg name=\"hwaddr\" type=\"s\"/>\n" +" <arg name=\"hostname\" type=\"s\"/>\n" +" <arg name=\"lease_info\" type=\"a{sv}\"/>\n" +" </signal>\n" #ifdef HAVE_DHCP " <method name=\"AddDhcpLease\">\n" " <arg name=\"ipaddr\" type=\"s\"/>\n" @@ -98,6 +105,12 @@ struct watch { struct watch *next; }; +struct lease_info { + char *key; + char *fmt; + char dbus_type; + DBusBasicValue value; +}; static dbus_bool_t add_watch(DBusWatch *watch, void *data) { @@ -828,6 +841,98 @@ void check_dbus_listeners() } #ifdef HAVE_DHCP +/* + As this function is called by emit_dbus_signal, we already have access to ipaddr, hwaddr and hostname attributes + NOTE: connection attribute is currently not NULL as it is verified by emit_dbus_signal +*/ +void emit_dhcplease_notification(DBusConnection *connection, int action, struct dhcp_lease *lease, char *ipaddr, char *hwaddr, char *hostname) +{ + DBusMessageIter array, dict, iter, variant; + dbus_uint64_t expires = lease->expires; + unsigned char *buf = lease->extradata; + dbus_int32_t act_type = action; + char *interface, *vendor_class; + DBusMessage* message = NULL; + struct lease_info *info; + int allocated = 0; + struct irec *it; + + interface = ""; + for (it = daemon->interfaces; it != NULL; it = it->next) + { + if (it->index == lease->last_interface) + { + interface = it->name; + break; + } + } + + vendor_class = ""; + /* As defined in rfc2131.c, the first data is the vendor class even if it is empty */ + if (buf && *buf != 0) + { + vendor_class = (char*)whine_malloc(lease->extradata_len + 1); + if (vendor_class) + { + allocated = 1; + strncpy(vendor_class, (const char*)buf, (lease->extradata_len)); + } + else + { + vendor_class = ""; + } + } + + struct lease_info infos[] = {{.key = "interface", .fmt = "s", .dbus_type = DBUS_TYPE_STRING, .value.str = interface}, + {.key = "vendor_class", .fmt = "s", .dbus_type = DBUS_TYPE_STRING, .value.str = vendor_class}, + {.key = "expiration", .fmt = "t", .dbus_type = DBUS_TYPE_UINT64, .value.u64 = expires}, + {NULL, NULL, DBUS_TYPE_INVALID, 0} + }; + + if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "DhcpLeaseNotification"))) + goto out; + + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &act_type); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ipaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hwaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hostname); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array); + for (info = infos; info->key; info++) { + dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict); + dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &info->key); + dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, info->fmt, &variant); + switch (info->dbus_type) + { + case DBUS_TYPE_STRING: + dbus_message_iter_append_basic(&variant, info->dbus_type, &info->value.str); + break; + + case DBUS_TYPE_UINT64: + dbus_message_iter_append_basic(&variant, info->dbus_type, &info->value.u64); + break; + + default: + dbus_message_iter_abandon_container(&dict, &variant); + dbus_message_iter_abandon_container_if_open(&array, &dict); + dbus_message_iter_abandon_container_if_open(&iter, &array); + dbus_message_unref(message); + my_syslog(LOG_WARNING, _("Unknown D-Bus type specified for key '%s'. This will completely disable 'DhcpLeaseNotification' signal"), + info->key); + goto out; + } + dbus_message_iter_close_container(&dict, &variant); + dbus_message_iter_close_container(&array, &dict); + } + dbus_message_iter_close_container(&iter, &array); + dbus_connection_send(connection, message, NULL); + dbus_message_unref(message); + +out: + if (vendor_class && allocated) + free(vendor_class); +} + void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname) { DBusConnection *connection = (DBusConnection *)daemon->dbus; @@ -878,6 +983,9 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname) dbus_connection_send(connection, message, NULL); dbus_message_unref(message); + + /* Now emit a notification with more informations */ + emit_dhcplease_notification(connection, action, lease, daemon->addrbuff, mac, hostname); } #endif diff --git a/src/rfc2131.c b/src/rfc2131.c index 0058747..0cea3c4 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -1366,7 +1366,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, lease->flags |= LEASE_CHANGED; #ifdef HAVE_SCRIPT - if (daemon->lease_change_command) + if (daemon->lease_change_command || daemon->dbus) { struct dhcp_netid *n; -- 2.24.0 _______________________________________________ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss