15 May 2021 - tsp
Last update 15 May 2021
5 mins
Basically it’s most of a note for myself to document the dhcpd.conf
options
that I’m using …
ISC-DHCP - one of the most used DHCP servers and the DHCP server of choice on FreeBSD in my opinion - supports calling external hooks while committing, expiring and releasing leases. This might be interesting to run external accounting or - as in my case - triggering some automation events. I’m personally using this for some different scenarios:
rsync
to synchronize
photos and recordings of the phone onto my local data storage solution (this
then triggers more automation events such as automatic indexing, etc.)To make this process more modular I’m injecting the join and leave events onto
the central message broker. I’m currently using RabbitMQ
as my central message broker since I’m used to this solution and it has proven to
work in a solid way - later on I plan to move on to an distributed (i.e. not running
on a single server or cluster to remove the single point of failure) message broker
solution. This is done using a small ANSI C native binary - currently using an external
lightweight MQTT library though I also plan to remove this external dependency.
I’m currently not using AMQP for this purpose since I wanted to have a small utility
that has no external dependencies except the libc
. This has been chosen since
the utility I’m running is executed in the chroot
of dhcpd
and most AMQP
client libraries do have somewhat more complex dependency chains.
Currently this depends on the small MQTT-C library that’s licensed under MIT license. I’ve somewhat modified the code and implemented a mini utility based on their simple publish example that allows me to publish an DHCP event including IP, MAC address and hostname to an local MQTT broker.
After the utility has been built using gmake
the following utilities have
been symlinked into the chroot
of dhcpd
:
mqttpublish
utility to ${CHROOT}/bin/mqttpublish
/libexec/ld-elf.so.1
to ${CHROOT}/libexec/ld-elf.so.1
/lib/libc.so.7
to ${CHROOT}/lib/libc.so.7
/lib/libthr.so.3
to ${CHROOT}/lib/libthr.so.3
Now I’ve added the on commit
, on release
and on expiry
handlers
to the /usr/local/etc/dhcpd.conf
. These handlers convert the lease addresses
from binary into a string format, output the MAC address in the way I’d expect it
to be written and choose the best fit for the hostname for my type of usage. This
information is passed to the mqttpublish
utility together with the IP address
of the broker, the port to be used, the topic to be published to as well as
the username and password for the MQTT broker. This user has only been granted
rights to publish into network/dhcp/+
topics and has not been assigned any
read permissions.
on commit {
set clientip = binary-to-ascii(10,8,".",leased-address);
set clientmac = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
set clientname = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "UNKNOWN");
execute("/bin/mqttpublish", "192.0.2.1", "1883", "network/dhcp/commit", "dhcpevents", "PASSWORD", clientip, clientmac, clientname);
}
on release {
set clientip = binary-to-ascii(10,8,".",leased-address);
set clientmac = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
set clientname = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "UNKNOWN");
execute("/bin/mqttpublish", "192.0.2.1", "1883", "network/dhcp/release", "dhcpevents", "PASSWORD", clientip, clientmac, clientname);
}
on expiry {
set clientip = binary-to-ascii(10,8,".",leased-address);
set clientmac = concat (
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":",
suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2)
);
set clientname = pick-first-value(host-decl-name, option fqdn.hostname, option host-name, "UNKNOWN");
execute("/bin/mqttpublish", "192.0.2.1", "1883", "network/dhcp/expire", "dhcpevents", "PASSWORD", clientip, clientmac, clientname);
}
During debugging it has been really useful to launch dhcpd in foreground. This can
easily be achieved by setting the -d
and -f
flags for dhcpd_flags
in your /etc/rc.conf
and launching the daemon. One could of course also start
the daemon manually.
dhcpd_flags="-d -f"
This article is tagged:
Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)
This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/