project/odhcpd.git
5 hours agostatefiles: fix stale pio handling for !ubus master
David Härdeman [Sun, 30 Nov 2025 22:13:39 +0000 (23:13 +0100)]
statefiles: fix stale pio handling for !ubus

Currently, config.c:odhcpd_reload() will call:
set_config()
// the piodir is set here
set_interface()
config_parse_interface()
statefiles_read_prefix_information()
statefiles_setup_dirfd()
ubus_apply_network()
config_parse_interface()
statefiles_read_prefix_information()

This works when ubus is enabled, because of the extra call to
ubus_apply_network() which will read the pio file after the
dirfd has been set up.

However, it won't work when ubus isn't enabled since it'll
turn ubus_apply_network() into a noop.

Fix this by moving the statefiles_setup_dirfd() calls into
set_config(), i.e. setup the dirfds as soon as the relevant
cfg options have been read.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 hours agoodhcpd: rename piofolder to piodir
David Härdeman [Sun, 30 Nov 2025 20:59:33 +0000 (21:59 +0100)]
odhcpd: rename piofolder to piodir

A "folder" is a Windows concept, rename the cfg option from "piofolder"
to "piodir", which will also make it more consistent with other cfg
options.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 hours agostatefiles: use tmpfile functions for pio files
David Härdeman [Fri, 28 Nov 2025 11:43:22 +0000 (12:43 +0100)]
statefiles: use tmpfile functions for pio files

Reduce code duplication by using the same tmpfile functions
for pio handling as well.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 hours agostatefiles: rename prefix information functions
David Härdeman [Fri, 28 Nov 2025 11:07:04 +0000 (12:07 +0100)]
statefiles: rename prefix information functions

This makes it clearer that the functions are in statefiles.c.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
6 hours agoconfig: move pio json handling to statefiles.c
David Härdeman [Fri, 28 Nov 2025 10:48:59 +0000 (11:48 +0100)]
config: move pio json handling to statefiles.c

The prefix information files are also examples of statefiles, and there
are some things which can be shared between e.g. the state file logic
and the pio file logic (like the conversion from MONOTIME to time_t and
back, and also the use of tmp files). That's for later patches though,
this just moves the code without any code changes to make subsequent
patches clearer.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
6 hours agostatefiles: add a dirfd helper function
David Härdeman [Fri, 28 Nov 2025 10:35:49 +0000 (11:35 +0100)]
statefiles: add a dirfd helper function

The same logic was repeated three times in config.c, move it
to a single function in statefiles.c.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
6 hours agostatefiles: add tmp helper functions
David Härdeman [Fri, 28 Nov 2025 10:16:23 +0000 (11:16 +0100)]
statefiles: add tmp helper functions

Move temporary file creation/finishing to separate functions.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/333
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
6 hours agostatefiles: fix escape sequence for broken hostname output
Kevin Darbyshire-Bryant [Fri, 5 Dec 2025 08:09:14 +0000 (08:09 +0000)]
statefiles: fix escape sequence for broken hostname output

Broken hostnames are being reported as "broken\x20-"
instead of "broken -" which I'm guessing is what was
intended.

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Link: https://github.com/openwrt/odhcpd/pull/340
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
7 hours agodhcpv4: don't send zero IPv6-only preferred option
David Härdeman [Tue, 9 Dec 2025 08:21:11 +0000 (09:21 +0100)]
dhcpv4: don't send zero IPv6-only preferred option

As noted in https://github.com/openwrt/openwrt/issues/21048, if the
ipv6_only_preferred option isn't set (or is set to zero), odhcpd will
still include the IPv6-Only Preferred option (with a zero value) in
DHCPv4 replies, while it should not return the option at all.

Closes: https://github.com/openwrt/openwrt/issues/21048
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/341
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 days agoRevert "dhcpv6-ia: add some noise to the T1 and T2 periods"
Kevin Darbyshire-Bryant [Fri, 5 Dec 2025 20:51:28 +0000 (20:51 +0000)]
Revert "dhcpv6-ia: add some noise to the T1 and T2 periods"

Accidental push to wrong branch/repo

This reverts commit 81ea5bfef775b8e2d4aae9826e84a040288864df.

4 days agoRevert "do not delegate ULA prefixes"
Kevin Darbyshire-Bryant [Fri, 5 Dec 2025 20:50:29 +0000 (20:50 +0000)]
Revert "do not delegate ULA prefixes"

Accidental push to wrong branch - oops

This reverts commit fd4714bb2dfec0fadf5b49f21487f37f4613dc0f.

4 days agodo not delegate ULA prefixes
Kevin Darbyshire-Bryant [Sat, 30 Dec 2023 11:32:55 +0000 (11:32 +0000)]
do not delegate ULA prefixes

4 days agodhcpv6-ia: add some noise to the T1 and T2 periods
Kevin Darbyshire-Bryant [Sun, 5 Nov 2023 15:43:27 +0000 (15:43 +0000)]
dhcpv6-ia: add some noise to the T1 and T2 periods

