Roy Marples [Mon, 29 Jun 2026 21:41:39 +0000 (22:41 +0100)]
options: Introduce policy groups
Remove the old bitmask array which we used to store which
options to request, remove, require, etc and replace with a
more generic policy group.
The policy group structure holds an array of option numbers
in each list - request, remove, require, etc.
Add a suite of helper functions around this to allow adding,
removing, checking, walking, etc.
This allows a much easier use of this in DHCP processing but more
importantly allows us to remove or reject options we do not
have a definition for.
Chris Patterson [Tue, 23 Jun 2026 19:30:57 +0000 (15:30 -0400)]
dhcp: add configurable backoff parameters for DHCPv4 (#593)
In cloud and virtual environments the DHCP service is typically
ready within hundreds of milliseconds of the interface coming up,
and once ready, responds within single-digit milliseconds. The
RFC 2131 defaults (4s initial interval, 64s backoff cap) are
designed for congested broadcast networks and are unnecessarily
conservative in this context.
Add three new configuration options to tune DHCPv4 retransmission:
initial_interval - initial retransmission interval (default 4s)
backoff_cutoff - exponential backoff cap (default 64s)
backoff_jitter - random jitter per retry (default ±1000ms)
Defaults match RFC 2131 so existing behaviour is unchanged.
Option naming aligns with dhclient (initial-interval, backoff-cutoff).
Minimum of 1 is enforced at parse time for interval and cutoff;
invalid values are logged and the default is used.
These options are DHCPv4-only; DHCPv6 retransmission follows
RFC 8415 constants and is not user-configurable.
Closes #406
Signed-off-by: Chris Patterson <cpatterson@microsoft.com>
Roy Marples [Mon, 22 Jun 2026 08:40:13 +0000 (09:40 +0100)]
hooks: don't read past truncated ip6 address starting fe
We want to append the interface name to link-local addresses.
But we might get a truncated address as well and an attacker
could just supply the fe part. In this case, ensure we have
enough of the address to read the next byte otherwise don't
append the interface name.
Roy Marples [Sat, 20 Jun 2026 08:49:44 +0000 (09:49 +0100)]
privsep: ps_root_readfile should return the real file size
readfile NUL terminates the buffer to make things easy.
We need to transmit this over IPC just ensure the receiver has
a big enough buffer, again to make things easy.
So on success, we need to trim the NUL from the returned length
so the actual file size is accurate.
Roy Marples [Mon, 8 Jun 2026 21:14:34 +0000 (22:14 +0100)]
DHCP6: guard against an interface delegated too disappearing
This is very unlikely in the real world because you don't
delegate to interfaces which are removable.
In my testing the guard is not needed as things are cleaned up
correctly but this guard still helps to make sure.
Roy Marples [Tue, 2 Jun 2026 12:26:28 +0000 (13:26 +0100)]
compat: Add support for getprogname(3)
Removes all inlined variations into a common single one.
Only supports Linux (which is all we did anyway), but now adds detection for program_invocation_short_name in libc and will use that OR package name.
All Linux libc should support this.
Roy Marples [Sun, 24 May 2026 15:19:01 +0000 (16:19 +0100)]
Darwin: Add initial support for macOS (#613)
Apple route(4) has some limitations as does getifaddrs(3).
Basically there is no means of being notified of carrier state
because Apple only reports this via media state which is an ioctl.
The good news is that we can build macOS on github so we
can get some BSD traceability at least.
Roy Marples [Thu, 21 May 2026 22:48:45 +0000 (23:48 +0100)]
eloop: Add eloop_openfdwaiter() and eloop_closefdwaiter()
Use kqueue or epoll for eloop_waitfd().
This requires opening a new kqueue or epoll to handle this as
this is a one shot event we don't want to touch the eloop events.
Roy Marples [Thu, 21 May 2026 07:43:58 +0000 (08:43 +0100)]
DHCP6: Delete the eloop event before closing an ia listener socket
This only happens when dhcpcd is running on a specific interface
and can trigger erroneous logs deleting the socket from
kqueue/epoll.
With the prior eloop it could also trigger ia events from a
non related fd if re-used.
Roy Marples [Sat, 9 May 2026 12:13:56 +0000 (13:13 +0100)]
privsep: Change IPC to use SOCK_STREAM (#604)
macOS does not support SOCK_SEQPACKET.
All our messages use a fixed header which includes the
lengths of all parts sent.
We can use these limits with MSG_WAITALL on blocking sockets
in place of MSG_EOR to get the same effect.
Roy Marples [Fri, 6 Mar 2026 23:02:36 +0000 (23:02 +0000)]
BSD: don't send uninitialised memory using ps_root_indirectioctl
This will affect FreeBSD and OpenBSD.
Use sendmsg to send the length of the interface name, then the
interface name and then the data rather than just sending
IFNAMSIZ which may have uninitialised bytes at the end.
Opimise ps_sendcmdmsg while here.
Hopefully helps #565 but I'm not hopeful.
Daniel Gröber [Fri, 6 Mar 2026 22:47:42 +0000 (22:47 +0000)]
manager: Fix loosing iface options on CARRIER
When an interface (re-)gains carrier dhcpcd_handlecarrier() runs
dhcpcd_initstate() to kick off profile re-selection. Previously this used
args originally passed when starting the manager (ctx->argv).
However interfaces started via the manager control
interface (dhcpcd_initstate1() in dhcpcd_handleargs()) may be started with
different args.
For example if we start a manager with
dhcpcd -M --inactive
and then start only IPv4 on an interface with
dhcpcd -4 iface0
a subsequent CARRIER event will reset the interface to what amounts to
"default config + `-M --inactive`" which in this case will enable ipv6
also!
To fix this we keep a copy of the arguments used to start an interface in
the manager (dhcpcd_handleargs()) code path around around (ifp->argv).
In the current implementation args passed for renew following the initial
interface start will not be persisted. This causes the interface to reset
to a state of "defaults + config + profile + start-cmdline".
For example (continuing the scenario above) after enabling ipv6 with -n:
$ dhcpcd -6 -n iface0
A subsequent CARRIER event will disable ipv6 again as the effective
arguments remain `-4 iface0` as passed during interface start.
Note the per-interface daemon code path wasn't affected as ctx->args
already contains the interface start args.