project/odhcpd.git
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/305
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
3 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 <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/303
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 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 <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agostatefiles: introduce statefiles_write()
David Härdeman [Fri, 7 Nov 2025 16:58:05 +0000 (17:58 +0100)]
statefiles: introduce statefiles_write()

First, the name makes it clearer that several files might be written
(and it doesn't refer to dhcpv6 anymore). This also lays the ground for
the coming patches.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agostatefiles: use dirfd in dhcpv6_ia_write_statefile()
David Härdeman [Fri, 7 Nov 2025 16:53:22 +0000 (17:53 +0100)]
statefiles: use dirfd in dhcpv6_ia_write_statefile()

Similarly to the hostsfile, use a dirfd to keep track of the directory
where the statefile is stored, simplifying the code a bit and avoiding
some more allocations.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agostatefiles: bail early in dhcpv6_ia_write_statefile()
David Härdeman [Fri, 7 Nov 2025 16:30:51 +0000 (17:30 +0100)]
statefiles: bail early in dhcpv6_ia_write_statefile()

Bail early if config.dhcp_statefile isn't set, thus reducing the amount
of indentation in the function. The diff looks pretty gnarly, but that's
diff's fault, the actual code isn't changed at all.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agostatefiles: simplify dhcpv6_ia_write_hostsfile()
David Härdeman [Fri, 7 Nov 2025 16:25:40 +0000 (17:25 +0100)]
statefiles: simplify dhcpv6_ia_write_hostsfile()

Use a dirfd to keep track of the hostsfile directory, also make sure
that the directory is created if necessary (this is in preparation for
writing per-interface hostsfiles).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agodhcpv6-ia: split statefile handling to separate file
David Härdeman [Fri, 7 Nov 2025 15:43:26 +0000 (16:43 +0100)]
dhcpv6-ia: split statefile handling to separate file

dhcpv6-ia.c is already quite long, which makes it harder to work with.
In addition, the whole statefile machinery isn't specific to the dhcpv6
server, but shared by the dhcpv4 and dhcpv6 servers, so split it out to
its own file.

This is in preparation for some more hacking on the statefile handling.

The copyright headers on statefiles.[ch] are the result of some git
archeology, and I've taken the liberty of putting them in REUSE format,
using only the initial copyright year for each contributor (one of the
recommendations from the REUSE project).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/302
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agosrc: replace #pragma once with defines
Álvaro Fernández Rojas [Mon, 10 Nov 2025 12:43:48 +0000 (13:43 +0100)]
src: replace #pragma once with defines

Replace #pragma once with defines since it's not standard.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agosrc: remove whitespaces at EOL
Álvaro Fernández Rojas [Mon, 10 Nov 2025 12:12:46 +0000 (13:12 +0100)]
src: remove whitespaces at EOL

These whitespaces do nothing and can be removed.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agovscode: add tab settings
Álvaro Fernández Rojas [Mon, 10 Nov 2025 12:38:04 +0000 (13:38 +0100)]
vscode: add tab settings

Add tag settings for Visual Studio Code.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agoodhcpd: Implement RFC9762 DHCPv6 PD Preferred flag for PIOs
Paul Donald [Sun, 9 Nov 2025 23:00:05 +0000 (00:00 +0100)]
odhcpd: Implement RFC9762 DHCPv6 PD Preferred flag for PIOs

The RFC defines the P flag for use within PIOs, and defines its meaning
as "purely a positive indicator, telling nodes that DHCPv6 PD is
available and the network prefers that nodes use it".

The RFC abstract lays out:

The (P) flag is used to indicate that the network prefers that clients
use the deployment model in RFC 9663 instead of using individual
addresses in the on-link prefix assigned using SLAAC, or DHCPv6 address
assignment.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/301
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
3 weeks agodhcpv4: add support for RFC4361-style clientid
David Härdeman [Thu, 9 Oct 2025 08:38:23 +0000 (10:38 +0200)]
dhcpv4: add support for RFC4361-style clientid

This adds support for DHCPv6-style client identifiers to the dhcpv4 codebase,
as per RFC4361. It also ensures RFC6842-compliance by including the client
identifier (no matter which kind it is) in replies.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/299
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: remove the "legacy" option
David Härdeman [Sun, 26 Oct 2025 09:19:14 +0000 (10:19 +0100)]
odhcpd: remove the "legacy" option

LuCI has already been updated so that the "dhcpv4" option is exposed in
the UI and the option also gets set when the user clicks the "Set up
DHCP Server" button in the "DHCP Server" tab in the interfaces view.
Furthermore, there are instructions in the UI to enable the DHCPv4
server on a per-interface basis.

Finally, the odhcp defaults script (in the openwrt repo) also sets the dhcpv4
option, as necessary.

People who don't use LuCI but prefer the cmdline should presumably be able to
figure out that the dhcpv4 option needs to be set (if it isn't already), so
remove the "legacy" option.

This supersedes this PR:
https://github.com/openwrt/odhcpd/pull/275

Note that the "maindhcp" option is used by both dnsmasq and odhcpd to control
which of them handles DHCPv4, and is now exposed in the LuCI UI as well, so it
cannot be removed.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: document the "upstream" option
David Härdeman [Sun, 26 Oct 2025 09:12:15 +0000 (10:12 +0100)]
odhcpd: document the "upstream" option

I'm not 100% sure about whether this option will get automagically set e.g. by
the data that is returned from the netifd ubus call, but this documentation is
better than nothing.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: document the "ra_advrouter" option
David Härdeman [Sun, 26 Oct 2025 08:57:03 +0000 (09:57 +0100)]
odhcpd: document the "ra_advrouter" option

Might see little practical use in the field, but the option is there, so let's
document it. Also align the documentation for the "ra_slaac" option.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: remove the "ra_management" option
David Härdeman [Sun, 26 Oct 2025 08:33:17 +0000 (09:33 +0100)]
odhcpd: remove the "ra_management" option

The option is marked as deprecated since 2019 in the odhcpd code base.

It has been superseded by the "ra_flags" and "ra_slaac" options, which provide
more fine-grained control, and having several different configuration options
controlling the same thing is a potential source of confusion.

The option is, and has always been, undocumented.

Furthermore, I've grepped through the LuCI source tree, and it contains logic
to control "ra_flags" and "ra_slaac", but no references to "ra_management" at
all.

The only references in the openwrt tree is inside the dnsmasq init script, but
that is a dnsmasq-internal thing and, again, the option cannot be set from
LuCI, meaning I think we can assume that it has limited usage.

So, remove it.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: remove the "pd_manager" and "pd_cer" options
David Härdeman [Sat, 25 Oct 2025 22:50:18 +0000 (00:50 +0200)]
odhcpd: remove the "pd_manager" and "pd_cer" options

As noted in the previous commit, Homenet is defunct.

The only users of these two options are Homenet/hnetd, so remove the options,
which results in a nice cleanup to src/dhcpv6-ia.c.

We also need to update the Makefile in the main OpenWrt repo.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: remove the "filter_class" option
David Härdeman [Sat, 25 Oct 2025 22:49:22 +0000 (00:49 +0200)]
odhcpd: remove the "filter_class" option

The "filter_class" option was first introduced as part of the effort to support
the Homenet Control Protocol (HNCP, RFC7368, RFC7788). At first it was
hardcoded to filter out the user class "HOMENET", and later it was made
configurable, but there appears to be no other use-cases than Homenet. There's
also legacy comments in the odhcpd code pointing at filtering out homenet user
classes (the comments are misleading since "filter_class" is not set by
default).

Homenet is effectively dead. The "hnetd" daemon last saw any code changes in
2018, doesn't compile with current versions of GCC, and was removed from
OpenWrt altogether in 2025 [1].

The OpenWrt wiki also notes [2] that HNCP is effectively dead, and that the
upstream website [3] is gone.

Searching for the Homenet Control Protocol mostly returns results pointing
either:
a) at the standards
b) at the OpenWrt/hnetd project
c) at various posts stating that it is dead

