ddclient seems to be updating IP, but reporting errors

jrm@

Developer
I'm seeing the following errors in /var/log/messages:
Code:
Oct 29 21:35:23 gly ddclient[1982]: WARNING: file /var/tmp/ddclient.cache, line 3: Invalid Value for keyword 'ip' = ''
Oct 29 21:35:23 gly ddclient[1982]: WARNING: skipping update of gly.ath.cx from to 129.173.34.203.
Oct 29 21:35:23 gly ddclient[1982]: WARNING: last updated but last attempt on Sat Oct 29 21:31:56 2011 failed.
Oct 29 21:35:23 gly ddclient[1982]: WARNING: Wait at least 5 minutes between update attempts.
Oct 29 21:40:24 gly ddclient[1982]: FAILED: updating gly.ath.cx: Could not connect to members.dyndns.org.
I think ddclient is updating when it's not necessary because of these errors, which is causing my host to be banned.

My configuration file is below with secure information XXed out:
Code:
daemon=600
login=xxx
mail=xxx
mail-xxx
password=xxx
pid=/var/run/ddclient.pid
protocol=dyndns2
server=members.dyndns.org
ssl=yes
syslog=yes
use=if, if=re0
gly.ath.cx
/var/tmp/ddclient.cache looks like:
Code:
##ddclient-3.8.1
##last updated at Sat Oct 29 21:45:24 2011 (1319935524)
atime=1319935524,backupmx=0,custom=0,host=gly.ath.cx,ip=,mtime=0,mx=,script=/nic/update,static=0,status=noconnect,
warned-min-error-interval=0,warned-min-interval=0,wildcard=0,wtime=0 gly.ath.cx
I've asked on the dyn forums and had one response, but I'm still not clear what the solution is. That response said:

Invalid Value for keyword 'ip' = ''. This is the culprit. The URL parameter isn't 'ip', but 'myip', and it is optional too. See also http://dyn.com/support/developers/api/perform-update/ You don't seem to have a default ddclient installation, apparently. Here is how you can correct the update URL:http://sourceforge.net/apps/trac/ddclient/ticket/30

I'm not specifying the values in the cache file, it's generated from the configuration file. As far as I can tell the configuration file is valid.
 
That response is bogus because the myip parameter is for the update URL, not for the cache file.

Try running ddclient in foreground with debug and verbose options turned on, something like:

# ddclient -debug -verbose -foreground -file /usr/local/etc/ddclient.conf

It may be a good idea to first stop the daemonized ddclient before running that.
 
The output is below. I changed the daemon value in the configuration file to 60 while I was testing. I think/hope since I'm getting my ip through the interface and not by web=checkip.dyndns.com this shouldn't cause a problem.


