[PATCH] odhcpd: send DHCPv6 lease events over U-Bus
Erin Kalousková
erin.kalouskova at nic.cz
Wed Nov 26 04:23:10 PST 2025
odhcpd currently only sends DHCPv4 lease events over U-Bus. For DHCPv6
the only option was to use a trigger hook script and then parse a lease
file and diff it against previous version.
This made it very inconvenient to use in cases like adding DHCP hosts to
DNS server and the behavior is also inconsistent with DHCPv4 counterpart.
Format of the U-Bus message is based on reply of `ipv6leases` U-Bus method.
This patch is largely based on
https://github.com/mikma/openwrt-odhcpd/commit/b796d613dfe74fd36a8df8564c51907321f6a187
Signed-off-by: Erin Kalousková <erin.kalouskova at nic.cz>
---
src/dhcpv6-ia.c | 12 +++++++-
src/odhcpd.h | 6 ++++
src/ubus.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index 8cc9515..ea8a63b 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -208,7 +208,7 @@ static void dhcpv6_ia_free_assignment(struct
dhcp_assignment *a)
close(a->managed_sock.fd.fd);
}
- if ((a->flags & OAF_BOUND) && (a->flags & OAF_DHCPV6_PD))
+ if (a->flags & OAF_BOUND)
apply_lease(a, false);
if (a->fr_cnt)
@@ -591,6 +591,10 @@ void dhcpv6_ia_write_statefile(void)
static void __apply_lease(struct dhcp_assignment *a,
struct odhcpd_ipaddr *addrs, ssize_t addr_len, bool add)
{
+ #ifdef WITH_UBUS
+ ubus_bcast_dhcp6_event(add ? "dhcpv6.ack" : "dhcpv6.release", a,
addr_len, addrs);
+ #endif
+
if (a->flags & OAF_DHCPV6_NA)
return;
@@ -844,6 +848,9 @@ static bool assign_na(struct interface *iface,
struct dhcp_assignment *a)
list_for_each_entry(c, &iface->ia_assignments, head) {
if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id >
a->assigned_host_id ) {
list_add_tail(&a->head, &c->head);
+ if (a->flags &OAF_BOUND)
+ apply_lease(a, true);
+
return true;
} else if (c->assigned_host_id == a->assigned_host_id)
return false;
@@ -891,6 +898,9 @@ static bool assign_na(struct interface *iface,
struct dhcp_assignment *a)
if (!(c->flags & OAF_DHCPV6_NA) || c->assigned_host_id > try) {
a->assigned_host_id = try;
list_add_tail(&a->head, &c->head);
+ if (a->flags &OAF_BOUND)
+ apply_lease(a, true);
+
return true;
} else if (c->assigned_host_id == try)
break;
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 916d6da..ee4b6f5 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -510,6 +510,12 @@ void ubus_apply_network(void);
bool ubus_has_prefix(const char *name, const char *ifname);
void ubus_bcast_dhcp_event(const char *type, const uint8_t *mac, const
size_t mac_len,
const struct in_addr *addr, const char *name, const char *interface);
+void ubus_bcast_dhcp6_event(
+ const char* type,
+ const struct dhcp_assignment *assignment,
+ size_t addrs_len,
+ const struct odhcpd_ipaddr addrs[static addrs_len]
+);
#endif
ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct
interface *iface,
diff --git a/src/ubus.c b/src/ubus.c
index 00fd171..f5ebc95 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -1,3 +1,4 @@
+#include <stdint.h>
#include <syslog.h>
#include <libubus.h>
#include <libubox/uloop.h>
@@ -6,7 +7,9 @@
#include <inttypes.h>
#include <libubox/utils.h>
+#include <time.h>
+#include "libubox/blobmsg.h"
#include "odhcpd.h"
#include "dhcpv6.h"
#include "dhcpv4.h"
@@ -416,6 +419,85 @@ void ubus_bcast_dhcp_event(const char *type, const
uint8_t *mac,
ubus_notify(ubus, &main_object, type, b.head, -1);
}
+void ubus_bcast_dhcp6_event(
+ const char* type,
+ const struct dhcp_assignment *assignment,
+ size_t addrs_len_,
+ const struct odhcpd_ipaddr addrs[static addrs_len_]
+) {
+ if (
+ type == NULL
+ || assignment == NULL
+ || (addrs_len_ != 0 && addrs == NULL)
+ || addrs_len_ > PTRDIFF_MAX
+ ) {
+ fputs(stderr, "[ubus_bcast_dhcp6_event]: parameter assertion failed");
+ return;
+ }
+
+ ptrdiff_t addrs_len = addrs_len_;
+
+ if (ubus == NULL || !main_object.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ if (assignment->hostname != NULL)
+ blobmsg_add_string(&b, "hostname", assignment->hostname);
+
+ if (assignment->iface != NULL && assignment->iface->ifname != NULL)
+ blobmsg_add_string(&b, "interface", assignment->iface->ifname);
+
+ if (assignment->iaid != 0)
+ blobmsg_add_u32(&b, "iaid", ntohl(assignment->iaid));
+
+ if (assignment->clid_len != 0) {
+ char *duid_buf = blobmsg_alloc_string_buffer(&b, "duid",
assignment->clid_len * 2 + 1);
+ odhcpd_hexlify(duid_buf, assignment->clid_data, assignment->clid_len);
+ blobmsg_add_string_buffer(&b);
+ }
+
+ blobmsg_add_u8(&b, "accept-reconf", assignment->accept_fr_nonce);
+ blobmsg_add_u64(&b, "valid-until", assignment->valid_until);
+ blobmsg_add_u64(&b, "preferred-until", assignment->preferred_until);
+
+ if (assignment->flags & OAF_DHCPV6_NA)
+ blobmsg_add_u64(&b, "assigned", assignment->assigned_host_id);
+ else
+ blobmsg_add_u16(&b, "assigned", assignment->assigned_subnet_id);
+
+ {
+ void *array_h = blobmsg_open_array(&b, "flags");
+ if (assignment->flags & OAF_BOUND)
+ blobmsg_add_string(&b, NULL, "bound");
+
+ if (assignment->flags & OAF_STATIC)
+ blobmsg_add_string(&b, NULL, "static");
+
+ blobmsg_close_array(&b, array_h);
+ }
+
+ void *array_h = blobmsg_open_array(&b, assignment->flags &
OAF_DHCPV6_NA ? "ipv6-addr" : "ipv6-prefix");
+ for (ptrdiff_t ix = 0; ix != addrs_len; ++ix) {
+ const struct odhcpd_ipaddr *entry = &addrs[ix];
+
+ void *table_h = blobmsg_open_table(&b, NULL);
+
+ char *addr_buf = blobmsg_alloc_string_buffer(&b, "address",
INET6_ADDRSTRLEN);
+ memset(addr_buf, 0, INET6_ADDRSTRLEN);
+
+ (void) inet_ntop(AF_INET6, &entry->addr.in6, addr_buf, INET6_ADDRSTRLEN);
+ blobmsg_add_string_buffer(&b);
+
+ if (entry->prefix != 128)
+ blobmsg_add_u32(&b, "prefix-length", entry->prefix);
+
+ blobmsg_close_table(&b, table_h);
+ }
+
+ blobmsg_close_array(&b, array_h);
+ ubus_notify(ubus, &main_object, type, b.head, -1);
+}
+
static void handle_event(_unused struct ubus_context *ctx, _unused
struct ubus_event_handler *ev,
_unused const char *type, struct blob_attr *msg)
{
--
2.52.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0x399339FCF5EEBDCF.asc
Type: application/pgp-keys
Size: 656 bytes
Desc: OpenPGP public key
URL: <http://lists.openwrt.org/pipermail/openwrt-devel/attachments/20251126/4820bd8a/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 236 bytes
Desc: OpenPGP digital signature
URL: <http://lists.openwrt.org/pipermail/openwrt-devel/attachments/20251126/4820bd8a/attachment.sig>
More information about the openwrt-devel
mailing list