Add a Safe dhcpcd Hook and Inspect Its DHCP Environment
You want something to happen the moment dhcpcd gets or renews a lease, and a hook is how. Inspect the environment dhcpcd-run-hooks hands to hooks, then add a small event logger, in about 15 minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
The examples match dhcpcd 10.0.6 from Ubuntu package dhcpcd-base 1:10.0.6-1ubuntu3.2. You need shell access and, for the persistent hook, sudo.
Warning
This runner is part of dhcpcd's network configuration path. A badly written hook can interrupt later hooks or change network state, so test the shell syntax before restarting anything. This guide does not restart dhcpcd or replace /etc/resolv.conf.
1. Confirm the installed runner and hook directory
The manual page calls the runner dhcpcd-run-hooks, but Ubuntu installs this version at /usr/lib/dhcpcd/dhcpcd-run-hooks, which is not normally on a user's PATH. Check the package and the system hook files:
$ dhcpcd --version
dhcpcd 10.0.6
$ dpkg-query -W -f='${Package} ${Version}\n' dhcpcd-base
dhcpcd-base 1:10.0.6-1ubuntu3.2
$ ls -1 /usr/lib/dhcpcd/dhcpcd-hooks
01-test
20-resolv.conf
30-hostname
50-ntp.conf
50-timesyncd.conf
On this installation, system hooks load from /usr/lib/dhcpcd/dhcpcd-hooks in lexical order. The runner also looks for /etc/dhcpcd.enter-hook before them and /etc/dhcpcd.exit-hook afterwards. The set of system hooks depends on the distribution, so inspect it instead of assuming every host handles DNS or NTP the same way.
Checkpoint
Confirm the package version and hook directory are the ones you mean to change. Do not edit a file in the system hook directory just to try an idea.
2. Inspect the event variables without changing the network
Every invocation has an interface and a reason. DHCP data being added uses names starting new_. Data being removed uses old_.
The installed 01-test hook prints selected variables when the reason is TEST, then stops the runner. That gives you a controlled way to learn the shape of the input:
$ env -i PATH=/usr/sbin:/usr/bin:/sbin:/bin \
interface=eth0 reason=TEST protocol=dhcp pid=1234 \
ifcarrier=up ifmetric=100 ifwireless=0 ifflags=0 ifmtu=1500 \
ifssid=demo /usr/lib/dhcpcd/dhcpcd-run-hooks TEST
interface='eth0'
pid='1234'
protocol='dhcp'
reason='TEST'
ifcarrier='up'
ifflags='0'
ifmetric='100'
ifmtu='1500'
ifssid='demo'
ifwireless='0'
That output is a diagnostic, not a real DHCP lease. For the full list of protocol variables this build knows about, run dhcpcd --variables. The reasons you will meet:
BOUNDandBOUND6. A new lease.RENEWandRENEW6. A renewal.EXPIREandEXPIRE6. State has expired.STOPandSTOP6. An interface stops.
Warning
Do not put exit or exec in a hook unless stopping the whole hook chain is deliberate. Hook files are loaded into the runner's current shell, not launched as independent processes.
3. Create one small enter hook
Write the following file as root. It logs only lease acquisition and renewal events through the system logger. It does not alter routes, DNS, the hostname or the lease:
$ sudo install -m 0755 /dev/stdin /etc/dhcpcd.enter-hook <<'EOF'
#!/bin/sh
case "$reason" in
BOUND|BOUND6|RENEW|RENEW6)
logger -t dhcpcd-hook -- "$interface $reason"
;;
esac
EOF
The variables are quoted because DHCP-provided strings are input, not trusted shell syntax. The case pattern also keeps carrier notifications and shutdown events out of this log. A hook can see values such as new_domain_name_servers or old_ip_address, but validate and quote them before using them in a command or file name.
Security warning
Keep the hook owned by root and not writable by ordinary users. Verify that before dhcpcd loads it.
$ sudo stat -c '%U:%G %a %n' /etc/dhcpcd.enter-hook
root:root 755 /etc/dhcpcd.enter-hook
$ sudo sh -n /etc/dhcpcd.enter-hook
If the syntax check reports an error, fix the file before you cause a real DHCP event.
Warning
The install command replaces an existing file. If that path already holds local policy, copy a known-good hook aside first.
4. Test the event branch and read the log
Run the runner with a synthetic renewal environment. This exercises the new hook without bringing an interface down or forcing a lease change:
$ env -i PATH=/usr/sbin:/usr/bin:/sbin:/bin \
interface=eth0 reason=RENEW protocol=dhcp pid=1234 \
ifcarrier=up ifmetric=100 ifwireless=0 \
/usr/lib/dhcpcd/dhcpcd-run-hooks RENEW
$ sudo journalctl -t dhcpcd-hook -n 1 --no-pager
Sep 23 12:34:56 host dhcpcd-hook[1234]: eth0 RENEW
Timestamp, host name and logger process details will differ. If no line appears, check three things:
- Is
loggerinstalled? - Is the reason exact? It must be one of the four case arms.
- Does the journal accept the tag? The tag is
dhcpcd-hook.
A synthetic run does not prove that a DHCP server supplies any particular option.
5. Understand ordering and recover cleanly
The enter hook runs before the packaged hooks, so changing a shared variable there can change what later hooks do. The exit hook runs last. Hook files in the system directory are read in lexical order, which is why 01-test and 20-resolv.conf have a visible order.
Avoid editing packaged files. An upgrade can replace them, and a local edit is hard to audit.
To undo the example logger, remove the enter hook, but only after checking it is the file you created. This changes service behaviour, so do it in a maintenance window if the hook has grown beyond this example:
$ sudo rm /etc/dhcpcd.enter-hook
$ test ! -e /etc/dhcpcd.enter-hook && echo 'custom enter hook removed'
custom enter hook removed
Recovery
If a real network event starts failing after a hook change, remove or restore that hook, run sudo sh -n on every local hook, and read the service journal with sudo journalctl -u dhcpcd -b --no-pager.
Warning
Do not use sudo dhcpcd as a general repair command. Restarting a DHCP client can disrupt addresses, routes and DNS.
Done means
- Version and runner known. You identified the installed dhcpcd version and the runner path.
- Variables inspected. You used
TESTwith a synthetic environment to see the hook variables. - Hook is safe. Your custom hook is root-owned, syntax-checked and quotes event data.
- Logger fires. A synthetic
RENEWrun produced the expected logger entry. - Order and removal understood. You know the enter, system and exit ordering, and can remove the example hook without restarting dhcpcd.