For a while now, I’ve been using DDNS services to remotely access machines for ssh etc. Most of these free services, such as dyndns and no-ip, require you to respond to an email every month or so to keep your account active. With this domain, I finally have an alternative: Real DNS!
I believe Bind is the most used DNS server, and it’s fairly simple to install. For remote update, I mostly followed this excellent tutorial. I ended up writing my own script to do the update.
The nsupdate tool is included with the dnsutils package and takes input of the form:
server ns1.example.com
zone example.com
update delete host.example.com.
update add host.example.com. 3600 A 123.123.123.123
send
quit
Note the trailing periods on the urls; these are important. This set of commands can be sent with the command nsupdate -v -k KEYFILE
. The KEYFILE is the key used to authenticate yourself to the server and control your access to the domain. Next you need the external ip address of the host. The most reliable way I’ve found, is using ifconfig.me. This has a helpful list of commands on the web site, for just an ip, it’s curl ifconfig.me/ip
. Here’s my full script:
#
# Tim Brooks 2012 <brooks@skoorb.net>
#
# nsupdater - Updates dns record for $HOSTNAME at $NAMESERVER
#
# Options:
TTL=3600
ALIAS=$HOSTNAME
DOMAIN="skoorb.net"
KEYFILE="/home/brooks/.dnskey.private"
NAMESERVER="ns1.skoorb.net"
valid_ip() {
local ip=$1
local stat=1
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
OIFS=$IFS
IFS='.'
ip=($ip)
IFS=$OIFS
[[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
&& ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
stat=$?
fi
return $stat
}
ns_update() {
# Get current external ip
local newip=$(curl --silent ifconfig.me)
local stat
if valid_ip $newip; then
echo -e "server $NAMESERVER\nzone $DOMAIN\nupdate delete $ALIAS.$DOMAIN. A\nupdate add $ALIAS.$DOMAIN. $TTL A $newip\nsend" | nsupdate -v -k $KEYFILE
stat=$?
# Log how things went to syslog
if [ $stat == 0 ]; then
logger -it nsupdate Updated dns record $ALIAS.$DOMAIN. to $newip
else
logger -ist nsupdate Failed to update dns record - nsupdate returned $stat
fi
else
logger -ist nsupdate "Got invalid IP address '$newip'"
fi
}
ns_setup() {
# Check if we have made a connection:
if [ "$DHCP4_IP_ADDRESS" != "" ]; then
ns_update
fi
# Old dhcp style
case $reason in
BOUND|RENEW|REBIND|REBOOT)
ns_update;;
esac
}
ns_setup
Lastly, we need some way to run this when our IP address changes. The standard way is to use dhclient, which has an exit hooks folder at /etc/dhcp/dhclient-exit-hooks.d/
. Unfortunately, many desktop systems use a different mechanism, which is the reason for the $DHCP4_IP_ADDRESS switch. To hook into network-manager, we need to also put our script at /etc/NetworkManager/dispatcher.d/
.
This needs updating to ipv6 at some point, but I had enough of a headache trying to understand the ipv4 DNS, so that will have to be another day.
There are comments.