Code:
jrm@xxx ~ % WARNING:  file /var/tmp/ddclient.cache, line 3: Invalid Value for keyword 'ip' = ''
=== opt ====
opt{cache}                           : <undefined>
opt{cmd}                             : <undefined>
opt{cmd-skip}                        : <undefined>
opt{daemon}                          : 60
opt{debug}                           : 1
opt{exec}                            : <undefined>
opt{facility}                        : <undefined>
opt{file}                            : /usr/local/etc/ddclient.conf
opt{force}                           : <undefined>
opt{foreground}                      : 1
opt{fw}                              : <undefined>
opt{fw-login}                        : <undefined>
opt{fw-password}                     : <undefined>
opt{fw-skip}                         : <undefined>
opt{geturl}                          : <undefined>
opt{help}                            : <undefined>
opt{host}                            : <undefined>
opt{if}                              : <undefined>
opt{if-skip}                         : <undefined>
opt{ip}                              : <undefined>
opt{login}                           : <undefined>
opt{mail}                            : <undefined>
opt{mail-failure}                    : <undefined>
opt{max-interval}                    : 2160000
opt{min-error-interval}              : 300
opt{min-interval}                    : 30
opt{options}                         : <undefined>
opt{password}                        : <undefined>
opt{pid}                             : <undefined>
opt{postscript}                      : <undefined>
opt{priority}                        : <undefined>
opt{protocol}                        : <undefined>
opt{proxy}                           : <undefined>
opt{query}                           : <undefined>
opt{quiet}                           : 0
opt{retry}                           : <undefined>
opt{server}                          : <undefined>
opt{ssl}                             : <undefined>
opt{syslog}                          : <undefined>
opt{test}                            : <undefined>
opt{timeout}                         : <undefined>
opt{use}                             : <undefined>
opt{verbose}                         : 1
opt{web}                             : <undefined>
opt{web-skip}                        : <undefined>
=== globals ====
globals{daemon}                      : 60
globals{debug}                       : 1
globals{file}                        : /usr/local/etc/ddclient.conf
globals{foreground}                  : 1
globals{if}                          : bge0
globals{login}                       : xxx
globals{mail}                        : xxx
globals{mail-failure}                : xxx
globals{password}                    : xxx
globals{pid}                         : /var/run/ddclient.pid
globals{protocol}                    : dyndns2
globals{quiet}                       : 0
globals{server}                      : members.dyndns.org
globals{ssl}                         : 1
globals{syslog}                      : 1
globals{use}                         : if
globals{verbose}                     : 1
=== config ====
config{xxx.ath.cx}{atime}            : 0
config{xxx.ath.cx}{backupmx}         : 0
config{xxx.ath.cx}{cacheable}        : ARRAY(0x34346eb0)
config{xxx.ath.cx}{cmd}              : <undefined>
config{xxx.ath.cx}{cmd-skip}         :
config{xxx.ath.cx}{custom}           : 0
config{xxx.ath.cx}{fw}               :
config{xxx.ath.cx}{fw-login}         : <undefined>
config{xxx.ath.cx}{fw-password}      :
config{xxx.ath.cx}{fw-skip}          :
config{xxx.ath.cx}{host}             : xxx.ath.cx
config{xxx.ath.cx}{if}               : bge0
config{xxx.ath.cx}{if-skip}          :
config{xxx.ath.cx}{ip}               : <undefined>
config{xxx.ath.cx}{login}            : xxx
config{xxx.ath.cx}{max-interval}     : 2160000
config{xxx.ath.cx}{min-error-interval} : 300
config{xxx.ath.cx}{min-interval}     : 30
config{xxx.ath.cx}{mtime}            : 0
config{xxx.ath.cx}{mx}               :
config{xxx.ath.cx}{password}         : xxx
config{xxx.ath.cx}{protocol}         : dyndns2
config{xxx.ath.cx}{script}           : /nic/update
config{xxx.ath.cx}{server}           : members.dyndns.org
config{xxx.ath.cx}{static}           : 0
config{xxx.ath.cx}{status}           :
config{xxx.ath.cx}{use}              : if
config{xxx.ath.cx}{warned-min-error-interval} : 0
config{xxx.ath.cx}{warned-min-interval} : 0
config{xxx.ath.cx}{web}              : dyndns
config{xxx.ath.cx}{web-skip}         :
config{xxx.ath.cx}{wildcard}         : 0
config{xxx.ath.cx}{wtime}            : 30
=== cache ====
cache{xxx.ath.cx}{atime}             : 1319933145
cache{xxx.ath.cx}{backupmx}          : 0
cache{xxx.ath.cx}{custom}            : 0
cache{xxx.ath.cx}{host}              : xxx.ath.cx
cache{xxx.ath.cx}{mtime}             : 0
cache{xxx.ath.cx}{mx}                :
cache{xxx.ath.cx}{script}            : /nic/update
cache{xxx.ath.cx}{static}            : 0
cache{xxx.ath.cx}{status}            : noconnect
cache{xxx.ath.cx}{warned-min-error-interval} : 0
cache{xxx.ath.cx}{warned-min-interval} : 0
cache{xxx.ath.cx}{wildcard}          : 0
cache{xxx.ath.cx}{wtime}             : 30
DEBUG:    get_ip: using if, bge0 reports xxx.xxx.32.103
DEBUG:
DEBUG:     nic_dyndns2_update -------------------
INFO:     setting IP address to xxx.xxx.32.103 for xxx.ath.cx
UPDATE:   updating xxx.ath.cx
DEBUG:    proxy  =
DEBUG:    url    = http://members.dyndns.org/nic/update?system=dyndns&hostname=xxx.ath.cx&myip=xxx.xxx.32.103
DEBUG:    server = members.dyndns.org
CONNECT:  members.dyndns.org
CONNECTED:  using SSL
SENDING:  GET /nic/update?system=dyndns&hostname=xxx.ath.cx&myip=xxx.xxx.32.103 HTTP/1.0
SENDING:   Host: members.dyndns.org
SENDING:   Authorization: Basic bTAyMDU0Mzpqcm04NzY0NA==
SENDING:   User-Agent: ddclient/3.8.1
SENDING:   Connection: close
SENDING:
RECEIVE:  HTTP/1.1 200 OK
RECEIVE:  Date: Sun, 30 Oct 2011 23:21:17 GMT
RECEIVE:  Server: Apache
RECEIVE:  X-User-Status: free
RECEIVE:  X-UpdateCode: n
RECEIVE:  Content-Type: text/plain
RECEIVE:  Accept-Ranges: none
RECEIVE:  Connection: close
RECEIVE:
FAILED:   updating xxx.ath.cx: Could not connect to members.dyndns.org.
DEBUG:    sleep 60
 