The IETF working group for Homenet is no more, and Éric Vyncke (Area Director
for the Internet Area of the IETF) mentioned wanting to avoid Homenet pitfalls
[4] (page 11) in the future of IPv6 autoconfig.

The current implementation is also contrary to the spirit of the RFCs
introducing the option (RFC3004 - DHCPv4; RFC8415, §21.15 - DHCPv6) where it is
described (example from RFC8415) as follows:

   The information contained in the data area of this option is
   contained in one or more opaque fields that represent the user class
   or classes of which the client is a member.  A server selects
   configuration information for the client based on the classes
   identified in this option.  For example, the User Class option can be
   used to configure all clients of people in the accounting department
   with a different printer than clients of people in the marketing
   department.

I.e., it's meant to be used in a manner similar to "tags" in dnsmasq.

Finally, the option has been undocumented for the whole existance of odhcpd.

So, remove this option.

[1] https://github.com/openwrt/routing/commit/85b868b3413a29da0bd6ecd3518c2d34a6ffb788
[2] https://openwrt.org/docs/guide-user/network/zeroconfig/hncp_configuration
[3] https://web.archive.org/web/20180831161552/http://homewrt.org/start
[4] https://ripe87.ripe.net/wp-content/uploads/presentations/102-20231130-RIPE-87-IPv6-from-IETF.pdf

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoconfig: drop iface_attr_info
David Härdeman [Fri, 24 Oct 2025 22:19:09 +0000 (00:19 +0200)]
config: drop iface_attr_info

