From 6ddecb4ecc86e33b948abfd697d21e229481ed89 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 14:03:17 -0400 Subject: [PATCH 01/91] Replace `use vars` with `our` From the documentation for `vars`: > NOTE: For use with variables in the current package for a single > scope, the functionality provided by this pragma has been superseded > by "our" declarations, available in Perl v5.6.0 or later, and use of > this pragma is discouraged. --- ddclient.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index c7c58a4..5f5baa1 100755 --- a/ddclient.in +++ b/ddclient.in @@ -134,9 +134,8 @@ my $last_emailbody = ''; ## flags and options to override). my $daemon_default = ($programd =~ /d$/) ? interval('5m') : undef; -use vars qw($file $lineno); -local $file = ''; -local $lineno = ''; +our $file = ''; +our $lineno = ''; $ENV{'PATH'} = (exists($ENV{PATH}) ? "$ENV{PATH}:" : "") . "/sbin:/usr/sbin:/bin:/usr/bin:/etc:/usr/lib:"; From ccc205301aab96cb5846bf1bbe08f54d68263437 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 14:14:56 -0400 Subject: [PATCH 02/91] Delete old test code It's better to start a test HTTP server or override `@curl` from tests in `t/*.pl`. --- ddclient.in | 67 ----------------------------------------------------- 1 file changed, 67 deletions(-) diff --git a/ddclient.in b/ddclient.in index 5f5baa1..108148c 100755 --- a/ddclient.in +++ b/ddclient.in @@ -119,12 +119,6 @@ sub subst_var { my $etc = subst_var('@sysconfdir@', '/etc/ddclient'); my $cachedir = subst_var('@localstatedir@', '/var') . '/cache/ddclient'; -my $savedir = '/tmp'; -if ($program =~ /test/i) { - $etc = '.'; - $cachedir = '.'; - $savedir = 'URL'; -} our @curl = (subst_var('@CURL@', 'curl')); our $emailbody = ''; @@ -1229,7 +1223,6 @@ my @opt = ( ["query", "!", "--{no}query : print {no} ip addresses and exit"], ["fw-banlocal", "!", ""], ## deprecated ["if-skip", "=s", ""], ## deprecated - ["test", "!", ""], ## hidden ["redirect", "=i", "--redirect= : enable and follow at most HTTP 30x redirections"], "", nic_examples(), @@ -2195,54 +2188,6 @@ sub test_possible_ip { exit 0 unless opt('debug'); } -###################################################################### -## load_file -###################################################################### -sub load_file { - my $file = shift; - my $buffer = ''; - - if (exists($ENV{'TEST_CASE'})) { - my $try = "$file-$ENV{'TEST_CASE'}"; - $file = $try if -f $try; - } - - local *FD; - if (open(FD, "< $file")) { - read(FD, $buffer, -s FD); - close(FD); - debug("Loaded %d bytes from %s", length($buffer), $file); - } else { - debug("Load failed from %s (%s)", $file, $!); - } - return $buffer; -} -###################################################################### -## save_file -###################################################################### -sub save_file { - my ($file, $buffer, $opt) = @_; - - $file .= "-$ENV{'TEST_CASE'}" if exists $ENV{'TEST_CASE'}; - if (defined $opt) { - my $i = 0; - while (-f "$file-$i") { - if ('unique' =~ /^$opt/i) { - my $a = join('\n', grep {!/^Date:/} split /\n/, $buffer); - my $b = join('\n', grep {!/^Date:/} split /\n/, load_file("$file-$i")); - last if $a eq $b; - } - $i++; - } - $file = "$file-$i"; - } - debug("Saving to %s", $file); - local *FD; - open(FD, "> $file") or return; - print FD $buffer; - close(FD); - return $buffer; -} ###################################################################### ## print_opt ## print_globals @@ -2809,18 +2754,6 @@ sub geturl { } } } - - ## during testing simulate reading the URL - if (opt('test')) { - my $filename = "$server/$url"; - $filename =~ s|/|%2F|g; - if (opt('exec')) { - $reply = save_file("$savedir/$filename", $reply, 'unique'); - } else { - $reply = load_file("$savedir/$filename"); - } - } - $reply =~ s/\r//g if defined $reply; return $reply; } From 0ea2f065137d200485b54d139da956a6ff1178cd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 13 Jun 2024 00:41:43 -0400 Subject: [PATCH 03/91] get_ip: Don't mutate `$arg` This makes log messages easier to understand. --- ddclient.in | 21 +++++++-------------- t/builtinfw_query.pl | 19 +++---------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/ddclient.in b/ddclient.in index 108148c..cf85f6e 100755 --- a/ddclient.in +++ b/ddclient.in @@ -216,17 +216,16 @@ sub query_cisco { $if =~ s%\/%\\\/%g; # Protect special HTML characters (like '?') $if =~ s/([\?&= ])/sprintf("%%%02x", ord($1))/ge; - my $url = ($asa) - ? "https://$fw/exec/show%20interface%20$if" - : "http://$fw/level/1/exec/show/ip/interface/brief/$if/CR"; my $reply = geturl( - url => $url, + url => ($asa) + ? "https://$fw/exec/show%20interface%20$if" + : "http://$fw/level/1/exec/show/ip/interface/brief/$if/CR", login => opt('fw-login', $h), password => opt('fw-password', $h), ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), ) // ''; - return ($url, $reply); + return $reply; } our %builtinfw = ( @@ -2774,7 +2773,6 @@ sub get_ip { warning("'%s' is not a valid IPv4 or IPv6 address", $ip // ''); $ip = undef; } - $arg = 'ip'; } elsif ($use eq 'if') { $ip = get_ip_from_interface($arg); } elsif ($use eq 'cmd') { @@ -2791,7 +2789,6 @@ sub get_ip { $skip //= $biw->{skip}; $url = $biw->{url}; } - $arg = $url; if ($url) { $reply = geturl( proxy => opt('proxy', $h), @@ -2811,7 +2808,7 @@ sub get_ip { $skip //= $fw->{'skip'}; if (defined(my $query = $fw->{'query'})) { $url = undef; - ($arg, $reply) = $query->($h); + $reply = $query->($h); } else { $url = "http://$url$fw->{'url'}" unless $url =~ /\//; } @@ -3165,7 +3162,6 @@ sub get_ipv4 { warning("'%s' is not a valid IPv4", $ipv4 // ''); $ipv4 = undef; } - $arg = 'ipv4'; # For debug message at end of function } elsif ($usev4 eq 'ifv4') { ## Obtain IPv4 address from interface mamed in "ifv4=" $ipv4 = get_ip_from_interface($arg, 4); @@ -3185,7 +3181,6 @@ sub get_ipv4 { warning("'--webv4=$url' is deprecated! $biw->{deprecated}") if $biw->{deprecated}; $skip //= $biw->{skip}; $url = $biw->{url}; - $arg = $url; } if ($url) { $reply = geturl( @@ -3211,7 +3206,7 @@ sub get_ipv4 { $skip //= $fw->{'skip'}; if (defined(my $query = $fw->{'queryv4'})) { $url = undef; - ($arg, $reply) = $query->($h); + $reply = $query->($h); } else { $url = "http://$url$fw->{'url'}" unless $url =~ /\//; } @@ -3268,7 +3263,6 @@ sub get_ipv6 { warning("'%s' is not a valid IPv6", $ipv6 // ''); $ipv6 = undef; } - $arg = 'ipv6'; # For debug message at end of function } elsif ($usev6 eq 'ifv6' || $usev6 eq 'if') { ## Obtain IPv6 address from interface mamed in "ifv6=" if ($usev6 eq 'if') { @@ -3302,7 +3296,6 @@ sub get_ipv6 { warning("'--webv6=$url' is deprecated! $biw->{deprecated}") if $biw->{deprecated}; $skip //= $biw->{skip}; $url = $biw->{url}; - $arg = $url; } if ($url) { $reply = geturl( @@ -3318,7 +3311,7 @@ sub get_ipv6 { $skip = opt('fwv6-skip', $h) // $fw->{'skip'}; if ($fw && defined(my $query = $fw->{'queryv6'})) { $skip //= $fw->{'skip'}; - ($arg, $reply) = $query->($h); + $reply = $query->($h); } else { warning("'--usev6=%s' is not implemented and does nothing", $usev6); } diff --git a/t/builtinfw_query.pl b/t/builtinfw_query.pl index 6151fc6..a784a33 100644 --- a/t/builtinfw_query.pl +++ b/t/builtinfw_query.pl @@ -1,33 +1,22 @@ use Test::More; -eval { require Test::MockModule; } or plan(skip_all => $@); SKIP: { eval { require Test::Warnings; } or skip($@, 1); } eval { require 'ddclient'; } or BAIL_OUT($@); -my $debug_msg; -my $module = Test::MockModule->new('ddclient'); -# Note: 'mock' is used instead of 'redefine' because 'redefine' is not available in the versions of -# Test::MockModule distributed with old Debian and Ubuntu releases. -$module->mock('debug', sub { - my $msg = sprintf(shift, @_); - return unless ($msg =~ qr/^get_ip(v[46])?:/); - BAIL_OUT("debug already called") if defined($debug_msg); - $debug_msg = $msg; -}); my $got_host; my $builtinfw = 't/builtinfw_query.pl'; $ddclient::builtinfw{$builtinfw} = { name => 'dummy device for testing', query => sub { ($got_host) = @_; - return ($got_host, "192.0.2.1 skip1 192.0.2.2 skip2 192.0.2.3"); + return '192.0.2.1 skip1 192.0.2.2 skip2 192.0.2.3'; }, queryv4 => sub { ($got_host) = @_; - return ($got_host, "192.0.2.4 skip1 192.0.2.5 skip3 192.0.2.6"); + return '192.0.2.4 skip1 192.0.2.5 skip3 192.0.2.6'; }, queryv6 => sub { ($got_host) = @_; - return ($got_host, "2001:db8::1 skip1 2001:db8::2 skip4 2001:db8::3"); + return '2001:db8::1 skip1 2001:db8::2 skip4 2001:db8::3'; }, }; %ddclient::builtinfw if 0; # suppress spurious warning "Name used only once: possible typo" @@ -81,12 +70,10 @@ for my $tc (@test_cases) { %{$tc->{cfgxtra}}, }; %ddclient::config if 0; # suppress spurious warning "Name used only once: possible typo" - undef($debug_msg); undef($got_host); my $got = $tc->{getip}($builtinfw, $h); is($got_host, $h, "host is passed through"); is($got, $tc->{want}, "returned IP matches"); - like($debug_msg, qr/\b\Q$h\E\b/, "returned arg is properly handled"); }; } From b9d372c12ddd17daad646f5a5aa023a808a207f2 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 13 Jun 2024 01:11:57 -0400 Subject: [PATCH 04/91] get_ip: Allow `$arg` to be undefined This is simpler, and makes it possible to distinguish unset from set to an empty string. --- ddclient.in | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ddclient.in b/ddclient.in index cf85f6e..cc0c7af 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2765,7 +2765,6 @@ sub get_ip { $use = 'disabled' if ($use eq 'no'); # backward compatibility my $h = shift; my ($ip, $arg, $reply, $url, $skip) = (undef, opt($use, $h), ''); - $arg = '' unless $arg; if ($use eq 'ip') { $ip = opt('ip', $h); @@ -2801,7 +2800,7 @@ sub get_ip { $reply = ''; } elsif ($use eq 'fw' || defined(my $fw = $builtinfw{$use})) { # Note that --use=firewallname uses --fw=arg, not --firewallname=arg. - $arg = opt('fw', $h) // ''; + $arg = opt('fw', $h); $url = $arg; $skip = opt('fw-skip', $h); if ($fw) { @@ -2838,7 +2837,7 @@ sub get_ip { $ip = undef; } - debug("get_ip: using %s, %s reports %s", $use, $arg, $ip // ""); + debug("get_ip: using %s, %s reports %s", $use, $arg // '', $ip // ''); return $ip; } @@ -3153,7 +3152,7 @@ sub get_ipv4 { my $reply = ''; ## Text returned from various methods my $url = ''; ## URL of website or firewall my $skip = undef; ## Regex of pattern to skip before looking for IP - my $arg = opt($usev4, $h) // ''; ## Value assigned to the "usev4" method + my $arg = opt($usev4, $h); ## Value assigned to the "usev4" method if ($usev4 eq 'ipv4') { ## Static IPv4 address is provided in "ipv4=
" @@ -3199,7 +3198,7 @@ sub get_ipv4 { warning("'--fw-skip' is deprecated for '--usev4=$usev4'; use '--fwv4-skip' instead") if (!defined(opt('fwv4-skip', $h)) && defined(opt('fw-skip', $h))); # Note that --usev4=firewallname uses --fwv4=arg (or --fw=arg), not --firewallname=arg. - $arg = opt('fwv4', $h) // opt('fw', $h) // ''; + $arg = opt('fwv4', $h) // opt('fw', $h); $url = $arg; $skip = opt('fwv4-skip', $h) // opt('fw-skip', $h); if ($fw) { @@ -3235,7 +3234,8 @@ sub get_ipv4 { $ipv4 //= extract_ipv4($reply); ## Return undef for loopback address unless statically assigned by "ipv4=0.0.0.0" $ipv4 = undef if (($usev4 ne 'ipv4') && (($ipv4 // '') eq '0.0.0.0')); - debug("get_ipv4: using (%s, %s) reports %s", $usev4, $arg, $ipv4 // ""); + debug("get_ipv4: using (%s, %s) reports %s", + $usev4, $arg // "", $ipv4 // ""); return $ipv4; } @@ -3250,7 +3250,7 @@ sub get_ipv6 { my $reply = ''; ## Text returned from various methods my $url = ''; ## URL of website or firewall my $skip = undef; ## Regex of pattern to skip before looking for IP - my $arg = opt($usev6, $h) // ''; ## Value assigned to the "usev6" method + my $arg = opt($usev6, $h); ## Value assigned to the "usev6" method if ($usev6 eq 'ipv6' || $usev6 eq 'ip') { ## Static IPv6 address is provided in "ipv6=
" @@ -3329,7 +3329,8 @@ sub get_ipv6 { $ipv6 //= extract_ipv6($reply); ## Return undef for loopback address unless statically assigned by "ipv6=::" $ipv6 = undef if (($usev6 ne 'ipv6') && ($usev6 ne 'ip') && (($ipv6 // '') eq '::')); - debug("get_ipv6: using (%s, %s) reports %s", $usev6, $arg, $ipv6 // ""); + debug("get_ipv6: using (%s, %s) reports %s", + $usev6, $arg // '', $ipv6 // ''); return $ipv6; } From 2530adb39ebf5a6102280231aac8b03f81c5e5e7 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 15:56:39 -0400 Subject: [PATCH 05/91] get_ip: Log message improvements --- ddclient.in | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ddclient.in b/ddclient.in index cc0c7af..4c15373 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2769,7 +2769,7 @@ sub get_ip { if ($use eq 'ip') { $ip = opt('ip', $h); if (!is_ipv4($ip) && !is_ipv6($ip)) { - warning("'%s' is not a valid IPv4 or IPv6 address", $ip // ''); + warning('not a valid IPv4 or IPv6 address: ' . ($ip // '')); $ip = undef; } } elsif ($use eq 'if') { @@ -2822,7 +2822,7 @@ sub get_ip { ) // ''; } } else { - warning("ignoring unsupported '--use=$use'"); + warning("ignoring unsupported '--use' strategy: $use"); } if (!defined $reply) { $reply = ''; @@ -2832,12 +2832,11 @@ sub get_ip { $reply =~ s/^.*?${skip}//is; } $ip //= extract_ipv4($reply) // extract_ipv6($reply); - warning("found neither IPv4 nor IPv6 address") if !defined($ip); if ($use ne 'ip' && ($ip // '') eq '0.0.0.0') { $ip = undef; } - - debug("get_ip: using %s, %s reports %s", $use, $arg // '', $ip // ''); + warning('did not find an IPv4 or IPv6 address') if !defined($ip); + debug("get_ip: using %s, %s reports %s", $use, $arg // '', $ip) if $ip; return $ip; } @@ -3158,7 +3157,7 @@ sub get_ipv4 { ## Static IPv4 address is provided in "ipv4=
" $ipv4 = $arg; if (!is_ipv4($ipv4)) { - warning("'%s' is not a valid IPv4", $ipv4 // ''); + warning('not a valid IPv4 address: ' . ($ipv4 // '')); $ipv4 = undef; } } elsif ($usev4 eq 'ifv4') { @@ -3221,7 +3220,7 @@ sub get_ipv4 { ) // ''; } } else { - warning("ignoring unsupported '--usev4=$usev4'"); + warning("ignoring unsupported '--usev4' strategy: $usev4"); } ## Set to loopback address if no text set yet @@ -3234,8 +3233,8 @@ sub get_ipv4 { $ipv4 //= extract_ipv4($reply); ## Return undef for loopback address unless statically assigned by "ipv4=0.0.0.0" $ipv4 = undef if (($usev4 ne 'ipv4') && (($ipv4 // '') eq '0.0.0.0')); - debug("get_ipv4: using (%s, %s) reports %s", - $usev4, $arg // "", $ipv4 // ""); + warning('did not find an IPv4 address') if !defined($ipv4); + debug("get_ipv4: using (%s, %s) reports %s", $usev4, $arg // "", $ipv4) if $ipv4; return $ipv4; } @@ -3260,7 +3259,7 @@ sub get_ipv6 { } $ipv6 = $arg; if (!is_ipv6($ipv6)) { - warning("'%s' is not a valid IPv6", $ipv6 // ''); + warning('not a valid IPv6 address: ' . ($ipv6 // '')); $ipv6 = undef; } } elsif ($usev6 eq 'ifv6' || $usev6 eq 'if') { @@ -3316,7 +3315,7 @@ sub get_ipv6 { warning("'--usev6=%s' is not implemented and does nothing", $usev6); } } else { - warning("ignoring unsupported '--usev6=$usev6'"); + warning("ignoring unsupported '--usev6' strategy: $usev6"); } ## Set to loopback address if no text set yet @@ -3329,8 +3328,8 @@ sub get_ipv6 { $ipv6 //= extract_ipv6($reply); ## Return undef for loopback address unless statically assigned by "ipv6=::" $ipv6 = undef if (($usev6 ne 'ipv6') && ($usev6 ne 'ip') && (($ipv6 // '') eq '::')); - debug("get_ipv6: using (%s, %s) reports %s", - $usev6, $arg // '', $ipv6 // ''); + warning('did not find an IPv6 address') if !defined($ipv6); + debug("get_ipv6: using (%s, %s) reports %s", $usev6, $arg // '', $ipv6) if $ipv6; return $ipv6; } From 5d68b11d78e8144b0b6c437e759761b5b9bb57f0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:26:38 -0400 Subject: [PATCH 06/91] get_ipv6: Factor out check for deprecated value --- ddclient.in | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/ddclient.in b/ddclient.in index 4c15373..8a4c598 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3249,14 +3249,18 @@ sub get_ipv6 { my $reply = ''; ## Text returned from various methods my $url = ''; ## URL of website or firewall my $skip = undef; ## Regex of pattern to skip before looking for IP - my $arg = opt($usev6, $h); ## Value assigned to the "usev6" method + my $argvar = $usev6; + if (grep($usev6 eq $_, qw(ip if cmd web))) { + my $new = $usev6 . 'v6'; + warning("'--usev6=$usev6' is deprecated; use '--usev6=$new'"); + $argvar = $new if defined(opt($new, $h)); + } + # Note that --usev6=firewallname uses --fwv6=arg, not --firewallname=arg. + $argvar = 'fwv6' if $builtinfw{$usev6}; + my $arg = opt($argvar, $h); if ($usev6 eq 'ipv6' || $usev6 eq 'ip') { ## Static IPv6 address is provided in "ipv6=
" - if ($usev6 eq 'ip') { - warning("'--usev6=ip' is deprecated. Use '--usev6=ipv6'"); - $arg = opt('ipv6', $h) // $arg; - } $ipv6 = $arg; if (!is_ipv6($ipv6)) { warning('not a valid IPv6 address: ' . ($ipv6 // '')); @@ -3264,17 +3268,9 @@ sub get_ipv6 { } } elsif ($usev6 eq 'ifv6' || $usev6 eq 'if') { ## Obtain IPv6 address from interface mamed in "ifv6=" - if ($usev6 eq 'if') { - warning("'--usev6=if' is deprecated. Use '--usev6=ifv6'"); - $arg = opt('ifv6', $h) // $arg; - } $ipv6 = get_ip_from_interface($arg, 6); } elsif ($usev6 eq 'cmdv6' || $usev6 eq 'cmd') { ## Obtain IPv6 address by executing the command in "cmdv6=" - if ($usev6 eq 'cmd') { - warning("'--usev6=cmd' is deprecated. Use '--usev6=cmdv6'"); - $arg = opt('cmdv6', $h) // $arg; - } warning("'--cmd-skip' ignored for '--usev6=$usev6'") if (opt('verbose') && opt('cmd-skip', $h)); if ($arg) { my $sys_cmd = quotemeta($arg); @@ -3283,10 +3279,6 @@ sub get_ipv6 { } } elsif ($usev6 eq 'webv6' || $usev6 eq 'web') { ## Obtain IPv6 address by accessing website at url in "webv6=" - if ($usev6 eq 'web') { - warning("'--usev6=web' is deprecated. Use '--usev6=webv6'"); - $arg = opt('webv6', $h) // $arg; - } warning("'--web-skip' ignored for '--usev6=$usev6'; use '--webv6-skip' instead") if (!defined(opt('webv6-skip', $h)) && defined(opt('web-skip', $h))); $url = $arg; From e891f53345c707c784a933f472285a520aa4425e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 14 Jun 2024 18:58:54 -0400 Subject: [PATCH 07/91] update_nics: Consistently use `--opt` instead of `opt` --- ddclient.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 8a4c598..676ce07 100755 --- a/ddclient.in +++ b/ddclient.in @@ -1399,8 +1399,8 @@ sub update_nics { # And if it is valid, remember it... $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd} = $ip; } else { - warning("%s: unable to determine IP address with strategy use=%s", $h, $use) - if !$daemon || opt('verbose'); + warning("%s: unable to determine IP address with strategy --use=%s", + $h, $use) if !$daemon || opt('verbose'); } } } From 0392c5e7257c6e81e9cc56d3089bf5b09454d1b0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 16:05:15 -0400 Subject: [PATCH 08/91] query_cisco: Delete redundant warning The same message is already logged in `get_ipv4`. --- ddclient.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 676ce07..c378fcc 100755 --- a/ddclient.in +++ b/ddclient.in @@ -208,8 +208,6 @@ sub query_cisco { my ($h, $asa, $v4) = @_; warning("'--if' is deprecated for '--usev4=cisco%s; use '--ifv4' instead", $asa ? '-asa' : '') if ($v4 && !defined(opt('ifv4')) && defined(opt('if', $h))); - warning("'--fw' is deprecated for '--usev4=cisco%s; use '--fwv4' instead", $asa ? '-asa' : '') - if ($v4 && !defined(opt('fwv4')) && defined(opt('fw', $h))); my $if = ($v4 ? opt('ifv4', $h) : undef) // opt('if', $h); my $fw = ($v4 ? opt('fwv4', $h) : undef) // opt('fw', $h); # Convert slashes to protected value "\/" From 1054e162fa74c62b3906d0ed9935a253fc1df219 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 15:43:15 -0400 Subject: [PATCH 09/91] query_cisco: Use host-specific option value --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index c378fcc..63dc020 100755 --- a/ddclient.in +++ b/ddclient.in @@ -207,7 +207,7 @@ our %builtinweb = ( sub query_cisco { my ($h, $asa, $v4) = @_; warning("'--if' is deprecated for '--usev4=cisco%s; use '--ifv4' instead", $asa ? '-asa' : '') - if ($v4 && !defined(opt('ifv4')) && defined(opt('if', $h))); + if ($v4 && !defined(opt('ifv4', $h)) && defined(opt('if', $h))); my $if = ($v4 ? opt('ifv4', $h) : undef) // opt('if', $h); my $fw = ($v4 ? opt('fwv4', $h) : undef) // opt('fw', $h); # Convert slashes to protected value "\/" From 1ad9b565bd5eeb2ddf8500aaf0ae00dfb272f2f2 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 25 Jul 2024 20:55:14 -0400 Subject: [PATCH 10/91] nic_updateable: Don't warn about success Why issue a warning that things have suddenly started going well? It's bizarre. --- ddclient.in | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/ddclient.in b/ddclient.in index 63dc020..2d0071d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3454,20 +3454,9 @@ sub nic_updateable { $usev6 = 'disabled' if ($usev6 eq 'no'); # backward compatibility $use = 'disabled' if ($usev4 ne 'disabled') || ($usev6 ne 'disabled'); - # If we have a valid IP address and we have previously warned that it was invalid. - # reset the warning count back to zero. - if (($use ne 'disabled') && $ip && $warned_ip{$host}) { - $warned_ip{$host} = 0; - warning("IP address for %s valid: %s. Reset warning count", $host, $ip); - } - if (($usev4 ne 'disabled') && $ipv4 && $warned_ipv4{$host}) { - $warned_ipv4{$host} = 0; - warning("IPv4 address for %s valid: %s. Reset warning count", $host, $ipv4); - } - if (($usev6 ne 'disabled') && $ipv6 && $warned_ipv6{$host}) { - $warned_ipv6{$host} = 0; - warning("IPv6 address for %s valid: %s. Reset warning count", $host, $ipv6); - } + $warned_ip{$host} = 0 if $use ne 'disabled' && $ip; + $warned_ipv4{$host} = 0 if $usev4 ne 'disabled' && $ipv4; + $warned_ipv6{$host} = 0 if $usev6 ne 'disabled' && $ipv6; if ($opt{'force'}) { info("forcing update of %s.", $host); From 8262f112eafc37123e18c9eb6b6fa5660a596ce8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 25 Jul 2024 21:10:19 -0400 Subject: [PATCH 11/91] nic_updateable: Read option value after loading config --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 2d0071d..504515a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -157,7 +157,6 @@ my %saved_opt; my $daemon; # Control how many times warning message logged for invalid IP addresses my (%warned_ip, %warned_ipv4, %warned_ipv6); -my $inv_ip_warn_count = opt('max-warn') // 1; sub T_ANY { 'any' } sub T_STRING { 'string' } @@ -3453,6 +3452,7 @@ sub nic_updateable { $use = 'disabled' if ($use eq 'no'); # backward compatibility $usev6 = 'disabled' if ($usev6 eq 'no'); # backward compatibility $use = 'disabled' if ($usev4 ne 'disabled') || ($usev6 ne 'disabled'); + my $inv_ip_warn_count = opt('max-warn'); $warned_ip{$host} = 0 if $use ne 'disabled' && $ip; $warned_ipv4{$host} = 0 if $usev4 ne 'disabled' && $ipv4; From bd437a0abfcbdc41dc0b578be3c31d19dd8ed0f8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 26 Jul 2024 02:48:00 -0400 Subject: [PATCH 12/91] nic_updateable: Log message improvements --- ddclient.in | 108 ++++++++++++++-------------------------------------- 1 file changed, 29 insertions(+), 79 deletions(-) diff --git a/ddclient.in b/ddclient.in index 504515a..1acbc05 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3453,47 +3453,38 @@ sub nic_updateable { $usev6 = 'disabled' if ($usev6 eq 'no'); # backward compatibility $use = 'disabled' if ($usev4 ne 'disabled') || ($usev6 ne 'disabled'); my $inv_ip_warn_count = opt('max-warn'); + my $previp = $recap{$host}{'ip'} || ''; + my $previpv4 = $recap{$host}{'ipv4'} || ''; + my $previpv6 = $recap{$host}{'ipv6'} || ''; + my %prettyt = map({ ($_ => $recap{$host}{$_} ? prettytime($recap{$host}{$_}) : ''); } + qw(atime mtime wtime)); + my %prettyi = map({ ($_ => prettyinterval($config{$host}{$_})); } + qw(max-interval min-error-interval min-interval)); $warned_ip{$host} = 0 if $use ne 'disabled' && $ip; $warned_ipv4{$host} = 0 if $usev4 ne 'disabled' && $ipv4; $warned_ipv6{$host} = 0 if $usev6 ne 'disabled' && $ipv6; if ($opt{'force'}) { - info("forcing update of %s.", $host); + info("$host: update forced via 'force' option"); $update = 1; } elsif (!exists($recap{$host})) { - info("forcing updating %s because no recap entry exists in cache file.", $host); + info("$host: update forced because the time of the previous update (or attempt) is unknown"); $update = 1; } elsif ($recap{$host}{'wtime'} && $recap{$host}{'wtime'} > $now) { - warning("cannot update %s from %s to %s until after %s.", - $host, - ($recap{$host}{'ip'} ? $recap{$host}{'ip'} : ''), $ip, - prettytime($recap{$host}{'wtime'}) - ); + warning("$host: cannot update IP from $previp to $ip until after $prettyt{'wtime'}"); } elsif ($recap{$host}{'mtime'} && interval_expired($host, 'mtime', 'max-interval')) { - warning("forcing update of %s from %s to %s; %s since last update on %s.", - $host, - ($recap{$host}{'ip'} ? $recap{$host}{'ip'} : ''), $ip, - prettyinterval($config{$host}{'max-interval'}), - prettytime($recap{$host}{'mtime'}) - ); + info("$host: update forced because it has been $prettyi{'max-interval'} since the previous update (on $prettyt{'mtime'})"); $update = 1; - } elsif ($use ne 'disabled' && ($recap{$host}{'ip'} // '') ne $ip) { + } elsif ($use ne 'disabled' && $previp ne $ip) { ## Check whether to update IP address for the "--use" method" if (($recap{$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, - ($recap{$host}{'ip'} ? $recap{$host}{'ip'} : ''), - $ip, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - prettyinterval($config{$host}{'min-interval'}) - ) + warning("$host: skipped update from $previp to $ip because it has been less than $prettyi{'min-interval'} since the previous update (on $prettyt{'mtime'})") if opt('verbose') || !($recap{$host}{'warned-min-interval'} // 0); $recap{$host}{'warned-min-interval'} = $now; @@ -3503,18 +3494,10 @@ sub nic_updateable { if (opt('verbose') || (!$recap{$host}{'warned-min-error-interval'} && ($warned_ip{$host} // 0) < $inv_ip_warn_count)) { - - 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, - ($recap{$host}{'ip'} ? $recap{$host}{'ip'} : ''), - $ip, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - ($recap{$host}{'atime'} ? prettytime($recap{$host}{'atime'}) : ''), - prettyinterval($config{$host}{'min-error-interval'}) - ); + warning("$host: skipped update from $previp to $ip because it has been less than $prettyi{'min-error-interval'} since the previous update attempt (on $prettyt{'atime'}), which failed"); if (!$ip && !opt('verbose')) { $warned_ip{$host} = ($warned_ip{$host} // 0) + 1; - warning("IP address for %s undefined. Warned %s times, suppressing further warnings", $host, $inv_ip_warn_count) + warning("$host: IP address undefined. Warned $inv_ip_warn_count times, suppressing further warnings") if ($warned_ip{$host} >= $inv_ip_warn_count); } } @@ -3525,18 +3508,11 @@ sub nic_updateable { $update = 1; } - } elsif ($usev4 ne 'disabled' && ($recap{$host}{'ipv4'} // '') ne $ipv4) { + } elsif ($usev4 ne 'disabled' && $previpv4 ne $ipv4) { ## Check whether to update IPv4 address for the "--usev4" method" if (($recap{$host}{'status-ipv4'} // '') 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, - ($recap{$host}{'ipv4'} ? $recap{$host}{'ipv4'} : ''), - $ipv4, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - prettyinterval($config{$host}{'min-interval'}) - ) + warning("$host: skipped update from $previpv4 to $ipv4 because it has been less than $prettyi{'min-interval'} since the previous update (on $prettyt{'mtime'})") if opt('verbose') || !($recap{$host}{'warned-min-interval'} // 0); $recap{$host}{'warned-min-interval'} = $now; @@ -3546,18 +3522,10 @@ sub nic_updateable { if (opt('verbose') || (!$recap{$host}{'warned-min-error-interval'} && ($warned_ipv4{$host} // 0) < $inv_ip_warn_count)) { - - 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, - ($recap{$host}{'ipv4'} ? $recap{$host}{'ipv4'} : ''), - $ipv4, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - ($recap{$host}{'atime'} ? prettytime($recap{$host}{'atime'}) : ''), - prettyinterval($config{$host}{'min-error-interval'}) - ); + warning("$host: skipped update from $previpv4 to $ipv4 because it has been less than $prettyi{'min-error-interval'} since the previous update attempt (on $prettyt{'atime'}), which failed"); if (!$ipv4 && !opt('verbose')) { $warned_ipv4{$host} = ($warned_ipv4{$host} // 0) + 1; - warning("IPv4 address for %s undefined. Warned %s times, suppressing further warnings", $host, $inv_ip_warn_count) + warning("$host: IPv4 address undefined. Warned $inv_ip_warn_count times, suppressing further warnings") if ($warned_ipv4{$host} >= $inv_ip_warn_count); } } @@ -3568,18 +3536,11 @@ sub nic_updateable { $update = 1; } - } elsif ($usev6 ne 'disabled' && ($recap{$host}{'ipv6'} // '') ne $ipv6) { + } elsif ($usev6 ne 'disabled' && $previpv6 ne $ipv6) { ## Check whether to update IPv6 address for the "--usev6" method" if (($recap{$host}{'status-ipv6'} // '') 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, - ($recap{$host}{'ipv6'} ? $recap{$host}{'ipv6'} : ''), - $ipv6, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - prettyinterval($config{$host}{'min-interval'}) - ) + warning("$host: skipped update from $previpv6 to $ipv6 because it has been less than $prettyi{'min-interval'} since the previous update (on $prettyt{'mtime'})") if opt('verbose') || !($recap{$host}{'warned-min-interval'} // 0); $recap{$host}{'warned-min-interval'} = $now; @@ -3589,18 +3550,10 @@ sub nic_updateable { if (opt('verbose') || (!$recap{$host}{'warned-min-error-interval'} && ($warned_ipv6{$host} // 0) < $inv_ip_warn_count)) { - - 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, - ($recap{$host}{'ipv6'} ? $recap{$host}{'ipv6'} : ''), - $ipv6, - ($recap{$host}{'mtime'} ? prettytime($recap{$host}{'mtime'}) : ''), - ($recap{$host}{'atime'} ? prettytime($recap{$host}{'atime'}) : ''), - prettyinterval($config{$host}{'min-error-interval'}) - ); + warning("$host: skipped update from $previpv6 to $ipv6 because it has been less than $prettyi{'min-error-interval'} since the previous update attempt (on $prettyt{'atime'}, which failed"); if (!$ipv6 && !opt('verbose')) { $warned_ipv6{$host} = ($warned_ipv6{$host} // 0) + 1; - warning("IPv6 address for %s undefined. Warned %s times, suppressing further warnings", $host, $inv_ip_warn_count) + warning("$host: IPv6 address undefined. Warned $inv_ip_warn_count times, suppressing further warnings") if ($warned_ipv6{$host} >= $inv_ip_warn_count); } } @@ -3621,15 +3574,12 @@ sub nic_updateable { } else { if (opt('verbose')) { - if ($use ne 'disabled') { - success("%s: skipped: IP address was already set to %s.", $host, $ip); - } - if ($usev4 ne 'disabled') { - success("%s: skipped: IPv4 address was already set to %s.", $host, $ipv4); - } - if ($usev6 ne 'disabled') { - success("%s: skipped: IPv6 address was already set to %s.", $host, $ipv6); - } + success("$host: skipped update because IP address is already set to $ip") + if $use ne 'disabled'; + success("$host: skipped update because IPv4 address is already set to $ipv4") + if $usev4 ne 'disabled'; + success("$host: skipped update because IPv6 address is already set to $ipv6") + if $usev6 ne 'disabled'; } } From 6aa68f72a774583c481cf706aed9de3158d5142d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 26 Jul 2024 19:38:01 -0400 Subject: [PATCH 13/91] logging: Change multi-line log message designation style Before, the first line of a multi-line log message was prefixed with a space while all subsequent messages were prefixed with `|`. Now the first line is prefixed with `>` and all subsequent lines with a space. This makes it easier to quickly discern message boundaries. --- ChangeLog.md | 5 +++-- ddclient.in | 7 ++++--- t/logmsg.pl | 16 ++++++++-------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index df6f9f0..78f4e3a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -68,9 +68,10 @@ repository history](https://github.com/ddclient/ddclient/commits/master). [#639](https://github.com/ddclient/ddclient/pull/639) * Updated sample systemd service unit file to improve logging in the systemd journal. [#669](https://github.com/ddclient/ddclient/pull/669) - * The second and subsequent lines in a multi-line log message are now prefixed - with a `|` character. + * The second and subsequent lines in a multi-line log message now have a + different prefix to distinguish them from separate log messages. [#676](https://github.com/ddclient/ddclient/pull/676) + [#719](https://github.com/ddclient/ddclient/pull/719) * `emailonly`: New `protocol` option that simply emails you when your IP address changes. [#654](https://github.com/ddclient/ddclient/pull/654) * `he.net`: Added support for updating Hurricane Electric records. diff --git a/ddclient.in b/ddclient.in index 1acbc05..2e93983 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2364,15 +2364,16 @@ sub logmsg { chomp($buffer); my $prefix = $args{pfx}; - $prefix = sprintf "%-9s ", $prefix if $prefix; + $prefix = sprintf "%-8s ", $prefix if $prefix; if ($file) { $prefix .= "file $file"; $prefix .= ", line $lineno" if $lineno; - $prefix .= ": "; + $prefix .= ": "; } if ($prefix) { + $prefix .= "> "; $buffer = "$prefix$buffer"; - $prefix =~ s/ $/| /; + $prefix =~ s/> $/ /; $buffer =~ s/\n/\n$prefix/g; } $buffer .= "\n"; diff --git a/t/logmsg.pl b/t/logmsg.pl index 347a69e..7bd8696 100644 --- a/t/logmsg.pl +++ b/t/logmsg.pl @@ -55,49 +55,49 @@ my @test_cases = ( { desc => 'single-line prefix', args => [pfx => 'PFX:', 'foo'], - want => "PFX: foo\n", + want => "PFX: > foo\n", }, { desc => 'multi-line prefix', args => [pfx => 'PFX:', "foo\nbar"], - want => "PFX: foo\nPFX: | bar\n", + want => "PFX: > foo\nPFX: bar\n", }, { desc => 'single-line long prefix', args => [pfx => 'VERY LONG PREFIX:', 'foo'], - want => "VERY LONG PREFIX: foo\n", + want => "VERY LONG PREFIX: > foo\n", }, { desc => 'multi-line long prefix', args => [pfx => 'VERY LONG PREFIX:', "foo\nbar"], - want => "VERY LONG PREFIX: foo\nVERY LONG PREFIX:| bar\n", + want => "VERY LONG PREFIX: > foo\nVERY LONG PREFIX: bar\n", }, { desc => 'single line, no prefix, file', args => ['foo'], file => 'name', - want => "file name: foo\n", + want => "file name: > foo\n", }, { desc => 'single line, no prefix, file, and line number', args => ['foo'], file => 'name', lineno => 42, - want => "file name, line 42: foo\n", + want => "file name, line 42: > foo\n", }, { desc => 'single line, prefix, file, and line number', args => [pfx => 'PFX:', 'foo'], file => 'name', lineno => 42, - want => "PFX: file name, line 42: foo\n", + want => "PFX: file name, line 42: > foo\n", }, { desc => 'multiple lines, prefix, file, and line number', args => [pfx => 'PFX:', "foo\nbar"], file => 'name', lineno => 42, - want => "PFX: file name, line 42: foo\nPFX: file name, line 42:| bar\n", + want => "PFX: file name, line 42: > foo\nPFX: file name, line 42: bar\n", }, ); From b1752c2622948184a1ae1b96900fa3aebff0939f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 25 Jul 2024 17:42:57 -0400 Subject: [PATCH 14/91] logging: Delete unused `msg` function --- ddclient.in | 1 - t/logmsg.pl | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 2e93983..859443a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2389,7 +2389,6 @@ sub logmsg { } } sub _logmsg_fmt { return (@_ > 1) ? sprintf(shift, @_) : shift; } -sub msg { logmsg( _logmsg_fmt(@_)); } sub verbose { logmsg(email => 1, pfx => shift, _logmsg_fmt(@_)) if opt('verbose'); } sub info { logmsg(email => 1, pfx => 'INFO:', _logmsg_fmt(@_)) if opt('verbose'); } sub debug { logmsg( pfx => 'DEBUG:', _logmsg_fmt(@_)) if opt('debug'); } diff --git a/t/logmsg.pl b/t/logmsg.pl index 7bd8696..f3577a5 100644 --- a/t/logmsg.pl +++ b/t/logmsg.pl @@ -122,18 +122,20 @@ for my $tc (@test_cases) { my $output; open(my $fh, '>', \$output); local *STDERR = $fh; - ddclient::msg('%%'); + local $ddclient::globals{debug} = 1; + ddclient::debug('%%'); close($fh); - is($output, "%%\n", 'single argument is printed directly, not via sprintf'); + is($output, "DEBUG: > %%\n", 'single argument is printed directly, not via sprintf'); } { my $output; open(my $fh, '>', \$output); local *STDERR = $fh; - ddclient::msg('%s', 'foo'); + local $ddclient::globals{debug} = 1; + ddclient::debug('%s', 'foo'); close($fh); - is($output, "foo\n", 'multiple arguments are formatted via sprintf'); + is($output, "DEBUG: > foo\n", 'multiple arguments are formatted via sprintf'); } done_testing(); From d48b482269c0edec6f4c481e88101f6ef1704981 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 25 Jul 2024 17:19:45 -0400 Subject: [PATCH 15/91] geturl: Log message improvements --- ddclient.in | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 859443a..7bdc0e9 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2702,8 +2702,7 @@ sub geturl { } if (!opt('exec')) { - debug("skipped network connection"); - verbose("SENDING:", "%s", "${server}/${url}"); + info("would request: ${protocol}://${server}/${url}"); } else { push(@curlopt, "silent"); push(@curlopt, "include"); ## Include HTTP response for compatibility @@ -2736,11 +2735,9 @@ sub geturl { # don't include ${url} as that might expose login credentials $0 = sprintf("%s - Curl system cmd sending to %s", $program, "${protocol}://${server}"); - verbose("SENDING:", "Curl system cmd to %s", "${protocol}://${server}"); - verbose("SENDING:", "%s", $_) for (@curlopt); - + debug("REQUEST: curl config:\n" . join("\n", @curlopt)); $reply = curl_cmd(@curlopt); - verbose("RECEIVE:", "%s", $reply // ""); + debug("RESPONSE: " . (defined($reply) ? "reply:\n$reply" : '')); if (!$reply) { # don't include ${url} as that might expose login credentials if ($ipversion != 0) { From 08626482c351ce09e908034d3a93bfc141aaebb0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 15:31:33 -0400 Subject: [PATCH 16/91] header_ok: Don't assume that it is only used for host updates --- ddclient.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 7bdc0e9..61beb78 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3604,22 +3604,23 @@ sub nic_updateable { ## header_ok ###################################################################### sub header_ok { - my ($host, $line) = @_; + my ($pfx, $line, $errlog) = @_; + $errlog //= \&failed; if (!$line) { - failed("updating %s: no response from server", $host); + $errlog->("$pfx: no response from server"); return 0; } $line =~ s/\r?\n.*//s; my ($code, $msg) = ($line =~ qr%^\s*HTTP/.*\s+(\d+)\s*(?:\s+([^\s].*))?$%i); if (!defined($code)) { - failed('updating %s: unexpected HTTP response: %s', $host, $line); + $errlog->("$pfx: unexpected HTTP response: $line"); return 0; } elsif ($code !~ qr/^2\d\d$/) { my %msgs = ( '401' => 'authentication failed', '403' => 'not authorized', ); - failed('updating %s: %s %s', $host, $code, $msg // $msgs{$code} // ''); + $errlog->("$pfx: $code " . ($msg // $msgs{$code} // '')); return 0; } return 1; From b563e9c2fd950ca39ecb7e508ffdfbd0b5929083 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 18:01:02 -0400 Subject: [PATCH 17/91] use=web: Add tests --- Makefile.am | 1 + t/use_web.pl | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 t/use_web.pl diff --git a/Makefile.am b/Makefile.am index 90d3597..eb2e77b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -77,6 +77,7 @@ handwritten_tests = \ t/parse_assignments.pl \ t/skip.pl \ t/ssl-validate.pl \ + t/use_web.pl \ t/variable_defaults.pl \ t/write_recap.pl generated_tests = \ diff --git a/t/use_web.pl b/t/use_web.pl new file mode 100644 index 0000000..82ff3a5 --- /dev/null +++ b/t/use_web.pl @@ -0,0 +1,120 @@ +use Test::More; +use Scalar::Util qw(blessed); +eval { require ddclient::Test::Fake::HTTPD; } or plan(skip_all => $@); +SKIP: { eval { require Test::Warnings; } or skip($@, 1); } +eval { require 'ddclient'; } or BAIL_OUT($@); +my $ipv6_supported = eval { + require IO::Socket::IP; + my $ipv6_socket = IO::Socket::IP->new( + Domain => 'PF_INET6', + LocalHost => '::1', + Listen => 1, + ); + defined($ipv6_socket); +}; +my $http_daemon_supports_ipv6 = eval { + require HTTP::Daemon; + HTTP::Daemon->VERSION(6.12); +}; + +my $builtinweb = 't/use_web.pl builtinweb'; +my $h = 't/use_web.pl hostname'; + +sub run_httpd { + my ($ipv) = @_; + return undef if $ipv eq '6' && (!$ipv6_supported || !$http_daemon_supports_ipv6); + my $httpd = ddclient::Test::Fake::HTTPD->new( + host => $ipv eq '4' ? '127.0.0.1' : '::1', + daemon_args => {V6Only => 1}, + ); + my $headers = ['content-type' => 'text/plain']; + my $content = $ipv eq '4' + ? '192.0.2.1 skip 192.0.2.2 skip2 192.0.2.3' + : '2001:db8::1 skip 2001:db8::2 skip2 2001:db8::3'; + $httpd->run(sub { return [200, $headers, [$content]]; }); + diag("started IPv$ipv server running at ${\($httpd->endpoint())}"); + return $httpd; +} +my %httpd = ( + '4' => run_httpd('4'), + '6' => run_httpd('6'), +); +my %ep = ( + '4' => $httpd{'4'}->endpoint(), + '6' => $httpd{'6'} ? $httpd{'6'}->endpoint() : undef, +); + +my @test_cases; +for my $ipv ('4', '6') { + my $ipv4 = $ipv eq '4'; + for my $sfx ('', "v$ipv") { + push( + @test_cases, + { + desc => "use$sfx=web$sfx web$sfx= IPv$ipv", + ipv6 => !$ipv4, + cfg => {"use$sfx" => "web$sfx", "web$sfx" => $ep{$ipv}}, + want => $ipv4 ? '192.0.2.1' : '2001:db8::1', + }, + { + desc => "use$sfx=web$sfx web$sfx= web$sfx-skip=skip IPv$ipv", + ipv6 => !$ipv4, + cfg => {"use$sfx" => "web$sfx", "web$sfx" => $ep{$ipv}, "web$sfx-skip" => 'skip'}, + # Note that "skip" should skip past the first "skip" and not past "skip2". + want => $ipv4 ? '192.0.2.2' : '2001:db8::2', + }, + { + desc => "use$sfx=web$sfx web$sfx= IPv$ipv", + ipv6 => !$ipv4, + cfg => {"use$sfx" => "web$sfx", "web$sfx" => $builtinweb}, + biw => {url => $ep{$ipv}}, + want => $ipv4 ? '192.0.2.1' : '2001:db8::1', + }, + { + desc => "use$sfx=web$sfx web$sfx= IPv$ipv", + ipv6 => !$ipv4, + cfg => {"use$sfx" => "web$sfx", "web$sfx" => $builtinweb}, + biw => {url => $ep{$ipv}, skip => 'skip'}, + # Note that "skip" should skip past the first "skip" and not past "skip2". + want => $ipv4 ? '192.0.2.2' : '2001:db8::2', + }, + { + desc => "use$sfx=web$sfx web$sfx= web$sfx-skip=skip2 IPv$ipv", + ipv6 => !$ipv4, + cfg => {"use$sfx" => "web$sfx", "web$sfx" => $builtinweb, "web$sfx-skip" => 'skip2'}, + biw => {url => $ep{$ipv}, skip => 'skip'}, + want => $ipv4 ? '192.0.2.3' : '2001:db8::3', + }, + ); + } +} + +for my $tc (@test_cases) { + my $subst = sub { + return map({ + my $class = blessed($_); + (defined($class) && $class->isa('EndpointPlaceholder')) ? do { + my $uri = ${$_}->clone(); + $uri->query_param(tc => $tc->{desc}); + $uri; + } : $_; + } @_); + }; + local $ddclient::builtinweb{$builtinweb} = $tc->{biw}; + $ddclient::builtinweb if 0; + local $ddclient::config{$h} = $tc->{cfg}; + $ddclient::config if 0; + SKIP: { + skip("IPv6 not supported on this system", 1) if $tc->{ipv6} && !$ipv6_supported; + skip("HTTP::Daemon too old for IPv6 support", 1) + if $tc->{ipv6} && !$http_daemon_supports_ipv6; + is(ddclient::get_ip($tc->{cfg}{use}, $h), $tc->{want}, $tc->{desc}) + if $tc->{cfg}{use}; + is(ddclient::get_ipv4($tc->{cfg}{usev4}, $h), $tc->{want}, $tc->{desc}) + if $tc->{cfg}{usev4}; + is(ddclient::get_ipv6($tc->{cfg}{usev6}, $h), $tc->{want}, $tc->{desc}) + if $tc->{cfg}{usev6}; + } +} + +done_testing(); From e272caa3859f12957246693132cefb94c3f31445 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 21:03:25 -0400 Subject: [PATCH 18/91] use=web, use=: Strip HTTP headers before searching for IP --- ChangeLog.md | 4 ++++ ddclient.in | 6 ++++++ t/use_web.pl | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 78f4e3a..6a64b47 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -131,6 +131,10 @@ repository history](https://github.com/ddclient/ddclient/commits/master). [#713](https://github.com/ddclient/ddclient/pull/713) * `easydns`: Fixed successful updates treated as failed updates. [#713](https://github.com/ddclient/ddclient/pull/713) + * Any IP addresses in an HTTP response's headers are now ignored when + obtaining the IP address from a web-based IP discovery service + (`--usev4=webv4`, `--usev6=webv6`) or from a router/firewall device. + [#719](https://github.com/ddclient/ddclient/pull/719) ## 2023-11-23 v3.11.2 diff --git a/ddclient.in b/ddclient.in index 61beb78..184ccee 100755 --- a/ddclient.in +++ b/ddclient.in @@ -222,6 +222,7 @@ sub query_cisco { ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; return $reply; } @@ -2788,6 +2789,7 @@ sub get_ip { url => $url, ssl_validate => opt('web-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; } } elsif ($use eq 'disabled') { ## This is a no-op... Do not get an IP address for this host/service @@ -2814,6 +2816,7 @@ sub get_ip { ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; } } else { warning("ignoring unsupported '--use' strategy: $use"); @@ -3181,6 +3184,7 @@ sub get_ipv4 { ipversion => 4, # when using a URL to find IPv4 address we should force use of IPv4 ssl_validate => opt('web-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; } } elsif ($usev4 eq 'disabled') { ## This is a no-op... Do not get an IPv4 address for this host/service @@ -3212,6 +3216,7 @@ sub get_ipv4 { ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; } } else { warning("ignoring unsupported '--usev4' strategy: $usev4"); @@ -3289,6 +3294,7 @@ sub get_ipv6 { ipversion => 6, # when using a URL to find IPv6 address we should force use of IPv6 ssl_validate => opt('web-ssl-validate', $h), ) // ''; + $reply =~ s/^.*?\n\n//s; } } elsif ($usev6 eq 'disabled') { $reply = ''; diff --git a/t/use_web.pl b/t/use_web.pl index 82ff3a5..e9a9771 100644 --- a/t/use_web.pl +++ b/t/use_web.pl @@ -27,7 +27,11 @@ sub run_httpd { host => $ipv eq '4' ? '127.0.0.1' : '::1', daemon_args => {V6Only => 1}, ); - my $headers = ['content-type' => 'text/plain']; + my $headers = [ + 'content-type' => 'text/plain', + 'this-ipv4-should-be-ignored' => 'skip skip2 192.0.2.255', + 'this-ipv6-should-be-ignored' => 'skip skip2 2001:db8::ff', + ]; my $content = $ipv eq '4' ? '192.0.2.1 skip 192.0.2.2 skip2 192.0.2.3' : '2001:db8::1 skip 2001:db8::2 skip2 2001:db8::3'; From 962abfbbc3efe22250b28051e0658a27d392eba8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 19:40:11 -0400 Subject: [PATCH 19/91] use=web, use=: Don't treat non-2xx results as successes --- ChangeLog.md | 7 ++++--- ddclient.in | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6a64b47..c54c01f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -131,9 +131,10 @@ repository history](https://github.com/ddclient/ddclient/commits/master). [#713](https://github.com/ddclient/ddclient/pull/713) * `easydns`: Fixed successful updates treated as failed updates. [#713](https://github.com/ddclient/ddclient/pull/713) - * Any IP addresses in an HTTP response's headers are now ignored when - obtaining the IP address from a web-based IP discovery service - (`--usev4=webv4`, `--usev6=webv6`) or from a router/firewall device. + * Any IP addresses in an HTTP response's headers or in an HTTP error + response's body are now ignored when obtaining the IP address from a + web-based IP discovery service (`--usev4=webv4`, `--usev6=webv6`) or from a + router/firewall device. [#719](https://github.com/ddclient/ddclient/pull/719) ## 2023-11-23 v3.11.2 diff --git a/ddclient.in b/ddclient.in index 184ccee..cc762ed 100755 --- a/ddclient.in +++ b/ddclient.in @@ -205,7 +205,8 @@ our %builtinweb = ( sub query_cisco { my ($h, $asa, $v4) = @_; - warning("'--if' is deprecated for '--usev4=cisco%s; use '--ifv4' instead", $asa ? '-asa' : '') + my $pfx = "'--use${\($v4 ? 'v4' : '')}=cisco${\($asa ? '-asa' : '')}'"; + warning("$pfx: '--if' is deprecated; use '--ifv4' instead") if ($v4 && !defined(opt('ifv4', $h)) && defined(opt('if', $h))); my $if = ($v4 ? opt('ifv4', $h) : undef) // opt('if', $h); my $fw = ($v4 ? opt('fwv4', $h) : undef) // opt('fw', $h); @@ -221,7 +222,8 @@ sub query_cisco { password => opt('fw-password', $h), ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), - ) // ''; + ); + return undef if !header_ok($pfx, $reply, \&warning); $reply =~ s/^.*?\n\n//s; return $reply; } @@ -2788,8 +2790,12 @@ sub get_ip { proxy => opt('proxy', $h), url => $url, ssl_validate => opt('web-ssl-validate', $h), - ) // ''; - $reply =~ s/^.*?\n\n//s; + ); + if (header_ok("'--use=web --web=$arg'", $reply, \&warning)) { + $reply =~ s/^.*?\n\n//s; + } else { + $reply = undef; + } } } elsif ($use eq 'disabled') { ## This is a no-op... Do not get an IP address for this host/service @@ -2815,8 +2821,12 @@ sub get_ip { password => opt('fw-password', $h), ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), - ) // ''; - $reply =~ s/^.*?\n\n//s; + ); + if (header_ok("'--use=$use --fw=$arg'", $reply, \&warning)) { + $reply =~ s/^.*?\n\n//s; + } else { + $reply = undef; + } } } else { warning("ignoring unsupported '--use' strategy: $use"); @@ -3183,8 +3193,12 @@ sub get_ipv4 { url => $url, ipversion => 4, # when using a URL to find IPv4 address we should force use of IPv4 ssl_validate => opt('web-ssl-validate', $h), - ) // ''; - $reply =~ s/^.*?\n\n//s; + ); + if (header_ok("'--usev4=webv4 --webv4=$arg'", $reply, \&warning)) { + $reply =~ s/^.*?\n\n//s; + } else { + $reply = undef; + } } } elsif ($usev4 eq 'disabled') { ## This is a no-op... Do not get an IPv4 address for this host/service @@ -3215,8 +3229,12 @@ sub get_ipv4 { ipversion => 4, # when using a URL to find IPv4 address we should force use of IPv4 ignore_ssl_option => 1, ssl_validate => opt('fw-ssl-validate', $h), - ) // ''; - $reply =~ s/^.*?\n\n//s; + ); + if (header_ok("'--usev4=$usev4 --fwv4=$arg'", $reply, \&warning)) { + $reply =~ s/^.*?\n\n//s; + } else { + $reply = undef; + } } } else { warning("ignoring unsupported '--usev4' strategy: $usev4"); @@ -3293,8 +3311,12 @@ sub get_ipv6 { url => $url, ipversion => 6, # when using a URL to find IPv6 address we should force use of IPv6 ssl_validate => opt('web-ssl-validate', $h), - ) // ''; - $reply =~ s/^.*?\n\n//s; + ); + if (header_ok("'--usev6=webv6 --webv6=$arg'", $reply, \&warning)) { + $reply =~ s/^.*?\n\n//s; + } else { + $reply = undef; + } } } elsif ($usev6 eq 'disabled') { $reply = ''; From 2ac61250e576027f39360508f3c767081032dc0d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:40:57 -0400 Subject: [PATCH 20/91] dnsexit2: Fix compatibility with old versions of Perl The non-destructive substitution modifier wasn't added until Perl v5.14.0. --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index cc762ed..69b1d93 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4035,7 +4035,7 @@ sub dnsexit2_update_host { failed("Full reply\n%s", $reply) unless opt('verbose'); return; } - my $body = ($reply =~ s/^.*?\r?\n\r?\n//sr); + (my $body = $reply) =~ s/^.*?\r?\n\r?\n//s; my $response = eval { decode_json($body); }; if (!$response) { failed("failed to parse response: $@"); From 3d894364bf5855fcb5c5fd00624f0fc4ecbcd252 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:44:49 -0400 Subject: [PATCH 21/91] dnsexit2: Delete redundant debug message `geturl` already debug logs the response. --- ddclient.in | 1 - 1 file changed, 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 69b1d93..27b9331 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4026,7 +4026,6 @@ sub dnsexit2_update_host { failed("updating %s: Could not connect to %s", $h, $url); return; }; - debug("%s", $reply); (my $http_status) = ($reply =~ m%^s*HTTP/.*\s+(\d+)%i); debug("HTTP response code: %s", $http_status); if ($http_status ne '200') { From 073fe5a51d76faa341c6854e1c9097419bd019ef Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:45:16 -0400 Subject: [PATCH 22/91] dnsexit2: Delete redundant HTTP status code check `header_ok` already checks for non-2xx codes. --- ddclient.in | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ddclient.in b/ddclient.in index 27b9331..9c74b69 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4026,14 +4026,6 @@ sub dnsexit2_update_host { failed("updating %s: Could not connect to %s", $h, $url); return; }; - (my $http_status) = ($reply =~ m%^s*HTTP/.*\s+(\d+)%i); - debug("HTTP response code: %s", $http_status); - if ($http_status ne '200') { - failed("Failed to update Host\n%s", $h); - failed("HTTP response code\n%s", $http_status); - failed("Full reply\n%s", $reply) unless opt('verbose'); - return; - } (my $body = $reply) =~ s/^.*?\r?\n\r?\n//s; my $response = eval { decode_json($body); }; if (!$response) { From e5b00216ecf5245aee1b776e1b57cf194720ee87 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:47:30 -0400 Subject: [PATCH 23/91] dnsexit2: Log message improvements --- ddclient.in | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9c74b69..7a3e5f7 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3993,7 +3993,7 @@ sub dnsexit2_update_host { if ($name =~ s/(?:^|\.)\Q$config{$h}{'zone'}\E$//) { # The zone was successfully trimmed from $name. } else { - fatal("Hostname %s does not end with the zone %s", $h, $config{$h}{'zone'}); + fatal("$h: hostname does not end with the zone: $config{$h}{'zone'}"); } # The IPv4 and IPv6 addresses must be updated together in a single API call. my %ips; @@ -4001,7 +4001,7 @@ sub dnsexit2_update_host { for my $ipv ('4', '6') { my $ip = delete($config{$h}{"wantipv$ipv"}) or next; $ips{$ipv} = $ip; - info("Going to update IPv%s address to %s for %s.", $ipv, $ip, $h); + info("$h: updating IPv$ipv address to $ip"); $config{$h}{"status-ipv$ipv"} = 'failed'; push(@updates, { name => $name, @@ -4023,18 +4023,17 @@ sub dnsexit2_update_host { }), ); unless ($reply && header_ok($h, $reply)) { - failed("updating %s: Could not connect to %s", $h, $url); + failed("$h: request to $url failed"); return; }; (my $body = $reply) =~ s/^.*?\r?\n\r?\n//s; my $response = eval { decode_json($body); }; if (!$response) { - failed("failed to parse response: $@"); + failed("$h: failed to parse response: $@"); return; } if (!defined($response->{'code'}) || !defined($response->{'message'})) { - failed("Did not receive expected 'code' and 'message' keys in server response:\n%s", - $body); + failed("$h: missing 'code' and 'message' properties in server response:\n$body"); return; } my %codemeaning = ( @@ -4048,32 +4047,33 @@ sub dnsexit2_update_host { '7' => ['error', 'Error getting post data. Our server has problem to receive your JSON posting.'], ); if (!exists($codemeaning{$response->{'code'}})) { - failed("Status code %s is unknown!", $response->{'code'}); + failed("$h: unknown status code: $response->{'code'}"); return; } my ($status, $message) = @{$codemeaning{$response->{'code'}}}; - info("Status: %s -- Message: %s", $status, $message); - info("Server Message: %s -- Server Details: %s", $response->{'message'}, - defined($response->{'details'}) ? $response->{'details'}[0] : "no details received"); + info("$h: $status: $message"); + info("$h: server message: $response->{'message'}"); + info("$h: server details: " . + (defined($response->{'details'}) ? $response->{'details'}[0] : "no details received")); if ($status ne 'good') { if ($status eq 'warning') { - warning("%s", $message); - warning("Server response: %s", $response->{'message'}); + warning("$h: $message"); + warning("$h: server response: $response->{'message'}"); } elsif ($status =~ m'^(badauth|error)$') { - failed("%s", $message); - failed("Server response: %s", $response->{'message'}); + failed("$h: $message"); + failed("$h: server response: $response->{'message'}"); } else { - failed("Unexpected status: %s", $status); + failed("$h: unexpected status: $status"); } return; } - success("%s", $message); + success("$h: $message"); $config{$h}{'mtime'} = $now; keys(%ips); # Reset internal iterator. while (my ($ipv, $ip) = each(%ips)) { $config{$h}{"ipv$ipv"} = $ip; $config{$h}{"status-ipv$ipv"} = 'good'; - success("Updated %s successfully to IPv%s address %s at time %s", $h, $ipv, $ip, prettytime($config{$h}{'mtime'})); + success("$h: updated IPv$ipv address to $ip"); } } From 56f0d931a457f62490f380150a3d214b2278feae Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:47:52 -0400 Subject: [PATCH 24/91] dnsexit2: Delete redundant check `header_ok` already checks whether the response is `undef`. --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 7a3e5f7..6396281 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4022,7 +4022,7 @@ sub dnsexit2_update_host { update => \@updates, }), ); - unless ($reply && header_ok($h, $reply)) { + if (!header_ok($h, $reply)) { failed("$h: request to $url failed"); return; }; From 4a394f4562ef12feeeee126238f92588fc622f0a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:48:45 -0400 Subject: [PATCH 25/91] dnsexit2: Delete rogue semicolon --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 6396281..a6b3f7f 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4025,7 +4025,7 @@ sub dnsexit2_update_host { if (!header_ok($h, $reply)) { failed("$h: request to $url failed"); return; - }; + } (my $body = $reply) =~ s/^.*?\r?\n\r?\n//s; my $response = eval { decode_json($body); }; if (!$response) { From 1c94ed6063c6fc24a3f1cf175ed6abfcda7e5689 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 18:49:43 -0400 Subject: [PATCH 26/91] dnsexit2: Check for JSON object, not just truthiness --- ddclient.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index a6b3f7f..a5de3c1 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4028,8 +4028,8 @@ sub dnsexit2_update_host { } (my $body = $reply) =~ s/^.*?\r?\n\r?\n//s; my $response = eval { decode_json($body); }; - if (!$response) { - failed("$h: failed to parse response: $@"); + if (ref($response) ne 'HASH') { + failed("$h: response is not a JSON object:\n$body"); return; } if (!defined($response->{'code'}) || !defined($response->{'message'})) { From 27143db56ee7518a9ce7a0d2ccc974112add191e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 19:14:22 -0400 Subject: [PATCH 27/91] dnsexit2: Pass an arrayref of headers for readability --- ddclient.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index a5de3c1..435f47a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4014,7 +4014,10 @@ sub dnsexit2_update_host { my $reply = geturl( proxy => opt('proxy'), url => $url, - headers => "Content-Type: application/json\nAccept: application/json", + headers => [ + 'Content-Type: application/json', + 'Accept: application/json', + ], method => 'POST', data => encode_json({ apikey => $config{$h}{'password'}, From 5b433c3cd556fa62e6748c8e30f22da28a731c7e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 19:21:00 -0400 Subject: [PATCH 28/91] noip: Delete redundant response check --- ddclient.in | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 435f47a..729a5c0 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4121,11 +4121,7 @@ sub nic_noip_update { url => $url, login => $groupcfg{'login'}, password => $groupcfg{'password'}, - ) // ''; - if ($reply eq '') { - failed("updating %s: Could not connect to %s.", $hosts, $groupcfg{'server'}); - next; - } + ); next if !header_ok($hosts, $reply); my @reply = split /\n/, $reply; From c0b28f344f27603546ca8ab1f378d275675f172b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 21:20:33 -0400 Subject: [PATCH 29/91] noip: Simplify response processing --- ddclient.in | 82 +++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/ddclient.in b/ddclient.in index 729a5c0..e1bc784 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4123,70 +4123,60 @@ sub nic_noip_update { password => $groupcfg{'password'}, ); next if !header_ok($hosts, $reply); - - my @reply = split /\n/, $reply; - my $state = 'header'; + (my $body = $reply) =~ s/^.*?\n\n//s or do { + failed("updating %s: Could not connect to %s.", $hosts, $groupcfg{'server'}); + next; + }; + my @reply = split(/\n/, $body); for my $line (@reply) { - if ($state eq 'header') { - $state = 'body'; + my ($status, $returnedips) = split / /, lc $line; + my $h = shift @hosts; - } elsif ($state eq 'body') { - $state = 'results' if $line eq ''; - - } elsif ($state =~ /^results/) { - $state = 'results2'; - - my ($status, $returnedips) = split / /, lc $line; - my $h = shift @hosts; + for my $ip (split_by_comma($returnedips)) { + next if (!$ip); + my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4'; + $config{$h}{"status-ipv$ipv"} = $status; + } + if ($status eq 'good') { + $config{$h}{'mtime'} = $now; for my $ip (split_by_comma($returnedips)) { next if (!$ip); my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4'; - $config{$h}{"status-ipv$ipv"} = $status; + $config{$h}{"ipv$ipv"} = $ip; + success("updating %s: %s: IPv%s address set to %s", $h, $status, $ipv, $ip); } - if ($status eq 'good') { + } elsif (exists $errors{$status}) { + if ($status eq 'nochg') { + warning("updating %s: %s: %s", $h, $status, $errors{$status}); $config{$h}{'mtime'} = $now; for my $ip (split_by_comma($returnedips)) { next if (!$ip); my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4'; $config{$h}{"ipv$ipv"} = $ip; - success("updating %s: %s: IPv%s address set to %s", $h, $status, $ipv, $ip); + $config{$h}{"status-ipv$ipv"} = 'good'; } - - } elsif (exists $errors{$status}) { - if ($status eq 'nochg') { - warning("updating %s: %s: %s", $h, $status, $errors{$status}); - $config{$h}{'mtime'} = $now; - for my $ip (split_by_comma($returnedips)) { - next if (!$ip); - my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4'; - $config{$h}{"ipv$ipv"} = $ip; - $config{$h}{"status-ipv$ipv"} = 'good'; - } - } else { - failed("updating %s: %s: %s", $h, $status, $errors{$status}); - } - - } elsif ($status =~ /w(\d+)(.)/) { - my ($wait, $units) = ($1, lc $2); - my ($sec, $scale) = ($wait, 1); - - ($scale, $units) = (1, 'seconds') if $units eq 's'; - ($scale, $units) = (60, 'minutes') if $units eq 'm'; - ($scale, $units) = (60*60, 'hours') if $units eq 'h'; - - $sec = $wait * $scale; - $config{$h}{'wtime'} = $now + $sec; - warning("updating %s: %s: wait %s %s before further updates", $h, $status, $wait, $units); - } else { - failed("updating %s: unexpected status (%s)", $h, $line); + failed("updating %s: %s: %s", $h, $status, $errors{$status}); } + + } elsif ($status =~ /w(\d+)(.)/) { + my ($wait, $units) = ($1, lc $2); + my ($sec, $scale) = ($wait, 1); + + ($scale, $units) = (1, 'seconds') if $units eq 's'; + ($scale, $units) = (60, 'minutes') if $units eq 'm'; + ($scale, $units) = (60*60, 'hours') if $units eq 'h'; + + $sec = $wait * $scale; + $config{$h}{'wtime'} = $now + $sec; + warning("updating %s: %s: wait %s %s before further updates", $h, $status, $wait, $units); + + } else { + failed("updating %s: unexpected status (%s)", $h, $line); } } - failed("updating %s: Could not connect to %s.", $hosts, $groupcfg{'server'}) - if $state ne 'results2'; } } From 2d60183e93747d81b4d88fbd26d505b1dc8000e1 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 24 Jul 2024 21:44:12 -0400 Subject: [PATCH 30/91] noip: Log message improvements --- ddclient.in | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ddclient.in b/ddclient.in index e1bc784..679d3aa 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4105,9 +4105,8 @@ sub nic_noip_update { delete $config{$_}{'wantipv4'} for @hosts; delete $config{$_}{'wantipv6'} for @hosts; - info("setting IPv4 address to %s for %s", $ipv4, $hosts) if $ipv4; - info("setting IPv6 address to %s for %s", $ipv6, $hosts) if $ipv6; - verbose("UPDATE:", "updating %s", $hosts); + info("$hosts: setting IPv4 address to $ipv4") if $ipv4; + info("$hosts: setting IPv6 address to $ipv6") if $ipv6; my $url = "https://$groupcfg{'server'}/nic/update?system=noip&hostname=$hosts&myip="; $url .= $ipv4 if $ipv4; @@ -4124,7 +4123,7 @@ sub nic_noip_update { ); next if !header_ok($hosts, $reply); (my $body = $reply) =~ s/^.*?\n\n//s or do { - failed("updating %s: Could not connect to %s.", $hosts, $groupcfg{'server'}); + failed("$hosts: request to $groupcfg{'server'} failed"); next; }; my @reply = split(/\n/, $body); @@ -4144,12 +4143,12 @@ sub nic_noip_update { next if (!$ip); my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4'; $config{$h}{"ipv$ipv"} = $ip; - success("updating %s: %s: IPv%s address set to %s", $h, $status, $ipv, $ip); + success("$h: $status: IPv$ipv address set to $ip"); } } elsif (exists $errors{$status}) { if ($status eq 'nochg') { - warning("updating %s: %s: %s", $h, $status, $errors{$status}); + warning("$h: $status: $errors{$status}"); $config{$h}{'mtime'} = $now; for my $ip (split_by_comma($returnedips)) { next if (!$ip); @@ -4158,7 +4157,7 @@ sub nic_noip_update { $config{$h}{"status-ipv$ipv"} = 'good'; } } else { - failed("updating %s: %s: %s", $h, $status, $errors{$status}); + failed("$h: $status: $errors{$status}"); } } elsif ($status =~ /w(\d+)(.)/) { @@ -4171,10 +4170,10 @@ sub nic_noip_update { $sec = $wait * $scale; $config{$h}{'wtime'} = $now + $sec; - warning("updating %s: %s: wait %s %s before further updates", $h, $status, $wait, $units); + warning("$h: $status: wait $wait $units before further updates"); } else { - failed("updating %s: unexpected status (%s)", $h, $line); + failed("$h: unexpected status: $line"); } } } From 95a10e2595e560469cc038eac920250880b3ce7f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 26 Jul 2024 19:55:02 -0400 Subject: [PATCH 31/91] dslreports1: Log message improvements --- ddclient.in | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ddclient.in b/ddclient.in index 679d3aa..b031a1a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4243,8 +4243,7 @@ sub nic_dslreports1_update { ## update each configured host for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; - info("setting IP address to %s for %s", $ip, $h); - verbose("UPDATE:", "updating %s", $h); + info("$h: setting IP address to $ip"); my $url; $url = "https://$config{$h}{'server'}/nic/"; @@ -4260,7 +4259,7 @@ sub nic_dslreports1_update { password => $config{$h}{'password'}, ) // ''; if ($reply eq '') { - failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: request to $config{$h}{'server'} failed"); next; } @@ -4272,15 +4271,13 @@ sub nic_dslreports1_update { if ($return_code !~ /NOERROR/) { $config{$h}{'status'} = 'failed'; - warning("SENT: %s", $url) unless opt('verbose'); - warning("REPLIED: %s", $reply); - failed("updating %s", $h); + failed("$h: $reply"); } else { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; - success("updating %s: %s: IP address set to %s", $h, $return_code, $ip); + success("$h: $return_code: IP address set to $ip"); } } } From 02c80fdf0958562c26c824a968bd911da299443c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 26 Jul 2024 19:56:14 -0400 Subject: [PATCH 32/91] dslreports1: Move out `else` case to improve readability --- ddclient.in | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index b031a1a..08cd151 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4272,13 +4272,12 @@ sub nic_dslreports1_update { if ($return_code !~ /NOERROR/) { $config{$h}{'status'} = 'failed'; failed("$h: $reply"); - - } else { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: $return_code: IP address set to $ip"); + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("$h: $return_code: IP address set to $ip"); } } From 2534375cfd62bbf1dd18baa05c8d19e2ff834f91 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 7 Jun 2024 17:16:45 -0400 Subject: [PATCH 33/91] dyndns1: Move `else` case up a level for readability --- ddclient.in | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 08cd151..c76022d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -3758,13 +3758,12 @@ sub nic_dyndns1_update { warning("SENT: %s", $url) unless opt('verbose'); warning("REPLIED: %s", $reply); failed("updating %s: %s", $h, $title); - - } else { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("updating %s: %s: IP address set to %s (%s)", $h, $return_code, $ip, $title); + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("updating %s: %s: IP address set to %s (%s)", $h, $return_code, $ip, $title); } } From f0edd7f781a2d5e8aee8660454ed150c48f7abce Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 21:59:20 -0400 Subject: [PATCH 34/91] domeneshop: Delete unnecessary comments --- ddclient.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index c76022d..056f4fd 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4316,8 +4316,6 @@ sub nic_domeneshop_update { my $endpointPath = "/v0/dyndns/update"; - ## update each configured host - ## should improve to update in one pass for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("Setting IP address to %s for %s", $ip, $h); @@ -4329,14 +4327,12 @@ sub nic_domeneshop_update { password => $config{$h}{'password'}, ); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("Updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; } next if !header_ok($h, $reply); - # evaluate response my @reply = split /\n/, $reply; my $status = shift(@reply); my $message = pop(@reply); From 231601ae54181c3c5fbf9f2a772cd54dfe04b4ab Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 21:59:52 -0400 Subject: [PATCH 35/91] domeneshop: Whitespace fixes --- ddclient.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 056f4fd..1d35b16 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4313,9 +4313,7 @@ EoEXAMPLE ###################################################################### sub nic_domeneshop_update { debug("\nnic_domeneshop_update -------------------"); - my $endpointPath = "/v0/dyndns/update"; - for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("Setting IP address to %s for %s", $ip, $h); @@ -4326,13 +4324,11 @@ sub nic_domeneshop_update { 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; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; my $status = shift(@reply); my $message = pop(@reply); From b4e08ae3ae0bf934c6d324f0647525bb3937260b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 22:07:15 -0400 Subject: [PATCH 36/91] domeneshop: Improve log messages --- ddclient.in | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 1d35b16..220ebd6 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4316,8 +4316,7 @@ sub nic_domeneshop_update { my $endpointPath = "/v0/dyndns/update"; for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; - info("Setting IP address to %s for %s", $ip, $h); - verbose("UPDATE:", "Updating %s", $h); + info("$h: Setting IP address to $ip"); my $reply = geturl( proxy => opt('proxy'), url => "$config{$h}{'server'}$endpointPath?hostname=$h&myip=$ip", @@ -4325,7 +4324,7 @@ sub nic_domeneshop_update { password => $config{$h}{'password'}, ); if (!defined($reply) || !$reply) { - failed("Updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: Request to $config{$h}{'server'} failed"); next; } next if !header_ok($h, $reply); @@ -4336,10 +4335,10 @@ sub nic_domeneshop_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; - success("updating %s: good: IP address set to %s", $h, $ip); + success("$h: IP address set to $ip"); } else { $config{$h}{'status'} = 'failed'; - failed("updating %s: Server said: '%s' '%s'", $h, $status, $message); + failed("$h: Server said: $status $message"); } } } From d391f41074e5d8738ae75f5c9a080c8eecf01a0c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 19 Jul 2024 18:43:22 -0400 Subject: [PATCH 37/91] domeneshop: Treat all 2xx as success --- ddclient.in | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/ddclient.in b/ddclient.in index 220ebd6..55b8eaf 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4328,18 +4328,10 @@ sub nic_domeneshop_update { next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; - my $status = shift(@reply); - my $message = pop(@reply); - if ($status =~ /204/) { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: IP address set to $ip"); - } else { - $config{$h}{'status'} = 'failed'; - failed("$h: Server said: $status $message"); - } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("$h: IP address set to $ip"); } } From 61fff1c344d8df14d3a76584e5131e2895b0b643 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 22:11:38 -0400 Subject: [PATCH 38/91] domeneshop: Inline an unnecessary variable --- ddclient.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 55b8eaf..0f2bf81 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4313,13 +4313,12 @@ EoEXAMPLE ###################################################################### sub nic_domeneshop_update { debug("\nnic_domeneshop_update -------------------"); - my $endpointPath = "/v0/dyndns/update"; for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("$h: Setting IP address to $ip"); my $reply = geturl( proxy => opt('proxy'), - url => "$config{$h}{'server'}$endpointPath?hostname=$h&myip=$ip", + url => "$config{$h}{'server'}/v0/dyndns/update?hostname=$h&myip=$ip", login => $config{$h}{'login'}, password => $config{$h}{'password'}, ); From ef8bf634fec70eccc1dd057df8b817a8635f2b3c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 19 Jul 2024 18:47:48 -0400 Subject: [PATCH 39/91] domeneshop: Add IPv6 support --- ChangeLog.md | 2 ++ ddclient.in | 34 ++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index c54c01f..6043520 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -84,6 +84,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master). records. [#695](https://github.com/ddclient/ddclient/pull/695) * `inwx`: New `protocol` option for updating [INWX](https://www.inwx.com/) records. [#690](https://github.com/ddclient/ddclient/pull/690) + * `domeneshop`: Add IPv6 support. + [#719](https://github.com/ddclient/ddclient/pull/719) ### Bug fixes diff --git a/ddclient.in b/ddclient.in index 0f2bf81..3228b5d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4314,23 +4314,25 @@ EoEXAMPLE sub nic_domeneshop_update { debug("\nnic_domeneshop_update -------------------"); for my $h (@_) { - my $ip = delete $config{$h}{'wantip'}; - info("$h: Setting IP address to $ip"); - my $reply = geturl( - proxy => opt('proxy'), - url => "$config{$h}{'server'}/v0/dyndns/update?hostname=$h&myip=$ip", - login => $config{$h}{'login'}, - password => $config{$h}{'password'}, - ); - if (!defined($reply) || !$reply) { - failed("$h: Request to $config{$h}{'server'} failed"); - next; + for my $ipv ('4', '6') { + my $ip = delete $config{$h}{"wantipv$ipv"} or next; + info("$h: Setting IPv$ipv address to $ip"); + my $reply = geturl( + proxy => opt('proxy'), + url => "$config{$h}{'server'}/v0/dyndns/update?hostname=$h&myip=$ip", + login => $config{$h}{'login'}, + password => $config{$h}{'password'}, + ); + if (!defined($reply) || !$reply) { + failed("$h: Request to $config{$h}{'server'} failed"); + next; + } + next if !header_ok($h, $reply); + $config{$h}{"ipv$ipv"} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{"status-ipv$ipv"} = 'good'; + success("$h: IPv$ipv address set to $ip"); } - next if !header_ok($h, $reply); - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: IP address set to $ip"); } } From 58c6caa5ffecdeb402a2f3fabcef6d9da610b2b1 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 20 Jul 2024 18:16:08 -0400 Subject: [PATCH 40/91] nfsn: Include host in failure message --- ddclient.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index 3228b5d..1c71d54 100755 --- a/ddclient.in +++ b/ddclient.in @@ -4758,13 +4758,13 @@ sub nic_nfsn_handle_error { $resp =~ s/^.*?\n\n//s; # Strip header my $json = eval { decode_json($resp) }; if ($@ || ref($json) ne 'HASH' || not defined $json->{'error'}) { - failed("Invalid error response: %s", $resp); + failed("$h: Invalid error response: $resp"); return; } failed("%s", $json->{'error'}); if (defined $json->{'debug'}) { - failed("%s", $json->{'debug'}); + failed("$h: $json->{'debug'}"); } } @@ -4833,7 +4833,7 @@ sub nic_nfsn_update { 'POST', $rm_body); if (!header_ok($h, $rm_resp)) { $config{$h}{'status'} = 'failed'; - nic_nfsn_handle_error($rm_resp); + nic_nfsn_handle_error($rm_resp, $h); next; } } From f807ba58ac4860bb7391cc9706414b6f70495b8f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 03:58:59 -0400 Subject: [PATCH 41/91] yandex: Don't treat an error as success --- ChangeLog.md | 2 ++ ddclient.in | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6043520..35aff37 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -138,6 +138,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master). web-based IP discovery service (`--usev4=webv4`, `--usev6=webv6`) or from a router/firewall device. [#719](https://github.com/ddclient/ddclient/pull/719) + * `yandex`: Errors are now retried. + [#719](https://github.com/ddclient/ddclient/pull/719) ## 2023-11-23 v3.11.2 diff --git a/ddclient.in b/ddclient.in index 1c71d54..29cb85f 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6298,13 +6298,12 @@ sub nic_yandex_update { $response = eval { decode_json($reply) }; if ($response->{success} eq 'error') { failed("%s", $response->{error}); - } else { - success("%s -- Updated Successfully to %s", $host, $ip); + next; } - $config{$host}{'ip'} = $ip; $config{$host}{'mtime'} = $now; $config{$host}{'status'} = 'good'; + success("%s -- Updated Successfully to %s", $host, $ip); } } From 459970c5e3282ead0cdabbcc72368627185cb0ff Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 04:02:37 -0400 Subject: [PATCH 42/91] yandex: Check for presence of success, not lack of error This is more resilient to bugs. --- ddclient.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 29cb85f..747346a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6259,7 +6259,7 @@ sub nic_yandex_update { # Strip header $reply =~ s/^.*?\n\n//s; my $response = eval { decode_json($reply) }; - if ($response->{success} eq 'error') { + if ($response->{success} ne 'ok') { failed("%s", $response->{error}); next; } @@ -6296,7 +6296,7 @@ sub nic_yandex_update { # Strip header $reply =~ s/^.*?\n\n//s; $response = eval { decode_json($reply) }; - if ($response->{success} eq 'error') { + if ($response->{success} ne 'ok') { failed("%s", $response->{error}); next; } From b80fe1b505750036d415621af1afd2bd772c5d40 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 15:47:23 -0400 Subject: [PATCH 43/91] duckdns: Delete unnecessary comments --- ddclient.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 747346a..a2b6c06 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6342,8 +6342,6 @@ EoEXAMPLE sub nic_duckdns_update { debug("\nnic_duckdns_update -------------------"); - ## update each configured host - ## should improve to update in one pass for my $h (@_) { my $ipv4 = delete $config{$h}{'wantipv4'}; my $ipv6 = delete $config{$h}{'wantipv6'}; @@ -6351,7 +6349,6 @@ sub nic_duckdns_update { info("setting IPv6 address to %s for %s", $ipv6, $h) if $ipv6; verbose("UPDATE:", "updating %s", $h); - # Set the URL that we're going to to update my $url; $url = "https://$config{$h}{'server'}/update"; $url .= "?domains="; @@ -6361,10 +6358,8 @@ sub nic_duckdns_update { $url .= "&ip=$ipv4" if $ipv4; $url .= "&ipv6=$ipv6" if $ipv6; - # Try to get URL my $reply = geturl(proxy => opt('proxy'), url => $url); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; From 98ed129b20762283844d5e74feb9579bf1834be2 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 15:48:47 -0400 Subject: [PATCH 44/91] duckdns: Whitespace fixes --- ddclient.in | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ddclient.in b/ddclient.in index a2b6c06..fa52485 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6341,35 +6341,29 @@ EoEXAMPLE ###################################################################### sub nic_duckdns_update { debug("\nnic_duckdns_update -------------------"); - for my $h (@_) { my $ipv4 = delete $config{$h}{'wantipv4'}; my $ipv6 = delete $config{$h}{'wantipv6'}; info("setting IPv4 address to %s for %s", $ipv4, $h) if $ipv4; info("setting IPv6 address to %s for %s", $ipv6, $h) if $ipv6; verbose("UPDATE:", "updating %s", $h); - my $url; - $url = "https://$config{$h}{'server'}/update"; + $url = "https://$config{$h}{'server'}/update"; $url .= "?domains="; $url .= $h; $url .= "&token="; $url .= $config{$h}{'password'}; $url .= "&ip=$ipv4" if $ipv4; $url .= "&ipv6=$ipv6" if $ipv6; - my $reply = geturl(proxy => opt('proxy'), url => $url); - if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; my $state = 'noresult'; my $line = ''; - for $line (@reply) { if ($line eq 'OK') { $config{$h}{'ipv4'} = $ipv4 if $ipv4; @@ -6380,7 +6374,6 @@ sub nic_duckdns_update { $state = 'result'; success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; - } elsif ($line eq 'KO') { $config{$h}{'status-ipv4'} = 'failed' if $ipv4; $config{$h}{'status-ipv6'} = 'failed' if $ipv6; @@ -6388,7 +6381,6 @@ sub nic_duckdns_update { failed("updating %s: Server said: '%s'", $h, $line); } } - if ($state eq 'noresult') { failed("updating %s: Server said: '%s'", $h, $line); } From 8a334fd9cf000f5cda280d14c2ae1d3f6bfd629a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 15:45:51 -0400 Subject: [PATCH 45/91] duckdns: Consolidate lines to improve readability --- ddclient.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index fa52485..aed3fce 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6347,12 +6347,7 @@ sub nic_duckdns_update { info("setting IPv4 address to %s for %s", $ipv4, $h) if $ipv4; info("setting IPv6 address to %s for %s", $ipv6, $h) if $ipv6; verbose("UPDATE:", "updating %s", $h); - my $url; - $url = "https://$config{$h}{'server'}/update"; - $url .= "?domains="; - $url .= $h; - $url .= "&token="; - $url .= $config{$h}{'password'}; + my $url = "https://$config{$h}{'server'}/update?domains=$h&token=$config{$h}{'password'}"; $url .= "&ip=$ipv4" if $ipv4; $url .= "&ipv6=$ipv6" if $ipv6; my $reply = geturl(proxy => opt('proxy'), url => $url); From 971e88452d07455049d38b2245ab6a89ebfaf711 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 15:51:42 -0400 Subject: [PATCH 46/91] duckdns: Improve log messages --- ddclient.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index aed3fce..779537b 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6344,9 +6344,8 @@ sub nic_duckdns_update { for my $h (@_) { my $ipv4 = delete $config{$h}{'wantipv4'}; my $ipv6 = delete $config{$h}{'wantipv6'}; - info("setting IPv4 address to %s for %s", $ipv4, $h) if $ipv4; - info("setting IPv6 address to %s for %s", $ipv6, $h) if $ipv6; - verbose("UPDATE:", "updating %s", $h); + info("$h: setting IPv4 address to $ipv4") if $ipv4; + info("$h: setting IPv6 address to $ipv6") if $ipv6; my $url = "https://$config{$h}{'server'}/update?domains=$h&token=$config{$h}{'password'}"; $url .= "&ip=$ipv4" if $ipv4; $url .= "&ipv6=$ipv6" if $ipv6; From 91fd9e384241a7dce0e40efe58bf5fcd5d23e189 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 19:57:12 -0400 Subject: [PATCH 47/91] duckdns: Simplify response processing --- ddclient.in | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/ddclient.in b/ddclient.in index 779537b..d8ef014 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6355,28 +6355,23 @@ sub nic_duckdns_update { next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; - my $state = 'noresult'; - my $line = ''; - for $line (@reply) { - if ($line eq 'OK') { - $config{$h}{'ipv4'} = $ipv4 if $ipv4; - $config{$h}{'ipv6'} = $ipv6 if $ipv6; - $config{$h}{'mtime'} = $now; - $config{$h}{'status-ipv4'} = 'good' if $ipv4; - $config{$h}{'status-ipv6'} = 'good' if $ipv6; - $state = 'result'; - success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; - success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; - } elsif ($line eq 'KO') { - $config{$h}{'status-ipv4'} = 'failed' if $ipv4; - $config{$h}{'status-ipv6'} = 'failed' if $ipv6; - $state = 'result'; - failed("updating %s: Server said: '%s'", $h, $line); - } - } - if ($state eq 'noresult') { - failed("updating %s: Server said: '%s'", $h, $line); + (my $body = $reply) =~ s/^.*?\n\n//s or do { + failed("$h: Invalid response from server"); + next; + }; + chomp($body); + if ($body eq 'OK') { + $config{$h}{'ipv4'} = $ipv4 if $ipv4; + $config{$h}{'ipv6'} = $ipv6 if $ipv6; + $config{$h}{'mtime'} = $now; + $config{$h}{'status-ipv4'} = 'good' if $ipv4; + $config{$h}{'status-ipv6'} = 'good' if $ipv6; + success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; + success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; + } else { + $config{$h}{'status-ipv4'} = 'failed' if $ipv4; + $config{$h}{'status-ipv6'} = 'failed' if $ipv6; + failed("updating %s: Server said: '%s'", $h, $body); } } } From 1eccfb8c77e61580066737a7f87b23fdd68e4740 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:00:01 -0400 Subject: [PATCH 48/91] duckdns: Invert condition to improve readability --- ddclient.in | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ddclient.in b/ddclient.in index d8ef014..81f0a66 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6360,19 +6360,19 @@ sub nic_duckdns_update { next; }; chomp($body); - if ($body eq 'OK') { - $config{$h}{'ipv4'} = $ipv4 if $ipv4; - $config{$h}{'ipv6'} = $ipv6 if $ipv6; - $config{$h}{'mtime'} = $now; - $config{$h}{'status-ipv4'} = 'good' if $ipv4; - $config{$h}{'status-ipv6'} = 'good' if $ipv6; - success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; - success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; - } else { + if ($body ne 'OK') { $config{$h}{'status-ipv4'} = 'failed' if $ipv4; $config{$h}{'status-ipv6'} = 'failed' if $ipv6; failed("updating %s: Server said: '%s'", $h, $body); + next; } + $config{$h}{'ipv4'} = $ipv4 if $ipv4; + $config{$h}{'ipv6'} = $ipv6 if $ipv6; + $config{$h}{'mtime'} = $now; + $config{$h}{'status-ipv4'} = 'good' if $ipv4; + $config{$h}{'status-ipv6'} = 'good' if $ipv6; + success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; + success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; } } From 7bdb554e361472920aadc4b15cc2a99938b532fc Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:05:52 -0400 Subject: [PATCH 49/91] duckdns: Update multiple hosts simultaneously --- ChangeLog.md | 2 ++ ddclient.in | 43 ++++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 35aff37..11bd94e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -86,6 +86,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master). records. [#690](https://github.com/ddclient/ddclient/pull/690) * `domeneshop`: Add IPv6 support. [#719](https://github.com/ddclient/ddclient/pull/719) + * `duckdns`: Multiple hosts with the same IP address are now updated together. + [#719](https://github.com/ddclient/ddclient/pull/719) ### Bug fixes diff --git a/ddclient.in b/ddclient.in index 81f0a66..ce357b2 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6341,38 +6341,43 @@ EoEXAMPLE ###################################################################### sub nic_duckdns_update { debug("\nnic_duckdns_update -------------------"); - for my $h (@_) { - my $ipv4 = delete $config{$h}{'wantipv4'}; - my $ipv6 = delete $config{$h}{'wantipv6'}; - info("$h: setting IPv4 address to $ipv4") if $ipv4; - info("$h: setting IPv6 address to $ipv6") if $ipv6; - my $url = "https://$config{$h}{'server'}/update?domains=$h&token=$config{$h}{'password'}"; + for my $group (group_hosts_by(\@_, qw(password server wantipv4 wantipv6))) { + my @hosts = @{$group->{hosts}}; + my %groupcfg = %{$group->{cfg}}; + my $hosts = join(',', @hosts); + my $ipv4 = $groupcfg{'wantipv4'}; + my $ipv6 = $groupcfg{'wantipv6'}; + delete $config{$_}{'wantipv4'} for @hosts; + delete $config{$_}{'wantipv6'} for @hosts; + info("$hosts: setting IPv4 address to $ipv4") if $ipv4; + info("$hosts: setting IPv6 address to $ipv6") if $ipv6; + my $url = "https://$groupcfg{'server'}/update?domains=$hosts&token=$groupcfg{'password'}"; $url .= "&ip=$ipv4" if $ipv4; $url .= "&ipv6=$ipv6" if $ipv6; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$hosts: Could not connect to $groupcfg{'server'}"); next; } - next if !header_ok($h, $reply); + next if !header_ok($hosts, $reply); (my $body = $reply) =~ s/^.*?\n\n//s or do { - failed("$h: Invalid response from server"); + failed("$hosts: Invalid response from server"); next; }; chomp($body); if ($body ne 'OK') { - $config{$h}{'status-ipv4'} = 'failed' if $ipv4; - $config{$h}{'status-ipv6'} = 'failed' if $ipv6; - failed("updating %s: Server said: '%s'", $h, $body); + failed("$hosts: Server said: $body"); next; } - $config{$h}{'ipv4'} = $ipv4 if $ipv4; - $config{$h}{'ipv6'} = $ipv6 if $ipv6; - $config{$h}{'mtime'} = $now; - $config{$h}{'status-ipv4'} = 'good' if $ipv4; - $config{$h}{'status-ipv6'} = 'good' if $ipv6; - success("updating %s: good: IPv4 address set to %s", $h, $ipv4) if $ipv4; - success("updating %s: good: IPv6 address set to %s", $h, $ipv6) if $ipv6; + for my $h (@hosts) { + $config{$h}{'ipv4'} = $ipv4 if $ipv4; + $config{$h}{'ipv6'} = $ipv6 if $ipv6; + $config{$h}{'mtime'} = $now; + $config{$h}{'status-ipv4'} = 'good' if $ipv4; + $config{$h}{'status-ipv6'} = 'good' if $ipv6; + } + success("$hosts: good: IPv4 address set to $ipv4") if $ipv4; + success("$hosts: good: IPv6 address set to $ipv6") if $ipv6; } } From f8bdc48e422f50989b5d2e1a1f705332c00efbf9 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:46:51 -0400 Subject: [PATCH 50/91] freemyip: Delete unnecessary comments --- ddclient.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index ce357b2..23bd882 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6420,7 +6420,6 @@ sub nic_freemyip_update { info("setting IP address to %s for %s", $ip, $h); verbose("UPDATE:", "updating %s", $h); - # Set the URL that we're going to to update my $url; $url = "https://$config{$h}{'server'}/update"; $url .= "?token="; @@ -6428,10 +6427,8 @@ sub nic_freemyip_update { $url .= "&domain="; $url .= $h; - # Try to get URL my $reply = geturl(proxy => opt('proxy'), url => $url); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; From 62154f986913ecd3fd233f2668706915da9fa9b0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:47:31 -0400 Subject: [PATCH 51/91] freemyip: Whitespace fixes --- ddclient.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 23bd882..abe3dd4 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6414,27 +6414,22 @@ EoEXAMPLE ###################################################################### sub nic_freemyip_update { debug("\nnic_freemyip_update -------------------"); - for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("setting IP address to %s for %s", $ip, $h); verbose("UPDATE:", "updating %s", $h); - my $url; - $url = "https://$config{$h}{'server'}/update"; + $url = "https://$config{$h}{'server'}/update"; $url .= "?token="; $url .= $config{$h}{'password'}; $url .= "&domain="; $url .= $h; - my $reply = geturl(proxy => opt('proxy'), url => $url); - if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; my $returned = pop(@reply); if ($returned =~ /OK/) { From b3006dd6c6850f7a61790b4cf585cf8a98b7271e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:48:42 -0400 Subject: [PATCH 52/91] freemyip: Consolidate lines for readability --- ddclient.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index abe3dd4..d10db43 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6418,12 +6418,7 @@ sub nic_freemyip_update { my $ip = delete $config{$h}{'wantip'}; info("setting IP address to %s for %s", $ip, $h); verbose("UPDATE:", "updating %s", $h); - my $url; - $url = "https://$config{$h}{'server'}/update"; - $url .= "?token="; - $url .= $config{$h}{'password'}; - $url .= "&domain="; - $url .= $h; + my $url = "https://$config{$h}{'server'}/update?token=$config{$h}{'password'}&domain=$h"; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); From c53f40d205c2e1dcbd801e78234b0a480b8e2ba9 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 22:53:01 -0400 Subject: [PATCH 53/91] freemyip: Improve log messages --- ddclient.in | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index d10db43..21d1ea5 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6416,12 +6416,11 @@ sub nic_freemyip_update { debug("\nnic_freemyip_update -------------------"); for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; - info("setting IP address to %s for %s", $ip, $h); - verbose("UPDATE:", "updating %s", $h); + info("$h: setting IP address to $ip"); my $url = "https://$config{$h}{'server'}/update?token=$config{$h}{'password'}&domain=$h"; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: Request to $config{$h}{'server'} failed"); next; } next if !header_ok($h, $reply); @@ -6431,10 +6430,10 @@ sub nic_freemyip_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; - success("updating %s: good: IP address set to %s", $h, $ip); + success("$h: good: IP address set to $ip"); } else { $config{$h}{'status'} = 'failed'; - failed("updating %s: Server said: '%s'", $h, $returned); + failed("$h: Server said: $returned"); } } } From 9343ebec890b96277ca5abf25d4e1ce06d5d1a4e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 22:57:01 -0400 Subject: [PATCH 54/91] freemyip: Don't bother setting `status` on error It's not necessary because it's already initialized to a non-success value. --- ddclient.in | 1 - 1 file changed, 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 21d1ea5..d9d18d8 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6432,7 +6432,6 @@ sub nic_freemyip_update { $config{$h}{'status'} = 'good'; success("$h: good: IP address set to $ip"); } else { - $config{$h}{'status'} = 'failed'; failed("$h: Server said: $returned"); } } From a252ff5ebe82407db5cff6c88ea47d3d159ec763 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 22:20:13 -0400 Subject: [PATCH 55/91] freemyip: Invert condition to improve readability --- ddclient.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index d9d18d8..1a26c1d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6426,14 +6426,14 @@ sub nic_freemyip_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned =~ /OK/) { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: good: IP address set to $ip"); - } else { + if ($returned !~ /OK/) { failed("$h: Server said: $returned"); + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("$h: good: IP address set to $ip"); } } From 3ece2017e978dbea8715c21b07d18f495e7d8502 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 20:51:10 -0400 Subject: [PATCH 56/91] freemyip: Skip headers before processing response This isn't strictly necessary but improves readability and consistency. --- ddclient.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 1a26c1d..2086e77 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6424,7 +6424,8 @@ sub nic_freemyip_update { next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; + (my $body = $reply) =~ s/^.*?\n\n//s; + my @reply = split(/\n/, $body); my $returned = pop(@reply); if ($returned !~ /OK/) { failed("$h: Server said: $returned"); From 1195a40c450f94fee947b0dcaea5b4807536650c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 21 Jul 2024 22:18:16 -0400 Subject: [PATCH 57/91] freemyip: Check entire result body, not just first line This is simpler, and should be more resilient to bugs. --- ddclient.in | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 2086e77..62015a2 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6425,10 +6425,8 @@ sub nic_freemyip_update { } next if !header_ok($h, $reply); (my $body = $reply) =~ s/^.*?\n\n//s; - my @reply = split(/\n/, $body); - my $returned = pop(@reply); - if ($returned !~ /OK/) { - failed("$h: Server said: $returned"); + if ($body !~ /OK/) { + failed("$h: Server said: $body"); next; } $config{$h}{'ip'} = $ip; From d62495c41e8c261bede1cce3e07bf98d5666d6f3 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 22 Jul 2024 22:33:11 -0400 Subject: [PATCH 58/91] ddns.fm: Improve log messages --- ddclient.in | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 62015a2..665c9a2 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6473,21 +6473,20 @@ sub nic_ddnsfm_update { # - IPv6 updates do not affect the IPv4 A record (if present). for my $ipv ('4', '6') { my $ip = delete $config{$h}{"wantipv$ipv"} or next; - info("setting IPv$ipv address to $ip for $h"); - verbose("UPDATE:", "updating %s", $h); + info("$h: setting IPv$ipv address to $ip"); my $reply = geturl( proxy => opt('proxy'), url => "$config{$h}{server}/update?key=$config{$h}{password}&domain=$h&myip=$ip", ); if (!$reply) { - failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: Request to $config{$h}{'server'} failed"); next; } next if !header_ok($h, $reply); $config{$h}{"ipv$ipv"} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{"status-ipv$ipv"} = 'good'; - success("updating $h: good: IPv$ipv address set to $ip"); + success("$h: IPv$ipv address set to $ip"); } } } From e155e1bf2c713408ca0d95c028eb978ac0fc2908 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:16:35 -0400 Subject: [PATCH 59/91] dondominio: Delete unnecessary comments --- ddclient.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 665c9a2..97a13bb 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6521,14 +6521,11 @@ EoEXAMPLE sub nic_dondominio_update { debug("\nnic_dondominio_update -------------------"); - ## update each configured host - ## should improve to update in one pass for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("setting IP address to %s for %s", $ip, $h); verbose("UPDATE:", "updating %s", $h); - # Set the URL that we're going to update my $url; $url = "https://$config{$h}{'server'}/plain/"; $url .= "?user="; @@ -6541,10 +6538,8 @@ sub nic_dondominio_update { $url .= $ip if $ip; - # Try to get URL my $reply = geturl(proxy => opt('proxy'), url => $url); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; From 17a002cbd62d9459a354935468bef36b14997cfb Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:17:32 -0400 Subject: [PATCH 60/91] dondominio: Whitespace fixes --- ddclient.in | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ddclient.in b/ddclient.in index 97a13bb..9798c0c 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6520,14 +6520,12 @@ EoEXAMPLE sub nic_dondominio_update { debug("\nnic_dondominio_update -------------------"); - for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("setting IP address to %s for %s", $ip, $h); verbose("UPDATE:", "updating %s", $h); - my $url; - $url = "https://$config{$h}{'server'}/plain/"; + $url = "https://$config{$h}{'server'}/plain/"; $url .= "?user="; $url .= $config{$h}{'login'}; $url .= "&password="; @@ -6536,16 +6534,12 @@ sub nic_dondominio_update { $url .= $h; $url .= "&ip="; $url .= $ip if $ip; - - my $reply = geturl(proxy => opt('proxy'), url => $url); - if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; my $returned = pop(@reply); if ($returned =~ /OK/ || $returned =~ /IP:$ip/) { From 7a43920b996542c39769d898086363292329daeb Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:19:04 -0400 Subject: [PATCH 61/91] dondominio: Improve log messages --- ddclient.in | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9798c0c..88778da 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6522,8 +6522,7 @@ sub nic_dondominio_update { debug("\nnic_dondominio_update -------------------"); for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; - info("setting IP address to %s for %s", $ip, $h); - verbose("UPDATE:", "updating %s", $h); + info("$h: setting IP address to $ip"); my $url; $url = "https://$config{$h}{'server'}/plain/"; $url .= "?user="; @@ -6536,7 +6535,7 @@ sub nic_dondominio_update { $url .= $ip if $ip; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: Request to $config{$h}{'server'} failed"); next; } next if !header_ok($h, $reply); @@ -6546,10 +6545,10 @@ sub nic_dondominio_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; - success("updating %s: good: IP address set to %s", $h, $ip); + success("$h: IP address set to $ip"); } else { $config{$h}{'status'} = 'failed'; - failed("updating %s: Server said: '%s'", $h, $returned); + failed("$h: Server said: $returned"); } } } From fe502abcd8895d0e5ea35985f4cd2e1ce930622c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:25:48 -0400 Subject: [PATCH 62/91] dondominio: Consolidate lines for readability --- ddclient.in | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ddclient.in b/ddclient.in index 88778da..5a7f9bf 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6523,15 +6523,7 @@ sub nic_dondominio_update { for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("$h: setting IP address to $ip"); - my $url; - $url = "https://$config{$h}{'server'}/plain/"; - $url .= "?user="; - $url .= $config{$h}{'login'}; - $url .= "&password="; - $url .= $config{$h}{'password'}; - $url .= "&host="; - $url .= $h; - $url .= "&ip="; + my $url = "https://$config{$h}{'server'}/plain/?user=$config{$h}{'login'}&password=$config{$h}{'password'}&host=$h&ip="; $url .= $ip if $ip; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { From 2823e47c58817864d0bfca00e5c2c17f1b34db33 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:26:14 -0400 Subject: [PATCH 63/91] dondominio: The IP address is always provided --- ddclient.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 5a7f9bf..655b0fa 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6523,8 +6523,7 @@ sub nic_dondominio_update { for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("$h: setting IP address to $ip"); - my $url = "https://$config{$h}{'server'}/plain/?user=$config{$h}{'login'}&password=$config{$h}{'password'}&host=$h&ip="; - $url .= $ip if $ip; + my $url = "https://$config{$h}{'server'}/plain/?user=$config{$h}{'login'}&password=$config{$h}{'password'}&host=$h&ip=$ip"; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { failed("$h: Request to $config{$h}{'server'} failed"); From 8b58f7bd99664034c14d7ed27bb83af044309650 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:27:52 -0400 Subject: [PATCH 64/91] dondominio: Don't bother setting `status` on error It's already initialized to a non-success value. --- ddclient.in | 1 - 1 file changed, 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 655b0fa..3a35034 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6538,7 +6538,6 @@ sub nic_dondominio_update { $config{$h}{'status'} = 'good'; success("$h: IP address set to $ip"); } else { - $config{$h}{'status'} = 'failed'; failed("$h: Server said: $returned"); } } From d79ef268bd6072ed450b71915339beac953cbcdb Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:28:58 -0400 Subject: [PATCH 65/91] dondominio: Combine regular expressions to improve readability --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 3a35034..b720d1d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6532,7 +6532,7 @@ sub nic_dondominio_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned =~ /OK/ || $returned =~ /IP:$ip/) { + if ($returned =~ /OK|IP:$ip/) { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; From 6ac5b41a2021192cd457a106acb33e1d45db50b9 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:29:47 -0400 Subject: [PATCH 66/91] dondominio: Invert condition to improve readability --- ddclient.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index b720d1d..5393143 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6532,14 +6532,14 @@ sub nic_dondominio_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned =~ /OK|IP:$ip/) { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: IP address set to $ip"); - } else { + if ($returned !~ /OK|IP:$ip/) { failed("$h: Server said: $returned"); + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("$h: IP address set to $ip"); } } From f42583c0cfb1461cad7dba356dd96dbcbc2c5345 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:31:17 -0400 Subject: [PATCH 67/91] dondominio: Quote interpolated variable in regex --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 5393143..9fde670 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6532,7 +6532,7 @@ sub nic_dondominio_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned !~ /OK|IP:$ip/) { + if ($returned !~ /OK|IP:\Q$ip\E/) { failed("$h: Server said: $returned"); next; } From 07800a4586097fd55d5292cae342073e58fa55df Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:35:29 -0400 Subject: [PATCH 68/91] dnsmadeeasy: Delete unnecessary comments --- ddclient.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9fde670..e357e1b 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6589,8 +6589,6 @@ sub nic_dnsmadeeasy_update { 'success' => 'Record successfully updated!', ); - ## update each configured host - ## should improve to update in one pass for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("Setting IP address to %s for %s", $ip, $h); @@ -6601,10 +6599,8 @@ sub nic_dnsmadeeasy_update { $url .= "&ip=$ip"; $url .= "&id=$h"; - # Try to get URL my $reply = geturl(proxy => opt('proxy'), url => $url); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("Updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; From c79d12263e642c448dc9fffd097388e8a4c583f8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:36:21 -0400 Subject: [PATCH 69/91] dnsmadeeasy: Whitespace fixes --- ddclient.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index e357e1b..811a184 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6576,7 +6576,6 @@ EoEXAMPLE ###################################################################### sub nic_dnsmadeeasy_update { debug("\nnic_dnsmadeeasy_update -------------------"); - my %messages = ( 'error-auth' => 'Invalid username or password, or invalid IP syntax', 'error-auth-suspend' => 'User has had their account suspended due to complaints or misuse of the service.', @@ -6588,7 +6587,6 @@ sub nic_dnsmadeeasy_update { 'error' => 'General system error unrecognized by the system.', 'success' => 'Record successfully updated!', ); - for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("Setting IP address to %s for %s", $ip, $h); @@ -6598,15 +6596,12 @@ sub nic_dnsmadeeasy_update { $url .= "&password=$config{$h}{'password'}"; $url .= "&ip=$ip"; $url .= "&id=$h"; - my $reply = geturl(proxy => opt('proxy'), url => $url); - if (!defined($reply) || !$reply) { failed("Updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); next; } next if !header_ok($h, $reply); - my @reply = split /\n/, $reply; my $returned = pop(@reply); if ($returned =~ 'success') { From 11876498d5cd7c478278b34b82edaecc608773cd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:38:26 -0400 Subject: [PATCH 70/91] dnsmadeeasy: Improve log messages --- ddclient.in | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 811a184..1056a1c 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6589,8 +6589,7 @@ sub nic_dnsmadeeasy_update { ); for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; - info("Setting IP address to %s for %s", $ip, $h); - verbose("UPDATE:", "Updating %s", $h); + info("$h: Setting IP address to $ip"); my $url = $config{$h}{'server'} . $config{$h}{'script'}; $url .= "?username=$config{$h}{'login'}"; $url .= "&password=$config{$h}{'password'}"; @@ -6598,7 +6597,7 @@ sub nic_dnsmadeeasy_update { $url .= "&id=$h"; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { - failed("Updating %s: Could not connect to %s.", $h, $config{$h}{'server'}); + failed("$h: Request to $config{$h}{'server'} failed"); next; } next if !header_ok($h, $reply); @@ -6608,10 +6607,10 @@ sub nic_dnsmadeeasy_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; - success("Updating %s: good: IP address set to %s", $h, $ip); + success("$h: IP address set to $ip"); } else { $config{$h}{'status'} = 'failed'; - failed("Updating %s: Server said: '%s': %s", $h, $returned, $messages{$returned}); + failed("$h: Server said: $returned: $messages{$returned}"); } } } From ca28694dd79e90057d71c9c6814227e8c5f90c37 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:49:21 -0400 Subject: [PATCH 71/91] dnsmadeeasy: Don't assume the result code is known --- ddclient.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 1056a1c..0f288c4 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6610,7 +6610,8 @@ sub nic_dnsmadeeasy_update { success("$h: IP address set to $ip"); } else { $config{$h}{'status'} = 'failed'; - failed("$h: Server said: $returned: $messages{$returned}"); + my $err = $messages{$returned} ? "$returned: $messages{$returned}" : $returned; + failed("$h: Server said: $err"); } } } From 971fe438a36d6206994636ef2f51c958f05d1613 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:38:55 -0400 Subject: [PATCH 72/91] dnsmadeeasy: Convert string literal to compiled regex for readability. --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 0f288c4..a38d70e 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6603,7 +6603,7 @@ sub nic_dnsmadeeasy_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned =~ 'success') { + if ($returned =~ qr/success/) { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{'status'} = 'good'; From b07aa91ed54241682ecb82a325a4927484cf1b5c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:41:53 -0400 Subject: [PATCH 73/91] dnsmadeeasy: Don't bother setting `status` on failure It's already initialized to a non-success value. --- ddclient.in | 1 - 1 file changed, 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index a38d70e..71ea8b6 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6609,7 +6609,6 @@ sub nic_dnsmadeeasy_update { $config{$h}{'status'} = 'good'; success("$h: IP address set to $ip"); } else { - $config{$h}{'status'} = 'failed'; my $err = $messages{$returned} ? "$returned: $messages{$returned}" : $returned; failed("$h: Server said: $err"); } From 2eb0398cf26767f2fd3453c87a63ff952912d0ee Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:42:47 -0400 Subject: [PATCH 74/91] dnsmadeeasy: Invert condition to improve readability --- ddclient.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 71ea8b6..2104d90 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6603,15 +6603,15 @@ sub nic_dnsmadeeasy_update { next if !header_ok($h, $reply); my @reply = split /\n/, $reply; my $returned = pop(@reply); - if ($returned =~ qr/success/) { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{'status'} = 'good'; - success("$h: IP address set to $ip"); - } else { + if ($returned !~ qr/success/) { my $err = $messages{$returned} ? "$returned: $messages{$returned}" : $returned; failed("$h: Server said: $err"); + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{'status'} = 'good'; + success("$h: IP address set to $ip"); } } From 3dae16457aed491382556c65c7c4776f714827e7 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:44:33 -0400 Subject: [PATCH 75/91] dnsmadeeasy: Consolidate lines for readability --- ddclient.in | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 2104d90..5077f60 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6590,11 +6590,7 @@ sub nic_dnsmadeeasy_update { for my $h (@_) { my $ip = delete $config{$h}{'wantip'}; info("$h: Setting IP address to $ip"); - my $url = $config{$h}{'server'} . $config{$h}{'script'}; - $url .= "?username=$config{$h}{'login'}"; - $url .= "&password=$config{$h}{'password'}"; - $url .= "&ip=$ip"; - $url .= "&id=$h"; + my $url = "$config{$h}{'server'}$config{$h}{'script'}?username=$config{$h}{'login'}&password=$config{$h}{'password'}&ip=$ip&id=$h"; my $reply = geturl(proxy => opt('proxy'), url => $url); if (!defined($reply) || !$reply) { failed("$h: Request to $config{$h}{'server'} failed"); From 4b5b8ab62d39d48855c0144f559ca83053bb7c74 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:05:02 -0400 Subject: [PATCH 76/91] porkbun: Delete unnecessary comments --- ddclient.in | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ddclient.in b/ddclient.in index 5077f60..63bf247 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6771,7 +6771,6 @@ sub nic_porkbun_update { for my $host (@_) { my ($sub_domain, $domain); if ($config{$host}{'root-domain'}) { - # Process 'root-domain' option $domain = $config{$host}{'root-domain'}; $sub_domain = $host; if ($host eq $domain) { @@ -6779,18 +6778,15 @@ sub nic_porkbun_update { } else { $sub_domain =~ s/\.$domain//; } - # Not valid if not an exact match and the root domain not stripped if ($sub_domain eq $host) { failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $host); next; } warning("%s has both 'root-domain' and 'on-root-domain' defined. The latter is ignored") if $config{$host}{'on-root-domain'}; } elsif ($config{$host}{'on-root-domain'}) { - # Process legacy 'on-root-domain' option $sub_domain = ''; $domain = $host; } else { - # Default to the subdomain/domain being split at the first dot ($sub_domain, $domain) = split(/\./, $host, 2); } info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; @@ -6818,7 +6814,6 @@ sub nic_porkbun_update { method => 'POST', data => $data, ); - # No response, declare as failed if (!defined($reply) || !$reply) { $config{$host}{"status-$ipv"} = "bad"; failed("updating %s: Could not connect to porkbun.com.", $host); @@ -6829,8 +6824,6 @@ sub nic_porkbun_update { failed("updating %s: failed (%s)", $host, $reply); next; } - # Strip header - # Porkbun sends data in chunks, so it is assumed to be one chunk and parsed forcibly. $reply =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { @@ -6874,7 +6867,6 @@ sub nic_porkbun_update { method => 'POST', data => $data, ); - # No response, declare as failed if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to porkbun.com.", $host); next; From 3f740c3e1909bcada59925f6b54651be15c564f9 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:10:32 -0400 Subject: [PATCH 77/91] porkbun: Whitespace fixes --- ddclient.in | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/ddclient.in b/ddclient.in index 63bf247..a2289f4 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6767,7 +6767,6 @@ EoEXAMPLE ###################################################################### sub nic_porkbun_update { debug("\nnic_porkbun_update -------------------"); - for my $host (@_) { my ($sub_domain, $domain); if ($config{$host}{'root-domain'}) { @@ -6790,29 +6789,26 @@ sub nic_porkbun_update { ($sub_domain, $domain) = split(/\./, $host, 2); } info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; - for my $ipv ('ipv4', 'ipv6') { my $ip = delete $config{$host}{"want$ipv"}; if (!$ip) { next; } my $rrset_type = is_ipv6($ip) ? "AAAA" : "A"; - info("setting %s address to %s for %s", $ipv, $ip, $host); verbose("UPDATE:","updating %s", $host); - my $url = "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain"; my $data = encode_json({ secretapikey => $config{$host}{'secretapikey'}, - apikey => $config{$host}{'apikey'}, + apikey => $config{$host}{'apikey'}, }); my $header = "Content-Type: application/json\n"; my $reply = geturl( - proxy => opt('proxy'), - url => $url, - headers => $header, - method => 'POST', - data => $data, + proxy => opt('proxy'), + url => $url, + headers => $header, + method => 'POST', + data => $data, ); if (!defined($reply) || !$reply) { $config{$host}{"status-$ipv"} = "bad"; @@ -6855,17 +6851,17 @@ sub nic_porkbun_update { $url = "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain"; $data = encode_json({ secretapikey => $config{$host}{'secretapikey'}, - apikey => $config{$host}{'apikey'}, - content => $ip, - ttl => $ttl, - notes => $notes, + apikey => $config{$host}{'apikey'}, + content => $ip, + ttl => $ttl, + notes => $notes, }); $reply = geturl( - proxy => opt('proxy'), - url => $url, - headers => $header, - method => 'POST', - data => $data, + proxy => opt('proxy'), + url => $url, + headers => $header, + method => 'POST', + data => $data, ); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to porkbun.com.", $host); From 1020145fdfc5832350190a6e2ada23be9af56a42 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:16:20 -0400 Subject: [PATCH 78/91] porkbun: Rename variables for brevity and consistency --- ddclient.in | 73 +++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/ddclient.in b/ddclient.in index a2289f4..59c86a2 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6767,40 +6767,41 @@ EoEXAMPLE ###################################################################### sub nic_porkbun_update { debug("\nnic_porkbun_update -------------------"); - for my $host (@_) { + for my $h (@_) { my ($sub_domain, $domain); - if ($config{$host}{'root-domain'}) { - $domain = $config{$host}{'root-domain'}; - $sub_domain = $host; - if ($host eq $domain) { + if ($config{$h}{'root-domain'}) { + $domain = $config{$h}{'root-domain'}; + $sub_domain = $h; + if ($h eq $domain) { $sub_domain = ''; } else { $sub_domain =~ s/\.$domain//; } - if ($sub_domain eq $host) { - failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $host); + if ($sub_domain eq $h) { + failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $h); next; } - warning("%s has both 'root-domain' and 'on-root-domain' defined. The latter is ignored") if $config{$host}{'on-root-domain'}; - } elsif ($config{$host}{'on-root-domain'}) { + warning("%s has both 'root-domain' and 'on-root-domain' defined. The latter is ignored") + if $config{$h}{'on-root-domain'}; + } elsif ($config{$h}{'on-root-domain'}) { $sub_domain = ''; - $domain = $host; + $domain = $h; } else { - ($sub_domain, $domain) = split(/\./, $host, 2); + ($sub_domain, $domain) = split(/\./, $h, 2); } info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; for my $ipv ('ipv4', 'ipv6') { - my $ip = delete $config{$host}{"want$ipv"}; + my $ip = delete $config{$h}{"want$ipv"}; if (!$ip) { next; } my $rrset_type = is_ipv6($ip) ? "AAAA" : "A"; - info("setting %s address to %s for %s", $ipv, $ip, $host); - verbose("UPDATE:","updating %s", $host); + info("setting %s address to %s for %s", $ipv, $ip, $h); + verbose("UPDATE:","updating %s", $h); my $url = "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain"; my $data = encode_json({ - secretapikey => $config{$host}{'secretapikey'}, - apikey => $config{$host}{'apikey'}, + secretapikey => $config{$h}{'secretapikey'}, + apikey => $config{$h}{'apikey'}, }); my $header = "Content-Type: application/json\n"; my $reply = geturl( @@ -6811,25 +6812,25 @@ sub nic_porkbun_update { data => $data, ); if (!defined($reply) || !$reply) { - $config{$host}{"status-$ipv"} = "bad"; - failed("updating %s: Could not connect to porkbun.com.", $host); + $config{$h}{"status-$ipv"} = "bad"; + failed("updating %s: Could not connect to porkbun.com.", $h); next; } - if (!header_ok($host, $reply)) { - $config{$host}{"status-$ipv"} = "bad"; - failed("updating %s: failed (%s)", $host, $reply); + if (!header_ok($h, $reply)) { + $config{$h}{"status-$ipv"} = "bad"; + failed("updating %s: failed (%s)", $h, $reply); next; } $reply =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { - $config{$host}{"status-$ipv"} = "bad"; - failed("%s -- Unexpected service response.", $host); + $config{$h}{"status-$ipv"} = "bad"; + failed("%s -- Unexpected service response.", $h); next; } if ($response->{status} ne 'SUCCESS') { - $config{$host}{"status-$ipv"} = "bad"; - failed("%s -- Unexpected status. (status = %s)", $host, $response->{status}); + $config{$h}{"status-$ipv"} = "bad"; + failed("%s -- Unexpected status. (status = %s)", $h, $response->{status}); next; } my $records = $response->{records}; @@ -6840,8 +6841,8 @@ sub nic_porkbun_update { } my $current_content = $records->[0]->{'content'}; if ($current_content eq $ip) { - $config{$host}{"status-$ipv"} = "good"; - success("updating %s: skipped: %s address was already set to %s.", $ipv, $host, $ip); + $config{$h}{"status-$ipv"} = "good"; + success("updating %s: skipped: %s address was already set to %s.", $ipv, $h, $ip); next; } my $ttl = $records->[0]->{'ttl'}; @@ -6850,8 +6851,8 @@ sub nic_porkbun_update { debug("notes = %s", $notes); $url = "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain"; $data = encode_json({ - secretapikey => $config{$host}{'secretapikey'}, - apikey => $config{$host}{'apikey'}, + secretapikey => $config{$h}{'secretapikey'}, + apikey => $config{$h}{'apikey'}, content => $ip, ttl => $ttl, notes => $notes, @@ -6864,19 +6865,19 @@ sub nic_porkbun_update { data => $data, ); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to porkbun.com.", $host); + failed("updating %s: Could not connect to porkbun.com.", $h); next; } - if (!header_ok($host, $reply)) { - failed("updating %s: failed (%s)", $host, $reply); + if (!header_ok($h, $reply)) { + failed("updating %s: failed (%s)", $h, $reply); next; } - $config{$host}{"status-$ipv"} = "good"; - success("updating %s: good: %s address set to %s", $ipv, $host, $ip); + $config{$h}{"status-$ipv"} = "good"; + success("updating %s: good: %s address set to %s", $ipv, $h, $ip); next; } else { - $config{$host}{"status-$ipv"} = "bad"; - failed("updating %s: No applicable existing records.", $host); + $config{$h}{"status-$ipv"} = "bad"; + failed("updating %s: No applicable existing records.", $h); next; } } From c6bcfd46440671a7c00c47bd11c2c63e56719d5f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 00:58:11 -0400 Subject: [PATCH 79/91] porkbun: Quote interpolated variable in regex --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 59c86a2..daadf0d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6775,7 +6775,7 @@ sub nic_porkbun_update { if ($h eq $domain) { $sub_domain = ''; } else { - $sub_domain =~ s/\.$domain//; + $sub_domain =~ s/\.\Q$domain\E//; } if ($sub_domain eq $h) { failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $h); From 4273580bdfc733b0c4e988ebb6b682d821232162 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:23:07 -0400 Subject: [PATCH 80/91] porkbun: Consolidate lines to improve readability --- ddclient.in | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index daadf0d..7714fc0 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6791,10 +6791,7 @@ sub nic_porkbun_update { } info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; for my $ipv ('ipv4', 'ipv6') { - my $ip = delete $config{$h}{"want$ipv"}; - if (!$ip) { - next; - } + my $ip = delete $config{$h}{"want$ipv"} or next; my $rrset_type = is_ipv6($ip) ? "AAAA" : "A"; info("setting %s address to %s for %s", $ipv, $ip, $h); verbose("UPDATE:","updating %s", $h); From 630a2d5d49638c0453cace7383fdb7bf68f77935 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:25:32 -0400 Subject: [PATCH 81/91] porkbun: Move "ipv" out of `$ipv` for consistency This also makes it possible to change "ipv4" and "ipv6" in log messages to "IPv4" and "IPv6". --- ddclient.in | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ddclient.in b/ddclient.in index 7714fc0..3a626b6 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6790,10 +6790,10 @@ sub nic_porkbun_update { ($sub_domain, $domain) = split(/\./, $h, 2); } info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; - for my $ipv ('ipv4', 'ipv6') { - my $ip = delete $config{$h}{"want$ipv"} or next; + for my $ipv ('4', '6') { + my $ip = delete $config{$h}{"wantipv$ipv"} or next; my $rrset_type = is_ipv6($ip) ? "AAAA" : "A"; - info("setting %s address to %s for %s", $ipv, $ip, $h); + info("setting ipv%s address to %s for %s", $ipv, $ip, $h); verbose("UPDATE:","updating %s", $h); my $url = "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain"; my $data = encode_json({ @@ -6809,24 +6809,24 @@ sub nic_porkbun_update { data => $data, ); if (!defined($reply) || !$reply) { - $config{$h}{"status-$ipv"} = "bad"; + $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: Could not connect to porkbun.com.", $h); next; } if (!header_ok($h, $reply)) { - $config{$h}{"status-$ipv"} = "bad"; + $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: failed (%s)", $h, $reply); next; } $reply =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { - $config{$h}{"status-$ipv"} = "bad"; + $config{$h}{"status-ipv$ipv"} = "bad"; failed("%s -- Unexpected service response.", $h); next; } if ($response->{status} ne 'SUCCESS') { - $config{$h}{"status-$ipv"} = "bad"; + $config{$h}{"status-ipv$ipv"} = "bad"; failed("%s -- Unexpected status. (status = %s)", $h, $response->{status}); next; } @@ -6838,8 +6838,8 @@ sub nic_porkbun_update { } my $current_content = $records->[0]->{'content'}; if ($current_content eq $ip) { - $config{$h}{"status-$ipv"} = "good"; - success("updating %s: skipped: %s address was already set to %s.", $ipv, $h, $ip); + $config{$h}{"status-ipv$ipv"} = "good"; + success("updating %s: skipped: ipv%s address was already set to %s.", $ipv, $h, $ip); next; } my $ttl = $records->[0]->{'ttl'}; @@ -6869,11 +6869,11 @@ sub nic_porkbun_update { failed("updating %s: failed (%s)", $h, $reply); next; } - $config{$h}{"status-$ipv"} = "good"; - success("updating %s: good: %s address set to %s", $ipv, $h, $ip); + $config{$h}{"status-ipv$ipv"} = "good"; + success("updating %s: good: ipv%s address set to %s", $ipv, $h, $ip); next; } else { - $config{$h}{"status-$ipv"} = "bad"; + $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: No applicable existing records.", $h); next; } From 038b31cf77fdc81929292f066ab0bb7842d90ba8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:12:31 -0400 Subject: [PATCH 82/91] porkbun: Simplify zone removal logic --- ddclient.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 3a626b6..f6ed02f 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6772,12 +6772,7 @@ sub nic_porkbun_update { if ($config{$h}{'root-domain'}) { $domain = $config{$h}{'root-domain'}; $sub_domain = $h; - if ($h eq $domain) { - $sub_domain = ''; - } else { - $sub_domain =~ s/\.\Q$domain\E//; - } - if ($sub_domain eq $h) { + if ($sub_domain !~ s/(?:^|\.)\Q$domain\E$//) { failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $h); next; } From 45d832145f2f64c6834a48eb2263a9554605ed2b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:29:35 -0400 Subject: [PATCH 83/91] porkbun: Simplify RR set type --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index f6ed02f..06c67d0 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6787,7 +6787,7 @@ sub nic_porkbun_update { info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; for my $ipv ('4', '6') { my $ip = delete $config{$h}{"wantipv$ipv"} or next; - my $rrset_type = is_ipv6($ip) ? "AAAA" : "A"; + my $rrset_type = $ipv eq '4' ? 'A' : 'AAAA'; info("setting ipv%s address to %s for %s", $ipv, $ip, $h); verbose("UPDATE:","updating %s", $h); my $url = "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain"; From bafd5a87158a5167c3e222c56ec85298ca1fbfe3 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:31:34 -0400 Subject: [PATCH 84/91] porkbun: Inline unnecessary variables --- ddclient.in | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/ddclient.in b/ddclient.in index 06c67d0..fc846bb 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6790,18 +6790,15 @@ sub nic_porkbun_update { my $rrset_type = $ipv eq '4' ? 'A' : 'AAAA'; info("setting ipv%s address to %s for %s", $ipv, $ip, $h); verbose("UPDATE:","updating %s", $h); - my $url = "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain"; - my $data = encode_json({ - secretapikey => $config{$h}{'secretapikey'}, - apikey => $config{$h}{'apikey'}, - }); - my $header = "Content-Type: application/json\n"; my $reply = geturl( proxy => opt('proxy'), - url => $url, - headers => $header, + url => "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain", + headers => ['Content-Type: application/json'], method => 'POST', - data => $data, + data => encode_json({ + secretapikey => $config{$h}{'secretapikey'}, + apikey => $config{$h}{'apikey'}, + }), ); if (!defined($reply) || !$reply) { $config{$h}{"status-ipv$ipv"} = "bad"; @@ -6841,20 +6838,18 @@ sub nic_porkbun_update { my $notes = $records->[0]->{'notes'}; debug("ttl = %s", $ttl); debug("notes = %s", $notes); - $url = "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain"; - $data = encode_json({ - secretapikey => $config{$h}{'secretapikey'}, - apikey => $config{$h}{'apikey'}, - content => $ip, - ttl => $ttl, - notes => $notes, - }); $reply = geturl( proxy => opt('proxy'), - url => $url, - headers => $header, + url => "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain", + headers => ['Content-Type: application/json'], method => 'POST', - data => $data, + data => encode_json({ + secretapikey => $config{$h}{'secretapikey'}, + apikey => $config{$h}{'apikey'}, + content => $ip, + ttl => $ttl, + notes => $notes, + }), ); if (!defined($reply) || !$reply) { failed("updating %s: Could not connect to porkbun.com.", $h); From c65d5c1254f15575ad8b46843b6c03572b164c9a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:34:28 -0400 Subject: [PATCH 85/91] porkbun: Don't bother setting `status` on failure It's already initialized to a non-success value. --- ddclient.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index fc846bb..452ba41 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6801,24 +6801,20 @@ sub nic_porkbun_update { }), ); if (!defined($reply) || !$reply) { - $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: Could not connect to porkbun.com.", $h); next; } if (!header_ok($h, $reply)) { - $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: failed (%s)", $h, $reply); next; } $reply =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { - $config{$h}{"status-ipv$ipv"} = "bad"; failed("%s -- Unexpected service response.", $h); next; } if ($response->{status} ne 'SUCCESS') { - $config{$h}{"status-ipv$ipv"} = "bad"; failed("%s -- Unexpected status. (status = %s)", $h, $response->{status}); next; } @@ -6863,7 +6859,6 @@ sub nic_porkbun_update { success("updating %s: good: ipv%s address set to %s", $ipv, $h, $ip); next; } else { - $config{$h}{"status-ipv$ipv"} = "bad"; failed("updating %s: No applicable existing records.", $h); next; } From 16b15ea08909690f2752db5d0fa26402b2f3f298 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:42:06 -0400 Subject: [PATCH 86/91] porkbun: Remove headers from HTTP response before processing --- ddclient.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 452ba41..7300c08 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6808,7 +6808,8 @@ sub nic_porkbun_update { failed("updating %s: failed (%s)", $h, $reply); next; } - $reply =~ qr/{(?:[^{}]*|(?R))*}/mp; + (my $body = $reply) =~ s/^.*?\n\n//s; + $body =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { failed("%s -- Unexpected service response.", $h); From 0c31681d35e3deb0cea5626d022b143364c074be Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:48:06 -0400 Subject: [PATCH 87/91] porkbun: Simplify array length check --- ddclient.in | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ddclient.in b/ddclient.in index 7300c08..f7a998a 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6821,10 +6821,8 @@ sub nic_porkbun_update { } my $records = $response->{records}; if (ref($records) eq 'ARRAY' && defined $records->[0]->{'id'}) { - my $count = scalar(@{$records}); - if ($count > 1) { - warning("updating %s: There are multiple applicable records. Only first record is used. Overwrite all with the same content."); - } + warning("updating %s: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") + if @$records > 1; my $current_content = $records->[0]->{'content'}; if ($current_content eq $ip) { $config{$h}{"status-ipv$ipv"} = "good"; From e1c8b26f7b11b7c080a1c312aa44959462e6ae75 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:51:03 -0400 Subject: [PATCH 88/91] porkbun: Simplify string equality check --- ddclient.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index f7a998a..5fcf31b 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6823,8 +6823,7 @@ sub nic_porkbun_update { if (ref($records) eq 'ARRAY' && defined $records->[0]->{'id'}) { warning("updating %s: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") if @$records > 1; - my $current_content = $records->[0]->{'content'}; - if ($current_content eq $ip) { + if ($records->[0]{'content'} eq $ip) { $config{$h}{"status-ipv$ipv"} = "good"; success("updating %s: skipped: ipv%s address was already set to %s.", $ipv, $h, $ip); next; From d8a23ff9a4994f2a0d5e352bae1785042a5ac3ac Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:11:23 -0400 Subject: [PATCH 89/91] porkbun: Improve log messages --- ddclient.in | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ddclient.in b/ddclient.in index 5fcf31b..c0ad334 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6770,26 +6770,25 @@ sub nic_porkbun_update { for my $h (@_) { my ($sub_domain, $domain); if ($config{$h}{'root-domain'}) { + warning("$h: both 'root-domain' and 'on-root-domain' are set; ignoring the latter") + if $config{$h}{'on-root-domain'}; $domain = $config{$h}{'root-domain'}; $sub_domain = $h; if ($sub_domain !~ s/(?:^|\.)\Q$domain\E$//) { - failed("'root-domain' (%s) is not part of the full host name (%s)!", $domain, $h); + failed("$h: hostname does not end with the 'root-domain' value: $domain"); next; } - warning("%s has both 'root-domain' and 'on-root-domain' defined. The latter is ignored") - if $config{$h}{'on-root-domain'}; } elsif ($config{$h}{'on-root-domain'}) { $sub_domain = ''; $domain = $h; } else { ($sub_domain, $domain) = split(/\./, $h, 2); } - info("subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; + info("$h: subdomain %s, root domain %s", $sub_domain, $domain) if $sub_domain ne ''; for my $ipv ('4', '6') { my $ip = delete $config{$h}{"wantipv$ipv"} or next; my $rrset_type = $ipv eq '4' ? 'A' : 'AAAA'; - info("setting ipv%s address to %s for %s", $ipv, $ip, $h); - verbose("UPDATE:","updating %s", $h); + info("$h: setting IPv$ipv address to $ip"); my $reply = geturl( proxy => opt('proxy'), url => "https://porkbun.com/api/json/v3/dns/retrieveByNameType/$domain/$rrset_type/$sub_domain", @@ -6801,31 +6800,31 @@ sub nic_porkbun_update { }), ); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to porkbun.com.", $h); + failed("$h: request to porkbun.com failed"); next; } if (!header_ok($h, $reply)) { - failed("updating %s: failed (%s)", $h, $reply); + failed("$h: $reply"); next; } (my $body = $reply) =~ s/^.*?\n\n//s; $body =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; if (!defined($response)) { - failed("%s -- Unexpected service response.", $h); + failed("$h: unexpected service response: $body"); next; } if ($response->{status} ne 'SUCCESS') { - failed("%s -- Unexpected status. (status = %s)", $h, $response->{status}); + failed("$h: unexpected status: $response->{status}"); next; } my $records = $response->{records}; if (ref($records) eq 'ARRAY' && defined $records->[0]->{'id'}) { - warning("updating %s: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") + warning("$h: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") if @$records > 1; if ($records->[0]{'content'} eq $ip) { $config{$h}{"status-ipv$ipv"} = "good"; - success("updating %s: skipped: ipv%s address was already set to %s.", $ipv, $h, $ip); + success("$h: skipped: IPv$ipv address was already set to $ip"); next; } my $ttl = $records->[0]->{'ttl'}; @@ -6846,18 +6845,18 @@ sub nic_porkbun_update { }), ); if (!defined($reply) || !$reply) { - failed("updating %s: Could not connect to porkbun.com.", $h); + failed("$h: request to porkbun.com failed"); next; } if (!header_ok($h, $reply)) { - failed("updating %s: failed (%s)", $h, $reply); + failed("$h: $reply"); next; } $config{$h}{"status-ipv$ipv"} = "good"; - success("updating %s: good: ipv%s address set to %s", $ipv, $h, $ip); + success("$h: IPv%s address set to $ip"); next; } else { - failed("updating %s: No applicable existing records.", $h); + failed("$h: no applicable existing records"); next; } } From 536c7c87a2542ff825b439b6a3de2e4be9118f0a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 01:56:19 -0400 Subject: [PATCH 90/91] porkbun: Invert condition to improve readability --- ddclient.in | 72 ++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/ddclient.in b/ddclient.in index c0ad334..7731ffb 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6819,46 +6819,44 @@ sub nic_porkbun_update { next; } my $records = $response->{records}; - if (ref($records) eq 'ARRAY' && defined $records->[0]->{'id'}) { - warning("$h: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") - if @$records > 1; - if ($records->[0]{'content'} eq $ip) { - $config{$h}{"status-ipv$ipv"} = "good"; - success("$h: skipped: IPv$ipv address was already set to $ip"); - next; - } - my $ttl = $records->[0]->{'ttl'}; - my $notes = $records->[0]->{'notes'}; - debug("ttl = %s", $ttl); - debug("notes = %s", $notes); - $reply = geturl( - proxy => opt('proxy'), - url => "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain", - headers => ['Content-Type: application/json'], - method => 'POST', - data => encode_json({ - secretapikey => $config{$h}{'secretapikey'}, - apikey => $config{$h}{'apikey'}, - content => $ip, - ttl => $ttl, - notes => $notes, - }), - ); - if (!defined($reply) || !$reply) { - failed("$h: request to porkbun.com failed"); - next; - } - if (!header_ok($h, $reply)) { - failed("$h: $reply"); - next; - } - $config{$h}{"status-ipv$ipv"} = "good"; - success("$h: IPv%s address set to $ip"); - next; - } else { + if (ref($records) ne 'ARRAY' || !defined($records->[0]{'id'})) { failed("$h: no applicable existing records"); next; } + warning("$h: There are multiple applicable records. Only first record is used. Overwrite all with the same content.") + if @$records > 1; + if ($records->[0]{'content'} eq $ip) { + $config{$h}{"status-ipv$ipv"} = "good"; + success("$h: skipped: IPv$ipv address was already set to $ip"); + next; + } + my $ttl = $records->[0]->{'ttl'}; + my $notes = $records->[0]->{'notes'}; + debug("ttl = %s", $ttl); + debug("notes = %s", $notes); + $reply = geturl( + proxy => opt('proxy'), + url => "https://porkbun.com/api/json/v3/dns/editByNameType/$domain/$rrset_type/$sub_domain", + headers => ['Content-Type: application/json'], + method => 'POST', + data => encode_json({ + secretapikey => $config{$h}{'secretapikey'}, + apikey => $config{$h}{'apikey'}, + content => $ip, + ttl => $ttl, + notes => $notes, + }), + ); + if (!defined($reply) || !$reply) { + failed("$h: request to porkbun.com failed"); + next; + } + if (!header_ok($h, $reply)) { + failed("$h: $reply"); + next; + } + $config{$h}{"status-ipv$ipv"} = "good"; + success("$h: IPv%s address set to $ip"); } } } From fc453a0de3f50300e13a8d69d68d56ddd89bdc0d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 23 Jul 2024 02:00:51 -0400 Subject: [PATCH 91/91] porkbun: Check for JSON object, not just non-null --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 7731ffb..728558d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6810,7 +6810,7 @@ sub nic_porkbun_update { (my $body = $reply) =~ s/^.*?\n\n//s; $body =~ qr/{(?:[^{}]*|(?R))*}/mp; my $response = eval { decode_json(${^MATCH}) }; - if (!defined($response)) { + if (ref($response) ne 'HASH') { failed("$h: unexpected service response: $body"); next; }