Delete the cache file and update your IP manually once at the dyndns website. Then run the same again.
 
Hi,

Sorry for my english.
I have same problem.

I think it's a ssl perl library bug (p5-IO-Socket-SSL-1.48).
I put
Code:
ssl=no
and it's working.

With the ssl support have
Code:
RECEIVE:  HTTP/1.1 200 OK
RECEIVE:  Date: Sun, 30 Oct 2011 23:21:17 GMT
RECEIVE:  Server: Apache
RECEIVE:  X-User-Status: free
RECEIVE:  X-UpdateCode: n
RECEIVE:  Content-Type: text/plain
RECEIVE:  Accept-Ranges: none
RECEIVE:  Connection: close
RECEIVE:

RECEIVE is null.

But with not ssl support have
Code:
RECEIVE:  HTTP/1.1 200 OK
RECEIVE:  Date: Mon, 31 Oct 2011 09:40:10 GMT
RECEIVE:  Server: Apache
RECEIVE:  X-User-Status: free
RECEIVE:  X-UpdateCode: n
RECEIVE:  Content-Type: text/plain
RECEIVE:  Accept-Ranges: none
RECEIVE:  Connection: close
RECEIVE:
RECEIVE:  nochg 107.197.89.36

RECEIVE not null.
 
jrm said:
Thanks @charles-martel, upgrading security/p5-IO-Socket-SSL did the trick.

I know this is an old thread but I think my problem is close to what has been discussed here.

I installed ddclient today:

Code:
cd /usr/ports/dns/ddclient
make install clean

I edited the /usr/local/etc/ddclient.conf file and tried to start ddclient. But unfortunately I got an error message when ddclient tried to update.

This is what i got in /var/log/messages:
Code:
WARNING:  cannot connect to **.*****.se:443 socket:  IO::Socket::IP configuration failed SSL connect attempt failed with unknown error error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

After that I tried to disable SSL in ddclient.conf:
Code:
ssl=no

And it then successfully was able to make an update. So clearly my problem has something to do with SSL.

I have the following "SSL-ports" installed:
Code:
p5-IO-Socket-IP-0.22           Drop-in replacement for IO::Socket::INET supporting IPv4 and IPv6
p5-IO-Socket-SSL-1.953         Perl5 interface to SSL sockets
p5-Net-SSLeay-1.55             Perl5 interface to SSL
p5-Socket-2.011                Networking constants and support functions

I have tried to reinstall them but as far as I can see these are the latest versions.
 
This is a new problem that I'm seeing on a couple of hosts as well.
 
This error has to do with recent changes to security/p5-IO-Socket-SSL - see here, and pay attention to the "MAJOR BEHAVIOR CHANGE" on 2013-07-3.

To overcome the situation, I did the following:

  1. Install security/ca_root_nss.
  2. Modify the installed ddclient perl script, by adding the recommended SSL_ca_file parameter for passing Mozilla's CA-Root file when creating a SSL socket.
