#!/bin/sh
#
# ifup_nsupdate
#
# DESCRIPTION:
# Goes in your LEAF system's /etc/network/if-up.d directory (or the equivalent
# directory on a normal Linux box) to update your name server with your
# dynamically-assigned IP address (e.g. from PPPoE). Requires a TSIG
# public/private keyfile pair generated by BIND 8's dnskeygen or BIND 9's
# dns-seckeygen to reside in /etc/nsupdate. The name of the private keyfile
# and a few other variables must be personalized below for this script to
# work!
#
# For more information on TSIG-based dynamic DNS, see the BIND documentation
# at and/or Jason Bodnar's very helpful "Dynamic DNS
# for the Home User" at (but
# ignore the part of that document talking about HTTP-based dynamic updates).
#
# COPYRIGHT:
# This file is Copyright (C) 2002 by its authors, and is released under the
# GNU General Public License .
#
# AUTHORS:
# DH = Dan
#
# DATE BY REVISION
# ========== == ==============================================================
# 2002-07-29 DH Original.
## The variables in this section MUST be configured:
# The FQDN you want to register as having your dynamic IP.
#DYNAMIC_IP_HOSTNAME=...
# The interface that has your external IP address bound to it. This is ppp0
# for PPP/PPPoE, or eth0 in direct-routed setups (with IPs assigned by DHCP).
EXTERNAL_IP_IFACE=ppp0
# Ordinarily nsupdate would figure out the responsible nameserver automatically,
# but on LEAF it tries to contact the caching nameserver at 127.0.0.1. Note
# that the nameserver must be specified by IP address, not DNS name, because
# dnscache won't have started when the interface is first being brought up.
#NAMESERVER=
# The public keyfile (K.++.key) must be in this same dir
# (which is intentionally only readable by root to protect the private key).
#PRIVATE_KEYFILE=/etc/nsupdate/K.++.private
# Now check that the user has been in here configuring (and made it to the last
# required variable); abort cleanly if not.
if [ x"$PRIVATE_KEYFILE" = x ]; then
echo "ERROR: $0 has not been configured. Aborting."
exit 1
fi
## These settings can usually be left as-is:
# ifup sets $IFACE in our environment (verified for the PPPoE case, at least),
# but to allow this script to be called directly, we need to set IFACE here.
if [ x"$IFACE" = x ]; then
IFACE=$EXTERNAL_IP_IFACE
fi
# For PPPoE, at least, the interface isn't actually up when we first get
# called, but it'll go up in the background if we wait a bit.
# $IFACE_UP_WAIT_TIME is how many seconds to wait between checks for the
# interface being up. $IFACE_UP_WAIT_MAX_RETRIES is how many times we'll try
# waiting before we give up.
IFACE_UP_WAIT_MAX_RETRIES=12
IFACE_UP_WAIT_TIME=5
# nsupdate has a pretty short timeout (and as of this writing there's no
# parameter to increase it) -- sometimes it fails just because the link is
# slow or the server is busy. Try up to $NSUPDATE_MAX_RETRIES times and wait
# $NSUPDATE_WAIT_TIME seconds between tries.
NSUPDATE_MAX_RETRIES=3
NSUPDATE_WAIT_TIME=5
# -d has nsupdate do debugging output, including the DNS server's response.
NSUPDATE_OPTIONS=-d
# The desired time-to-live (in seconds) for this dynamic DNS setting.
TTL=300
# If ifup isn't being run on the appropriate interface, exit now before we
# potentially try to do an rdate (and of course try to do the update itself).
if [ "$IFACE" != "$EXTERNAL_IP_IFACE" ]; then
exit
fi
# If the machine's time is way out-of-sync with the nameserver (as it will be
# if the machine's CMOS clock is set to the local time but /etc/localtime is
# still the installation-default of UTC), the DNS update will fail. Generally
# it should be enough to install the appropriate /usr/share/zoneinfo file and
# point /etc/localtime at it, but if the clock is still too far off from the
# nameserver's you might need to uncomment this line (note it'll only be useful
# if the nameserver's time/tcp port is open -- if it's not, you'll need to look
# to an NTP solution).
#rdate $NAMESERVER
## Ordinarily, you shouldn't need to modify anything below this line.
this_script=`basename $0`
# For testing purposes, you can set environment variable $IP to arbitrary val.
if [ x"$IP" = x ]; then
times_waited=0
while ! ip addr list $IFACE 2>/dev/null \
| grep "inet [0-9]" 1>/dev/null 2>&1; do
if [ $times_waited = $IFACE_UP_WAIT_MAX_RETRIES ]; then
echo "$this_script: Exceeded IFACE_UP_WAIT_MAX_RETRIES of"\
"$IFACE_UP_WAIT_MAX_RETRIES. Aborting."
exit 1
fi
times_waited=`expr $times_waited + 1`
echo "$this_script: $IFACE not up yet. Sleeping"\
"$IFACE_UP_WAIT_TIME seconds (repetition $times_waited of"\
"$IFACE_UP_WAIT_MAX_RETRIES)."
sleep $IFACE_UP_WAIT_TIME
done
IP=`ip addr list $IFACE | grep "inet [0-9]" \
| sed 's/^.*inet \(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\).*$/\1/'`
fi
ADD_CMD="update add $DYNAMIC_IP_HOSTNAME $TTL A $IP\n"
DELETE_CMD="update delete $DYNAMIC_IP_HOSTNAME A\n"
SERVER_CMD="server $NAMESERVER\n"
nsupdate_exit=1
times_nsupdated=0
while [ $nsupdate_exit != 0 ]; do
echo -e "$SERVER_CMD$DELETE_CMD$ADD_CMD" \
| nsupdate $NSUPDATE_OPTIONS -k $PRIVATE_KEYFILE >/dev/null
nsupdate_exit=$?
times_nsupdated=`expr $times_nsupdated + 1`
if [ $nsupdate_exit = 0 ]; then
echo "$this_script: nsupdate succeeded."
else
echo -e "$this_script: nsupdate failed (try $times_nsupdated of"\
"$NSUPDATE_MAX_RETRIES).\c"
if [ $times_nsupdated -lt $NSUPDATE_MAX_RETRIES ]; then
echo " Sleeping $NSUPDATE_WAIT_TIME seconds before retry."
sleep $NSUPDATE_WAIT_TIME
else
echo
break
fi
fi
done
exit $nsupdate_exit