Fork me on GitHub

NSupdate

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.

Comments !

blogroll

accounts