Updates here are based on work I have done for the AstLinux project (AstLinux.org)
Adding comprehensive framework for IPv6 support. IPv6 and IPv4 exist side-by-side The same network interface may have both IPv4 and IPv6. Therefore to support both we add the following options. usev6 = [ ip, if, cmd, web ] ipv6 = [ set an IPv6 address (usev6=ip) ] webv6 = [ url of a web server that will return your IPv6 address (usev6=web)] webv6-skip = [ string to skip to before looking for IPv6 address] cmdv6 = [ system command to execute that will return an IPv6 address (usev6=cmd)] cmdv6-skip = [ string to skip to before looking for IPv6 address ] There is no ifv6. It is assumed that if=interface will be the same for both IPv4 and IPv6 You can mix methods for IPv4 and IPv6 for the same interface. For example use=web usev6=if if=eth0 web=http://ipdetect.dnspark.com/ Would be a valid method for a system behind an IPv4 NAT connection, IPv6 would be obtained from the eth0 interface (globaly routable address) and the public IPv4 from external web site. Support for updating AAAA (IPv6) records is added for freedns.afraid.org. The existing IPv6 nsupdate method was updated to account for new design. Optional support is added for cURL as some embedded systems do not have perl NET6 and SSL packages installed. Set with option curl=yes Submitted code is ready for code review and comment.
This commit is contained in:
parent
7cad3a497f
commit
d07b52f75a
1 changed files with 464 additions and 171 deletions
635
ddclient
635
ddclient
|
|
@ -24,7 +24,6 @@ use strict;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
use Sys::Hostname;
|
use Sys::Hostname;
|
||||||
use IO::Socket;
|
use IO::Socket;
|
||||||
use Data::Validate::IP;
|
|
||||||
|
|
||||||
my $version = "3.8.3";
|
my $version = "3.8.3";
|
||||||
my $programd = $0;
|
my $programd = $0;
|
||||||
|
|
@ -59,17 +58,20 @@ sub T_FILE {'file name'};
|
||||||
sub T_FQDNP {'fully qualified host name and optional port number'};
|
sub T_FQDNP {'fully qualified host name and optional port number'};
|
||||||
sub T_PROTO {'protocol'}
|
sub T_PROTO {'protocol'}
|
||||||
sub T_USE {'ip strategy'}
|
sub T_USE {'ip strategy'}
|
||||||
|
sub T_USEV6 {'ipv6 strategy'}
|
||||||
sub T_IF {'interface'}
|
sub T_IF {'interface'}
|
||||||
sub T_PROG {'program name'}
|
sub T_PROG {'program name'}
|
||||||
sub T_IP {'ip'}
|
sub T_IP {'ip'}
|
||||||
|
sub T_IPV6 {'ipv6'}
|
||||||
sub T_POSTS {'postscript'};
|
sub T_POSTS {'postscript'};
|
||||||
|
|
||||||
## strategies for obtaining an ip address.
|
## strategies for obtaining an ip address.
|
||||||
my %builtinweb = (
|
my %builtinweb = (
|
||||||
'dyndns' => { 'url' => 'http://checkip.dyndns.org/', 'skip' =>
|
'dyndns' => { 'url' => 'http://checkip.dyndns.org/', 'skip' => 'Current IP Address:', },
|
||||||
'Current IP Address:', },
|
|
||||||
'dnspark' => { 'url' => 'http://ipdetect.dnspark.com/', 'skip' => 'Current Address:', },
|
'dnspark' => { 'url' => 'http://ipdetect.dnspark.com/', 'skip' => 'Current Address:', },
|
||||||
'loopia' => { 'url' => 'http://dns.loopia.se/checkip/checkip.php', 'skip' => 'Current IP Address:', },
|
'loopia' => { 'url' => 'http://dns.loopia.se/checkip/checkip.php', 'skip' => 'Current IP Address:', },
|
||||||
|
'whatismyv6' => { 'url' => 'http://whatismyv6.com/', 'skip' => 'Address of:', },
|
||||||
|
'nsupdate.info' => { 'url' => 'https://ipv6.nsupdate.info/myip', , },
|
||||||
);
|
);
|
||||||
my %builtinfw = (
|
my %builtinfw = (
|
||||||
'watchguard-soho' => {
|
'watchguard-soho' => {
|
||||||
|
|
@ -302,6 +304,17 @@ sub ip_strategies_usage {
|
||||||
return map { sprintf(" -use=%-22s %s.", $_, $ip_strategies{$_}) } sort keys %ip_strategies;
|
return map { sprintf(" -use=%-22s %s.", $_, $ip_strategies{$_}) } sort keys %ip_strategies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my %ipv6_strategies = (
|
||||||
|
'ip' => ": obtain IP from -ipv6 {address}",
|
||||||
|
'if' => ": obtain IP from the -if {interface}",
|
||||||
|
'cmd' => ": obtain IP from the -cmdv6 {external-command}",
|
||||||
|
'web' => ": obtain IP from an IP discovery page on the web"
|
||||||
|
);
|
||||||
|
sub ipv6_strategies_usage {
|
||||||
|
return map { sprintf(" -usev6=%-22s %s.", $_, $ipv6_strategies{$_}) } sort keys %ipv6_strategies;
|
||||||
|
}
|
||||||
|
|
||||||
my %web_strategies = (
|
my %web_strategies = (
|
||||||
'dyndns'=> 1,
|
'dyndns'=> 1,
|
||||||
'dnspark'=> 1,
|
'dnspark'=> 1,
|
||||||
|
|
@ -329,11 +342,15 @@ my %variables = (
|
||||||
'protocol' => setv(T_PROTO, 0, 0, 1, 'dyndns2', undef),
|
'protocol' => setv(T_PROTO, 0, 0, 1, 'dyndns2', undef),
|
||||||
|
|
||||||
'use' => setv(T_USE, 0, 0, 1, 'ip', undef),
|
'use' => setv(T_USE, 0, 0, 1, 'ip', undef),
|
||||||
|
'usev6' => setv(T_USEV6, 0, 0, 1, undef, undef),
|
||||||
'ip' => setv(T_IP, 0, 0, 1, undef, undef),
|
'ip' => setv(T_IP, 0, 0, 1, undef, undef),
|
||||||
|
'ipv6' => setv(T_IPV6, 0, 0, 1, undef, undef),
|
||||||
'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef),
|
'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef),
|
||||||
'if-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
'if-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef),
|
'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef),
|
||||||
'web-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
'web-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
|
'webv6' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
|
'webv6-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
'fw' => setv(T_ANY, 0, 0, 1, '', undef),
|
'fw' => setv(T_ANY, 0, 0, 1, '', undef),
|
||||||
'fw-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
'fw-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
'fw-banlocal' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
'fw-banlocal' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
||||||
|
|
@ -341,12 +358,15 @@ my %variables = (
|
||||||
'fw-password' => setv(T_PASSWD,1, 0, 1, '', undef),
|
'fw-password' => setv(T_PASSWD,1, 0, 1, '', undef),
|
||||||
'cmd' => setv(T_PROG, 0, 0, 1, '', undef),
|
'cmd' => setv(T_PROG, 0, 0, 1, '', undef),
|
||||||
'cmd-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
'cmd-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
|
'cmdv6' => setv(T_PROG, 0, 0, 1, '', undef),
|
||||||
|
'cmdv6-skip' => setv(T_STRING,1, 0, 1, '', undef),
|
||||||
|
|
||||||
'timeout' => setv(T_DELAY, 0, 0, 1, interval('120s'), interval('120s')),
|
'timeout' => setv(T_DELAY, 0, 0, 1, interval('120s'), interval('120s')),
|
||||||
'retry' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
'retry' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
||||||
'force' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
'force' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
||||||
'ssl' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
'ssl' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
||||||
'ipv6' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
'curl' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
||||||
|
|
||||||
'syslog' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
'syslog' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
||||||
'facility' => setv(T_STRING,0, 0, 1, 'daemon', undef),
|
'facility' => setv(T_STRING,0, 0, 1, 'daemon', undef),
|
||||||
'priority' => setv(T_STRING,0, 0, 1, 'notice', undef),
|
'priority' => setv(T_STRING,0, 0, 1, 'notice', undef),
|
||||||
|
|
@ -370,10 +390,13 @@ my %variables = (
|
||||||
'host' => setv(T_STRING, 1, 1, 1, '', undef),
|
'host' => setv(T_STRING, 1, 1, 1, '', undef),
|
||||||
|
|
||||||
'use' => setv(T_USE, 0, 0, 1, 'ip', undef),
|
'use' => setv(T_USE, 0, 0, 1, 'ip', undef),
|
||||||
|
'usev6' => setv(T_USE, 0, 0, 1, undef, undef),
|
||||||
'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef),
|
'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef),
|
||||||
'if-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
'if-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef),
|
'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef),
|
||||||
'web-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
'web-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
|
'webv6' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
|
'webv6-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
'fw' => setv(T_ANY, 0, 0, 1, '', undef),
|
'fw' => setv(T_ANY, 0, 0, 1, '', undef),
|
||||||
'fw-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
'fw-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
'fw-banlocal' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
'fw-banlocal' => setv(T_BOOL, 0, 0, 1, 0, undef),
|
||||||
|
|
@ -381,8 +404,12 @@ my %variables = (
|
||||||
'fw-password' => setv(T_PASSWD,0, 0, 1, '', undef),
|
'fw-password' => setv(T_PASSWD,0, 0, 1, '', undef),
|
||||||
'cmd' => setv(T_PROG, 0, 0, 1, '', undef),
|
'cmd' => setv(T_PROG, 0, 0, 1, '', undef),
|
||||||
'cmd-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
'cmd-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
'ipv6' => setv(T_BOOL, 0, 0, 0, 0, undef),
|
'cmdv6' => setv(T_PROG, 0, 0, 1, '', undef),
|
||||||
|
'cmdv6-skip' => setv(T_STRING,0, 0, 1, '', undef),
|
||||||
|
|
||||||
|
|
||||||
'ip' => setv(T_IP, 0, 1, 0, undef, undef),
|
'ip' => setv(T_IP, 0, 1, 0, undef, undef),
|
||||||
|
'ipv6' => setv(T_IPV6, 0, 1, 0, undef, undef),
|
||||||
'wtime' => setv(T_DELAY, 0, 1, 1, 0, interval('30s')),
|
'wtime' => setv(T_DELAY, 0, 1, 1, 0, interval('30s')),
|
||||||
'mtime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
'mtime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
||||||
'atime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
'atime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
||||||
|
|
@ -418,6 +445,7 @@ my %variables = (
|
||||||
'password' => setv(T_PASSWD, 1, 0, 1, '', undef),
|
'password' => setv(T_PASSWD, 1, 0, 1, '', undef),
|
||||||
'host' => setv(T_STRING, 1, 1, 1, '', undef),
|
'host' => setv(T_STRING, 1, 1, 1, '', undef),
|
||||||
'ip' => setv(T_IP, 0, 1, 0, undef, undef),
|
'ip' => setv(T_IP, 0, 1, 0, undef, undef),
|
||||||
|
'ipv6' => setv(T_IPV6, 0, 1, 0, undef, undef),
|
||||||
'wtime' => setv(T_DELAY, 0, 1, 1, 0, interval('30s')),
|
'wtime' => setv(T_DELAY, 0, 1, 1, 0, interval('30s')),
|
||||||
'mtime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
'mtime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
||||||
'atime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
'atime' => setv(T_NUMBER, 0, 1, 0, 0, undef),
|
||||||
|
|
@ -693,14 +721,19 @@ my @opt = (
|
||||||
"",
|
"",
|
||||||
[ "use", "=s", "-use which : how the should IP address be obtained." ],
|
[ "use", "=s", "-use which : how the should IP address be obtained." ],
|
||||||
&ip_strategies_usage(),
|
&ip_strategies_usage(),
|
||||||
|
[ "usev6", "=s", "-usev6 which : how the should IPv6 address be obtained." ],
|
||||||
|
&ipv6_strategies_usage(),
|
||||||
"",
|
"",
|
||||||
[ "ip", "=s", "-ip address : set the IP address to 'address'" ],
|
[ "ip", "=s", "-ip address : set the IP address to 'address'" ],
|
||||||
|
[ "ipv6", "=s", "-ipv6 address : set the IPv6 address to 'address'" ],
|
||||||
"",
|
"",
|
||||||
[ "if", "=s", "-if interface : obtain IP address from 'interface'" ],
|
[ "if", "=s", "-if interface : obtain IP address from 'interface'" ],
|
||||||
[ "if-skip", "=s", "-if-skip pattern : skip any IP addresses before 'pattern' in the output of ifconfig {if}" ],
|
[ "if-skip", "=s", "-if-skip pattern : skip any IP addresses before 'pattern' in the output of ifconfig {if}" ],
|
||||||
"",
|
"",
|
||||||
[ "web", "=s", "-web provider|url : obtain IP address from provider's IP checking page" ],
|
[ "web", "=s", "-web provider|url : obtain IP address from provider's IP checking page" ],
|
||||||
[ "web-skip", "=s", "-web-skip pattern : skip any IP addresses before 'pattern' on the web provider|url" ],
|
[ "web-skip", "=s", "-web-skip pattern : skip any IP addresses before 'pattern' on the web provider|url" ],
|
||||||
|
[ "webv6", "=s", "-webv6 provider|url : obtain IPv6 address from provider's IP checking page" ],
|
||||||
|
[ "webv6-skip", "=s", "-webv6-skip pattern : skip any IPv6 addresses before 'pattern' on the web provider|url" ],
|
||||||
"",
|
"",
|
||||||
[ "fw", "=s", "-fw address|url : obtain IP address from firewall at 'address'" ],
|
[ "fw", "=s", "-fw address|url : obtain IP address from firewall at 'address'" ],
|
||||||
[ "fw-skip", "=s", "-fw-skip pattern : skip any IP addresses before 'pattern' on the firewall address|url" ],
|
[ "fw-skip", "=s", "-fw-skip pattern : skip any IP addresses before 'pattern' on the firewall address|url" ],
|
||||||
|
|
@ -710,6 +743,8 @@ my @opt = (
|
||||||
"",
|
"",
|
||||||
[ "cmd", "=s", "-cmd program : obtain IP address from by calling {program}" ],
|
[ "cmd", "=s", "-cmd program : obtain IP address from by calling {program}" ],
|
||||||
[ "cmd-skip", "=s", "-cmd-skip pattern : skip any IP addresses before 'pattern' in the output of {cmd}" ],
|
[ "cmd-skip", "=s", "-cmd-skip pattern : skip any IP addresses before 'pattern' in the output of {cmd}" ],
|
||||||
|
[ "cmdv6", "=s", "-cmdv6 program : obtain IPv6 address from by calling {program}" ],
|
||||||
|
[ "cmdv6-skip", "=s", "-cmdv6-skip pattern : skip any IPv6 addresses before 'pattern' in the output of {cmd}" ],
|
||||||
"",
|
"",
|
||||||
[ "login", "=s", "-login user : login as 'user'" ],
|
[ "login", "=s", "-login user : login as 'user'" ],
|
||||||
[ "password", "=s", "-password secret : use password 'secret'" ],
|
[ "password", "=s", "-password secret : use password 'secret'" ],
|
||||||
|
|
@ -718,6 +753,7 @@ my @opt = (
|
||||||
[ "options", "=s", "-options opt,opt : optional per-service arguments (see below)" ],
|
[ "options", "=s", "-options opt,opt : optional per-service arguments (see below)" ],
|
||||||
"",
|
"",
|
||||||
[ "ssl", "!", "-{no}ssl : do updates over encrypted SSL connection" ],
|
[ "ssl", "!", "-{no}ssl : do updates over encrypted SSL connection" ],
|
||||||
|
[ "curl", "!", "-{no}curl : use cURL for network connections (default nocurl)" ],
|
||||||
[ "retry", "!", "-{no}retry : retry failed updates." ],
|
[ "retry", "!", "-{no}retry : retry failed updates." ],
|
||||||
[ "force", "!", "-{no}force : force an update even if the update may be unnecessary" ],
|
[ "force", "!", "-{no}force : force an update even if the update may be unnecessary" ],
|
||||||
[ "timeout", "=i", "-timeout max : wait at most 'max' seconds for the host to respond" ],
|
[ "timeout", "=i", "-timeout max : wait at most 'max' seconds for the host to respond" ],
|
||||||
|
|
@ -731,7 +767,6 @@ my @opt = (
|
||||||
[ "debug", "!", "-{no}debug : print {no} debugging information" ],
|
[ "debug", "!", "-{no}debug : print {no} debugging information" ],
|
||||||
[ "verbose", "!", "-{no}verbose : print {no} verbose information" ],
|
[ "verbose", "!", "-{no}verbose : print {no} verbose information" ],
|
||||||
[ "quiet", "!", "-{no}quiet : print {no} messages for unnecessary updates" ],
|
[ "quiet", "!", "-{no}quiet : print {no} messages for unnecessary updates" ],
|
||||||
[ "ipv6", "!", "-{no}ipv6 : use ipv6" ],
|
|
||||||
[ "help", "", "-help : this message" ],
|
[ "help", "", "-help : this message" ],
|
||||||
[ "postscript", "", "-postscript : script to run after updating ddclient, has new IP as param" ],
|
[ "postscript", "", "-postscript : script to run after updating ddclient, has new IP as param" ],
|
||||||
|
|
||||||
|
|
@ -818,7 +853,11 @@ do {
|
||||||
# usage("invalid argument '-use %s'; possible values are:\n\t%s", $opt{'use'}, join("\n\t,",sort keys %ip_strategies))
|
# usage("invalid argument '-use %s'; possible values are:\n\t%s", $opt{'use'}, join("\n\t,",sort keys %ip_strategies))
|
||||||
usage("invalid argument '-use %s'; possible values are:\n%s", $opt{'use'}, join("\n",ip_strategies_usage()))
|
usage("invalid argument '-use %s'; possible values are:\n%s", $opt{'use'}, join("\n",ip_strategies_usage()))
|
||||||
unless exists $ip_strategies{lc opt('use')};
|
unless exists $ip_strategies{lc opt('use')};
|
||||||
|
if (defined($opt{'usev6'})) {
|
||||||
|
usage("invalid argument '-usev6 %s'; possible values are:\n%s", $opt{'usev6'}, join("\n",ipv6_strategies_usage()))
|
||||||
|
unless exists $ipv6_strategies{lc opt('usev6')};
|
||||||
|
}
|
||||||
|
|
||||||
$daemon = $opt{'daemon'};
|
$daemon = $opt{'daemon'};
|
||||||
$daemon = 0 if opt('force');
|
$daemon = 0 if opt('force');
|
||||||
|
|
||||||
|
|
@ -879,9 +918,10 @@ sub runpostscript {
|
||||||
sub update_nics {
|
sub update_nics {
|
||||||
my %examined = ();
|
my %examined = ();
|
||||||
my %iplist = ();
|
my %iplist = ();
|
||||||
|
my %ipv6list = ();
|
||||||
|
|
||||||
foreach my $s (sort keys %services) {
|
foreach my $s (sort keys %services) {
|
||||||
my (@hosts, %ips) = ();
|
my (@hosts, %ips, %ipsv6) = ();
|
||||||
my $updateable = $services{$s}{'updateable'};
|
my $updateable = $services{$s}{'updateable'};
|
||||||
my $update = $services{$s}{'update'};
|
my $update = $services{$s}{'update'};
|
||||||
|
|
||||||
|
|
@ -890,33 +930,54 @@ sub update_nics {
|
||||||
$examined{$h} = 1;
|
$examined{$h} = 1;
|
||||||
# we only do this once per 'use' and argument combination
|
# we only do this once per 'use' and argument combination
|
||||||
my $use = opt('use', $h);
|
my $use = opt('use', $h);
|
||||||
|
my $usev6 = opt('usev6', $h);
|
||||||
my $arg_ip = opt('ip', $h) || '';
|
my $arg_ip = opt('ip', $h) || '';
|
||||||
|
my $arg_ipv6 = opt('ipv6', $h) || '';
|
||||||
my $arg_fw = opt('fw', $h) || '';
|
my $arg_fw = opt('fw', $h) || '';
|
||||||
my $arg_if = opt('if', $h) || '';
|
my $arg_if = opt('if', $h) || '';
|
||||||
my $arg_web = opt('web', $h) || '';
|
my $arg_web = opt('web', $h) || '';
|
||||||
|
my $arg_webv6 = opt('webv6', $h) || '';
|
||||||
my $arg_cmd = opt('cmd', $h) || '';
|
my $arg_cmd = opt('cmd', $h) || '';
|
||||||
|
my $arg_cmdv6 = opt('cmdv6', $h) || '';
|
||||||
my $ip = "";
|
my $ip = "";
|
||||||
|
my $ipv6 = "";
|
||||||
if (exists $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd}) {
|
if (exists $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd}) {
|
||||||
$ip = $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd};
|
$ip = $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd};
|
||||||
} else {
|
} else {
|
||||||
$ip = get_ip($use, $h);
|
$ip = get_ip($use, $h);
|
||||||
if (!defined $ip || !$ip) {
|
if (!defined $ip || !$ip) {
|
||||||
warning("unable to determine IP address")
|
warning("%s: unable to determine IPv4 address", $h)
|
||||||
if !$daemon || opt('verbose');
|
if !$daemon || opt('verbose');
|
||||||
next;
|
} elsif ($ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
|
||||||
|
warning("%s: malformed IPv4 address (%s)", $h, $ip);
|
||||||
|
} else {
|
||||||
|
$iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd} = $ip;
|
||||||
}
|
}
|
||||||
if ($ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
|
debug("IPv4 %s", define($ip, "<undefined>"));
|
||||||
if( !ipv6_match($ip) ) {
|
|
||||||
warning("malformed IP address (%s)", $ip);
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd} = $ip;
|
|
||||||
}
|
}
|
||||||
$config{$h}{'wantip'} = $ip;
|
$config{$h}{'wantip'} = $ip;
|
||||||
|
if (defined($usev6)) {
|
||||||
|
if (exists $ipv6list{$usev6}{$arg_ipv6}{$arg_fw}{$arg_if}{$arg_webv6}{$arg_cmdv6}) {
|
||||||
|
$ipv6 = $ipv6list{$usev6}{$arg_ipv6}{$arg_fw}{$arg_if}{$arg_webv6}{$arg_cmdv6};
|
||||||
|
} else {
|
||||||
|
$ipv6 = get_ipv6($usev6, $h);
|
||||||
|
if (!defined $ipv6 || !$ipv6) {
|
||||||
|
warning("%s: unable to determine IPv6 address", $h)
|
||||||
|
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/
|
||||||
|
warning("%s: malformed IPv6 address (%s)", $h, $ipv6);
|
||||||
|
} else {
|
||||||
|
$ipv6list{$usev6}{$arg_ipv6}{$arg_fw}{$arg_if}{$arg_webv6}{$arg_cmdv6} = $ipv6;
|
||||||
|
}
|
||||||
|
debug("IPv6 %s", define($ipv6, "<undefined>"));
|
||||||
|
}
|
||||||
|
$config{$h}{'wantipv6'} = $ipv6;
|
||||||
|
}
|
||||||
next if !nic_updateable($h, $updateable);
|
next if !nic_updateable($h, $updateable);
|
||||||
push @hosts, $h;
|
push @hosts, $h;
|
||||||
$ips{$ip} = $h;
|
$ips{$ip} = $h if (defined($ip));
|
||||||
|
$ipsv6{$ipv6} = $h if (defined($ipv6));
|
||||||
}
|
}
|
||||||
if (@hosts) {
|
if (@hosts) {
|
||||||
$0 = sprintf("%s - updating %s", $program, join(',', @hosts));
|
$0 = sprintf("%s - updating %s", $program, join(',', @hosts));
|
||||||
|
|
@ -969,7 +1030,7 @@ sub write_cache {
|
||||||
## merge the updated host entries into the cache.
|
## merge the updated host entries into the cache.
|
||||||
foreach my $h (keys %config) {
|
foreach my $h (keys %config) {
|
||||||
if (! exists $cache{$h} || $config{$h}{'update'}) {
|
if (! exists $cache{$h} || $config{$h}{'update'}) {
|
||||||
map {$cache{$h}{$_} = $config{$h}{$_} } @{$config{$h}{'cacheable'}};
|
map { defined($config{$h}{$_}) ? ($cache{$h}{$_} = $config{$h}{$_}) : () } @{$config{$h}{'cacheable'}};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
map {$cache{$h}{$_} = $config{$h}{$_} } qw(atime wtime status);
|
map {$cache{$h}{$_} = $config{$h}{$_} } qw(atime wtime status);
|
||||||
|
|
@ -1229,6 +1290,10 @@ sub init_config {
|
||||||
$opt{'use'} = 'if' if !define($opt{'use'}) && defined($opt{'if'});
|
$opt{'use'} = 'if' if !define($opt{'use'}) && defined($opt{'if'});
|
||||||
$opt{'use'} = 'web' if !define($opt{'use'}) && defined($opt{'web'});
|
$opt{'use'} = 'web' if !define($opt{'use'}) && defined($opt{'web'});
|
||||||
|
|
||||||
|
## infer the IPv6 strategy if possible
|
||||||
|
$opt{'usev6'} = 'ip' if !define($opt{'usev6'}) && defined($opt{'ipv6'});
|
||||||
|
$opt{'usev6'} = 'web' if !define($opt{'usev6'}) && defined($opt{'webv6'});
|
||||||
|
|
||||||
## sanity check
|
## sanity check
|
||||||
$opt{'max-interval'} = min(interval(opt('max-interval')), interval(default('max-interval')));
|
$opt{'max-interval'} = min(interval(opt('max-interval')), interval(default('max-interval')));
|
||||||
$opt{'min-interval'} = max(interval(opt('min-interval')), interval(default('min-interval')));
|
$opt{'min-interval'} = max(interval(opt('min-interval')), interval(default('min-interval')));
|
||||||
|
|
@ -1431,8 +1496,7 @@ sub test_possible_ip {
|
||||||
local $opt{'debug'} = 0;
|
local $opt{'debug'} = 0;
|
||||||
|
|
||||||
printf "use=ip, ip=%s address is %s\n", opt('ip'), define(get_ip('ip'), 'NOT FOUND')
|
printf "use=ip, ip=%s address is %s\n", opt('ip'), define(get_ip('ip'), 'NOT FOUND')
|
||||||
if defined opt('ip');
|
if defined opt('ip');
|
||||||
|
|
||||||
{
|
{
|
||||||
local $opt{'use'} = 'if';
|
local $opt{'use'} = 'if';
|
||||||
foreach my $if (grep {/^[a-zA-Z]/} `ifconfig -a`) {
|
foreach my $if (grep {/^[a-zA-Z]/} `ifconfig -a`) {
|
||||||
|
|
@ -1466,6 +1530,32 @@ sub test_possible_ip {
|
||||||
local $opt{'use'} = 'cmd';
|
local $opt{'use'} = 'cmd';
|
||||||
printf "use=cmd, cmd=%s address is %s\n", opt('cmd'), define(get_ip('cmd'), 'NOT FOUND');
|
printf "use=cmd, cmd=%s address is %s\n", opt('cmd'), define(get_ip('cmd'), 'NOT FOUND');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Now for IPv6
|
||||||
|
printf "use=ip, ipv6=%s address is %s\n", opt('ipv6'), define(get_ipv6('ip'), 'NOT FOUND')
|
||||||
|
if defined opt('ipv6');
|
||||||
|
{
|
||||||
|
local $opt{'use'} = 'if';
|
||||||
|
foreach my $if (grep {/^[a-zA-Z]/} `ifconfig -a`) {
|
||||||
|
$if =~ s/:?\s.*//is;
|
||||||
|
local $opt{'if'} = $if;
|
||||||
|
printf "use=if, ifv6=%s address is %s\n", opt('if'), define(get_ipv6('if'), 'NOT FOUND');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
local $opt{'use'} = 'web';
|
||||||
|
foreach my $web (sort keys %builtinweb) {
|
||||||
|
local $opt{'webv6'} = $web;
|
||||||
|
printf "use=web, webv6=$web address is %s\n", define(get_ipv6('web'), 'NOT FOUND');
|
||||||
|
}
|
||||||
|
printf "use=web, webv6=%s address is %s\n", opt('webv6'), define(get_ipv6('web'), 'NOT FOUND')
|
||||||
|
if ! exists $builtinweb{opt('webv6')};
|
||||||
|
}
|
||||||
|
if (opt('cmd')) {
|
||||||
|
local $opt{'use'} = 'cmd';
|
||||||
|
printf "use=cmd, cmdv6=%s address is %s\n", opt('cmd'), define(get_ipv6('cmd'), 'NOT FOUND');
|
||||||
|
}
|
||||||
|
|
||||||
exit 0 unless opt('debug');
|
exit 0 unless opt('debug');
|
||||||
}
|
}
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
@ -1839,6 +1929,10 @@ sub check_value {
|
||||||
$value = lc $value;
|
$value = lc $value;
|
||||||
return undef if ! exists $ip_strategies{$value};
|
return undef if ! exists $ip_strategies{$value};
|
||||||
|
|
||||||
|
} elsif ($type eq T_USEV6) {
|
||||||
|
$value = lc $value;
|
||||||
|
return undef if ! exists $ipv6_strategies{$value};
|
||||||
|
|
||||||
} elsif ($type eq T_FILE) {
|
} elsif ($type eq T_FILE) {
|
||||||
return undef if $value eq "";
|
return undef if $value eq "";
|
||||||
|
|
||||||
|
|
@ -1855,9 +1949,11 @@ sub check_value {
|
||||||
# return undef if $value =~ /:/;
|
# return undef if $value =~ /:/;
|
||||||
|
|
||||||
} elsif ($type eq T_IP) {
|
} elsif ($type eq T_IP) {
|
||||||
if( !ipv6_match($value) ) {
|
return undef if $value !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
||||||
return undef if $value !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
||||||
}
|
} elsif ($type eq T_IPV6) {
|
||||||
|
# This little gem from http://home.deds.nl/~aeron/regex/
|
||||||
|
return undef if $value !~ /^(((?=.*(::))(?!.*\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;
|
||||||
}
|
}
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
@ -1952,11 +2048,13 @@ sub geturl {
|
||||||
my $url = shift || '';
|
my $url = shift || '';
|
||||||
my $login = shift || '';
|
my $login = shift || '';
|
||||||
my $password = shift || '';
|
my $password = shift || '';
|
||||||
|
my $ipversion = shift || '';
|
||||||
my ($peer, $server, $port, $default_port, $use_ssl);
|
my ($peer, $server, $port, $default_port, $use_ssl);
|
||||||
my ($sd, $rq, $request, $reply);
|
my ($sd, $rq, $request, $reply);
|
||||||
|
|
||||||
debug("proxy = $proxy");
|
debug("proxy = $proxy");
|
||||||
debug("url = %s", $url);
|
debug("url = %s", $url);
|
||||||
|
debug("ip ver = %s", $ipversion);
|
||||||
## canonify proxy and url
|
## canonify proxy and url
|
||||||
my $force_ssl;
|
my $force_ssl;
|
||||||
$force_ssl = 1 if ($url =~ /^https:/);
|
$force_ssl = 1 if ($url =~ /^https:/);
|
||||||
|
|
@ -1975,71 +2073,74 @@ sub geturl {
|
||||||
if ( $force_ssl || ($globals{'ssl'} and (caller(1))[3] ne 'main::get_ip') ) {
|
if ( $force_ssl || ($globals{'ssl'} and (caller(1))[3] ne 'main::get_ip') ) {
|
||||||
$use_ssl = 1;
|
$use_ssl = 1;
|
||||||
$default_port = 443;
|
$default_port = 443;
|
||||||
load_ssl_support;
|
|
||||||
} else {
|
} else {
|
||||||
$use_ssl = 0;
|
$use_ssl = 0;
|
||||||
$default_port = 80;
|
$default_port = 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
## determine peer and port to use.
|
if (! opt('curl') ) {
|
||||||
$peer = $proxy || $server;
|
# Access network using perl functions.
|
||||||
$peer =~ s%/.*%%;
|
## determine peer and port to use.
|
||||||
$port = $peer;
|
$peer = $proxy || $server;
|
||||||
$port =~ s%^.*:%%;
|
$peer =~ s%/.*%%;
|
||||||
$port = $default_port unless $port =~ /^\d+$/;
|
$port = $peer;
|
||||||
$peer =~ s%:.*$%%;
|
$port =~ s%^.*:%%;
|
||||||
|
$port = $default_port unless $port =~ /^\d+$/;
|
||||||
|
$peer =~ s%:.*$%%;
|
||||||
|
|
||||||
my $to = sprintf "%s%s", $server, $proxy ? " via proxy $peer:$port" : "";
|
my $to = sprintf "%s%s", $server, $proxy ? " via proxy $peer:$port" : "";
|
||||||
verbose("CONNECT:", "%s", $to);
|
verbose("CONNECT:", "%s", $to);
|
||||||
|
|
||||||
$request = "GET ";
|
$request = "GET ";
|
||||||
$request .= "http://$server" if $proxy;
|
$request .= "http://$server" if $proxy;
|
||||||
$request .= "/$url HTTP/1.0\n";
|
$request .= "/$url HTTP/1.0\n";
|
||||||
$request .= "Host: $server\n";
|
$request .= "Host: $server\n";
|
||||||
|
|
||||||
my $auth = encode_base64("${login}:${password}", "");
|
my $auth = encode_base64("${login}:${password}", "");
|
||||||
$request .= "Authorization: Basic $auth\n" if $login || $password;
|
$request .= "Authorization: Basic $auth\n" if $login || $password;
|
||||||
$request .= "User-Agent: ${program}/${version}\n";
|
$request .= "User-Agent: ${program}/${version}\n";
|
||||||
$request .= "Connection: close\n";
|
$request .= "Connection: close\n";
|
||||||
$request .= "\n";
|
$request .= "\n";
|
||||||
|
|
||||||
## make sure newlines are <cr><lf> for some pedantic proxy servers
|
## make sure newlines are <cr><lf> for some pedantic proxy servers
|
||||||
($rq = $request) =~ s/\n/\r\n/g;
|
($rq = $request) =~ s/\n/\r\n/g;
|
||||||
|
|
||||||
# local $^W = 0;
|
# local $^W = 0;
|
||||||
$0 = sprintf("%s - connecting to %s port %s", $program, $peer, $port);
|
$0 = sprintf("%s - connecting to %s port %s", $program, $peer, $port);
|
||||||
if (! opt('exec')) {
|
if (! opt('exec')) {
|
||||||
debug("skipped network connection");
|
debug("skipped network connection");
|
||||||
verbose("SENDING:", "%s", $request);
|
verbose("SENDING:", "%s", $request);
|
||||||
} elsif ($use_ssl) {
|
} elsif ($ipversion eq '6') {
|
||||||
$sd = IO::Socket::SSL->new(
|
load_ipv6_support;
|
||||||
PeerAddr => $peer,
|
$sd = IO::Socket::INET6->new(
|
||||||
PeerPort => $port,
|
PeerAddr => $peer,
|
||||||
Proto => 'tcp',
|
PeerPort => $port,
|
||||||
MultiHomed => 1,
|
Proto => 'tcp',
|
||||||
Timeout => opt('timeout'),
|
MultiHomed => 1,
|
||||||
);
|
Timeout => opt('timeout'),
|
||||||
|
);
|
||||||
|
defined $sd or warning("cannot connect to $peer:$port socket: $@");
|
||||||
|
} elsif ($use_ssl) {
|
||||||
|
load_ssl_support;
|
||||||
|
$sd = IO::Socket::SSL->new(
|
||||||
|
PeerAddr => $peer,
|
||||||
|
PeerPort => $port,
|
||||||
|
Proto => 'tcp',
|
||||||
|
MultiHomed => 1,
|
||||||
|
Timeout => opt('timeout'),
|
||||||
|
);
|
||||||
defined $sd or warning("cannot connect to $peer:$port socket: $@ " . IO::Socket::SSL::errstr());
|
defined $sd or warning("cannot connect to $peer:$port socket: $@ " . IO::Socket::SSL::errstr());
|
||||||
} elsif ($globals{'ipv6'}) {
|
|
||||||
load_ipv6_support;
|
} else {
|
||||||
$sd = IO::Socket::INET6->new(
|
$sd = IO::Socket::INET->new(
|
||||||
PeerAddr => $peer,
|
PeerAddr => $peer,
|
||||||
PeerPort => $port,
|
PeerPort => $port,
|
||||||
Proto => 'tcp',
|
Proto => 'tcp',
|
||||||
MultiHomed => 1,
|
MultiHomed => 1,
|
||||||
Timeout => opt('timeout'),
|
Timeout => opt('timeout'),
|
||||||
);
|
);
|
||||||
defined $sd or warning("cannot connect to $peer:$port socket: $@");
|
defined $sd or warning("cannot connect to $peer:$port socket: $@");
|
||||||
} else {
|
}
|
||||||
$sd = IO::Socket::INET->new(
|
|
||||||
PeerAddr => $peer,
|
|
||||||
PeerPort => $port,
|
|
||||||
Proto => 'tcp',
|
|
||||||
MultiHomed => 1,
|
|
||||||
Timeout => opt('timeout'),
|
|
||||||
);
|
|
||||||
defined $sd or warning("cannot connect to $peer:$port socket: $@");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined $sd) {
|
if (defined $sd) {
|
||||||
## send the request to the http server
|
## send the request to the http server
|
||||||
|
|
@ -2075,6 +2176,37 @@ sub geturl {
|
||||||
}
|
}
|
||||||
$0 = sprintf("%s - closed %s port %s", $program, $peer, $port);
|
$0 = sprintf("%s - closed %s port %s", $program, $peer, $port);
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
# Access network using cURL.
|
||||||
|
my $curlopt = '';
|
||||||
|
my $protocol = 'http';
|
||||||
|
$curlopt = '--ipv4' if ($ipversion eq '4');
|
||||||
|
$curlopt = '--ipv6' if ($ipversion eq '6');
|
||||||
|
if ($use_ssl) {
|
||||||
|
$protocol = 'https';
|
||||||
|
$curlopt .= ' --insecure';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! opt('exec')) {
|
||||||
|
debug("skipped network connection");
|
||||||
|
verbose("SENDING:", "%s", '${protocol}://${server}/${url}');
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$0 = sprintf("%s - curl sending to %s", $program, '${protocol}://${server}/${url}');
|
||||||
|
my $timeout = opt('timeout');
|
||||||
|
|
||||||
|
$reply = `/usr/bin/curl -si0 --user "${login}:${password}" --user-agent "${program}/${version}" \\
|
||||||
|
--connect-timeout $timeout --max-time $timeout $curlopt \\
|
||||||
|
--url "${protocol}://${server}/${url}" 2>/dev/null`;
|
||||||
|
|
||||||
|
if (! $reply) {
|
||||||
|
warning("curl cannot connect to ${protocol}://${server}/${url}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
## during testing simulate reading the URL
|
## during testing simulate reading the URL
|
||||||
if (opt('test')) {
|
if (opt('test')) {
|
||||||
my $filename = "$server/$url";
|
my $filename = "$server/$url";
|
||||||
|
|
@ -2168,7 +2300,8 @@ sub get_ip {
|
||||||
$arg = $url;
|
$arg = $url;
|
||||||
|
|
||||||
if ($url) {
|
if ($url) {
|
||||||
$reply = geturl(opt('proxy', $h), $url) || '';
|
# when using a web server to find public IPv4 address we should force use of IPv4
|
||||||
|
$reply = geturl(opt('proxy', $h), $url, '', '', '4') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif (($use eq 'cisco')) {
|
} elsif (($use eq 'cisco')) {
|
||||||
|
|
@ -2230,11 +2363,6 @@ sub get_ip {
|
||||||
$ip = $1;
|
$ip = $1;
|
||||||
$ip = un_zero_pad($ip);
|
$ip = un_zero_pad($ip);
|
||||||
$ip = filter_local($ip) if opt('fw-banlocal', $h);
|
$ip = filter_local($ip) if opt('fw-banlocal', $h);
|
||||||
} elsif ( $ip = ipv6_match($reply) ) {
|
|
||||||
$ip = un_zero_pad($ip);
|
|
||||||
$ip = filter_local($ip) if opt('fw-banlocal', $h);
|
|
||||||
} else {
|
|
||||||
warning("found neither ipv4 nor ipv6 address");
|
|
||||||
}
|
}
|
||||||
if (($use ne 'ip') && (define($ip,'') eq '0.0.0.0')) {
|
if (($use ne 'ip') && (define($ip,'') eq '0.0.0.0')) {
|
||||||
$ip = undef;
|
$ip = undef;
|
||||||
|
|
@ -2245,31 +2373,69 @@ sub get_ip {
|
||||||
}
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
## ipv6_match determine ipv6 address from given string and return them
|
## get_ipv6
|
||||||
######################################################################
|
######################################################################
|
||||||
sub ipv6_match {
|
sub get_ipv6 {
|
||||||
my $content = shift;
|
my $usev6 = lc shift;
|
||||||
my $omits;
|
my $h = shift;
|
||||||
my $ip = "";
|
my ($ipv6, $arg, $reply, $url, $skip) = (undef, opt($usev6, $h), '');
|
||||||
my $linenumbers = 0;
|
$arg = '' unless $arg;
|
||||||
|
|
||||||
my @values = split('\n', $content);
|
if ($usev6 eq 'ip') {
|
||||||
foreach my $val (@values) {
|
$ipv6 = opt('ipv6', $h);
|
||||||
next unless $val =~ /((:{0,2}[A-F0-9]{1,4}){0,7}:{1,2}[A-F0-9]{1,4})/ai; # invalid char
|
$arg = 'ipv6';
|
||||||
my $parsed = $1;
|
|
||||||
|
} elsif ($usev6 eq 'if') {
|
||||||
# check for at least 7 colons
|
$skip = opt('if-skip', $h) || '';
|
||||||
my $count_colon = () = $parsed =~ /:/g;
|
$reply = `ip -6 addr list dev $arg | grep "scope.global" 2> /dev/null`;
|
||||||
if ($count_colon != 7) {
|
if ($reply =~ /.*? ([0-9:][^\/]*)/i) {
|
||||||
# or one double colon
|
$reply = $1;
|
||||||
my $count_double_colon = () = $parsed =~ /::/g;
|
}
|
||||||
if ($count_double_colon != 1) {
|
else {
|
||||||
next
|
$reply = ''
|
||||||
}
|
}
|
||||||
}
|
} elsif ($usev6 eq 'cmd') {
|
||||||
return $parsed;
|
$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) || '';
|
||||||
|
|
||||||
|
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, '', '', '6') || '';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return;
|
if (!defined $reply) {
|
||||||
|
$reply = '';
|
||||||
|
}
|
||||||
|
if ($skip) {
|
||||||
|
$skip =~ s/ /\\s/is;
|
||||||
|
$reply =~ s/^.*?${skip}//is;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract IPv6 address from the text
|
||||||
|
$ipv6 = $& if ($reply =~ /(?i)(?<![:.\w])(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}(?![:.\w])/);
|
||||||
|
|
||||||
|
if (($usev6 ne 'ip') && (define($ipv6,'') eq '::')) {
|
||||||
|
$ipv6 = undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("get_ipv6: using %s, %s reports %s", $usev6, $arg, define($ipv6, "<undefined>"));
|
||||||
|
return $ipv6;
|
||||||
}
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
@ -2361,6 +2527,7 @@ sub nic_updateable {
|
||||||
my $sub = shift;
|
my $sub = shift;
|
||||||
my $update = 0;
|
my $update = 0;
|
||||||
my $ip = $config{$host}{'wantip'};
|
my $ip = $config{$host}{'wantip'};
|
||||||
|
my $ipv6 = $config{$host}{'wantipv6'};
|
||||||
|
|
||||||
if ($config{$host}{'login'} eq '') {
|
if ($config{$host}{'login'} eq '') {
|
||||||
warning("null login name specified for host %s.", $host);
|
warning("null login name specified for host %s.", $host);
|
||||||
|
|
@ -2410,13 +2577,13 @@ sub nic_updateable {
|
||||||
|
|
||||||
} 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.",
|
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,
|
$host,
|
||||||
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
|
($cache{$host}{'ip'} ? $cache{$host}{'ip'} : '<nothing>'),
|
||||||
$ip,
|
$ip,
|
||||||
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
|
($cache{$host}{'mtime'} ? prettytime($cache{$host}{'mtime'}) : '<never>'),
|
||||||
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
|
($cache{$host}{'atime'} ? prettytime($cache{$host}{'atime'}) : '<never>'),
|
||||||
prettyinterval($config{$host}{'min-error-interval'})
|
prettyinterval($config{$host}{'min-error-interval'})
|
||||||
)
|
)
|
||||||
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
|
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
|
||||||
|
|
||||||
|
|
@ -2425,7 +2592,37 @@ sub nic_updateable {
|
||||||
} else {
|
} else {
|
||||||
$update = 1;
|
$update = 1;
|
||||||
}
|
}
|
||||||
|
} elsif ((!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'})
|
||||||
|
)
|
||||||
|
if opt('verbose') || !define($cache{$host}{'warned-min-interval'}, 0);
|
||||||
|
|
||||||
|
$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'})
|
||||||
|
)
|
||||||
|
if opt('verbose') || !define($cache{$host}{'warned-min-error-interval'}, 0);
|
||||||
|
|
||||||
|
$cache{$host}{'warned-min-error-interval'} = $now;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$update = 1;
|
||||||
|
}
|
||||||
} elsif (defined($sub) && &$sub($host)) {
|
} elsif (defined($sub) && &$sub($host)) {
|
||||||
$update = 1;
|
$update = 1;
|
||||||
} elsif ((defined($cache{$host}{'static'}) && defined($config{$host}{'static'}) &&
|
} elsif ((defined($cache{$host}{'static'}) && defined($config{$host}{'static'}) &&
|
||||||
|
|
@ -3772,10 +3969,14 @@ EoEXAMPLE
|
||||||
##
|
##
|
||||||
######################################################################
|
######################################################################
|
||||||
sub nic_freedns_update {
|
sub nic_freedns_update {
|
||||||
|
|
||||||
|
|
||||||
debug("\nnic_freedns_update -------------------");
|
debug("\nnic_freedns_update -------------------");
|
||||||
|
|
||||||
## First get the list of updatable hosts
|
## First get the list of updatable hosts
|
||||||
my $url;
|
my $url;
|
||||||
$url = "http://$config{$_[0]}{'server'}/api/?action=getdyndns&sha=".&sha1_hex("$config{$_[0]}{'login'}|$config{$_[0]}{'password'}");
|
# note, use '&v=2' in $url in order to pull IPv6 AAAA records as well as IPv4 A records
|
||||||
|
$url = "http://$config{$_[0]}{'server'}/api/?action=getdyndns&v=2&sha=".&sha1_hex("$config{$_[0]}{'login'}|$config{$_[0]}{'password'}");
|
||||||
my $reply = geturl(opt('proxy'), $url);
|
my $reply = geturl(opt('proxy'), $url);
|
||||||
if (!defined($reply) || !$reply || !header_ok($_[0], $reply)) {
|
if (!defined($reply) || !$reply || !header_ok($_[0], $reply)) {
|
||||||
failed("updating %s: Could not connect to %s for site list.", $_[0], $url);
|
failed("updating %s: Could not connect to %s for site list.", $_[0], $url);
|
||||||
|
|
@ -3783,9 +3984,22 @@ sub nic_freedns_update {
|
||||||
}
|
}
|
||||||
my @lines = split("\n", $reply);
|
my @lines = split("\n", $reply);
|
||||||
my %freedns_hosts;
|
my %freedns_hosts;
|
||||||
|
my %freedns_hosts_ipv6;
|
||||||
|
|
||||||
|
# We have retrieved list of URLs associated with users FreeDNS account.
|
||||||
|
# Store them into freedns_hosts separating IPv4 (A records) from IPv6 (AAAA records)
|
||||||
grep {
|
grep {
|
||||||
my @rec = split(/\|/, $_);
|
my @rec = split(/\|/, $_);
|
||||||
$freedns_hosts{$rec[0]} = \@rec if ($#rec > 0);
|
if ($#rec > 0) {
|
||||||
|
# This little gem from http://home.deds.nl/~aeron/regex/
|
||||||
|
if ($rec[1] =~ /^(((?=.*(::))(?!.*\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) {
|
||||||
|
debug("Host: %s, IPv6: %s", $rec[0], $rec[1]);
|
||||||
|
$freedns_hosts_ipv6{$rec[0]} = \@rec;
|
||||||
|
} else {
|
||||||
|
debug("Host: %s, IPv4: %s", $rec[0], $rec[1]);
|
||||||
|
$freedns_hosts{$rec[0]} = \@rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
} @lines;
|
} @lines;
|
||||||
if (!keys %freedns_hosts) {
|
if (!keys %freedns_hosts) {
|
||||||
failed("Could not get freedns update URLs from %s", $config{$_[0]}{'server'});
|
failed("Could not get freedns update URLs from %s", $config{$_[0]}{'server'});
|
||||||
|
|
@ -3795,41 +4009,81 @@ sub nic_freedns_update {
|
||||||
foreach my $h (@_) {
|
foreach my $h (@_) {
|
||||||
if(!$h){ next };
|
if(!$h){ next };
|
||||||
my $ip = delete $config{$h}{'wantip'};
|
my $ip = delete $config{$h}{'wantip'};
|
||||||
info("setting IP address to %s for %s", $ip, $h);
|
my $ipv6 = delete $config{$h}{'wantipv6'};
|
||||||
verbose("UPDATE:","updating %s", $h);
|
|
||||||
|
|
||||||
if($ip eq $freedns_hosts{$h}->[1]) {
|
info("%s: setting IP address(s) to %s / %s", $h, define($ip, "<undefined>"), define($ipv6, "<undefined>"));
|
||||||
$config{$h}{'ip'} = $ip;
|
|
||||||
$config{$h}{'mtime'} = $now;
|
|
||||||
$config{$h}{'status'} = 'good';
|
|
||||||
success("update not necessary %s: good: IP address already set to %s", $h, $ip);
|
|
||||||
} else {
|
|
||||||
my $reply = geturl(opt('proxy'), $freedns_hosts{$h}->[2]);
|
|
||||||
if (!defined($reply) || !$reply) {
|
|
||||||
failed("updating %s: Could not connect to %s.", $h, $freedns_hosts{$h}->[2]);
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
if(!header_ok($h, $reply)) {
|
|
||||||
$config{$h}{'status'} = 'failed';
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($reply =~ /Updated.*$h.*to.*$ip/) {
|
if (defined($freedns_hosts{$h}) && defined($ip)) {
|
||||||
|
if($ip eq $freedns_hosts{$h}->[1]) {
|
||||||
$config{$h}{'ip'} = $ip;
|
$config{$h}{'ip'} = $ip;
|
||||||
$config{$h}{'mtime'} = $now;
|
$config{$h}{'mtime'} = $now;
|
||||||
$config{$h}{'status'} = 'good';
|
$config{$h}{'status'} = 'good';
|
||||||
success("updating %s: good: IP address set to %s", $h, $ip);
|
success("update not necessary %s: good: IPv4 address already set to %s", $h, $ip);
|
||||||
} elsif ($reply =~ /Address (\d+\.\d+\.\d+\.\d+) has not changed/) {
|
|
||||||
$ip = $1;
|
|
||||||
$config{$h}{'mtime'} = $now;
|
|
||||||
$config{$h}{'status'} = 'good';
|
|
||||||
$config{$h}{'ip'} = $ip;
|
|
||||||
success("updating %s: good: IP address %s has not changed", $h, $ip);
|
|
||||||
} else {
|
} else {
|
||||||
$config{$h}{'status'} = 'failed';
|
debug("Update: %s", $freedns_hosts{$h}->[2]."&address=".$ip);
|
||||||
warning("SENT: %s", $freedns_hosts{$h}->[2]) unless opt('verbose');
|
my $reply = geturl(opt('proxy'), $freedns_hosts{$h}->[2]."&address=".$ip);
|
||||||
warning("REPLIED: %s", $reply);
|
if (!defined($reply) || !$reply) {
|
||||||
failed("updating %s: Invalid reply.", $h);
|
failed("updating %s: Could not connect to %s.", $h, $freedns_hosts{$h}->[2]);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
if(!header_ok($h, $reply)) {
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($reply =~ /Updated.*$h.*to.*$ip/) {
|
||||||
|
$config{$h}{'ip'} = $ip;
|
||||||
|
$config{$h}{'mtime'} = $now;
|
||||||
|
$config{$h}{'status'} = 'good';
|
||||||
|
success("updating %s: good: IP address set to %s", $h, $ip);
|
||||||
|
} else {
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
warning("SENT: %s", $freedns_hosts{$h}->[2]) unless opt('verbose');
|
||||||
|
warning("REPLIED: %s", $reply);
|
||||||
|
failed("updating %s: Invalid reply.", $h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$daemon || opt('verbose')) {
|
||||||
|
warning("%s: Cannot set IPv4 to %s No A record at FreeDNS", $h, $ip) if (!defined($freedns_hosts{$h}) && defined($ip));
|
||||||
|
warning("%s: Cannot set IPv4, A record exists but no address provided", $h) if (defined($freedns_hosts{$h}) && !defined($ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined($freedns_hosts_ipv6{$h}) && defined($ipv6)) {
|
||||||
|
if($ipv6 eq $freedns_hosts_ipv6{$h}->[1]) {
|
||||||
|
$config{$h}{'ipv6'} = $ipv6;
|
||||||
|
$config{$h}{'mtime'} = $now;
|
||||||
|
$config{$h}{'status'} = 'good';
|
||||||
|
success("update not necessary %s: good: IPv6 address already set to %s", $h, $ipv6);
|
||||||
|
} else {
|
||||||
|
debug("Update: %s", $freedns_hosts_ipv6{$h}->[2]."&address=".$ipv6);
|
||||||
|
my $reply = geturl(opt('proxy'), $freedns_hosts_ipv6{$h}->[2]."&address=".$ipv6);
|
||||||
|
if (!defined($reply) || !$reply) {
|
||||||
|
failed("updating %s: Could not connect to %s.", $h, $freedns_hosts_ipv6{$h}->[2]);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
if(!header_ok($h, $reply)) {
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($reply =~ /Updated.*$h.*to.*$ipv6/) {
|
||||||
|
$config{$h}{'ipv6'} = $ipv6;
|
||||||
|
$config{$h}{'mtime'} = $now;
|
||||||
|
$config{$h}{'status'} = 'good';
|
||||||
|
success("updating %s: good: IPv6 address set to %s", $h, $ipv6);
|
||||||
|
} else {
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
warning("SENT: %s", $freedns_hosts_ipv6{$h}->[2]) unless opt('verbose');
|
||||||
|
warning("REPLIED: %s", $reply);
|
||||||
|
failed("updating %s: Invalid reply.", $h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$daemon || opt('verbose')) {
|
||||||
|
warning("%s: Cannot set IPv6 to %s No AAAA record at FreeDNS", $h, $ipv6) if (!defined($freedns_hosts_ipv6{$h}) && defined($ipv6));
|
||||||
|
warning("%s: Cannot set IPv6, AAAA record exists but no address provided", $h) if (defined($freedns_hosts_ipv6{$h}) && !defined($ipv6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4133,48 +4387,87 @@ sub nic_nsupdate_update {
|
||||||
my $server = $config{$h}{'server'};
|
my $server = $config{$h}{'server'};
|
||||||
my $zone = $config{$h}{'zone'};
|
my $zone = $config{$h}{'zone'};
|
||||||
my $ip = $config{$h}{'wantip'};
|
my $ip = $config{$h}{'wantip'};
|
||||||
my $recordtype = '';
|
my $ipv6 = $config{$h}{'wantipv6'};
|
||||||
if (is_ipv6($ip)) {
|
|
||||||
$recordtype = 'AAAA';
|
|
||||||
} else {
|
|
||||||
$recordtype = 'A';
|
|
||||||
}
|
|
||||||
delete $config{$_}{'wantip'} foreach @hosts;
|
delete $config{$_}{'wantip'} foreach @hosts;
|
||||||
|
delete $config{$_}{'wantipv6'} foreach @hosts;
|
||||||
|
|
||||||
info("setting IP address to %s for %s", $ip, $hosts);
|
##TODO
|
||||||
verbose("UPDATE:","updating %s", $hosts);
|
## Requires testing with new IPv6 code
|
||||||
|
##TODO
|
||||||
|
if (defined($ip)) {
|
||||||
|
info("setting IP address to %s for %s", $ip, $hosts);
|
||||||
|
verbose("UPDATE:","updating %s", $hosts);
|
||||||
|
|
||||||
## send separate requests for each zone with all hosts in that zone
|
## send separate requests for each zone with all hosts in that zone
|
||||||
my $instructions = <<EoINSTR1;
|
my $instructions = <<EoINSTR1;
|
||||||
server $server
|
server $server
|
||||||
zone $zone.
|
zone $zone.
|
||||||
EoINSTR1
|
EoINSTR1
|
||||||
foreach (@hosts) {
|
foreach (@hosts) {
|
||||||
$instructions .= <<EoINSTR2;
|
$instructions .= <<EoINSTR2;
|
||||||
update delete $_. $recordtype
|
update delete $_. A
|
||||||
update add $_. $config{$_}{'ttl'} $recordtype $ip
|
update add $_. $config{$_}{'ttl'} A $ip
|
||||||
EoINSTR2
|
EoINSTR2
|
||||||
}
|
}
|
||||||
$instructions .= <<EoINSTR3;
|
$instructions .= <<EoINSTR3;
|
||||||
send
|
send
|
||||||
EoINSTR3
|
EoINSTR3
|
||||||
my $command = "$binary -k $keyfile";
|
my $command = "$binary -k $keyfile";
|
||||||
$command .= " -v" if ynu($config{$h}{'tcp'}, 1, 0, 0);
|
$command .= " -v" if ynu($config{$h}{'tcp'}, 1, 0, 0);
|
||||||
$command .= " -d" if (opt('debug'));
|
$command .= " -d" if (opt('debug'));
|
||||||
verbose("UPDATE:", "nsupdate command is: %s", $command);
|
verbose("UPDATE:", "nsupdate command is: %s", $command);
|
||||||
verbose("UPDATE:", "nsupdate instructions are:\n%s", $instructions);
|
verbose("UPDATE:", "nsupdate instructions are:\n%s", $instructions);
|
||||||
|
|
||||||
my $status = pipecmd($command, $instructions);
|
my $status = pipecmd($command, $instructions);
|
||||||
if ($status eq 1) {
|
if ($status eq 1) {
|
||||||
foreach (@hosts) {
|
foreach (@hosts) {
|
||||||
$config{$_}{'ip'} = $ip;
|
$config{$_}{'ip'} = $ip;
|
||||||
$config{$_}{'mtime'} = $now;
|
$config{$_}{'mtime'} = $now;
|
||||||
success("updating %s: %s: IP address set to %s", $_, $status, $ip);
|
success("updating %s: %s: IP address set to %s", $_, $status, $ip);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (@hosts) {
|
||||||
|
failed("updating %s", $_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
if ( defined($ipv6) ) {
|
||||||
|
info("setting IPv6 address to %s for %s", $ipv6, $hosts);
|
||||||
|
verbose("UPDATE:","updating %s", $hosts);
|
||||||
|
|
||||||
|
## send separate requests for each zone with all hosts in that zone
|
||||||
|
my $instructions = <<EoINSTR1;
|
||||||
|
server $server
|
||||||
|
zone $zone.
|
||||||
|
EoINSTR1
|
||||||
foreach (@hosts) {
|
foreach (@hosts) {
|
||||||
failed("updating %s", $_);
|
$instructions .= <<EoINSTR2;
|
||||||
|
update delete $_. AAAA
|
||||||
|
update add $_. $config{$_}{'ttl'} AAAA $ipv6
|
||||||
|
EoINSTR2
|
||||||
}
|
}
|
||||||
|
$instructions .= <<EoINSTR3;
|
||||||
|
send
|
||||||
|
EoINSTR3
|
||||||
|
my $command = "$binary -k $keyfile";
|
||||||
|
$command .= " -v" if ynu($config{$h}{'tcp'}, 1, 0, 0);
|
||||||
|
$command .= " -d" if (opt('debug'));
|
||||||
|
verbose("UPDATE:", "nsupdate command is: %s", $command);
|
||||||
|
verbose("UPDATE:", "nsupdate instructions are:\n%s", $instructions);
|
||||||
|
|
||||||
|
my $status = pipecmd($command, $instructions);
|
||||||
|
if ($status eq 1) {
|
||||||
|
foreach (@hosts) {
|
||||||
|
$config{$_}{'ip'} = $ipv6;
|
||||||
|
$config{$_}{'mtime'} = $now;
|
||||||
|
success("updating %s: %s: IPv6 address set to %s", $_, $status, $ipv6);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (@hosts) {
|
||||||
|
failed("updating %s", $_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue