…
Recently I came into the situation that I wanted to automate something based on the state of my printer. If I turn it on, a light above it should turn on so the tiny screen on it becomes readable. And when the printer turns off again, the light should turn off. To do this, I needed some way to determine when my printer turns on. Luckily it’s very reliable at getting DHCP leases and releasing them when it turns off again. Additionally, the DHCP server that ships with OpenWRT has a flag to accept a script it should run when leases are changed1
-6 –dhcp-script=
Whenever a new DHCP lease is created, or an old one destroyed, or a TFTP file transfer completes, the executable specified by this option is run. must be an absolute pathname, no PATH search occurs. The arguments to the process are “add”, “old” or “del”, the MAC address of the host (or DUID for IPv6) , the IP address, and the hostname, if known. “add” means a lease has been created, “del” means it has been destroyed, “old” is a notification of an existing lease when dnsmasq starts or a change to MAC address or hostname of an existing lease (also, lease length or expiry and client-id, if –leasefile-ro is set and lease expiry if –script-on-renewal is set). If the MAC address is from a network type other than ethernet, it will have the network type prepended, eg “06-01:23:45:67:89:ab” for token ring. The process is run as root (assuming that dnsmasq was originally run as root) even if dnsmasq is configured to change UID to an unprivileged user.
So this shouldn’t be a big deal, right?
OpenWRT configuration
OpenWRT also packages mosquitto_pub which I tend to use for CLI interactions
with my MQTT broker. And since my broker doesn’t do SSL, I installed
mosquitto-client-nossl on my OpenWRT router:
$ opkg update
$ opkg install mosquitto-client-nossl
I then placed the following script in /bin/pub_dhcp
#!/bin/sh
/usr/bin/mosquitto_pub \
-h mqtt.aada.cat \
-t network/dhcp/leases \
-m "{\"action\": \"$1\", \"mac-addr\": \"$2\", \"ip-addr\": \"$3\", \"host\": \"$4\"}"
# vim: ft=sh
As dhcpscript is listed as an option in the OpenWRT wiki page2 for
dnsmasq I added a line in /etc/config/dhcp for dnsmasq to pick up the script
config dnsmasq
[...]
option dhcpscript '/bin/pub_dhcp'
After restarting dnsmasq, this should be everything under ordinary circumstances.
But unfortunately I found out fairly quickly that things would be a bit more
complicated than that since doing only this didn’t work. After several hours of
debugging and a good night of sleep, I realised what was up. OpenWRT has,
perhaps quite wisely, put dnsmasq into a jail. In the init script, which is
not just responsible for controlling the state of the service, but also
creating the actual configuration and setting up jails and such, this
manifested in the following lines in dnsmasq_start():
procd_add_jail dnsmasq ubus log
procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS
procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE
procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript
procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers
procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
case "$logfacility" in */*)
[ ! -e "$logfacility" ] && touch "$logfacility"
procd_add_jail_mount_rw "$logfacility"
esac
[ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile
Note the line where $user_dhcpscript is added with several other files into the jail.
Notably, nothing in the init script was checking for dependencies of the script itself.
So I worked around this by sneakily adding /usr/bin/mosquitto_pub into the init script:
procd_add_jail_mount /usr/bin/mosquitto_pub
I then restarted dnsmasq.
/etc/init.d/dnsmasq restart
And then, subscribing to the appropriate topic, I was able to get events for my printer turning on
$ mosquitto_sub -h mqtt.aada.cat -t network/dhcp/leases
{"action": "add", "mac-addr": "40:f8:df:0a:63:2b", "ip-addr": "192.168.1.25", "host": "g550"}
…and off!
$ mosquitto_sub -h mqtt.aada.cat -t network/dhcp/leases
{"action": "del", "mac-addr": "40:f8:df:0a:63:2b", "ip-addr": "192.168.1.25", "host": "g550"}
With the messages finally being published, I was able to automate my printer’s lighting in Apache NiFi.
Now I am wondering what other interesting things I might be able to do with changes to DHCP leases.