DHCPD New Lease Notifier
Posted by Dave Eddy on Apr 12 2018 - tags: techThree years ago I set up SmartOS as a Home Router which required creating a zone specifically for handling DHCP requests on my network. As part of wanting to have more visibility into my network, I wrote a program to notify me whenever a new DHCP lease was given out by the server.
https://github.com/bahamas10/node-dhcpd-notifier
Usage
The program works by watching the dhcpd.leases
file on a regular interval and
looking for leases that haven’t been seen before. When a new lease is seen, a
configurable external program is executed with environmental variables set that
contain information about the new lease seen. From there, I have it execute a
script I wrote to send a pushover notification to my
phone.
In order to use this program you need to have node.js on
a machine that has read access to the dhcpd.leases
file. Then, install
dhcpd-notifier
from npm.
npm install -g dhcpd-notifier
Create a config file (json) with some basic information for the daemon.
{
"leases": "/var/db/isc-dhcp/dhcpd.leases",
"interval": 10,
"loglevel": "debug",
"exec": {
"file": "./new-lease",
"timeout": 30
}
}
This tells dhcpd-notifier
to read /var/db/isc-dhcp/dhcpd.leases
every 10
seconds, log with debug
log output, and to execute ./new-lease
for every
new lease seen, killing the script if it takes more than 30 seconds to execute.
For this example my new-lease
script looks something like this, to see a more
detailed example see
example-script
in the repo.
#!/usr/bin/env bash
ip=$DHCPD_NOTIFIER_IP
hostname=${DHCPD_NOTIFIER_HOSTNAME:-unknown}
mac=${DHCPD_NOTIFIER_MAC:-unknown}
title="dhcp lease for \"$hostname\""
msg="$ip - $mac"
PUSHOVER_USER='foo' \
PUSHOVER_TOKEN='bar' \
pushover "$title" "$msg"
The pushover
command source is at the bottom of this blog post.
Note: bunyan
is required to
parse the log output in a meaningful way.
$ dhcpd-notifier config.json | bunyan
[2018-04-13T03:31:35.482Z] DEBUG: dhcpd-notifier/53675 on dhcp.rapture.com: loaded config
config: {
"leases": "/var/db/isc-dhcp/dhcpd.leases",
"interval": 10,
"loglevel": "debug",
"exec": {
"file": "./new-lease",
"timeout": 30
},
"aliases": {},
"ignore": []
}
[2018-04-13T03:31:35.486Z] INFO: dhcpd-notifier/53675 on dhcp.rapture.com: watching file /var/db/isc-dhcp/dhcpd.leases for changes every 10 seconds
And an example lease will look something like this:
[2018-04-13T01:12:24.471Z] INFO: dhcpd-notifier/37209 on dhcp.rapture.com: new lease: "meka" 10.0.1.225 40:8d:5c:XX:XX:XX (Meka Windows Desktop Ethernet)
[2018-04-13T01:12:24.472Z] DEBUG: dhcpd-notifier/37209 on dhcp.rapture.com: executing "./new-lease"
opts: {
"env": {
"DHCPD_NOTIFIER_CONFIG": "/opt/custom/etc/dhcpd-notifier/config.json",
"LANG": "C",
"PATH": "/opt/local/sbin:/opt/local/bin:/opt/custom/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PWD": "/var/empty",
"TZ": "UTC",
"DHCPD_NOTIFIER_LEASE": "{\"ip\":\"10.0.1.225\",\"starts\":\"2018-04-13T01:12:15.000Z\",\"ends\":\"2018-04-13T03:12:15.000Z\",\"cltt\":\"2018-04-13T01:12:15.000Z\",\"binding state\":\"active\",\"next binding state\":\"free\",\"rewind binding state\":\"free\",\"hardware ethernet\":\"40:8d:5c:XX:XX:XX\",\"uid\":\"\\\\001@\\\\215\\\\\\\\\\\\274f>\",\"set vendor-class-identifier\":\"= \\\"MSFT 5.0\\\"\",\"client-hostname\":\"meka\",\"alias\":\"Meka Windows Desktop Ethernet\"}",
"DHCPD_NOTIFIER_ALIAS": "Meka Windows Desktop Ethernet",
"DHCPD_NOTIFIER_HOSTNAME": "meka",
"DHCPD_NOTIFIER_MAC": "40:8d:5c:XX:XX:XX",
"DHCPD_NOTIFIER_IP": "10.0.1.225"
},
"timeout": 30000,
"encoding": "utf8"
}
[2018-04-13T01:12:25.248Z] DEBUG: dhcpd-notifier/37209 on dhcp.rapture.com: execution succeeded (stderr="")
stdout: {"status":1,"request":"4790324e-8c64-4aad-849f-836317ccf648"}
Extras
pushover
#!/usr/bin/env node
/*
* Simple pushover CLI
*
* Author: Dave Eddy <[email protected]>
* Date: March 21, 2017
* License: MIT
*/
var po = new (require('pushover-notifications'))({
user: process.env.PUSHOVER_USER,
token: process.env.PUSHOVER_TOKEN,
});
process.argv.shift();
process.argv.shift();
var title = process.argv.shift();
var msg = process.argv.join(' ');
if (!title || !msg) {
console.error('usage: pushover <title> <msg>');
process.exit(1);
}
var msg = {
title: title,
message: msg
};
po.send(msg, function (err, result) {
if (err)
throw err;
console.log(result);
});