Without this, all the clients get the same timeouts and try to renew
addresses at the same time.  Reduce the T1 & T2 by a pseudo random 0 to
127 seconds, thus the renew attempts are likely to be spread out a bit
in time.

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
5 days agorouter: skip if branch in PIO clear functions
Álvaro Fernández Rojas [Thu, 4 Dec 2025 14:48:44 +0000 (15:48 +0100)]
router: skip if branch in PIO clear functions

We can skip the if branch that replaces the expired/duplicated ra_pio
value in the router_clear_*_ra_pio() functions.

Suggested-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/336
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 days agorouter: optimize duplicated PIO comparison
Álvaro Fernández Rojas [Thu, 4 Dec 2025 14:38:20 +0000 (15:38 +0100)]
router: optimize duplicated PIO comparison

Compare prefix and length with a single memcmp instead of performing
separate comparisons.

Suggested-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/336
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 days agorouter: remove duplicated PIOs
Álvaro Fernández Rojas [Mon, 1 Dec 2025 10:07:43 +0000 (11:07 +0100)]
router: remove duplicated PIOs

There can be duplicated PIOs if the user changed the assigned prefix length
in the configuration.

Link: https://github.com/openwrt/odhcpd/pull/336
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
5 days agorouter: rename router_clear_ra_pio
Álvaro Fernández Rojas [Wed, 3 Dec 2025 07:26:33 +0000 (08:26 +0100)]
router: rename router_clear_ra_pio

This function clears the expired RA PIOs, so router_clear_expired_ra_pio
is a better name.

Link: https://github.com/openwrt/odhcpd/pull/336
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
7 days agorouter: improve RA PIO search logic
Álvaro Fernández Rojas [Fri, 28 Nov 2025 09:39:42 +0000 (10:39 +0100)]
router: improve RA PIO search logic

We need to properly handle when the user modifies the prefix length
assigned to an interface by:
- Checking if the prefix matches the address taking into account:
    - The biggest length of address and PIO.
    - A minimum PIO of /64.
- Updating addresses and lengths for existing PIOs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
7 days agoformal: fix workflow permissions
George Sapkin [Wed, 26 Nov 2025 13:33:30 +0000 (15:33 +0200)]
formal: fix workflow permissions

Fix formality check permissions that are needed to post optional
summaries back to the PR.

Link: openwrt/actions-shared-workflows#64
Signed-off-by: George Sapkin <george@sapk.in>
Link: https://github.com/openwrt/odhcpd/pull/325
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
8 days agobuild: disable static libraries
Álvaro Fernández Rojas [Sun, 30 Nov 2025 23:41:12 +0000 (00:41 +0100)]
build: disable static libraries

Allows linking against shared json-c, which reduces the binary size and
matches the OpenWrt package binary.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
8 days agodhcpv6-ia: fix crash in dhcpv6_free_lease()
David Härdeman [Mon, 1 Dec 2025 07:37:32 +0000 (08:37 +0100)]
dhcpv6-ia: fix crash in dhcpv6_free_lease()

Note that dhcpv6_free_lease() can be called with a NULL argument e.g.
from dhcpv6_ia_handle_IAs() when iface->no_dynamic_dhcp is set and a
client without a static lease cfg tries to get a dynamic lease.

Closes: #321
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/335
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
8 days agobuild: fix BUILD_ARGS
Álvaro Fernández Rojas [Mon, 1 Dec 2025 08:02:50 +0000 (09:02 +0100)]
build: fix BUILD_ARGS

Commit ef8de928da7f forced DHCPV4_SUPPORT and UBUS cmake options, but should
have fixed BUILD_ARGS instead (-WITH_UBUS=ON -> -DUBUS=ON).

Fixes: ef8de928da7f ("build: enable DHCPV4_SUPPORT and UBUS")
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agostatefiles: change ipv4 MAC statefile syntax
David Härdeman [Sun, 30 Nov 2025 18:14:17 +0000 (19:14 +0100)]
statefiles: change ipv4 MAC statefile syntax

This changes the MAC representation in the lease/statefile so that it
reads "aa:bb:cc:dd:ee:ff" instead of "aabbccddeeff".

No functional changes, but this makes it easier to parse the statefile
in rpcd-mod-luci (for reporting the MAC addresses in LuCI).

We should probably change lease->hwaddr to be a struct ether_addr,
to make it clearer that we only support MAC addresses as hwaddr,
but that's a topic for a different PR.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/332
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agoodhcpd: remove OAF_BOUND
David Härdeman [Thu, 27 Nov 2025 17:02:11 +0000 (18:02 +0100)]
odhcpd: remove OAF_BOUND

Replace the OAF_BOUND flag with a simple boolean.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/331
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agodhcpv6: remove OAF_TENTATIVE
David Härdeman [Sun, 23 Nov 2025 23:32:22 +0000 (00:32 +0100)]
dhcpv6: remove OAF_TENTATIVE

The flag was only set in two places, and never used. Its meaning was
also essentially the inverse of OAF_BOUND.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/331
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agoodhcpd: remove OAF_STATIC
David Härdeman [Sun, 23 Nov 2025 23:19:15 +0000 (00:19 +0100)]
odhcpd: remove OAF_STATIC