Code:
...
line 1859:
    } elsif ($use_ssl) {
            $sd = IO::Socket::SSL->new(
            PeerAddr => $peer,
            PeerPort => $port,
            Proto => 'tcp',
            MultiHomed => 1, 
            Timeout => opt('timeout'),
            [FILE]SSL_ca_file => '/usr/local/share/certs/ca-root-nss.crt',[/FILE]
        );
...

The green line is the only change that needs to be made.
 
SirDice said:
Would the change still be needed if you enable ETCSYMLINK in security/ca_root_nss?

I just checked it, and it didn't work on my machine. However, I got OpenSSL from the ports installed, and perhaps the ETCSYMLINK need to go to somewhere in the /usr/local/openssl hierarchy.

Anyway, after browsing the ddclient Perl script, I was no more convinced to use it in the long run -- 3500 lines of Perl, only for updating the IP of a dynamic DNS? I did some experiments using ftp/curl, and I came up more quickly than I thought with a slim solution.

My /etc/dhclient-exit-hooks is now calling the following shell script instead of ddclient, and the new IP is passed in the first parameter $1.

Code:
#!/bin/sh

if [ -e /var/tmp/currentIP ] ; then
    currentIP=`/bin/cat /var/tmp/currentIP`
else
    currentIP=
fi
  
if [ "$1" = "" ] ; then
    newIP=`/sbin/ifconfig [I]iface[/I] | /usr/bin/sed -n '/.inet /{s///;s/ .*//;p;}'`
else
    newIP=$1
fi

if [ "$newIP" = "" -o "$newIP" = "$currentIP" ] ; then
    echo "nochg $currentIP"
else
    /usr/local/bin/curl -u [I]username[/I]:[I]password[/I] "https://dyndns.aprovider.com/nic/update?system=dyndns&hostname=myd.com,mail.myd.com&myip=$newIP&mx=mail.myd.com&backmx=NO"
    echo "$newIP" > /var/tmp/currentIP
fi

If the script is invoked on the command line without IP, it picks the IP from the respective output of ifconfig.

With that in place, I could already abandon ddclient on my systems.


Update: Improved the script by calling all external commands by its full path. Many thanks to @kpa.
 
Last edited by a moderator:
You might want to call curl with a full path. It makes me uneasy when a shell script that is run with root privileges trusts that the PATH is correct.
 
Am I correct in reading that the user name and password are on the command line? That's not ideal, but it's a great start. Can anyone think of a more optimal solution?
 
dvl@ said:
Am I correct in reading that the user name and password are on the command line? That's not ideal, but it's a great start. Can anyone think of a more optimal solution?

You can store them in a .netrc file and call curl with the --netrc option.
 
SirDice said:
You can store them in a .netrc file and call curl with the --netrc option.

I will try that. If I get it working, I'll post back the changes. I like keeping things out of the command line.
 
I have the --netrc option working via the command line. ~/.netrc contains this:

Code:
machine members.dyndns.org login MYLOGIN password MYPASS

The command looks like this:

curl -v --netrc "https://members.dyndns.org/nic/update?hostname=YOURHOSTNAME&myip=YOURIP&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"

Comment: It'd be nicer if we could do this with fetch(1)(), if only because it is built in.
 
Now the question I have: where should the .netrc be? It should be in the home directory of the user in question. However, the bind user, by default has no home directory. I am tempted to create a user just for this command, then use sudo -u to invoke curl.

Comments?
 
The bind user does have a home directory like every user must have but it's the / directory. If BIND is running as chroot(8)ed as it is by default the home directory is actually /var/named.
 
And I then realized that it would be root running this, not bind. dhclient runs as root.
 
I find that $1 never has a value, but $new_ip_address and $old_ip_address have the expected values. I haven't had an IP address change yet, nor gone through a reboot, but I shall report back after I've used this script a bit more.
 
dvl@ said:
I find that $1 never has a value, but $new_ip_address and $old_ip_address have the expected values. I haven't had an IP address change yet, nor gone through a reboot, but I shall report back after I've used this script a bit more.

Ah, perhaps I didn't make that part clear enough. In my setup this script is called /etc/dns_update.sh and it does not replace /etc/dhclient-exit-hooks but it is called from it:

/etc/dhclient-exit-hooks
Code:
#!/bin/sh
case "$new_ip_address" in
10.*) ;;
172.1[6-9].* | 172.2[0-9].* | 172.3[0-1].*) ;;
192.168.*) ;;
"") ;;
*)
    /etc/dns_update.sh $new_ip_address > /dev/null 2>&1
    ;;
esac

I choose it this way, because at times it is useful to call /etc/dns_update.sh manually. In this case the new IP address can be given on the command line, or the script would pick it from the output of ifconfig.

If you use that script as a replacement for /etc/dhclient-exit-hooks then it may more or less look like so:

Code:
#!/bin/sh
case "$new_ip_address" in
10.*) ;;
172.1[6-9].* | 172.2[0-9].* | 172.3[0-1].*) ;;
192.168.*) ;;
"") ;;
*)
    if [ -e /var/tmp/currentIP ] ; then
        currentIP=`/bin/cat /var/tmp/currentIP`
    else
        currentIP=
    fi

    if [ "$new_ip_address" = "$currentIP" ] ; then
        echo "nochg $currentIP"
    else
        /usr/local/bin/curl -u username:password "https://dyndns.aprovider.com/nic/update?system=dyndns&hostname=myd.com,mail.myd.com&myip=$new_ip_address&mx=mail.myd.com&backmx=NO"
        echo "$new_ip_address" > /var/tmp/currentIP
    fi
    ;;
esac
 
Today it finally happened... my IP address changed. Here are the log entries:

