Skip to content

Instantly share code, notes, and snippets.

@ae-s
Last active February 11, 2023 02:12
Show Gist options
  • Save ae-s/781962e2e2d3ae3c5543f5ee84e9b334 to your computer and use it in GitHub Desktop.
Save ae-s/781962e2e2d3ae3c5543f5ee84e9b334 to your computer and use it in GitHub Desktop.
nsupdate $(ip neigh list)
#!/bin/bash
# Tiny tool to run as a cronjob, which will update
# (using nsupdate) your zone files to include dhcp-
# and statelessly-assigned addresses.
# Space-separated list of address-to-name resolution methods to try.
# They'll be tried in the order listed here.
METHODS="hostfile avahi localdns"
# Zone to update for each type of IP address. In my home network,
# ipv4 is natted but ipv6 is globally reachable. So I only publish
# records for ipv6 addresses.
ZONE4=
ZONE4KEY=
ZONE6=lab.xrtc.net.
ZONE6KEY=/config/Klab.xrtc.net.private
# Subnets to restrict query to. In my home network, 192.168.0.0/24 is
# available for guest use, while 22.2.3.0/24 is hosts that I actually
# care about.
#
# Restricting NET6 to 2000::/3 will only publish globally reachable
# IPv6 addresses.
NET4=22.2.3.0/24
NET6=2000::/3
IF4=br0
IF6=br0
zeroize_macaddrs ()
{
sed -e 's/\(\s\)\([0-9a-f]\):/\10\2:/' -e 's/\([^0-9a-f]\)\([0-9a-f]\):/\10\2:/g' -e 's/:\([0-9a-f]\)$/:0\1/'
}
lowercase ()
{
tr A-Z a-z
}
# Some DHCP servers can be configured to update the /etc/hosts file
# with the MAC address. If yours does this, the records it puts in
# will be useful for other address families too!
#
# If your DHCP server does this but treats leading zeros in MAC
# addresses differently than 'ip', then, well, you're intermittently
# fucked.
resolve_hostfile ()
{
local ip mac name_ip_raw name_ip name_mac_raw name_mac
ip="$1"
mac="$2"
name_ip_raw=$( fgrep -i "$ip" /etc/hosts | lowercase | cut -f2 )
# Remove domain name, if present
name_ip=${name_ip_raw%%.*}
name_mac_raw=$( cat /etc/hosts | lowercase | zeroize_macaddrs | fgrep -i "$mac" | cut -f2 )
# Remove domain name, if present
name_mac=${name_mac_raw%%.*}
# Prefer the IP-matched name, but also accept MAC-matched name.
echo ${name_ip:-$name_mac}
}
# nope
resolve_avahi ()
{
echo
}
# Maybe localhost has a DNS server that knows things!
resolve_localdns ()
{
local ip name_raw name
ip="$1"
name_raw=$( host "$ip" localhost | tail -n 1 | cut -d\ -f5 )
name=${name_raw%%.*}
echo $name
}
list4 ()
{
ip neigh show ${IF4:+dev $IF4} to ${NET4:-0/0} |\
lowercase |\
grep lladdr |\
zeroize_macaddrs |\
cut -d\ -f1,3
}
list6 ()
{
ip neigh show ${IF6:+dev $IF6} to ${NET6:-::/0} |\
lowercase |\
grep lladdr |\
zeroize_macaddrs |\
cut -d\ -f1,3
}
do_resolve ()
{
local method name addr mac
addr="$1"
mac="$2"
unset name
# try, in order, all the configured resolution methods
for method in $METHODS ; do
name=$( resolve_$method $addr $mac )
# if we got a name that's nonempty, that's a winner!
if [ x"$name" != "x" ] ; then
#echo found $addr as $name using $method >&2
break
fi
done
echo "$name"
}
do_update ()
{
# Remove any old record and add the new one
echo update delete $2 $3
echo update add $2 30 $3 $1
}
do_entry ()
{
local addr mac zone name
addr="$1"
mac="$2"
zone="$3"
type="$4"
name=$( do_resolve $addr $mac )
# no name for this address, sorry bub
if [ x"$name" == "x" ] ; then return ; fi
if [ x"$name" == "x3(NXDOMAIN)" ] ; then return ; fi
#echo do_update addr =$addr name =$name zone =$zone
do_update $addr $name.$zone $type
}
if [ x"$ZONE4" != "x" ] ; then
( echo zone $ZONE4
list4 | while read addr mac ; do
do_entry $addr $mac $ZONE4 A
done
echo send
echo show
) | nsupdate -k "$ZONE4KEY"
fi
if [ x"$ZONE6" != "x" ] ; then
( echo zone $ZONE6
#echo update delete
list6 | while read addr mac ; do
do_entry $addr $mac $ZONE6 AAAA
done
echo show
echo send
) | nsupdate -k "$ZONE6KEY"
fi
# Now, after we've added all these, flush the cache so that only new
# addresses are added in the future. This is sub-optimal because it
# will cause requests for neighbors to be reissued before necessary,
# but ... whatever. Computers can deal and I'm not running a very big
# network.
ip neigh flush dev $IF4
ip neigh flush dev $IF6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment