OpenWrt Forum Archive

Topic: dyndns with udhcpc mini-how to

The content of this topic has been archived on 1 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

This is a mini-howto about how to update dynds dns record using udhcpc client and a shell script.

We have to make a copy from /usr/share/udhcpc/default.script default script:

cp /usr/share/udhcpc/default.script /etc/dhcp-dyndns

Now we have to edit /etc/dhcp-dyndns for add dyndns update, this is my /etc/dhcp-dyndns.

#!/bin/sh
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
# (slightly modified)

[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1

RESOLV_CONF="/tmp/resolv.conf"

case "$1" in
        deconfig)
                ifconfig $interface 0.0.0.0
                ;;

        renew|bound)
                ifconfig $interface $ip 
                ${broadcast:+broadcast $broadcast} 
                ${subnet:+netmask $subnet}

                if [ -n "$router" ] ; then
                        echo "deleting routers"
                        while route del default gw 0.0.0.0 dev $interface ; do
                                :
                        done

                        for i in $router ; do
                                route add default gw $i dev $interface
                        done
                fi

                echo -n > $RESOLV_CONF
                ${domain:+echo search $domain >> $RESOLV_CONF}
                for i in $dns ; do
                        echo adding dns $i
                        echo nameserver $i >> $RESOLV_CONF  
              wget -O /dev/null http://USER:PASSWORD@members.dyndns.org/nic/update?hostname=DOMAIN
                done
                ;;
esac
exit 0

This is the line that we have to add (replace user, password and domain with your settings):

wget -O /dev/null http://USER:PASSWORD@members.dyndns.org/nic/update?hostname=DOMAIN

And finally, we need launch udhcpc like here:

udhcpc -i vlan1 -b -s /etc/dhcp-dyndns

When dhcpd give a new ip, /etc/dhcp-dyndns, udhcpc will exec /etc/dhcp-dyndns script.

Sorry for my english smile

I found problems using it for a few days, dyndns suspend my account for excessives update request ... i don't know why udhcpc does a lot of request ... it only should do it if the ip changes.

So .. y make a little bash script that only make a request if ip changes, is this:

#!/bin/bash

USER=""
PASSWORD=""
DOMAIN=""
VLAN=$(nvram get wan_ifname)
IP=$(ip addr show $VLAN | grep 'inet ' | cut -d t -f2 | cut -d / -f1 | cut -b 2-)
IPANT=$(cat /etc/lastip)

check() {
if [ "$IP" != "$IPANT" ]; then
        echo $IP > /etc/lastip
        wget -O /dev/null http://$USER:$PASSWORD@members.dyndns.org/nic/update?hostname=$DOMAIN
fi
}

while [ 1 ]; do check; sleep 300; done

You should create /etc/lastip file before launch the script, and ... you can launch the script with something like:

sh <script_name.sh> &

or add this into /etc/init.d/.... for automatic start.

Isn't the best way but ... appears to work well.

There's no point in wearing out the flash chip by writing /etc/lastip; just do a dns lookup to see what the last ip was:

#!/bin/sh
USER="username"
PASS="password"
DOMAIN="example.com"

registered=$(nslookup $DOMAIN||sed s/[^0-9.]//g|tail -n1)

while :; do
  current=$(wget -O - http://checkip.dyndns.org|sed s/[^0-9.]//g)
  [ "$current" != "$registered" ] && {                           
     wget -O /dev/null http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN &&
     registered=$current
  }                     
  sleep 300             
done &    

There's no point in wearing out the flash chip by writing /etc/lastip; just do a dns lookup to see what the last ip was:

#!/bin/sh
USER="username"
PASS="password"
DOMAIN="example.com"

registered=$(nslookup $DOMAIN||sed s/[^0-9.]//g|tail -n1)

while :; do
  current=$(wget -O - http://checkip.dyndns.org|sed s/[^0-9.]//g)
  [ "$current" != "$registered" ] && {                           
     wget -O /dev/null http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN &&
     registered=$current
  }                     
  sleep 300             
done &    

Ok, perfect, but there was a little error in your sintaxis, in this line:
registered=$(nslookup $DOMAIN||sed s/[^0-9.]//g|tail -n1)

is only one |, like this:

registered=$(nslookup $DOMAIN|sed s/[^0-9.]//g|tail -n1)

smile

Opps. I tossed it together as an example without actually testing it.

Anyways, here's the corrected version for cut&paste:

#!/bin/sh
USER="username"
PASS="password"
DOMAIN="example.com"

registered=$(nslookup $DOMAIN|sed s/[^0-9.]//g|tail -n1)

while :; do
  current=$(wget -O - http://checkip.dyndns.org|sed s/[^0-9.]//g)
  [ "$current" != "$registered" ] && {                           
     wget -O /dev/null http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN &&
     registered=$current
  }                     
  sleep 300             
done &

thanks,
it worked really well

Javiergonzalez00 wrote:

I found problems using it for a few days, dyndns suspend my account for excessives update request ... i don't know why udhcpc does a lot of request ... it only should do it if the ip changes

If you're ppp half-bridging an ethernet modem like the X-Modem from adslnation, they have very small lease times, so you'll hit the renew state of udhcpc constantly. This howto was very useful. Thanks!

you should make another addition to the code. the problem is that if you don't update your account for about 20 days it gets cancelled..

Please advice where I should add this script to, and how to make this process run automatically at startup

I have a slightly different solution that is lightweight, works with dyndns, and uses the nvram to store config data so ddns data and cache info is saved over a reboot. Uses the following nvram vars:

ddns_enable=1
ddns_hostname=<the host>
ddns_cache=<used by script>
ddns_username=<dyndns.org username>
ddns_passwd=<dyndns org password>
ddns_interval=<minimal interval between updates, default 600 seconds>

Please note that I have not tested the script fully, since I only have limited updates. Please also note that you should have set up ntpclient to keep the time in sync.
Copy this script into /usr/bin/dyndns.sh, execute chmod +x /usr/bin/dyndns.sh and find some way of starting it automatically. You can use the /etc/ppp/ip-up script for
example if you use pppoe, udhcpcd update file, or cron. Note however that dyndns blocks timed updates, i.e. every 24 hours when the lease expires or a timed cron. To
workaround, you may want to sleep a random number of minutes/hours before updating. You will have to add the 28 days thing yourself. Its nothing more than checking
if $(($CURRENTDATE-$LASTDATE)) is greater than 2419200 (28 days in seconds).

#!/bin/sh                                                                                                                           
                                                                                                                                    
if [ "$(nvram get ddns_enable)" -eq "1" ]                                                                                           
then                                                                                                                                
        ## get variables from nvram and command line                                                                                
        HOSTNAME=$(nvram get ddns_hostname)                                                                                         
        USERNAME=$(nvram get ddns_username)                                                                                         
        PASSWORD=$(nvram get ddns_password)                                                                                         
        INTERVAL=$(nvram get ddns_interval)                                                                                         
        LASTUPDATE=$(nvram get ddns_cache | awk 'BEGIN { FS=","; }{print $1}')                                                      
        LASTIP=$(nvram get ddns_cache | awk 'BEGIN { FS=","; }{print $2}')                                                          
        NEWIP="$1"                                                                                                                  
        CURRENTDATE=$(date +%s)                                                                                                     
                                                                                                                                    
        ## get the IP address from wan_ifname if not supplied                                                                       
        if [ -z "$NEWIP" ]                                                                                                          
        then                                                                                                                        
                NEWIP=$(ifconfig $(nvram get wan_ifname) | grep inet | awk '{print $2}' | cut -c 6-)                                
        fi                                                                                                                          
                                                                                                                                    
        ## set default values for ddns_cache if not set                                                                             
        if [  -z "$LASTUPDATE"  -o  -z "$LASTIP"  ]                                                                                 
        then                                                                                                                        
                LASTUPDATE=0                                                                                                        
                LASTIP=0.0.0.0                                                                                                      
        fi                                                                                                                          
                                                                                                                                    
        ## set default values for ddns_interval if not set                                                                          
        if [ -z "$INTERVAL" ]                                                                                                       
        then                                                                                                                        
                INTERVAL=600                                                                                                        
        fi                                                                                                                          
                                                                                                                                    
        ## do the update if the ip changed and the interval is exceeded                                                             
        if [ -n "$CURRENTDATE" -a $(($CURRENTDATE-$LASTUPDATE)) -gt $INTERVAL -a  "$LASTIP" != "$NEWIP" ]                           
        then                                                                                                                        
               echo "Updating $HOSTNAME to $NEWIP"                                                                                 
               wget -qO /dev/null http://$USERNAME:$PASSWORD@members.dyndns.org/nic/update?hostname=$HOSTNAME                      
               nvram set ddns_cache="$CURRENTDATE,$NEWIP"                                                                          
               nvram commit                                                                                                        
                                                                                                                                    
        else                                                                                                                        
                echo "No update needed for $HOSTNAME"                                                                               
        fi                                                                                                                          
                                                                                                                                    
fi

(Last edited by xFallenAngel on 24 Jul 2005, 12:37)

Restating what I said earlier - please, don't write to the flash on a regular interval. This is especially true for "nvram commit" since that writes to the same portion of the flash each time. While one script won't really cause much damage, if multiple scripts do this or if the script has an error you can wear out the flash chip.

Ah yes, I understand. Should have thought of that. Now how did linksys do it? I used the variables they provided, including ddns_cache. I don't know if they wrote to the nvram or if they kept changes uncommited, but they used this nvram variable to keep a cache of what IP was updated, iirc.

Hi OpenWRT-Dyndns-Folks,

in my opinion an ideal solution for pppoe-based (dsl) connections that are automatically disconnected every x hours is the following method/script:

From the pppd manpage:
pppd executes a so called ip-up script triggered (by a successfull connection).

pppd provides all interessting connection parameters (Local IP, Remote IP, etc...) as arguments to ip-up. For details see the example-script below.
1.) The main advantage of ip-up is in my opinion that a dyndns-Update is really only called on demand.
2.) There is no "sleep-idel-loop", no checking whether the ip has changed or not.
3.) The risk to get temporarily banned by dyndns (because of unneeded/doubled updates of the same IP) is also nearly zero because after a reconnect you normaly get a new IP address.
4.) The ip-up script is in my opinion also a perfect place to trigger special/custom firewall rules and/or vpn-connections...

Cheers dp
P.S.: Thanks to the OpenWRT-Community for the nice project!

So if your internet connection is ppp(oe) based - like mine - I suggest placing the following shell-script in the file /etc/ppp/ip-up:

#!/bin/ash
USERNAME="root"
PASSWORD="erpo2isds12mn1awro"
DDHOSTNAME="linux-depp.dyndns.org"

DEBUG=0
LOGGER=/usr/bin/logger

BASENAME=`basename $0`
INTERFACE=$1
DEVICE=$2
SPEED=$3
LOCALIP=$4
REMOTEIP=$5
TYP=$6

if [ "$DEBUG" = "1" ]; then
        DATE=`date`
        $LOGGER -t $BASENAME "Debug parameters of $BASENAME: if:$INTERFACE, dev:$DEVICE, speed:$SPEED, lip:$LOCALIP, rip:$REMOTEIP, typ:$TYP"
        echo "$DATE" >> /etc/ppp/ip-up-debug
        echo -e "$BASENAME: Parameters: if: $INTERFACE, dev: $DEVICE, speed: $SPEED, lip: $LOCALIP, rip: $REMOTEIP, typ: $TYP\n" >> /etc/ppp/ip-up-debug
        echo "wget -O /dev/null http://$USERNAME:$PASSWORD@members.dyndns.org/nic/update?hostname=$DDHOSTNAME"
else
        logger -t $BASENAME "Updating dyndns entry for $DDHOSTNAME"
        wget -O /dev/null http://$USERNAME:$PASSWORD@members.dyndns.org/nic/update?hostname=$DDHOSTNAME
fi

Could someone post the latest, greatest code and details for setting up a dyndns update? Thanks.

I'm bit confused. how to add wildcard=ON to string. I tried following but seems that wildcard is not been swiched on after update.

http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN&wildcard=ON &&
       registered=$current


Also copmare to http://www.dyndns.com/developers/specs/syntax.html  update syntacs here looks different. How so?

Can someone help me out with getting this to work? I am using the code posted by Member dp above but it isn't working. I think it is because the syntax of the dyndns update url has changed some. I don't really know shell scripting at all so if anyone could help me out I'd appreciate it.

Awesome!! Thanks for the help.

silver wrote:

http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN&wildcard=ON &&
       registered=$current

@silver: You need to escape the "&" between multiple arguments with a preceding "\" - like this:

http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN\&wildcard=ON &&
       registered=$current
mbm wrote:

Opps. I tossed it together as an example without actually testing it.

Anyways, here's the corrected version for cut&paste:

#!/bin/sh
USER="username"
PASS="password"
DOMAIN="example.com"

registered=$(nslookup $DOMAIN|sed s/[^0-9.]//g|tail -n1)

while :; do
  current=$(wget -O - http://checkip.dyndns.org|sed s/[^0-9.]//g)
  [ "$current" != "$registered" ] && {                           
     wget -O /dev/null http://$USER:$PASS@members.dyndns.org/nic/update?hostname=$DOMAIN &&
     registered=$current
  }                     
  sleep 300             
done &

Only to say that if u use http://www.whatismyip.org/ rather than http://checkip.dyndns.org you haven't to use sed s/[^0-9.]//g).

why not use ez-ipupdate? am i missing something here?

ez-ipupdate will update even when the IP address hasn't changed and get you banned from DynDNS.

Seems to me that we should take the working version of this code and turn it into an installable package. It'd be a very useful tool.

Nik wrote:

ez-ipupdate will update even when the IP address hasn't changed and get you banned from DynDNS.

it seems to me then that ez-ipupdate should be removed from openwrt, or have a warning attached, that it will update unnecessarily. i'm working on changing the hotplug script for ez-ipupdate to make it not do this. i haven't looked at the ez-ipupdate source, but will try to implement the necessary functionality into the hotplug script and go from there. we'll see if people prefer this solution over the above. I'm not a fan of having a script sleep for some time period and then try to restart and check things again. It seems to me that these things get hung up, especially on equipment that just sits around for forever w/o maintentance like (some) of our routers do. will post back soon.

this will only execute the typical hotplug script if the ipaddress is different than the one that was previously stored or if it hasn't been updated in 20 days (1728000 = 20days * 24 h/d * 60 m/h * 60 s/m..right). the only thing i'm worried about is tmp getting cleared on a reboot/unplug. this would cause the cache file to get wiped, which would cause a possibly unwarranted update. I'm not too sure if this is the case though. This script will not behave well if the cache file is missing. What i need to know is should we go ahead and do an update if the cache file is missing? I am assuming yes, and i have it setup to do update if there is no cache file below. this would be nicer if i could have the substance of the script ([ "$ACTION" =.... }) just once in the script so i could just reference it as something like "$update."  i've had bad luck in the past trying to put multiple lines of code in a single variable, so to me, that doesn't seem like the best idea. but if you know how to do it properly, please do.

it just makes more sense to me to try to keep with the ez-ipupdate package since it supports a number of webservices. i looked into using the recommended unix client (by dyndns.org), ddclient, but it requires a perl install and is like 3000 lines of code, which i don't feel like going through (nor would i understand all of it).

edit: did i mention that this is not thoroughly tested and may burn your computer, kill your dog, and steal your SO?
edit2: oh, this is a modified hotplug script. it goes in /etc/hotplug.d/iface
edit3: why am i not using the nslookup method for finding out what the dns entry is? b/c i have one of my dns aliases set in /etc/hosts so that i can have my laptop configured to use the dns entry and have it work inside and outside my lan. this will not "regularly" write to the flash, unless you define regularly as everytime your IP updates, which shouldn't be that often. I don't see a reliable way of storing when the last update time was done otherwise.
edit4: typo. also, note that there is no configuration that needs to be done with this. you just configure ez-ipupdate like you normally would, which will be more supportive of different services.

. /etc/functions.sh
NAME=ez-ipupdate
CONFIG=/etc/$NAME.conf
COMMAND=/usr/sbin/$NAME



ipthen=`cat $CONFIG | grep cache | sed 's/cache-file=//'`
if ! [ -f $ipthen ] ; then
        [ "$ACTION" = "ifup" -a "$INTERFACE" = "wan" ] && {
                [ -x $COMMAND ] && [ -r $CONFIG ] && {
                        IFNAME=$(nvram get ${INTERFACE}_ifname)
                        $COMMAND -c $CONFIG -i $IFNAME 2>&1 | logger -t $NAME
                } &
        }
        exit
fi
ipthen=`cat $ipthen | sed 's/.*,//'`
ipnow=`nvram get wan_ifname`
ipnow=`ifconfig $ipnow | grep inet | sed 's/.*inet addr:\(.*\) B.*/\1/'`
if [ $ipthen != $ipnow ] ; then
        [ "$ACTION" = "ifup" -a "$INTERFACE" = "wan" ] && {
                [ -x $COMMAND ] && [ -r $CONFIG ] && {
                        IFNAME=$(nvram get ${INTERFACE}_ifname)
                        $COMMAND -c $CONFIG -i $IFNAME 2>&1 | logger -t $NAME
                } &
        }
        exit
fi
timethen=`cat $CONFIG | grep cache | sed 's/cache-file=//'`
timethen=`cat $timethen | sed 's/,.*//'`
timenow=`date +%s`
elapse=`expr $timenow - $timethen`
if [ $elapse -gt 1728000 ] ; then
        [ "$ACTION" = "ifup" -a "$INTERFACE" = "wan" ] && {
                [ -x $COMMAND ] && [ -r $CONFIG ] && {
                        IFNAME=$(nvram get ${INTERFACE}_ifname)
                        $COMMAND -c $CONFIG -i $IFNAME 2>&1 | logger -t $NAME
                } &
        }
        exit
fi

(Last edited by lostnihilist on 14 Oct 2006, 09:56)

lostnihilist wrote:

why not use ez-ipupdate? am i missing something here?

Well, for starters, ez-ipupdate doesn't seem to have been updated in over 4 years.  And in my case, it doesn't support http://sitelutions.com, whom I've been using for over 2 years now with no problems.  It also appears that this only supports the updating of one DNS entry, I could be wrong on that, though, the docs for this thing are almost nonexistent.

The discussion might have continued from here.