Udhcpc.user script documentation and how to hotplug for DHCP events

Hi, guys! I've been looking for ways to execute programmes/scripts on DHCP events. To be more specific, I want to update my dynamic DNS (FreeDNS) when, and only when there's a potential change on the WAN interface(s) IP address(es) (yeah, I had a cron job doing it every ten minutes, but I always found that rather ugly, IMNSHO).
It took me quite a bit searching in order to find this trac entry mentioning an elusive /etc/udhcpc.user script (for which there isn't even a stub in the base-files package). So, I created this one…

#!/bin/sh
env | logger
exit 0

… sent USR1 to the udhcpc PID and got quite a number of juicy variables in the log, namely $ip (the IP address), $INTERFACE (the interface name) and $interface (the physical device). With this information, I changed my script to…

#!/bin/sh
if [ "wan" = $INTERFACE ]; then
	/usr/bin/wget -q -O - 'https://sync.afraid.org/u/[token redacted]/?myip='${ip}''
fi
exit 0

… which works like a charm!
So, my question is simple: am I doing this right? Can I rely on these variables to always exist and contain the information I need, or are there any changes planned? Thanks in advance! :wink:

2 Likes

You are aware that there is a ddns package that does this, aren't you?

2 Likes

Like much of Linux and most OSes, for that matter, you can rely on undocumented behavior ...

... until it changes.

In this particular case, exported variables for a user-defined script call, they are probably reasonably stable.

2 Likes

Yes. And why exactly should I replace a five line script that does exactly what I need with a 14 kiB package?

Actually, it doesn't. I just read the source code. It's a hotplug-triggered service that does periodic checks. It's not DHCP-event driven, from what I can tell.

Your original question partially answers the second one - an actively maintained package that would likely shield you from changes in underlying behavior.

The second is ease of use. I understand the attraction of “click-and-go” support for a large number of providers. Even though I hand-edit my config, 14 kB, which is probably only 7 kB in a ROM beats trying to find documentation for a new provider, script it, handle error conditions, test it, and add it to my builds.

2 Likes

Thanks for bringing it up, changed my cron-based nsupdate to the DHCP event triggered update!

Would be great if you created a wiki article on that, including all variables available in the script.

2 Likes

It's time-based and also event (not only DHCP) driven. But I am not trying to sell you anything, enjoy your script if it meets your needs.

1 Like

Hey, I was sold quite a while ago. :wink: I used the ddns-scripts package for a long time (about six years) and gave it up when FreeDNS implemented the new API (which, for some reason, I couldn't convince ddns-scripts to use properly, at the time).
I started this topic mainly because there was no documentation about the udhcpc.user script, to raise awareness about it (hoping someday it'll be promoted to a first-class citizen), and also because I thought someone else could be interested in the information herein (and I was right).
Sure, maybe I'm "holding it wrong", but my configuration is already complex enough that I'm bitten more often than not by packages which should Just Work™ (e.g.: just yesterday, with banip, which gets utterly confused with my seven firewall zones).
So, I'm fully aware of the limitations, I know if it breaks I get to keep the pieces but, if it happens, I can always put them back together. :grin:

tl;dr yes, see this doc for what variables are created https://udhcp.busybox.net/README.udhcpc

full info post:

Next time you are doing some detective work I suggest you do a github (or openwrt source text content) search for udhcpc.user to look around on what interacts with it in the source.
You find that such file is called at the end of /usr/share/udhcpc/default.script, and also the /lib/netifd/dhcp.script as added in that ticket you saw.

https://github.com/openwrt/openwrt/blob/master/package/network/config/netifd/files/usr/share/udhcpc/default.script

https://github.com/openwrt/openwrt/blob/master/package/network/config/netifd/files/lib/netifd/dhcp.script

If you look at the top of both scripts, the very first line is
[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1

So yeah they are run by "udhcpc", and that is a busybox tool (embedded device light version of core commandline tools), the dhcp client used by OpenWrt.

The documentation is in its old project page https://udhcp.busybox.net/ that has now been moved to busybox project infrastructure since the application was merged into busybox, and you can find the full client documentation about what variables it generates for use in scripts if you scroll down and click on Client README https://udhcp.busybox.net/README.udhcpc

It says:
When an event occurs, udhcpc calls the action script. The script by default is /usr/share/udhcpc/default.script
(for "events" it means something related to DHCP changes)

And then it says

The paramaters for enviromental variables are as follows:

$HOME		- The set $HOME env or "/"
$PATH		- the set $PATH env or "/bin:/usr/bin:/sbin:/usr/sbin"
$1		- What action the script should perform
interface	- The interface this was obtained on
ip		- The obtained IP
siaddr		- The bootp next server option
sname		- The bootp server name option
boot_file	- The bootp boot file option
subnet		- The assigend subnet mask
timezone	- Offset in seconds from UTC
router		- A list of routers
timesvr		- A list of time servers
namesvr		- A list of IEN 116 name servers
dns		- A list of DNS server
logsvr		- A list of MIT-LCS UDP log servers
cookiesvr	- A list of RFC 865 cookie servers
lprsvr		- A list of LPR servers
hostname	- The assigned hostname
bootsize	- The length in 512 octect blocks of the bootfile
domain		- The domain name of the network
swapsvr		- The IP address of the client's swap server
rootpath	- The path name of the client's root disk
ipttl		- The TTL to use for this network
mtu		- The MTU to use for this network
broadcast	- The broadcast address for this network
ntpsrv		- A list of NTP servers
wins		- A list of WINS servers
lease		- The lease time, in seconds
dhcptype	- DHCP message type (safely ignored)
serverid	- The IP of the server
message		- Reason for a DHCPNAK
tftp		- The TFTP server name
bootfile	- The bootfile name

I think this interface is not going to change anytime soon, that's a core tool, the dhcp client application used in OpenWrt.

I also think that it should be fairly trivial to add a line that calls network hotplug scripts when DHCP events happen by adding a line in the two linked scripts above, so packages can rely on DHCP events too without having to make a custom user config script like you did.

4 Likes

Hmm, more rummaging in OpenWrt sources and it seems there is a dhcp hotplug for scripts found in /etc/hotplug.d/dhcp, but only for events triggered by dnsmasq (the DHCP server used by OpenWrt).
They are not triggered for DHCP client events like what you need.

It does show how you can add hotplugging for DHCP client events, just add the same in the scripts I linked above, and it should then call stuff in /etc/hotplug.d/dhcp for DHCP client events too.

https://github.com/openwrt/openwrt/blob/master/package/network/services/dnsmasq/files/dhcp-script.sh

Would be cool if after testing this, someone could open a PR to merge this in OpenWrt. I'm currently away from home and I can't really test much.

1 Like

Precisely! That's exactly what I meant by making udhcpc a first-class citizen. I don't know if the other DHCP clients/servers (odhcpc6 and odhcpd) generate hotplug events, but I was sure that dnsmasq generated and udhcpc didn't. I'm sorry for not being more explicit, I assumed it was obvious. I actually read the udhcpc documentation, but I seem to have missed the environment variables section. Thanks a lot for your detailed reply! :smiley:

A good point.
It seems odhcpd (DHCP server for IPv6) and odhcp6c (DHCP client for IPv6) aren't triggering hotplug scripts either.

Both have a script hook they call every time there is a DHCP update so it's the same thing as above to add the hotplug functionality.
https://github.com/openwrt/openwrt/blob/master/package/network/ipv6/odhcp6c/files/dhcpv6.script for odhcp6c and
https://github.com/openwrt/openwrt/blob/master/package/network/services/odhcpd/files/odhcpd-update for odhcpd

an update: I asked on mailing list and Hans Dedecker (a core OpenWrt developer and more or less maintainer of these daemons) https://www.mail-archive.com/openwrt-devel@lists.openwrt.org/msg49345.html said that the odhcpd-update script is not the same thing, and that at the moment odhcpd does not call any script on DHCP lease changes, so it cannot do any hotplug.

If you have a usecase for hotplug scripts for DHCP lease events in IPv6, please send an email in the mailing list to ask if the feature can be added, or contribute it yourself.

1 Like

Hi, Alberto! Thanks for the heads-up, I also follow the mailing list, so I had read your email thread. :wink: To be honest, I don't have much of a use-case for DHCP server lease events (maybe logging, at most, but I personally don't care). So, when my ISP starts providing IPv6 (not holding my breath) and I feel the need for it, I'll implement it myself, if nobody beats me to it. :slightly_smiling_face: