Fixed bug that would cause IPv4 address to be updated even if it was unchanged.

Caused by testing for IPv6 address change even though no IPv6 update was requested.
Added capability to specify whether IPv4 or IPv6 should be updated or not with new
values:
use=no
usev6=no
This commit is contained in:
David Kerr 2016-09-20 22:14:47 -04:00
parent c9523f382c
commit 15ad4b54b5

248
ddclient
View file

@ -292,6 +292,7 @@ my %builtinfw = (
},
);
my %ip_strategies = (
'no' => ": do not obtain an IPv4 address for this host",
'ip' => ": obtain IP from -ip {address}",
'web' => ": obtain IP from an IP discovery page on the web",
'fw' => ": obtain IP from the firewall specified by -fw {type|address}",
@ -307,6 +308,7 @@ sub ip_strategies_usage {
my %ipv6_strategies = (
'no' => ": do not obtain an IPv6 address for this host",
'ip' => ": obtain IP from -ipv6 {address}",
'if' => ": obtain IP from the -if {interface}",
'cmd' => ": obtain IP from the -cmdv6 {external-command}",
@ -391,7 +393,7 @@ my %variables = (
'host' => setv(T_STRING, 1, 1, 1, '', undef),
'use' => setv(T_USE, 0, 0, 1, 'ip', undef),
'usev6' => setv(T_USE, 0, 0, 1, undef, undef),
'usev6' => setv(T_USEV6, 0, 0, 1, undef, undef),
'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef),
'if-skip' => setv(T_STRING,0, 0, 1, '', undef),
'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef),
@ -947,7 +949,7 @@ sub update_nics {
} else {
$ip = get_ip($use, $h);
if (!defined $ip || !$ip) {
warning("%s: unable to determine IPv4 address", $h)
warning("%s: unable to determine IPv4 address with strategy use=%s", $h, $use)
if !$daemon || opt('verbose');
} elsif ($ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
warning("%s: malformed IPv4 address (%s)", $h, $ip);
@ -963,7 +965,7 @@ sub update_nics {
} else {
$ipv6 = get_ipv6($usev6, $h);
if (!defined $ipv6 || !$ipv6) {
warning("%s: unable to determine IPv6 address", $h)
warning("%s: unable to determine IPv6 address with strategy usev6=%s", $h, $usev6)
if !$daemon || opt('verbose');
} elsif ($ipv6 !~ /^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/ai) {
# That little gem from http://home.deds.nl/~aeron/regex/
@ -2273,35 +2275,35 @@ sub get_ip {
$arg = '' unless $arg;
if ($use eq 'ip') {
$ip = opt('ip', $h);
$arg = 'ip';
$ip = opt('ip', $h);
$arg = 'ip';
} elsif ($use eq 'if') {
$skip = opt('if-skip', $h) || '';
$reply = `ifconfig $arg 2> /dev/null`;
$reply = `ip addr list dev $arg 2> /dev/null` if $?;
$reply = '' if $?;
$skip = opt('if-skip', $h) || '';
$reply = `ifconfig $arg 2> /dev/null`;
$reply = `ip addr list dev $arg 2> /dev/null` if $?;
$reply = '' if $?;
} elsif ($use eq 'cmd') {
if ($arg) {
$skip = opt('cmd-skip', $h) || '';
$reply = `$arg`;
$reply = '' if $?;
}
if ($arg) {
$skip = opt('cmd-skip', $h) || '';
$reply = `$arg`;
$reply = '' if $?;
}
} elsif ($use eq 'web') {
$url = opt('web', $h) || '';
$skip = opt('web-skip', $h) || '';
$url = opt('web', $h) || '';
$skip = opt('web-skip', $h) || '';
if (exists $builtinweb{$url}) {
$skip = $builtinweb{$url}->{'skip'} unless $skip;
$url = $builtinweb{$url}->{'url'};
}
$arg = $url;
if (exists $builtinweb{$url}) {
$skip = $builtinweb{$url}->{'skip'} unless $skip;
$url = $builtinweb{$url}->{'url'};
}
$arg = $url;
if ($url) {
# when using a web server to find public IPv4 address we should force use of IPv4
$reply = geturl(opt('proxy', $h), $url, undef, undef, undef, undef, undef, '4') || '';
if ($url) {
# when using a web server to find public IPv4 address we should force use of IPv4
$reply = geturl(opt('proxy', $h), $url, undef, undef, undef, undef, undef, '4') || '';
}
} elsif (($use eq 'cisco')) {
@ -2338,6 +2340,9 @@ sub get_ip {
$reply = geturl('', $url, opt('fw-login', $h), opt('fw-password', $h)) || '';
$arg = $url;
} elsif ($use eq 'no') {
$reply = '0.0.0.0';
} else {
$url = opt('fw', $h) || '';
$skip = opt('fw-skip', $h) || '';
@ -2354,7 +2359,8 @@ sub get_ip {
}
if (!defined $reply) {
$reply = '';
}
}
if ($skip) {
$skip =~ s/ /\\s/is;
$reply =~ s/^.*?${skip}//is;
@ -2365,7 +2371,7 @@ sub get_ip {
$ip = filter_local($ip) if opt('fw-banlocal', $h);
}
if (($use ne 'ip') && (define($ip,'') eq '0.0.0.0')) {
$ip = undef;
$ip = undef;
}
debug("get_ip: using %s, %s reports %s", $use, $arg, define($ip, "<undefined>"));
@ -2389,38 +2395,41 @@ sub get_ipv6 {
$skip = opt('if-skip', $h) || '';
$reply = `ip -6 addr list dev $arg | grep "scope.global" 2> /dev/null`;
if ($reply =~ /.*? ([0-9:][^\/]*)/i) {
$reply = $1;
$reply = $1;
}
else {
$reply = ''
}
} elsif ($usev6 eq 'cmd') {
$arg = opt('cmdv6', $h);
if ($arg) {
$skip = opt('cmdv6-skip', $h) || '';
debug("GetIPv6 cmd: %s",$arg);
$reply = `$arg`;
$reply = '' if $?;
}
$arg = opt('cmdv6', $h);
if ($arg) {
$skip = opt('cmdv6-skip', $h) || '';
debug("GetIPv6 cmd: %s",$arg);
$reply = `$arg`;
$reply = '' if $?;
}
} elsif ($usev6 eq 'web') {
$url = opt('webv6', $h) || '';
$skip = opt('webv6-skip', $h) || '';
$url = opt('webv6', $h) || '';
$skip = opt('webv6-skip', $h) || '';
if (exists $builtinweb{$url}) {
$skip = $builtinweb{$url}->{'skip'} unless $skip;
$url = $builtinweb{$url}->{'url'};
if (exists $builtinweb{$url}) {
$skip = $builtinweb{$url}->{'skip'} unless $skip;
$url = $builtinweb{$url}->{'url'};
}
$arg = $url;
if ($url) {
# when using a web server to find our IPv6 address we should force use of IPv6
$reply = geturl(opt('proxy', $h), $url, undef, undef, undef, undef, undef, '6') || '';
}
} elsif ($usev6 eq 'no') {
$reply = '';
}
$arg = $url;
if ($url) {
# when using a web server to find our IPv6 address we should force use of IPv6
$reply = geturl(opt('proxy', $h), $url, undef, undef, undef, undef, undef, '6') || '';
}
}
if (!defined $reply) {
$reply = '';
$reply = '::';
}
if ($skip) {
$skip =~ s/ /\\s/is;
@ -2530,101 +2539,99 @@ sub nic_updateable {
my $ipv6 = $config{$host}{'wantipv6'};
if ($config{$host}{'login'} eq '') {
warning("null login name specified for host %s.", $host);
warning("null login name specified for host %s.", $host);
} elsif ($config{$host}{'password'} eq '') {
warning("null password specified for host %s.", $host);
warning("null password specified for host %s.", $host);
} elsif ($opt{'force'}) {
info("forcing update of %s.", $host);
$update = 1;
info("forcing update of %s.", $host);
$update = 1;
} elsif (!exists($cache{$host})) {
info("forcing updating %s because no cached entry exists.", $host);
$update = 1;
info("forcing updating %s because no cached entry exists.", $host);
$update = 1;
} elsif ($cache{$host}{'wtime'} && $cache{$host}{'wtime'} > $now) {
warning("cannot update %s from %s to %s until after %s.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'), $ip,
prettytime($cache{$host}{'wtime'})
);
warning("cannot update %s from %s to %s until after %s.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'), $ip,
prettytime($cache{$host}{'wtime'})
);
} elsif ($cache{$host}{'mtime'} && interval_expired($host, 'mtime', 'max-interval')) {
warning("forcing update of %s from %s to %s; %s since last update on %s.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'), $ip,
prettyinterval($config{$host}{'max-interval'}),
prettytime($cache{$host}{'mtime'})
);
$update = 1;
warning("forcing update of %s from %s to %s; %s since last update on %s.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'), $ip,
prettyinterval($config{$host}{'max-interval'}),
prettytime($cache{$host}{'mtime'})
);
$update = 1;
} elsif ((!exists($cache{$host}{'ip'})) ||
("$cache{$host}{'ip'}" ne "$ip")) {
} elsif (defined($cache{$host}{'use'} && ($cache{$host}{'use'} ne 'no')) &&
((!exists($cache{$host}{'ip'})) || ("$cache{$host}{'ip'}" ne "$ip"))) {
if (($cache{$host}{'status'} eq 'good') &&
!interval_expired($host, 'mtime', 'min-interval')) {
warning("skipping update of %s from %s to %s.\nlast updated %s.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
$ip,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
prettyinterval($config{$host}{'min-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-interval'}, 0);
warning("skipping update of %s from %s to %s.\nlast updated %s.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
$ip,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
prettyinterval($config{$host}{'min-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-interval'}, 0);
$cache{$host}{'warned-min-interval'} = $now;
$cache{$host}{'warned-min-interval'} = $now;
} elsif (($cache{$host}{'status'} ne 'good') && !interval_expired($host, 'atime', 'min-error-interval')) {
} elsif (($cache{$host}{'status'} ne 'good') && !interval_expired($host, 'atime', 'min-error-interval')) {
warning("skipping update of %s from %s to %s.\nlast updated %s but last attempt on %s failed.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
$ip,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
prettyinterval($config{$host}{'min-error-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
$cache{$host}{'warned-min-error-interval'} = $now;
warning("skipping update of %s from %s to %s.\nlast updated %s but last attempt on %s failed.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
$ip,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
prettyinterval($config{$host}{'min-error-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
} else {
$update = 1;
}
$cache{$host}{'warned-min-error-interval'} = $now;
} else {
$update = 1;
}
} elsif ((!exists($cache{$host}{'ipv6'})) ||
("$cache{$host}{'ipv6'}" ne "$ipv6")) {
} elsif (defined($cache{$host}{'usev6'} && ($cache{$host}{'usev6'} ne 'no') ) &&
((!exists($cache{$host}{'ipv6'})) || ("$cache{$host}{'ipv6'}" ne "$ipv6"))) {
if (($cache{$host}{'status'} eq 'good') &&
!interval_expired($host, 'mtime', 'min-interval')) {
warning("skipping update of %s from %s to %s.\nlast updated %s.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ipv6'} ? $cache{$host}{'ipv6'} : '<nothing>'),
$ipv6,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
prettyinterval($config{$host}{'min-interval'})
$host,
($cache{$host}{'ipv6'} ? $cache{$host}{'ipv6'} : '<nothing>'),
$ipv6,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
prettyinterval($config{$host}{'min-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-interval'}, 0);
$cache{$host}{'warned-min-interval'} = $now;
$cache{$host}{'warned-min-interval'} = $now;
} elsif (($cache{$host}{'status'} ne 'good') && !interval_expired($host, 'atime', 'min-error-interval')) {
warning("skipping update of %s from %s to %s.\nlast updated %s but last attempt on %s failed.\nWait at least %s between update attempts.",
$host,
($cache{$host}{'ipv6'} ? $cache{$host}{'ipv6'} : '<nothing>'),
$ipv6,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
prettyinterval($config{$host}{'min-error-interval'})
$host,
($cache{$host}{'ipv6'} ? $cache{$host}{'ipv6'} : '<nothing>'),
$ipv6,
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
prettyinterval($config{$host}{'min-error-interval'})
)
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
$cache{$host}{'warned-min-error-interval'} = $now;
$cache{$host}{'warned-min-error-interval'} = $now;
} else {
$update = 1;
}
} elsif (defined($sub) && &$sub($host)) {
$update = 1;
$update = 1;
} elsif ((defined($cache{$host}{'static'}) && defined($config{$host}{'static'}) &&
($cache{$host}{'static'} ne $config{$host}{'static'})) ||
(defined($cache{$host}{'wildcard'}) && defined($config{$host}{'wildcard'}) &&
@ -2633,28 +2640,29 @@ sub nic_updateable {
($cache{$host}{'mx'} ne $config{$host}{'mx'})) ||
(defined($cache{$host}{'backupmx'}) && defined($config{$host}{'backupmx'}) &&
($cache{$host}{'backupmx'} ne $config{$host}{'backupmx'})) ) {
info("updating %s because host settings have been changed.", $host);
$update = 1;
info("updating %s because host settings have been changed.", $host);
$update = 1;
} else {
success("%s: skipped: IP address was already set to %s.", $host, $ip)
if opt('verbose');
success("%s: skipped: IP address was already set to %s.", $host, $ip)
if opt('verbose');
}
$config{$host}{'status'} = define($cache{$host}{'status'},'');
$config{$host}{'update'} = $update;
if ($update) {
$config{$host}{'status'} = 'noconnect';
$config{$host}{'atime'} = $now;
$config{$host}{'wtime'} = 0;
$config{$host}{'warned-min-interval'} = 0;
$config{$host}{'warned-min-error-interval'} = 0;
$config{$host}{'status'} = 'noconnect';
$config{$host}{'atime'} = $now;
$config{$host}{'wtime'} = 0;
$config{$host}{'warned-min-interval'} = 0;
$config{$host}{'warned-min-error-interval'} = 0;
delete $cache{$host}{'warned-min-interval'};
delete $cache{$host}{'warned-min-error-interval'};
delete $cache{$host}{'warned-min-interval'};
delete $cache{$host}{'warned-min-error-interval'};
}
return $update;
}
######################################################################
## header_ok
######################################################################