This flag does nothing more than document if lease_cfg is set in the
respective dhcpv[46]_lease structs.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/331
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agoodhcpd: remove OAF_BROKEN_HOSTNAME
David Härdeman [Sun, 23 Nov 2025 23:05:33 +0000 (00:05 +0100)]
odhcpd: remove OAF_BROKEN_HOSTNAME

A bool is quite a bit more ergonomic (as the diff for this commit
shows).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/331
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
9 days agostatefiles: remove hosts entries from statefile
David Härdeman [Sun, 23 Nov 2025 22:38:04 +0000 (23:38 +0100)]
statefiles: remove hosts entries from statefile

Further simplify statefiles.c by removing the hosts entries from the
statefile (they can be found in the dedicated hosts files instead).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/331
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
11 days agobuild: enable DHCPV4_SUPPORT and UBUS
Álvaro Fernández Rojas [Fri, 28 Nov 2025 11:48:11 +0000 (12:48 +0100)]
build: enable DHCPV4_SUPPORT and UBUS

Enable DHCPV4_SUPPORT and UBUS in order to correctly build all the source
code.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
11 days agoubus: fix shadow local variable
Álvaro Fernández Rojas [Fri, 28 Nov 2025 11:46:38 +0000 (12:46 +0100)]
ubus: fix shadow local variable

Fix leftover shadowed local variable in ubus code from commit a170d63874f2.

src/ubus.c:130:38: error: declaration of 'a' shadows a previous local [-Werror=shadow=local]
  130 |                 struct dhcpv6_lease *a, *border;
      |                                      ^
src/ubus.c:118:15: note: shadowed declaration is here
  118 |         void *a;
      |               ^

Fixes: a170d63874f2 ("src: fix shadowed local variables")
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
11 days agosrc: fix shadowed local variables
Álvaro Fernández Rojas [Fri, 28 Nov 2025 07:32:10 +0000 (08:32 +0100)]
src: fix shadowed local variables

Fix shadowed local variables and enable warning to prevent more shadowed
variables in the future.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
11 days agodhcpv6-ia: fix a crash when static lease isn't configured
David Härdeman [Thu, 27 Nov 2025 23:30:59 +0000 (00:30 +0100)]
dhcpv6-ia: fix a crash when static lease isn't configured

Quoting from https://github.com/openwrt/odhcpd/issues/321:
  [71802.880039] odhcpd[22696]: segfault at 78...

Quoting from https://forum.openwrt.org/t/odhcpd-crash-loop-when-receiving-packet/243015/69:
  [   77.761062] odhcpd[2075]: segfault at 78...

0x78 is the offset of duid_count in struct lease_cfg, so if lease_cfg is
null, we'd end up reading from address 0x78 when trying to read
lease_cfg->duid_count.

This should fix the issue. Thanks to @klipz in the forums for giving me
SSH access to an awesome test sandbox.

Closes: https://github.com/openwrt/odhcpd/issues/321
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/328
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
11 days agodhcpv4: support IPv6-only preferred (RFC8925)
David Härdeman [Sun, 23 Nov 2025 18:17:04 +0000 (19:17 +0100)]
dhcpv4: support IPv6-only preferred (RFC8925)

This adds support for RFC8925/IPv6-only preferred to the DHCPv4 server.

Closes: https://github.com/openwrt/odhcpd/pull/235
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/327
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv6-ia: fix realloc bug
David Härdeman [Thu, 27 Nov 2025 10:35:09 +0000 (11:35 +0100)]
dhcpv6-ia: fix realloc bug

Commit b9db4d7061a08bf82a25222074065cce71973d0c introduced a bug, the
"hostname" variable used for the realloc would shadow the real hostname
defined at the beginning of the function. Fix this by using a different
variable name.

Fixes: b9db4d7061a0 ("dhcpv6: handle realloc failure")
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/326
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agonetlink: make it clearer that we're handling realloc correctly
David Härdeman [Sun, 23 Nov 2025 14:15:33 +0000 (15:15 +0100)]
netlink: make it clearer that we're handling realloc correctly

This doesn't really change the code, it just makes it clearer when
grepping for realloc() that failure is handled correctly.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv6: handle realloc failure
David Härdeman [Sun, 23 Nov 2025 14:12:01 +0000 (15:12 +0100)]
dhcpv6: handle realloc failure

Another realloc failure case.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoconfig: handle realloc failure in piofolder parsing
David Härdeman [Sun, 23 Nov 2025 14:00:45 +0000 (15:00 +0100)]
config: handle realloc failure in piofolder parsing

Another realloc that goes unchecked.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoconfig: fix realloc() error handling for "dhcpv6_raw" option
David Härdeman [Sun, 23 Nov 2025 13:53:35 +0000 (14:53 +0100)]
config: fix realloc() error handling for "dhcpv6_raw" option

Check the return value from realloc() to avoid leaking memory.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoconfig: fix realloc() handling for the "upstream" option
David Härdeman [Sun, 23 Nov 2025 13:50:00 +0000 (14:50 +0100)]
config: fix realloc() handling for the "upstream" option

Deal properly with realloc() failure.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoconfig: fix (S)NTP realloc handling
David Härdeman [Sun, 23 Nov 2025 13:46:49 +0000 (14:46 +0100)]
config: fix (S)NTP realloc handling

Make sure that realloc errors are dealt with properly in the (S)NTP
option parsing.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: iface->dhcpv4_router -> iface->dhcpv4_routers
David Härdeman [Sat, 22 Nov 2025 09:13:02 +0000 (10:13 +0100)]
dhcpv4: iface->dhcpv4_router -> iface->dhcpv4_routers

This makes it clearer that the variable stores multiple addresses, also
fix a potential realloc memleak.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoodhcpd: rename iface->search -> iface->dns_search
David Härdeman [Thu, 20 Nov 2025 16:17:49 +0000 (17:17 +0100)]
odhcpd: rename iface->search -> iface->dns_search

And fix some bugs/nits in the process, e.g.:
 - realloc() not handled properly in config.c
 - replace a number of magic values
 - in router.c, the DNSSL options has 8 bytes of superfluous padding

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoodhcpd: consistent dns naming
David Härdeman [Thu, 20 Nov 2025 15:25:26 +0000 (16:25 +0100)]
odhcpd: consistent dns naming

Rename iface->dns to iface->dns6_addrs
Rename iface->dhcpv4_dns to iface->dns4_addrs

This makes it clearer what is stored in each.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: remove iface->dhcpv4_bcast
David Härdeman [Thu, 20 Nov 2025 12:51:25 +0000 (13:51 +0100)]
dhcpv4: remove iface->dhcpv4_bcast

This is also covered by iface->dhcpv4_own_ip

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: remove iface->dhcpv4_mask
David Härdeman [Thu, 20 Nov 2025 12:47:13 +0000 (13:47 +0100)]
dhcpv4: remove iface->dhcpv4_mask

This is already covered by iface->dhcpv4_own_ip

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: rename iface->dhcpv4_local -> iface->dhcpv4_own_ip
David Härdeman [Wed, 19 Nov 2025 23:29:18 +0000 (00:29 +0100)]
dhcpv4: rename iface->dhcpv4_local -> iface->dhcpv4_own_ip

"local" isn't very informative, the local what?

In addition, use a struct odhpd_ipaddr instead of a struct in_addr, the
former can already store the prefix_len, broadcast and netmask address,
this will allow the separate iface->dhcpv4_bcast and iface->dhcpv4_mask
members to be removed (see subsequent patches).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: simplify pool determination
David Härdeman [Wed, 19 Nov 2025 18:43:36 +0000 (19:43 +0100)]
dhcpv4: simplify pool determination

This simplifies the logic to determine a dynamic dhcp pool range based
on the prefix length (when "start" and "limit" aren't set).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agonetlink: add netmask for IPv4
David Härdeman [Tue, 18 Nov 2025 07:55:41 +0000 (08:55 +0100)]
netlink: add netmask for IPv4

Add a netmask member to struct odhcpd_ipaddr, this is mostly for
convenience.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agonetlink: variable naming cleanup
David Härdeman [Tue, 18 Nov 2025 07:53:37 +0000 (08:53 +0100)]
netlink: variable naming cleanup

Correct some comments, use boolean where a boolean value is expected,
rename more "struct odhcpd_ipaddr" variables to indicate that it is a
struct odhcpd_ipaddr and indicate plural/IPv4/IPv6 in the variable
names.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: fix no_dynamic_dhcp
David Härdeman [Mon, 17 Nov 2025 23:32:21 +0000 (00:32 +0100)]
dhcpv4: fix no_dynamic_dhcp

This fixes the support for running with no_dynamic_dhcp in the DHCPv4
server.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoodhcpd: rename iface->addr4 -> iface->oaddrs4
David Härdeman [Mon, 17 Nov 2025 22:58:48 +0000 (23:58 +0100)]
odhcpd: rename iface->addr4 -> iface->oaddrs4

Rename iface->addr4 to iface->oaddrs4, to make it clearer from a cursory
glance that this isn't e.g. "struct in_addr" addresses but a number of
"struct odhcpd_ipaddr" addresses.

At the same time, rename iface->addr4_len to iface->oaddrs4_cnt, to make
it clear that this is a count and not e.g. an allocation length.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoodhcpd: rename prefix -> prefix_len
David Härdeman [Mon, 17 Nov 2025 22:37:50 +0000 (23:37 +0100)]
odhcpd: rename prefix -> prefix_len

Change a bunch of places where a prefix length is stored as "prefix" to
instead call the length "prefix_len", to make it clearer that it is not
a prefix that is stored.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agoodhcpd: rename union if_addr -> in46_addr
David Härdeman [Mon, 17 Nov 2025 22:11:08 +0000 (23:11 +0100)]
odhcpd: rename union if_addr -> in46_addr

Anyone reading "union if_addr" might be tempted to think it's got
something to do with an interface addr (e.g. a MAC, or something). In
reality, it's an IPv4/IPv6 addr (i.e. struct in_addr or struct
in6_addr), so rename it to make things clearer.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
12 days agodhcpv4: improve pool var naming
David Härdeman [Mon, 17 Nov 2025 21:51:34 +0000 (22:51 +0100)]
dhcpv4: improve pool var naming

The uci cfg options might have somewhat confusing names, but
that doesn't mean we have to perpetuate those names throughout the
source.

Also, move the checking of whether the pool parameters from when
we are setting up a pool to where the cfg variables are actually set
from config.

Finally, there's no need to store the pool start and end as "struct
in_addr" in struct interface, because the start and end actually aren't
IPv4 addresses.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agondp: correctness fix for BPF filter
David Härdeman [Fri, 17 Oct 2025 13:32:08 +0000 (15:32 +0200)]
ndp: correctness fix for BPF filter

Note that AF_PACKET sockets start receiving packets as soon as they are
created.  Thus, a packet can arrive between the creation of the socket
and the time the real filter is installed. Fix this using the same
technique as used in libpcap, i.e. by installing a drop-all filter,
removing any packets from the socket, then installing the real filter
later (an atomic operation which replaces the drop filter).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/319
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agodhcpv4: add BPF to dhcpv4_setup_interface()
David Härdeman [Fri, 17 Oct 2025 12:49:25 +0000 (14:49 +0200)]
dhcpv4: add BPF to dhcpv4_setup_interface()

This means the kernel won't even pass packets which we are not
interested in.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/318
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agodhcpv4: define val where it is used in dhcpv4_setup_interface()
David Härdeman [Fri, 17 Oct 2025 11:59:37 +0000 (13:59 +0200)]
dhcpv4: define val where it is used in dhcpv4_setup_interface()

This makes it a tiny bit easier to see immediately what "val" is.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/318
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agodhcpv4: simplify error handling in dhcpv4_setup_interface()
David Härdeman [Fri, 17 Oct 2025 11:57:14 +0000 (13:57 +0200)]
dhcpv4: simplify error handling in dhcpv4_setup_interface()

Remove the "ret" variable which can anyway always just be -1 on error,
and rename the "out" label to "error" to clarify that it's only used on
error.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/318
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agodhcvp4: use tmp fd in dhcpv4_setup_interface()
David Härdeman [Fri, 17 Oct 2025 11:54:50 +0000 (13:54 +0200)]
dhcvp4: use tmp fd in dhcpv4_setup_interface()

This makes the code a little bit easier to read.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/318
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agodhcpv4: replace ToS precedence
David Härdeman [Fri, 17 Oct 2025 11:43:17 +0000 (13:43 +0200)]
dhcpv4: replace ToS precedence

The IPTOS_PREC_* values are deprecated since RFC2474 §4.2.2.1 (Dec 1998)
replaced them with class selector codepoints.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/318
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
2 weeks agostatefiles: fix off-by-one-bug
David Härdeman [Sun, 23 Nov 2025 18:34:51 +0000 (19:34 +0100)]
statefiles: fix off-by-one-bug

The string with the final hostsfile name is "%s.%s", so we need two
extra bytes for the separating "." and for the trailing null byte.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/322
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoall: implement RFC8910 captive portal (CP) option for DHCPv4
Paul Donald [Mon, 17 Nov 2025 19:43:15 +0000 (20:43 +0100)]
all: implement RFC8910 captive portal (CP) option for DHCPv4

https://www.rfc-editor.org/rfc/rfc8910.html

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/315
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoall: implement RFC8910 captive portal (CP) option
Paul Donald [Sun, 16 Nov 2025 12:47:34 +0000 (13:47 +0100)]
all: implement RFC8910 captive portal (CP) option

https://www.rfc-editor.org/rfc/rfc8910.html

RFC8910 defines a captive portal API URI for a CP client to consume.

With captive_portal_uri set to 'https://test.example.com'

Produces in RA:

ICMPv6 Option (DHCP Captive-Portal)
    Type: DHCP Captive-Portal (37)
    Length: 4 (32 bytes)
    Captive Portal: https://test.example.com

And in DHCPv6 Reply:

Captive Portal
    Option: Captive Portal (103)
    Length: 24
    Captive Portal: https://test.example.com

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/315
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agogithub: ci: add MIPS64, PowerPC64 and RISCV64
Álvaro Fernández Rojas [Mon, 17 Nov 2025 14:58:49 +0000 (15:58 +0100)]
github: ci: add MIPS64, PowerPC64 and RISCV64

MIPS64, PowerPC64 and RISCV64 are popular OpenWrt archs.
Refactor the sizes build step to generate the table programatically.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agorouter: Modify relayed RA PIO L and RA M/O flags according to interface policy
Paul Donald [Fri, 7 Nov 2025 18:54:41 +0000 (19:54 +0100)]
router: Modify relayed RA PIO L and RA M/O flags according to interface policy

Effectively:
-clear the L flag
-apply local M and O flags if we are not DHCPv6 relay mode

h/t user @Shine-

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/300
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agodhcpv6: prevent network loop scenario
Paul Donald [Mon, 17 Nov 2025 01:15:51 +0000 (02:15 +0100)]
dhcpv6: prevent network loop scenario