BLOBMSG_TYPE_STRING is the default type for BLOBMSG_TYPE_ARRAY, so this
doesn't add anything.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoREADME.md: add missing options
David Härdeman [Wed, 22 Oct 2025 00:54:46 +0000 (02:54 +0200)]
README.md: add missing options

I did a quick dig through the source, and these are all the options that are
supported but which do not have any corresponding documentation. Subsequent
patches will go through the options one by one.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/294
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agodhcpv4: lazy store statefiles
David Härdeman [Fri, 10 Oct 2025 17:55:36 +0000 (19:55 +0200)]
dhcpv4: lazy store statefiles

Currently, the dhcpv4 server saves the statefile on every change and
also calls the leasetrigger script every time the statefile is updated
(which triggers a dnsmasq reload).

In addition, odhcpd wakes up every second (see dhcpv4_valid_until_cb())
to go through all existing leases to see if any lease has expired.

With this change, the wakeups are reduced to every 5 seconds, and the
statefile is only written (if necessary) during that wakeup.

Before this change (without any leasetrigger, test on my laptop, not a
real OpenWrt device):

$ time sudo ./build/dhcpdig -4 benchmark foo-client

Thread[**]: req 10000101/0 rel 10000101/0 rep 10000101/0

real 55m29.406s
user 0m0.005s
sys 0m0.010s

(This is a simple benchmark tool I wrote, it runs 10 threads which
divide the DHVPv4 pool into 10 chunks and then performs 1 million random
addr req/release per thread in a loop).

After this change:

$ time sudo ./build/dhcpdig -4 benchmark foo-client

Thread[**]: req 10000101/0 rel 10000101/0 rep 10000101/0

real 1m48.123s
user 0m0.005s
sys 0m0.005s

A 3082% speedup.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/298
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agodhcpv6: create struct dhcpv6_lease
David Härdeman [Thu, 9 Oct 2025 05:26:00 +0000 (07:26 +0200)]
dhcpv6: create struct dhcpv6_lease

This concludes the lease/assignment struct saga. "struct dhcp_assignment" is
converted to "struct dhcpv6_lease" and various function names, etc are updated.

I intentionally did *not* change variable names here to keep the patch as
simple as possible. Therefore, the DHCPv6 codebase is still full of lots of
variables named things like "a". I expect that to change over time when I
tackle DHCPv6 code in ernest. But it'll have to do for now.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/292
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agodhcpv4: create struct dhcpv4_lease
David Härdeman [Thu, 9 Oct 2025 05:13:58 +0000 (07:13 +0200)]
dhcpv4: create struct dhcpv4_lease

This makes it easier to understand what is actually going on, makes the
structs clearer and avoids layers of indirection like using free
callbacks. I understand the original motivation for unifying the struct
for DHCPv4 and DHCPv6, but it's more hassle than it is worth.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/292
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoodhcpd: struct lease -> struct lease_cfg
David Härdeman [Sun, 19 Oct 2025 07:47:37 +0000 (09:47 +0200)]
odhcpd: struct lease -> struct lease_cfg

Both the DHCPv4 and DHCPv6 RFCs use the term "lease" to refer to what in the
odhcpd codebase is "struct assignment".

Some examples:

RFC2131, §2.2:

   In this document, the period over which a network address
   is allocated to a client is referred to as a "lease" [11].  The
   client may extend its lease with subsequent requests.  The client may
   issue a message to release the address back to the server when the
   client no longer needs the address.  The client may ask for a
   permanent assignment by asking for an infinite lease.  Even when
   assigning "permanent" addresses, a server may choose to give out
   lengthy but non-infinite leases to allow detection of the fact that
   the client has been retired.

RFC8415, §4.2:

   lease                     A contract by which the server grants the
                             use of an address or delegated prefix to
                             the client for a specified period of time.

For example in §7.3:

   RENEW (5)                 A client sends a Renew message to the
                             server that originally provided the
                             client's leases and configuration
                             parameters to extend the lifetimes on the
                             leases assigned to the client and to update
                             other configuration parameters.

There's also a bit of confusion in the odhcpd codebase, where the two are
sometimes used interchangeably, see e.g. handle_*_leases() in ubus.c which
correspond to the ubus methods "ipv4leases" and "ipv6leases" but which then
returns "assignments", or dhcpv4_lease() in dhcpv4.c, which returns an
"assignment". There's more examples.

To put it differently, "assignment" when used in the RFCs is essentially
the verb, the server assigns, and "lease" is the noun - the server
assigns a lease.

So rename "struct lease" to "struct lease_cfg" to better describe what it is
used for. I.e. it contains the cfg for a host which can provide the parameters
for a static lease (and it comes from a "host" uci section) but it isn't a
*lease* per se.

This is a bit a of pet peeve of mine, but I found it quite confusing when I
first started hacking on odhcpd. It also lays the foundation for later patches
which rework/split/rename "struct assignment".

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/292
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agodhcpv4: use leasetime from a->lease
David Härdeman [Thu, 9 Oct 2025 04:35:26 +0000 (06:35 +0200)]
dhcpv4: use leasetime from a->lease

Note that a->leasetime can ever only be zero or == a->lease->leasetime,
so simplify this a bit in preparation for the next patch.

src/config.c also changes a->leasetime, but always to match
a->lease->leasetime.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/292
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agorouter: always use link-local src address for RAs
David Härdeman [Sun, 2 Nov 2025 18:25:13 +0000 (19:25 +0100)]
router: always use link-local src address for RAs

This is a follow-up to:
https://github.com/openwrt/odhcpd/pull/242

As noted by @willmo [1], RAs are currently not strictly limited to using a
link-local source address, which they should according to RFC4861, §4.2.

This is usually not an issue, since router solicitations typically
originate from link-local source addresses or the undefined address,
meaning that odhcpd will reply with its own link-local address
(auto-selected by the kernel).

But if a solicitation is sent from e.g. a GUA/ULA address, odhpcd will
currently reply using it's own GUA/ULA address.

While fixing this, correct some misleading comments.

[1] https://github.com/openwrt/odhcpd/pull/242#issuecomment-3475020864

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/297
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agorouter: Rewrite the ingress MTU to one configured for the interface
Paul Donald [Tue, 28 Oct 2025 18:28:42 +0000 (19:28 +0100)]
router: Rewrite the ingress MTU to one configured for the interface

There are edge cases where routers forward ICMPv6 RA which contain an MTU which
is too large/small for the receiving client. Override the ingress MTU with the
value configured on the interface.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/296
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agorouter: utilize interface ra_mtu for RA
Paul Donald [Thu, 30 Oct 2025 00:53:44 +0000 (01:53 +0100)]
router: utilize interface ra_mtu for RA

MTU is now set at configure time.

Change ra_mtu to uint32 since it never stores a negative value.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/296
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agoconfig: clamp ra_mtu to interface MTU, and default ra_mtu to interface MTU
Paul Donald [Thu, 30 Oct 2025 00:52:20 +0000 (01:52 +0100)]
config: clamp ra_mtu to interface MTU, and default ra_mtu to interface MTU

Set ra_mtu max to that of its interface. We also default ra_mtu if the user
did not configure it.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/296
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agonetlink: Store interface MTU at link change
Paul Donald [Sun, 2 Nov 2025 16:40:14 +0000 (17:40 +0100)]
netlink: Store interface MTU at link change

This is used for clamping MTU values.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/296
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
4 weeks agogithub: fix CI apt dependencies
Álvaro Fernández Rojas [Mon, 3 Nov 2025 06:38:52 +0000 (07:38 +0100)]
github: fix CI apt dependencies

We need to run 'apt update' before installing the APT packages.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agoodhcpd: more fixes for IID calculations
David Härdeman [Sun, 26 Oct 2025 13:59:46 +0000 (14:59 +0100)]
odhcpd: more fixes for IID calculations

This is the followup to pull request #290.

First, note that in dhcpv6_ia_enum_addrs(), the prefix + IID are currently
combined based on iface->dhcpv6_hostid_len, which is wrong. The latter only
defines the number of bits (typically 12) which should be used to
generate/constrain IIDs, but not the actual IID length.

The actual length of the IID is defined by the length of the prefix
(i.e.  128 - prefix length), the reason this hasn't been noticed is
probably that the higher bits of the IID area in the prefix (the struct
odhcpd_ipdaddr which corresponds to the DHCP server's own IPv6 address
on the interface) are often anyway zero (i.e. people often use an
address like fd00:1234:5678:abcd::1/64 for the server if they have
received a prefix like fd00:1234:5678::/48 from the upstream router).

Second, build_ia() unconditionally writes 64 bits of struct
dhcp_assignment->assigned_host_id (IID) to the struct in6_addr to use for a
given client (i.e. assumes the prefix to be at least /64 or shorter).

This is a first stab at fixing it. I've tried it, and successfully obtained a
lease using a /96 prefix.

There are still some murky corners here though, for example, if
"dhcpv6_hostidlength" is set to 64, there are no real checks that the prefix
length is compatible with that (so we might end up generating an IID of 64
bits, making sure that it is unique and not taken, and then truncate it
silently to a 32 bit IID in case the prefix is /96). But that's a topic for a
different day (and can only be triggered by non-standard configurations).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/295
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv6: support a configurable DUID
David Härdeman [Fri, 10 Oct 2025 07:38:38 +0000 (09:38 +0200)]
dhcpv6: support a configurable DUID

Allow the use of a (stable) globally configured DUID as the server identifier.