Code:
Oct  2 05:06:33 bast dyndns: /etc/dhclient-exit-hooks has been invoked
Oct  2 05:06:33 bast dyndns: 'ARPSEND' 'fxp0' '' '' ''
Oct  2 05:06:33 bast dyndns: new IP from ifconfig is 173.49.195.214
Oct  2 05:06:33 bast dyndns: Ooops, IP has not actually changed from 173.49.195.214
Oct  2 05:06:33 bast dyndns: all done here
Oct  2 05:06:35 bast dyndns: /etc/dhclient-exit-hooks has been invoked
Oct  2 05:06:35 bast dyndns: 'ARPCHECK' 'fxp0' '' '' ''
Oct  2 05:06:35 bast dyndns: new IP from ifconfig is 173.49.195.214
Oct  2 05:06:35 bast dyndns: Ooops, IP has not actually changed from 173.49.195.214
Oct  2 05:06:35 bast dyndns: all done here
Oct  2 05:06:35 bast dyndns: /etc/dhclient-exit-hooks has been invoked
Oct  2 05:06:35 bast dyndns: 'BOUND' 'fxp0' '' '98.111.147.220' ''
Oct  2 05:06:35 bast dyndns: new IP from dhclient is 98.111.147.220

Here is the code I have so far:

Code:
#!/bin/sh

logger -t dyndns /etc/dhclient-exit-hooks has been invoked

logger -t dyndns "'$reason' '$interface' '$medium' '$new_ip_address' '$old_ip_address'"

if [ "${old_ip_address}" = "" ]
then
    if [ -e /var/tmp/currentIP ]
    then
        old_ip_address=`/bin/cat /var/tmp/currentIP`
    fi
fi

if [ "$new_ip_address" = "" ] ; then
    new_ip_address=`/sbin/ifconfig fxp0 | /usr/bin/sed -n '/.inet /{s///;s/ .*//;p;}'`
    logger -t dyndns "new IP from ifconfig is ${new_ip_address}"
else
    logger -t dyndns "new IP from dhclient is ${new_ip_address}"
fi

if [ "${new_ip_address}" = "" -o "${new_ip_address}" = "${old_ip_address}" ] ; then
    echo "nochg ${old_ip_address}"
    logger -t dyndns "Ooops, IP has not actually changed from ${old_ip_address}"
else
    /usr/local/bin/curl -v --netrc "https://members.dyndns.org/nic/update?hostname=dlangille.isa-geek.net&myip=${new_ip_address}&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
    echo "${new_ip_address}" > /var/tmp/currentIP
    logger -t dyndns "updated from ${old_ip_address} to ${new_ip_address}"
fi

logger -t dyndns "all done here"

As discusses previously, the user name and password for dyndns.org is in /root/.netrc and is of the form:

Code:
machine members.dyndns.org login MYLOGIN password MYPASSWORD

This keeps the login details off the command line where other users might see it via ps.

Mind you, in this particular case, I am no longer using dyndns.org (the free trial ended). I am usinf dns/noip for my dyndns issues. But I will continue to use /etc/dhclient-exit-hooks for keeping track of IP address changes. I think there is a similar hook in dns/noip, but I have yet to investigate it.
 
Here's my slightly modified version of /etc/dhclient-exit-hooks. The main changes are:

  • also log to a file because when the system is booting up, the messages from the script don't make it to the system log
  • check if $reason is set to 'PREINIT'.

Code:
#!/bin/sh

dyn_log() {
    /usr/bin/logger -t dyndns $1
    echo `date` $1 >> /var/log/dhclient-exit-hooks.log
}

dyn_log "/etc/dhclient-exit-hooks has been invoked."
dyn_log "'$reason' '$interface' '$medium' '$new_ip_address' '$old_ip_address'"

if [ "$reason" = "PREINIT" ]; then
    dyn_log "The call to dhclient was a PREINIT, so no update will be made."
    exit
fi

case "$new_ip_address" in
    10.* | 172.1[6-9].* | 172.2[0-9].* | 172.3[0-1].* | 192.168.*)
	dyn_log "The new IP is private, so no update will be made."
	exit;;
esac

last_sent_ip=`/bin/cat /var/tmp/last_sent_ip`

if [ "$new_ip_address" = "$last_sent_ip" ]; then
    dyn_log "IP has not changed from $last_sent_ip, so no update will be made."
else
    hostname=`/bin/hostname`
    /usr/local/bin/curl -v --netrc "https://members.dyndns.org/nic/update?hostname=${hostname}&myip=${new_ip_address}&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
    dyn_log "IP has been updated from '$last_sent_ip' to $new_ip_address."
    echo "$new_ip_address" > /var/tmp/last_sent_ip
fi
 
Back
Top