diff --git a/ddclient b/ddclient index ddf1066..86a32f3 100755 --- a/ddclient +++ b/ddclient @@ -1521,7 +1521,12 @@ sub test_possible_ip { sub test_geturl { my $url = shift; - my $reply = geturl(opt('proxy'), $url, opt('login'), opt('password')); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => opt('login'), + password => opt('password'), + }); print "URL $url\n"; print defined($reply) ? $reply : "\n"; exit; @@ -1995,13 +2000,15 @@ EOM ## geturl ###################################################################### sub geturl { - my $proxy = shift || ''; - my $url = shift || ''; - my $login = shift || ''; - my $password = shift || ''; - my $headers = shift || ''; - my $method = shift || 'GET'; - my $data = shift || ''; + my ($params) = @_; + my $proxy = $params->{proxy} // ''; + my $url = $params->{url} // ''; + my $login = $params->{login} // ''; + my $password = $params->{password} // ''; + my $ipversion = $params->{ipversion} // ''; + my $headers = $params->{headers} // ''; + my $method = $params->{method} // 'GET'; + my $data = $params->{data} // ''; my ($peer, $server, $port, $default_port, $use_ssl); my ($sd, $request, $reply); @@ -2021,7 +2028,6 @@ sub geturl { if ($force_ssl || ($globals{'ssl'} and (caller(1))[3] ne 'main::get_ip')) { $use_ssl = 1; $default_port = 443; - load_ssl_support; } else { $use_ssl = 0; $default_port = 80; @@ -2030,6 +2036,7 @@ sub geturl { debug("protocol = %s", $use_ssl ? "https" : "http"); debug("server = %s", $server); debug("url = %s", $url); + debug("ip ver = %s", $ipversion); ## determine peer and port to use. $peer = $proxy || $server; @@ -2039,9 +2046,6 @@ sub geturl { $port = $default_port unless $port =~ /^\d+$/; $peer =~ s%:.*$%%; - my $to = sprintf "%s%s", $server, $proxy ? " via proxy $peer:$port" : ""; - verbose("CONNECT:", "%s", $to); - $request = "$method "; if (!$use_ssl) { $request .= "http://$server" if $proxy; @@ -2067,57 +2071,61 @@ sub geturl { $request .= $data; $rq .= $data; - - $0 = sprintf("%s - connecting to %s port %s", $program, $peer, $port); - if (!opt('exec')) { - debug("skipped network connection"); - verbose("SENDING:", "%s", $request); - } elsif ($use_ssl) { - $sd = IO::Socket::SSL->new( - PeerAddr => $peer, - PeerPort => $port, - Proto => 'tcp', - MultiHomed => 1, - Timeout => opt('timeout'), - ); - defined $sd or warning("cannot connect to %s:%s socket: %s %s", $peer, $port, $@, IO::Socket::SSL::errstr()); - } elsif ($globals{'ipv6'}) { + my $socket_class = 'IO::Socket::INET'; + if ($use_ssl) { + # IO::Socket::SSL will load IPv6 support if available on the system. + load_ssl_support; + $socket_class = 'IO::Socket::SSL'; + } elsif ($globals{'ipv6'} || $ipversion eq '6') { load_ipv6_support; - $sd = IO::Socket::INET6->new( - PeerAddr => $peer, - PeerPort => $port, - Proto => 'tcp', - MultiHomed => 1, - Timeout => opt('timeout'), - ); - defined $sd or warning("cannot connect to %s:%s socket: %s", $peer, $port, $@); - } else { - $sd = IO::Socket::INET->new( - PeerAddr => $peer, - PeerPort => $port, - Proto => 'tcp', - MultiHomed => 1, - Timeout => opt('timeout'), - ); - defined $sd or warning("cannot connect to %s:%s socket: %s", $peer, $port, $@); + $socket_class = 'IO::Socket::INET6'; + } + my %socket_args = ( + PeerAddr => $peer, + PeerPort => $port, + Proto => 'tcp', + MultiHomed => 1, + Timeout => opt('timeout'), + ); + if ($ipversion eq '4') { + $socket_args{Domain} = PF_INET; + $socket_args{Family} = AF_INET; + } elsif ($ipversion eq '6') { + $socket_args{Domain} = PF_INET6; + $socket_args{Family} = AF_INET6; + } elsif ($ipversion ne '') { + fatal("geturl passed unsupported 'ipversion' value %s", $ipversion); } + my $ipv = $ipversion eq '' ? '' : sprintf(" (IPv%s)", $ipversion); + my $peer_port_ipv = sprintf("%s:%s%s", $peer, $port, $ipv); + my $to = sprintf("%s%s%s", $server, $proxy ? " via proxy $peer:$port" : "", $ipv); + verbose("CONNECT:", "%s", $to); + $0 = sprintf("%s - connecting to %s", $program, $peer_port_ipv); + if (opt('exec')) { + $sd = $socket_class->new(%socket_args); + defined($sd) or warning("cannot connect to %s socket: %s%s", $peer_port_ipv, $@, + $use_ssl ? ' ' . IO::Socket::SSL::errstr() : ''); + } else { + debug("skipped network connection"); + verbose("SENDING:", "%s", $request); + } if (defined $sd) { ## send the request to the http server verbose("CONNECTED: ", $use_ssl ? 'using SSL' : 'using HTTP'); verbose("SENDING:", "%s", $request); - $0 = sprintf("%s - sending to %s port %s", $program, $peer, $port); + $0 = sprintf("%s - sending to %s", $program, $peer_port_ipv); my $result = syswrite $sd, $rq; if ($result != length($rq)) { - warning("cannot send to %s:%s (%s).", $peer, $port, $!); + warning("cannot send to %s (%s).", $peer_port_ipv, $!); } else { - $0 = sprintf("%s - reading from %s port %s", $program, $peer, $port); + $0 = sprintf("%s - reading from %s", $program, $peer_port_ipv); eval { local $SIG{'ALRM'} = sub { die "timeout"; }; alarm(opt('timeout')) if opt('timeout') > 0; while ($_ = <$sd>) { - $0 = sprintf("%s - read from %s port %s", $program, $peer, $port); + $0 = sprintf("%s - read from %s", $program, $peer_port_ipv); verbose("RECEIVE:", "%s", define($_, "")); $reply .= $_ if defined $_; } @@ -2134,7 +2142,7 @@ sub geturl { $reply = '' if !defined $reply; } } - $0 = sprintf("%s - closed %s port %s", $program, $peer, $port); + $0 = sprintf("%s - closed %s", $program, $peer_port_ipv); ## during testing simulate reading the URL if (opt('test')) { @@ -2229,7 +2237,7 @@ sub get_ip { $arg = $url; if ($url) { - $reply = geturl(opt('proxy', $h), $url) || ''; + $reply = geturl({ proxy => opt('proxy', $h), url => $url }) || ''; } } elsif (($use eq 'cisco')) { @@ -2245,9 +2253,13 @@ sub get_ip { # Protect special HTML characters (like '?') $queryif =~ s/([\?&= ])/sprintf("%%%02x", ord($1))/ge; - $url = "http://" . opt('fw', $h) . "/level/1/exec/show/ip/interface/brief/${queryif}/CR"; - $reply = geturl('', $url, opt('fw-login', $h), opt('fw-password', $h)) || ''; - $arg = $url; + $url = "http://" . opt('fw', $h) . "/level/1/exec/show/ip/interface/brief/${queryif}/CR"; + $reply = geturl({ + url => $url, + login => opt('fw-login', $h), + password => opt('fw-password', $h), + }) || ''; + $arg = $url; } elsif (($use eq 'cisco-asa')) { # Stuff added to support Cisco ASA ip https daemon @@ -2262,9 +2274,13 @@ sub get_ip { # Protect special HTML characters (like '?') $queryif =~ s/([\?&= ])/sprintf("%%%02x", ord($1))/ge; - $url = "https://" . opt('fw', $h) . "/exec/show%20interface%20${queryif}"; - $reply = geturl('', $url, opt('fw-login', $h), opt('fw-password', $h)) || ''; - $arg = $url; + $url = "https://" . opt('fw', $h) . "/exec/show%20interface%20${queryif}"; + $reply = geturl({ + url => $url, + login => opt('fw-login', $h), + password => opt('fw-password', $h), + }) || ''; + $arg = $url; } else { $url = opt('fw', $h) || ''; @@ -2277,7 +2293,11 @@ sub get_ip { $arg = $url; if ($url) { - $reply = geturl('', $url, opt('fw-login', $h), opt('fw-password', $h)) || ''; + $reply = geturl({ + url => $url, + login => opt('fw-login', $h), + password => opt('fw-password', $h), + }) || ''; } } if (!defined $reply) { @@ -2656,7 +2676,12 @@ sub nic_dyndns1_update { $url .= "&backmx=" . ynu($config{$h}{'backupmx'}, 'YES', 'NO'); } - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; @@ -2819,7 +2844,12 @@ sub nic_dyndns2_update { $url .= "&backmx=" . ynu($config{$h}{'backupmx'}, 'YES', 'NO'); } - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $hosts, $config{$h}{'server'}); last; @@ -2924,7 +2954,12 @@ sub nic_noip_update { $url .= "&myip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $hosts, $config{$h}{'server'}); last; @@ -3059,7 +3094,12 @@ sub nic_dslreports1_update { $url .= "&myip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; @@ -3134,7 +3174,12 @@ sub nic_hammernode1_update { $url .= "&ip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); last; @@ -3224,7 +3269,12 @@ sub nic_zoneedit1_update { $url .= "&dnsto=$ip" if $ip; $url .= "&zone=$config{$h}{'zone'}" if defined $config{$h}{'zone'}; - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $hosts, $config{$h}{'server'}); last; @@ -3374,7 +3424,12 @@ sub nic_easydns_update { $url .= "&backmx=" . ynu($config{$h}{'backupmx'}, 'YES', 'NO'); } - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $hosts, $config{$h}{'server'}); last; @@ -3488,7 +3543,7 @@ sub nic_namecheap_update { $url .= "&ip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); last; @@ -3619,7 +3674,13 @@ sub nic_nfsn_make_request { $header .= "Content-Type: application/x-www-form-urlencoded\n"; } - return geturl(opt('proxy'), $url, '', '', $header, $method, $body); + return geturl({ + proxy => opt('proxy'), + url => $url, + headers => $header, + method => $method, + data => $body, + }); } ###################################################################### @@ -3792,7 +3853,7 @@ sub nic_sitelutions_update { $url .= "&ip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); last; @@ -3863,7 +3924,7 @@ sub nic_freedns_update { ## First get the list of updatable hosts my $url; $url = "http://$config{$_[0]}{'server'}/api/?action=getdyndns&sha=" . &sha1_hex("$config{$_[0]}{'login'}|$config{$_[0]}{'password'}"); - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); if (!defined($reply) || !$reply || !header_ok($_[0], $reply)) { failed("updating %s: Could not connect to %s for site list.", $_[0], $url); return; @@ -3891,7 +3952,7 @@ sub nic_freedns_update { $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]); + my $reply = geturl({proxy => opt('proxy'), url => $freedns_hosts{$h}->[2] }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $freedns_hosts{$h}->[2]); last; @@ -3968,7 +4029,12 @@ sub nic_changeip_update { $url .= "&ip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); last; @@ -4044,7 +4110,7 @@ sub nic_dtdns_update { $url .= $config{$h}{'client'}; # Try to get URL - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); # No response, declare as failed if (!defined($reply) || !$reply) { @@ -4129,7 +4195,12 @@ sub nic_googledomains_update { $url .= "&myip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, $config{$host}{'login'}, $config{$host}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$host}{'login'}, + password => $config{$host}{'password'}, + }); unless ($reply) { failed("updating %s: Could not connect to %s.", $host, $config{$host}{'server'}); last; @@ -4338,7 +4409,7 @@ sub nic_cloudflare_update { my $url = "https://$config{$key}{'server'}/zones?"; $url .= "name=".$config{$key}{'zone'}; - my $reply = geturl(opt('proxy'), $url, undef, undef, $headers); + my $reply = geturl({ proxy => opt('proxy'), url => $url, headers => $headers }); unless ($reply) { failed("updating %s: Could not connect to %s.", $domain, $config{$key}{'server'}); last; @@ -4369,7 +4440,7 @@ sub nic_cloudflare_update { $url .= "type=A&name=$domain"; } - $reply = geturl(opt('proxy'), $url, undef, undef, $headers); + $reply = geturl({ proxy => opt('proxy'), url => $url, headers => $headers }); unless ($reply) { failed("updating %s: Could not connect to %s.", $domain, $config{$key}{'server'}); last; @@ -4395,7 +4466,13 @@ sub nic_cloudflare_update { # Set domain $url = "https://$config{$key}{'server'}/zones/$zone_id/dns_records/$dns_rec_id"; my $data = "{\"content\":\"$ip\"}"; - $reply = geturl(opt('proxy'), $url, undef, undef, $headers, "PATCH", $data); + $reply = geturl({ + proxy => opt('proxy'), + url => $url, + headers => $headers, + method => "PATCH", + data => $data, + }); unless ($reply) { failed("updating %s: Could not connect to %s.", $domain, $config{$domain}{'server'}); last; @@ -4479,7 +4556,7 @@ sub nic_yandex_update { my $url = "https://$config{$host}{'server'}/api2/admin/dns/list?"; $url .= "domain="; $url .= $config{$key}{'login'}; - my $reply = geturl(opt('proxy'), $url, '', '', $headers); + my $reply = geturl({ proxy => opt('proxy'), url => $url, headers => $headers }); unless ($reply) { failed("updating %s: Could not connect to %s.", $host, $config{$key}{'server'}); last; @@ -4510,7 +4587,13 @@ sub nic_yandex_update { $data .= "&content="; $data .= $ip if $ip; - $reply = geturl(opt('proxy'), $url, '', '', $headers, 'POST', $data); + $reply = geturl({ + proxy => opt('proxy'), + url => $url, + headers => $headers, + method => 'POST', + data => $data, + }); unless ($reply) { failed("updating %s: Could not connect to %s.", $host, $config{$host}{'server'}); last; @@ -4588,7 +4671,7 @@ sub nic_duckdns_update { # Try to get URL - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); # No response, declare as failed if (!defined($reply) || !$reply) { @@ -4659,7 +4742,7 @@ sub nic_freemyip_update { $url .= $h; # Try to get URL - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); # No response, declare as failed if (!defined($reply) || !$reply) { @@ -4787,7 +4870,12 @@ sub nic_woima_update { $url .= "&backmx=" . ynu($config{$h}{'backupmx'}, 'YES', 'NO'); } - my $reply = geturl(opt('proxy'), $url, $config{$h}{'login'}, $config{$h}{'password'}); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); last; @@ -4903,7 +4991,7 @@ sub nic_dondominio_update { # Try to get URL - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); # No response, declare as failed if (!defined($reply) || !$reply) { @@ -4989,7 +5077,7 @@ sub nic_dnsmadeeasy_update { $url .= "&id=$h"; # Try to get URL - my $reply = geturl(opt('proxy'), $url); + my $reply = geturl({ proxy => opt('proxy'), url => $url }); # No response, declare as failed if (!defined($reply) || !$reply) { @@ -5060,7 +5148,12 @@ sub nic_ovh_update { $url .= "&myip="; $url .= $ip if $ip; - my $reply = geturl(opt('proxy'), $url, "$config{$h}{'login'}", "$config{$h}{'password'}"); + my $reply = geturl({ + proxy => opt('proxy'), + url => $url, + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + }); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'});