Currently, odhcpd generates a per-interface DUID-LL, meaning that the DUID is
not stable across interfaces and will change if/when hardware changes.

Supporting a stable DUID brings odhcpd's behaviour in line with RFC8415, §11:

                                                      ...The DUID is
   designed to be unique across all DHCP clients and servers, and stable
   for any specific client or server.  That is, the DUID used by a
   client or server SHOULD NOT change over time if at all possible; for
   example, a device's DUID should not change as a result of a change in
   the device's network hardware or changes to virtual interfaces...

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/274
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv6-ia: split reconf_msg struct into partial structs
David Härdeman [Fri, 10 Oct 2025 07:32:33 +0000 (09:32 +0200)]
dhcpv6-ia: split reconf_msg struct into partial structs

Change send_reconf() so that the various options are each in separate struct.
This makes it easy to support a variable-length server DUID in the future.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/274
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv6: split clientid to a separate struct
David Härdeman [Fri, 10 Oct 2025 07:05:02 +0000 (09:05 +0200)]
dhcpv6: split clientid to a separate struct

Change handle_client_request() so that the serverid and clientid are in
separate structs. This makes it easy to support a variable-length server DUID
in the future.

Note that some of the variables (like "dest") have a bit misleading names now,
but that is something that I plan to address later, this patch was
intentionally kept as simple as possible.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/274
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv6-ia: simplify/fix IID calculations
David Härdeman [Sat, 25 Oct 2025 10:25:33 +0000 (12:25 +0200)]
dhcpv6-ia: simplify/fix IID calculations

This is a first stab at simplifying the IID calculations introduced with
commit 7000557cd8f6396b82cb35e0cdf9b72b18288fbc.

See the discussion in:
https://github.com/openwrt/openwrt/issues/20523

Note that a "cold" jrand48() doesn't have much of an avalance effect in
case of two very similar DUIDs, but it shouldn't matter because we're
not looking for any kind of cryptographic randomness...just a
predictable PRNG where the same DUID will (usually) get the same IPv6
addr (if available).

Closes: https://github.com/openwrt/odhcpd/issues/293
Closes: https://github.com/openwrt/openwrt/issues/20523
Fixes: 7000557cd8f6 ("dhcpv6-ia: respect prefix assigned to interface (>= /64)")
Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/290
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agoodhcpd: change "-c" cmd line arg to take a dir
David Härdeman [Sat, 25 Oct 2025 13:32:06 +0000 (15:32 +0200)]
odhcpd: change "-c" cmd line arg to take a dir

After the TZ support was added, odhcpd now reads two cfg files
potentially. Instead of adding a separate switch for the system UCI
file, I've changed the "-c" argument to take a directory. This is more
future-proof and also serves as a preparation for the global DUID PR
(which will necessitate reading from the UCI "network" file as well).

While I was at it, I also made some tiny improvements to the
odhcpd_reload() function to avoid an unnecessary allocation.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/291
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv4: dhcpv4_lease() - clarify which variables are requests
David Härdeman [Wed, 8 Oct 2025 15:50:47 +0000 (17:50 +0200)]
dhcpv4: dhcpv4_lease() - clarify which variables are requests

By consistently using the "req_" prefix, it's clearer which variables
relate to things the client has requested or which come from the client
request.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/286
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv4: dhcpv4_lease() - simplification
David Härdeman [Wed, 8 Oct 2025 15:28:39 +0000 (17:28 +0200)]
dhcpv4: dhcpv4_lease() - simplification

Reduce indentation, check some conditions and bail early, break it into clearer
chunks and add some comments.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/286
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv4: dhcpv4_lease() - convert to switch statement
David Härdeman [Wed, 8 Oct 2025 15:23:46 +0000 (17:23 +0200)]
dhcpv4: dhcpv4_lease() - convert to switch statement

And move the simple cases first, also bail if there's nothing to do.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/286
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
5 weeks agodhcpv4: dhcpv4_assign() - explain address assignment
David Härdeman [Wed, 8 Oct 2025 13:46:24 +0000 (15:46 +0200)]
dhcpv4: dhcpv4_assign() - explain address assignment

Add some debug statements that also serve as comments explaining the logic
of dhcpv4_assign() and which make it easier to understand why a
requested address was not provided.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/286
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv6: send timezone only when client requests
Paul Donald [Sat, 25 Oct 2025 00:24:58 +0000 (02:24 +0200)]
dhcpv6: send timezone only when client requests

Commit 7956f4271b4e added support for RFC4833 timezones but didn't check
if clients had actually requested them.

Fixes: 7956f4271b4e ("dhcpv6: RFC4833 timezones")
Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/289
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: bump problem scenario up to warn
Paul Donald [Wed, 22 Oct 2025 14:36:22 +0000 (16:36 +0200)]
dhcpv4: bump problem scenario up to warn

This way a potential failure scenario is visible with odhcpds default log
level of warn.

Closes https://github.com/openwrt/odhcpd/issues/228

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/287
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoconfig: properly set log level from uci
Álvaro Fernández Rojas [Wed, 22 Oct 2025 14:32:23 +0000 (16:32 +0200)]
config: properly set log level from uci

The condition to set the log level from the uci config if it hadn't been
set from the command line should be inverted to work properly.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv6: RFC4833 timezones
Paul Donald [Wed, 22 Oct 2025 00:17:06 +0000 (02:17 +0200)]
dhcpv6: RFC4833 timezones

This implements RFC4833 - supplying timezone information to clients that
request them. Both forms are possible, when timezone is configured in
the uci system settings (the luci GUI saves both forms to the config).

e.g.
```
config system
option zonename 'America/Puerto Rico'
option timezone 'AST4'
```

There is also an odhcpd flag to disable their use, set in uci dhcp.

```
config odhcpd 'odhcpd'
option enable_tzdb '0'
```

Once enabled, the options, when requested, are sent:
NEW_POSIX_TIMEZONE 41 // 'AST4'
NEW_TZDB_TIMEZONE 42 // 'America/Puerto_Rico'

Wireshark disassemble of options sent to client:

```
...
Time Zone Database
    Option: Time Zone Database (42)
    Length: 19
    TZ-database: America/Puerto_Rico
Time Zone
    Option: Time Zone (41)
    Length: 4
    Time-zone: AST4
```

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/284
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv6-ia: respect prefix assigned to interface (>= /64)
Matthias Riegler [Mon, 12 Jun 2023 19:01:08 +0000 (21:01 +0200)]
dhcpv6-ia: respect prefix assigned to interface (>= /64)

When odhcpd hands out DHCPv6 leases on an interface with a prefix >= /64
(e.g. /96), leases can be outside of the allocated /96 on the interface.
Fixes https://github.com/openwrt/odhcpd/issues/199.

Signed-off-by: Matthias Riegler <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/219
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcpd: improve odhcpd_urandom()
David Härdeman [Mon, 20 Oct 2025 20:57:52 +0000 (22:57 +0200)]
odhcpd: improve odhcpd_urandom()

First, note that not a single caller checks the return value - which is
quite reasonable. What are they supposed to do with a failure?

Second, none of the callers do anything that's *really*
security-sensitive, the closest we have is the force reconf nonce, and
that is blorted out over the network, so it's really a best-effort kind
of thing.

Third, odhcpd_urandom() currently doesn't check if it e.g. got
interrupted by a signal.

So, simplify and modernize this a bit by using getrandom(), which allows
us to skip one fd, and which avoids syscalls by using the vDSO approach
instead. Also, check for things like signal interrupts (don't really
happen on calls for entropy < 256 bytes, but still). And make a
reasonable effort, but not much more.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/285
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoconfig: fix erroneous clamp message if clamp value == max
Paul Donald [Tue, 21 Oct 2025 13:46:29 +0000 (15:46 +0200)]
config: fix erroneous clamp message if clamp value == max

If the clamp value is equal to and only equal to PD_MIN_LEN_MAX then the warn
is emitted, when it shouldn't be since PD_MIN_LEN_MAX is a valid max value.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/283
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: bail earlier on release/decline
David Härdeman [Wed, 8 Oct 2025 14:21:22 +0000 (16:21 +0200)]
dhcpv4: bail earlier on release/decline

And make it clearer that the return value from dhcpv4_lease isn't used.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: don't hardcode options array length
David Härdeman [Tue, 7 Oct 2025 08:09:38 +0000 (10:09 +0200)]
dhcpv4: don't hardcode options array length

Instead of copying around the same data on the stack, keep two arrays with
mandatory and requested options, then loop over both of them.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: shrink struct dhcpv4_message
David Härdeman [Tue, 7 Oct 2025 07:49:10 +0000 (09:49 +0200)]
dhcpv4: shrink struct dhcpv4_message

The options padding can now be removed.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for forcereconf messages, fix hash
David Härdeman [Tue, 7 Oct 2025 04:37:22 +0000 (06:37 +0200)]
dhcpv4: use iovec for forcereconf messages, fix hash

Do the same iovec conversion for dhcpv4_fr_send(), and remove dhcpv4_put() now
that the last user is gone. Yay.

Note that there was a bug in dhcpv4_fr_send() in that it would first
perform:
md5_hash(&fr_msg, sizeof(fr_msg), &md5);
And later:
sendto(/* fd */, &fr_msg, PACKET_SIZE(&fr_msg, cursor), ...)