It's possible for odhcpd to talk with its (odhcp6c) self in a network loop
scenario with strange results. Prevent this by returning early.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/314
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agodhcpv4: simplify random address selection
David Härdeman [Sat, 11 Oct 2025 09:25:26 +0000 (11:25 +0200)]
dhcpv4: simplify random address selection

Simplify the generation of random addresses, and make the code easier
to follow, by using the same approach as in dhcpv6.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/313
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoodhcpd: update devel-build.sh
David Härdeman [Sun, 16 Nov 2025 20:10:40 +0000 (21:10 +0100)]
odhcpd: update devel-build.sh

Now that ubus can be disabled at runtime, we can default to building
it in, making it easier to catch compile-time errors in ubus.c.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/312
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoodhcpd: make ubus optional at runtime
David Härdeman [Sun, 16 Nov 2025 17:55:59 +0000 (18:55 +0100)]
odhcpd: make ubus optional at runtime

This is mostly for developer convenience, allowing ubus to be built in, but
disabled at will when launching odhcpd.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/312
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoodhcpd: simplify signal handling
David Härdeman [Sun, 16 Nov 2025 13:00:36 +0000 (14:00 +0100)]
odhcpd: simplify signal handling

Currently, odhcpd's main() function will:
 - call uloop_init()
 - set up some signal handlers for SIGUSR1/SIGINT/SIGTERM
   (SIGUSR1 is ignored, the other handlers call uloop_end())
 - call odhcpd_run(), which will:
 - set up some signal handlers for SIGTERM/SIGINT/SIGHUP
   (the first two call uloop_end(), SIGHUP calls odhcpd_reload())

Note that uloop_init() will call uloop_setup_signals() which will call
uloop_setup_signals() which will install handlers for SIGINT/SIGTERM
which will set uloop_cancelled to true (e.g. the same thing that
uloop_end() does).

In other words, the signal handlers are modified three times, and since
the default "exit" action is to call uloop_end(), there's nothing that
will actually react to signals until uloop_run() is called, meaning that
the startup will be uninterruptible if e.g. ubus_init() fails since
it'll just retry in a loop with no handling of signals.

So, simplify and fix this by letting uloop handle the signals and
checking if uloop has been told to exit, removing a bunch of
special-purpose code.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/312
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agosrc: improve attributes
Álvaro Fernández Rojas [Thu, 13 Nov 2025 10:28:12 +0000 (11:28 +0100)]
src: improve attributes

- Properly guard odhcp6c.h attributes with `#ifndef` to avoid redefining
them when including external headers.
- Also convert the remaining __attribute__ usages to the custom
declarations.
- Consolidate custom declarations with _o_ prefix.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/307
3 weeks agosrc: consolidate and improve fallthrough
Álvaro Fernández Rojas [Fri, 14 Nov 2025 06:57:21 +0000 (07:57 +0100)]
src: consolidate and improve fallthrough

- Enable fallthrough warnings.
- Use fallthrough attribute instead of comments.
- Drop unneeded fallthroughs (no code between two case statements).

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/307
3 weeks agodhcpv6-ia: add missing limits header
Álvaro Fernández Rojas [Fri, 14 Nov 2025 16:42:35 +0000 (17:42 +0100)]
dhcpv6-ia: add missing limits header

Fix the following build error by including <limits.h>:
src/dhcpv6-ia.c: In function 'handle_addrlist_change':
src/dhcpv6-ia.c:495:53: error: 'INT_MAX' undeclared (first use in this function)
  495 |                                         a->fr_cnt = INT_MAX;
      |                                                     ^~~~~~~
src/dhcpv6-ia.c:33:1: note: 'INT_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?
   32 | #include <libubox/md5.h>
  +++ |+#include <limits.h>
   33 |
src/dhcpv6-ia.c:495:53: note: each undeclared identifier is reported only once for each function it appears in
  495 |                                         a->fr_cnt = INT_MAX;
      |                                                     ^~~~~~~

Fixes: 7136fbe390a5 ("dhcpv6-ia: split statefile handling to separate file")
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Link: https://github.com/openwrt/odhcpd/pull/311
3 weeks agoconfig: fix memleak during odhcpd reload
Fei Lv [Fri, 14 Nov 2025 07:31:22 +0000 (15:31 +0800)]
config: fix memleak during odhcpd reload

- The memset in close_interface reset the pios pointer before it
  could be freed, causing a memory leak. Relocate the free call
  to clean_interface to ensure proper deallocation.

- Use realloc instead of malloc in config_load_ra_pio()
  This function may be called multiple times during odhcpd reload,
  and using malloc without freeing the previous allocation was
  causing memory leaks.

Signed-off-by: Fei Lv <feilv@asrmicro.com>
Link: https://github.com/openwrt/odhcpd/pull/309
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agodhcpv4: update ubus DHCPv4 events/methods
David Härdeman [Mon, 10 Nov 2025 22:36:27 +0000 (23:36 +0100)]
dhcpv4: update ubus DHCPv4 events/methods

This is based on the assumption that we don't really have any consumers
of ubus DHCPv4 events (yet).

With that in mind, rename and simplify the event function (yes, we
should add a sibling function for DHCPv6 leases later).

Also, take the chance to improve some naming, and introduce additional
attributes to the ubus event/method (the interface name and the
DUID/IAID, if known).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/306
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoodhcpd: rename dhcpv6_lease->clid[_data|_len]
David Härdeman [Mon, 10 Nov 2025 22:19:31 +0000 (23:19 +0100)]
odhcpd: rename dhcpv6_lease->clid[_data|_len]

The option is called clientid, but the option carries a DUID. So what
we're storing is a DUID, not a CLID.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/306
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoodhcpd: rename [lease_cfg|dhcpv4_lease]->ipaddr to ipv4
David Härdeman [Mon, 10 Nov 2025 22:03:25 +0000 (23:03 +0100)]
odhcpd: rename [lease_cfg|dhcpv4_lease]->ipaddr to ipv4

"ipaddr" doesn't say if it's IPv4 or IPv6, and we want to be clear in a
dual-stack codebase.

And at the same time, use a struct in_addr to store the IPv4 address,
which is just less confusing.

Finally, remove all uses of "inet_ntoa()", which is deprecated.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/306
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agodhcpv4: use an AVL to store leases
David Härdeman [Sat, 11 Oct 2025 06:29:07 +0000 (08:29 +0200)]
dhcpv4: use an AVL to store leases

An AVL has O(log n) complexity vs O(n) for a linked list in all the
operations we care about (insertion and search).

Also, it makes the code simpler by not having to care about details like
how to sort the leases.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/306
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agogithub: ci: add powerpc arch
Álvaro Fernández Rojas [Fri, 14 Nov 2025 13:16:16 +0000 (14:16 +0100)]
github: ci: add powerpc arch

PowerPC is another popular OpenWrt arch.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agogithub: ci: add cmake build and source directories
Álvaro Fernández Rojas [Fri, 14 Nov 2025 13:14:34 +0000 (14:14 +0100)]
github: ci: add cmake build and source directories

Add cmake build and source directories to suppress the following warning:
CMake Warning:
  No source or binary directory provided. Both will be assumed to be the
  same as the current working directory, but note that this warning will
  become a fatal error in future CMake releases.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agogithub: ci: disable json-c tests
Álvaro Fernández Rojas [Fri, 14 Nov 2025 07:36:51 +0000 (08:36 +0100)]
github: ci: disable json-c tests

Disable BUILD_TESTING to save time when building json-c.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
3 weeks agoscripts: devel-build: disable json-c tests
Álvaro Fernández Rojas [Fri, 14 Nov 2025 07:35:18 +0000 (08:35 +0100)]
scripts: devel-build: disable json-c tests

Disable BUILD_TESTING to save time when building json-c.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agonetlink: fix typo in debug msg
David Härdeman [Tue, 11 Nov 2025 12:08:22 +0000 (13:08 +0100)]
netlink: fix typo in debug msg

As noted by @CasperVector in #115, there's a typo in netlink.c,
checking if true is true isn't very useful :)

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/305
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agosrc: fix whitespace issues
Álvaro Fernández Rojas [Mon, 10 Nov 2025 12:36:33 +0000 (13:36 +0100)]
src: fix whitespace issues

- Remove double whitespaces.
- Convert whitespace alignments to tabs.
- Fix code comments using whitespaces.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agovscode: enable indentation detection
Álvaro Fernández Rojas [Tue, 11 Nov 2025 11:44:57 +0000 (12:44 +0100)]
vscode: enable indentation detection

Fixes issues with VSCode forcing whitespaces instead of tabs for indentation.

Fixes: df1824aec66c ("vscode: add tab settings")
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agoodhcpd: add support for "ignore"
David Härdeman [Sun, 9 Nov 2025 17:36:03 +0000 (18:36 +0100)]
odhcpd: add support for "ignore"

This is inspired by @Kasoo's work in PR #234, but slightly different.

The "ip" option now takes "ignore" as a value , but it'll only disable
DHCPv4 for a matching client.

Similarly, the "hostid" option now also understands "ignore", which will
disable DHCPv6 for a matching client.

Of course, this is all based on client-reported MAC
addresses/DUIDs/client IDs/etc, so it's not actually a security feature.

Closes: https://github.com/openwrt/odhcpd/pull/234
Closes: https://github.com/openwrt/odhcpd/issues/198
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/303
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: support per-interface hosts files
David Härdeman [Sat, 8 Nov 2025 18:52:44 +0000 (19:52 +0100)]
statefiles: support per-interface hosts files

With this change, the "hostsfile" option is changed to a "hostsdir"
option. If set, per-interface hosts files will be written to the
directory (this requires some changes to the UCI defaults in the OpenWrt
repo). This prevents the hostnames from one interface "leaking" into
other interfaces, which might not be desirable e.g. when running several
instances of dnsmasq.

dnsmasq already supports reading several hosts files from a directory
(via the "--hostsdir=" option), so some changes to dnsmasq's init script
will also be necessary (depending on whether the user wants dnsmasq to
support resolution of all hosts or just the host on a given interface).

Making hosts files (rather than odhcpd's state file) the primary
interface for dnsmasq to be made aware of active leases/hostnames is
also an important first step towards making the statefile properly
private (the other important consumer is LuCI, via its rpcd plugin),
which is necessary if we want to support persisting leases across
restarts of odhcpd (or even reboots, if writing to flash is deemed
acceptable) in the future (since I want to extend the state file to
capture the full state of leases so that they can be properly
reconstructed).

In addition, the use of "--hostsdir=" in dnsmasq would make the
"leasetrigger" unnecessary, since it just restarts dnsmasq to make it
aware of the changes to the hostsfile. That still leaves the case when
dnsmasq uses multiple instances and only wants to read a specific
hostsfile (which, AFAIK, doesn't support automatic detection of when
that specific file changes).

Closes: https://github.com/openwrt/odhcpd/issues/237
Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: don't make hostsfile dependent on statefile
David Härdeman [Sat, 8 Nov 2025 17:33:07 +0000 (18:33 +0100)]
statefiles: don't make hostsfile dependent on statefile

Right now, the hosts file will only be created if the statefile is also
configured (and that fact isn't documented in the README.md, only in
commit logs (see 4bbc6e74248feeb756bd03dc500fb4f446ccfc49).

With this patch, the hostsfile is generated whether the statefile is
configured or not.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: don't write expired leases
David Härdeman [Sat, 8 Nov 2025 17:17:34 +0000 (18:17 +0100)]
statefiles: don't write expired leases

This also aligns the behaviour of state and host files.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: simplify statefiles_write_state6()
David Härdeman [Sat, 8 Nov 2025 17:09:45 +0000 (18:09 +0100)]
statefiles: simplify statefiles_write_state6()

By collecting the addresses first and writing the hosts entries, we can
write the state line straight to the file, without having to use a
buffer as an intermediary. This also makes the ordering in the function
more logical, as it reflects the order things get written to file.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: write straight to file in statefiles_write_state4()
David Härdeman [Sat, 8 Nov 2025 16:48:00 +0000 (17:48 +0100)]
statefiles: write straight to file in statefiles_write_state4()

Instead of writing to a buffer, then to a file, just write straight to
file. This also makes the order of the steps in the function more
logical (i.e. matches the order in which things are actually written to
file).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: correct some comments/variable names
David Härdeman [Sat, 8 Nov 2025 15:17:56 +0000 (16:17 +0100)]
statefiles: correct some comments/variable names

Correct some comments and variable names in statefiles_write_state[46].

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: unify host4 writing
David Härdeman [Sat, 8 Nov 2025 14:56:30 +0000 (15:56 +0100)]
statefiles: unify host4 writing

The statefile contains host entries and state comments. Reuse the host
writing functionality for IPv4 hosts, and remove some duplication.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: unify host6 writing
David Härdeman [Sat, 8 Nov 2025 14:46:14 +0000 (15:46 +0100)]
statefiles: unify host6 writing

The statefile is a mix of state comments and hostsfile entries, reuse the
hosts writing logic when writing the statefile to reduce duplication.
(note that this has a tiny extra cost in that inet_ntop() is called
twice, that'll go away later when we drop the hostsfile style lines from
the statefile).

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: group functions
David Härdeman [Sat, 8 Nov 2025 14:28:49 +0000 (15:28 +0100)]
statefiles: group functions

Move statefiles_write_state6() so that all host/state functions are
grouped together.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: add function to write IPv4 hosts
David Härdeman [Sat, 8 Nov 2025 14:24:13 +0000 (15:24 +0100)]
statefiles: add function to write IPv4 hosts

Analogous to statefiles_write_host6().

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: simplify state/host file writing
David Härdeman [Sat, 8 Nov 2025 14:08:17 +0000 (15:08 +0100)]
statefiles: simplify state/host file writing

Simplify and rename:
dhcpv6_write_ia_addrhosts() -> statefiles_write_host6()
dhcpv6_write_ia_addr() -> statefiles_write_state6()

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: move dhcpv6_ia_enum_addrs() to odhcpd.c
David Härdeman [Sat, 8 Nov 2025 13:40:39 +0000 (14:40 +0100)]
statefiles: move dhcpv6_ia_enum_addrs() to odhcpd.c

dhcpv6_ia_enum_addrs() is used in several different places (ubus,
statesfile, dhcpv6-ia), so move it to a more central location. At the
same time, rename it to odhcpd_enum_addr6().

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: add dhcpv6_lease to dhcpv6_log_ia_addr() args
David Härdeman [Sat, 8 Nov 2025 13:22:23 +0000 (14:22 +0100)]
statefiles: add dhcpv6_lease to dhcpv6_log_ia_addr() args

"lease" is more obvious than "ctxt->c" (which is a struct dhcpv6_lease).
This also means that the lease can be moved out from "struct
write_ctxt", so that the dhcpv4 and dhcpv6 code looks more similar.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
4 weeks agostatefiles: create helper functions to write leases
David Härdeman [Sat, 8 Nov 2025 12:17:58 +0000 (13:17 +0100)]
statefiles: create helper functions to write leases

Break statesfiles_write_state() into smaller parts, making it easier to
read and understand the logic of each part.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>