But PACKET_SIZE is much smaller than sizeof(fr_msg), meaning that the hash is
not computed for the actual packet that gets sent.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: fix padding of iovec message in dhcpv4_handle_msg()
David Härdeman [Mon, 6 Oct 2025 17:17:10 +0000 (19:17 +0200)]
dhcpv4: fix padding of iovec message in dhcpv4_handle_msg()

Fix the FIXME added earlier by calculating the length of the iovec package and
adding padding as necessary to comply with the BOOTP specification (which
defines the minimum length of a message as 300 bytes).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: some minor cleanups post-iovec
David Härdeman [Mon, 6 Oct 2025 14:45:38 +0000 (16:45 +0200)]
dhcpv4: some minor cleanups post-iovec

Do some cleanups, remove some magic numbers, make sure structs are defined with
the members in their actual order and without missing members.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for forcerenew opts
David Härdeman [Mon, 6 Oct 2025 14:29:12 +0000 (16:29 +0200)]
dhcpv4: use iovec for forcerenew opts

That's the last bunch of options :)

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for router and DNS server
David Härdeman [Mon, 6 Oct 2025 14:06:32 +0000 (16:06 +0200)]
dhcpv4: use iovec for router and DNS server

And some more options converted.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for DNS search and MTU
David Härdeman [Mon, 6 Oct 2025 13:40:23 +0000 (15:40 +0200)]
dhcpv4: use iovec for DNS search and MTU

Some more options converted.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for netmask/hostname/broadcast
David Härdeman [Mon, 6 Oct 2025 13:00:59 +0000 (15:00 +0200)]
dhcpv4: use iovec for netmask/hostname/broadcast

More simple conversions.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for leasetime/renew/rebind
David Härdeman [Mon, 6 Oct 2025 12:03:34 +0000 (14:03 +0200)]
dhcpv4: use iovec for leasetime/renew/rebind

Move some more options over to use an iovec. Note that the FIXME will be
addressed in a later patch.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: introduce a reply_opts array
David Härdeman [Mon, 6 Oct 2025 11:39:25 +0000 (13:39 +0200)]
dhcpv4: introduce a reply_opts array

Add a simple array to record the options we want to send back. This is just a
placeholder in preparation for later patches.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for DNR
David Härdeman [Mon, 6 Oct 2025 11:21:21 +0000 (13:21 +0200)]
dhcpv4: use iovec for DNR

Another simple conversion to use iovec.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for NTP
David Härdeman [Mon, 6 Oct 2025 10:23:18 +0000 (12:23 +0200)]
dhcpv4: use iovec for NTP

Note that the previous code would send out several NTP options if
the client requested the option more than once, and would also send
out zero-sized options (against RFC2132, §8.3).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: use iovec for message and serverid
David Härdeman [Mon, 6 Oct 2025 09:39:20 +0000 (11:39 +0200)]
dhcpv4: use iovec for message and serverid

Start converting options over to an iovec based solution.

Also change the name of "type" in struct dhcpv4_option, both the DHCPv4 and
DHCPv6 RFCs call these "option codes", not types.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: reorder some more variables in dhcpv4_handle_msg()
David Härdeman [Mon, 6 Oct 2025 09:05:54 +0000 (11:05 +0200)]
dhcpv4: reorder some more variables in dhcpv4_handle_msg()

Sort the variables into request and response variables for clarity.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: remove one more variable from dhcpv4_handle_msg()
David Härdeman [Mon, 6 Oct 2025 08:47:35 +0000 (10:47 +0200)]
dhcpv4: remove one more variable from dhcpv4_handle_msg()

It's only used once, and there's no lack of variables to keep track of in
dhcpv4_handle_msg().

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: move dest handling from dhcpv4_handle_msg()
David Härdeman [Mon, 6 Oct 2025 08:44:42 +0000 (10:44 +0200)]
dhcpv4: move dest handling from dhcpv4_handle_msg()

dhcpv4_handle_msg() is already over 300 lines of code, break out the
destination handling into a separate function to make the former function a bit
more manageable in size.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: don't copy reqopts around
David Härdeman [Mon, 6 Oct 2025 07:48:43 +0000 (09:48 +0200)]
dhcpv4: don't copy reqopts around

Ok, this is a bit weird, dhcpv4_handle_msg() passes reqopts to dhcpv4_lease(),
which stashes a copy of the reqopts in the struct dhcp_assignment, and then
dhcpv4_handle_msg() uses the stashed copy instead.

The only reason a copy is made seems to be so that the requested options can
later be reported via ubus (in "ubus call dhcp ipv4leases"), but it is hard to
see a use-case for that (the DHCP server has already replied to the client by
the time the lease is available over ubus) and we don't do anything similar for
DHCPv6, so remove the extra copying.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: more refactoring of dhcpv4_handle_msg()
David Härdeman [Sun, 5 Oct 2025 19:21:50 +0000 (21:21 +0200)]
dhcpv4: more refactoring of dhcpv4_handle_msg()

Move some gnarly conditionals into a switch in preparation of later patches.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: clarify variable names in dhcpv4_handle_msg()
David Härdeman [Sun, 5 Oct 2025 19:04:17 +0000 (21:04 +0200)]
dhcpv4: clarify variable names in dhcpv4_handle_msg()

Make it clearer which variables relate to the request, and which ones relate to
the reply that we're constructing.

Also fix the missing endianness conversion for req_leasetime (not so severe
though, a bogus leasetime value will be overridden with limits that are set
per-lease or per-interface).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: some more cleanups to dhcpv4_handle_msg()
David Härdeman [Sun, 5 Oct 2025 18:35:23 +0000 (20:35 +0200)]
dhcpv4: some more cleanups to dhcpv4_handle_msg()

Most notably, neither hostname, nor reqopts actually need to be copied from
req, they are used in a read-only fashion throughout the rest of the function
(and any functions it calls). Also switch some complicated if-else constructs
over to switch-case.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv4: preparations for iovec usage
David Härdeman [Thu, 25 Sep 2025 15:09:08 +0000 (17:09 +0200)]
dhcpv4: preparations for iovec usage

dhcpv4.c currently builds DHCPv4 messages by lots of repeated calls to the
dhcpv4_put() method, which basically does a whole lot of copies to the stack.
The following set of patches convert dhcpv4.c over to use iovecs, which avoids
almost all of the stack allocations and copies.

The first step is to lay the groundwork by changing dhcpv4_send_reply() and the
corresponding dhcpv6_4o6_send_reply() in dhcpv6.c so that they both take an
iovec instead of a plain buffer. Also introduce the first (very very simple)
iovec for dhcpv4_handle_msg() which just contains the whole packet, plus the
end marker as a separate vector element. It will be filled out further in
subsequent patches.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcdp: use a more suitable clock
David Härdeman [Fri, 10 Oct 2025 20:57:08 +0000 (22:57 +0200)]
odhcdp: use a more suitable clock

In my testing, CLOCK_MONOTONIC_COARSE uses about 1/3 of the CPU cycles.

And the accuracy is completely irrelevant.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/282
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv6: change dhcpv6 message type check in relay
Paul Donald [Fri, 3 Oct 2025 12:59:55 +0000 (14:59 +0200)]
dhcpv6: change dhcpv6 message type check in relay

When compiled, the switch instruction jump table O(1) is more efficient
than multiple logical comparisons in the if block (4-5 checks).

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/279
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agodhcpv6: move dhcpv6 message type check for early exit
Paul Donald [Sun, 19 Oct 2025 17:30:38 +0000 (19:30 +0200)]
dhcpv6: move dhcpv6 message type check for early exit

Avoid doing a bunch of work if the message type we received is not a
client type and does not warrant a reply. Exit early.

Clarify and comment message type handling.

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/279
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcpd: add a simple build script
David Härdeman [Fri, 17 Oct 2025 19:25:10 +0000 (21:25 +0200)]
odhcpd: add a simple build script

Inspired from the ci script and the scripts I've been using. Should make it a
little bit easier for people who want to contribute to odhcpd.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/280
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agogithub: improve CI
Álvaro Fernández Rojas [Sat, 18 Oct 2025 08:13:26 +0000 (10:13 +0200)]
github: improve CI

- Remove unneeded CMAKE_SYSTEM_PROCESSOR.
- Add summary table with sizes (in bytes) for each arch/variant.
- Upload generated binaries as artifacts.
- Add OpenWrt formalities.

Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcpd: shrink binary size by creating a logging function
David Härdeman [Fri, 17 Oct 2025 19:45:38 +0000 (21:45 +0200)]
odhcpd: shrink binary size by creating a logging function

Moving the logging to a real function helps shrink the binary size back to what
it was before the logging patches.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/273
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcpd: support stderr logging
David Härdeman [Wed, 8 Oct 2025 05:44:56 +0000 (07:44 +0200)]
odhcpd: support stderr logging

This is just for debugging purposes. Also, make sure that a cmdline loglevel
doesn't get overwritten by what's in the cfg file (it's customary that
command-line options take precedence over configuration file settings).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/273
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
6 weeks agoodhcpd: add log helpers
David Härdeman [Wed, 8 Oct 2025 05:27:08 +0000 (07:27 +0200)]
odhcpd: add log helpers

These a just a bit more succinct than their syslog equivalents. Also, this lays
the ground for the next patch.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/273
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
7 weeks agoconfig: cap dhcpv6_pd_min_len to max instead of only logging error
Paul Donald [Fri, 10 Oct 2025 11:44:28 +0000 (13:44 +0200)]
config: cap dhcpv6_pd_min_len to max instead of only logging error

Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/225
Signed-off-by: Álvaro Fernández Rojas <[email protected]>