Merge pull request #662 from rhansen/skip

Distinguish unset `--*-skip` settings from set to the empty string
This commit is contained in:
Richard Hansen 2024-05-12 16:03:28 -04:00 committed by GitHub
commit 5eb6a6d755
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 200 additions and 32 deletions

View file

@ -68,6 +68,7 @@ handwritten_tests = \
t/is-and-extract-ipv6.pl \ t/is-and-extract-ipv6.pl \
t/is-and-extract-ipv6-global.pl \ t/is-and-extract-ipv6-global.pl \
t/parse_assignments.pl \ t/parse_assignments.pl \
t/skip.pl \
t/ssl-validate.pl \ t/ssl-validate.pl \
t/write_cache.pl t/write_cache.pl
generated_tests = \ generated_tests = \

View file

@ -95,7 +95,7 @@ sub T_IPV6 { 'ipv6' }
sub T_POSTS { 'postscript' } sub T_POSTS { 'postscript' }
## strategies for obtaining an ip address. ## strategies for obtaining an ip address.
my %builtinweb = ( our %builtinweb = (
'dyndns' => {'url' => 'http://checkip.dyndns.org/', 'skip' => 'Current IP Address:'}, 'dyndns' => {'url' => 'http://checkip.dyndns.org/', 'skip' => 'Current IP Address:'},
'freedns' => {'url' => 'https://freedns.afraid.org/dynamic/check.php'}, 'freedns' => {'url' => 'https://freedns.afraid.org/dynamic/check.php'},
'googledomains' => {'url' => 'https://domains.google.com/checkip'}, # Deprecated! See https://github.com/ddclient/ddclient/issues/622 for more details 'googledomains' => {'url' => 'https://domains.google.com/checkip'}, # Deprecated! See https://github.com/ddclient/ddclient/issues/622 for more details
@ -112,7 +112,7 @@ my %builtinweb = (
'nsupdate.info-ipv6' => {'url' => 'https://ipv6.nsupdate.info/myip'}, 'nsupdate.info-ipv6' => {'url' => 'https://ipv6.nsupdate.info/myip'},
'zoneedit' => {'url' => 'https://dynamic.zoneedit.com/checkip.html'}, 'zoneedit' => {'url' => 'https://dynamic.zoneedit.com/checkip.html'},
); );
my %builtinfw = ( our %builtinfw = (
'2wire' => { '2wire' => {
'name' => '2Wire 1701HG Gateway', 'name' => '2Wire 1701HG Gateway',
'url' => '/xslt?PAGE=B01', 'url' => '/xslt?PAGE=B01',
@ -429,21 +429,21 @@ my %variables = (
'ifv4' => setv(T_IF, 0, 0, 'default', undef), 'ifv4' => setv(T_IF, 0, 0, 'default', undef),
'ifv6' => setv(T_IF, 0, 0, 'default', undef), 'ifv6' => setv(T_IF, 0, 0, 'default', undef),
'web' => setv(T_STRING,0, 0, 'dyndns', undef), 'web' => setv(T_STRING,0, 0, 'dyndns', undef),
'web-skip' => setv(T_STRING,1, 0, '', undef), 'web-skip' => setv(T_STRING,0, 0, undef, undef),
'webv4' => setv(T_STRING,0, 0, 'ipify-ipv4', undef), 'webv4' => setv(T_STRING,0, 0, 'ipify-ipv4', undef),
'webv4-skip' => setv(T_STRING,1, 0, '', undef), 'webv4-skip' => setv(T_STRING,0, 0, undef, undef),
'webv6' => setv(T_STRING,0, 0, 'ipify-ipv6', undef), 'webv6' => setv(T_STRING,0, 0, 'ipify-ipv6', undef),
'webv6-skip' => setv(T_STRING,1, 0, '', undef), 'webv6-skip' => setv(T_STRING,0, 0, undef, undef),
'fw' => setv(T_ANY, 0, 0, '', undef), 'fw' => setv(T_ANY, 0, 0, '', undef),
'fw-skip' => setv(T_STRING,1, 0, '', undef), 'fw-skip' => setv(T_STRING,0, 0, undef, undef),
'fwv4' => setv(T_ANY, 0, 0, '', undef), 'fwv4' => setv(T_ANY, 0, 0, '', undef),
'fwv4-skip' => setv(T_STRING,1, 0, '', undef), 'fwv4-skip' => setv(T_STRING,0, 0, undef, undef),
'fwv6' => setv(T_ANY, 0, 0, '', undef), 'fwv6' => setv(T_ANY, 0, 0, '', undef),
'fwv6-skip' => setv(T_STRING,1, 0, '', undef), 'fwv6-skip' => setv(T_STRING,0, 0, undef, undef),
'fw-login' => setv(T_LOGIN, 1, 0, '', undef), 'fw-login' => setv(T_LOGIN, 1, 0, '', undef),
'fw-password' => setv(T_PASSWD,1, 0, '', undef), 'fw-password' => setv(T_PASSWD,1, 0, '', undef),
'cmd' => setv(T_PROG, 0, 0, '', undef), 'cmd' => setv(T_PROG, 0, 0, '', undef),
'cmd-skip' => setv(T_STRING,1, 0, '', undef), 'cmd-skip' => setv(T_STRING,0, 0, undef, undef),
'cmdv4' => setv(T_PROG, 0, 0, '', undef), 'cmdv4' => setv(T_PROG, 0, 0, '', undef),
'cmdv6' => setv(T_PROG, 0, 0, '', undef), 'cmdv6' => setv(T_PROG, 0, 0, '', undef),
@ -484,23 +484,23 @@ my %variables = (
'ifv4' => setv(T_IF, 0, 0, 'default', undef), 'ifv4' => setv(T_IF, 0, 0, 'default', undef),
'ifv6' => setv(T_IF, 0, 0, 'default', undef), 'ifv6' => setv(T_IF, 0, 0, 'default', undef),
'web' => setv(T_STRING,0, 0, 'dyndns', undef), 'web' => setv(T_STRING,0, 0, 'dyndns', undef),
'web-skip' => setv(T_STRING,0, 0, '', undef), 'web-skip' => setv(T_STRING,0, 0, undef, undef),
'web-ssl-validate' => setv(T_BOOL, 0, 0, 1, undef), 'web-ssl-validate' => setv(T_BOOL, 0, 0, 1, undef),
'webv4' => setv(T_STRING,0, 0, 'ipify-ipv4', undef), 'webv4' => setv(T_STRING,0, 0, 'ipify-ipv4', undef),
'webv4-skip' => setv(T_STRING,1, 0, '', undef), 'webv4-skip' => setv(T_STRING,0, 0, undef, undef),
'webv6' => setv(T_STRING,0, 0, 'ipify-ipv6', undef), 'webv6' => setv(T_STRING,0, 0, 'ipify-ipv6', undef),
'webv6-skip' => setv(T_STRING,1, 0, '', undef), 'webv6-skip' => setv(T_STRING,0, 0, undef, undef),
'fw' => setv(T_ANY, 0, 0, '', undef), 'fw' => setv(T_ANY, 0, 0, '', undef),
'fw-skip' => setv(T_STRING,0, 0, '', undef), 'fw-skip' => setv(T_STRING,0, 0, undef, undef),
'fw-login' => setv(T_LOGIN, 0, 0, '', undef), 'fw-login' => setv(T_LOGIN, 0, 0, '', undef),
'fw-password' => setv(T_PASSWD,0, 0, '', undef), 'fw-password' => setv(T_PASSWD,0, 0, '', undef),
'fw-ssl-validate' => setv(T_BOOL, 0, 0, 1, undef), 'fw-ssl-validate' => setv(T_BOOL, 0, 0, 1, undef),
'fwv4' => setv(T_ANY, 0, 0, '', undef), 'fwv4' => setv(T_ANY, 0, 0, '', undef),
'fwv4-skip' => setv(T_STRING,1, 0, '', undef), 'fwv4-skip' => setv(T_STRING,0, 0, undef, undef),
'fwv6' => setv(T_ANY, 0, 0, '', undef), 'fwv6' => setv(T_ANY, 0, 0, '', undef),
'fwv6-skip' => setv(T_STRING,1, 0, '', undef), 'fwv6-skip' => setv(T_STRING,0, 0, undef, undef),
'cmd' => setv(T_PROG, 0, 0, '', undef), 'cmd' => setv(T_PROG, 0, 0, '', undef),
'cmd-skip' => setv(T_STRING,0, 0, '', undef), 'cmd-skip' => setv(T_STRING,0, 0, undef, undef),
'cmdv4' => setv(T_PROG, 0, 0, '', undef), 'cmdv4' => setv(T_PROG, 0, 0, '', undef),
'cmdv6' => setv(T_PROG, 0, 0, '', undef), 'cmdv6' => setv(T_PROG, 0, 0, '', undef),
@ -2728,19 +2728,19 @@ sub get_ip {
} elsif ($use eq 'cmd') { } elsif ($use eq 'cmd') {
if ($arg) { if ($arg) {
$skip = opt('cmd-skip', $h) // ''; $skip = opt('cmd-skip', $h);
$reply = `$arg`; $reply = `$arg`;
$reply = '' if $?; $reply = '' if $?;
} }
} elsif ($use eq 'web') { } elsif ($use eq 'web') {
$url = opt('web', $h) // ''; $url = opt('web', $h) // '';
$skip = opt('web-skip', $h) // ''; $skip = opt('web-skip', $h);
if (exists $builtinweb{$url}) { if (exists $builtinweb{$url}) {
warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains'); warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains');
$skip = $builtinweb{$url}->{'skip'} unless $skip; $skip //= $builtinweb{$url}->{'skip'};
$url = $builtinweb{$url}->{'url'}; $url = $builtinweb{$url}->{'url'};
} }
$arg = $url; $arg = $url;
@ -2758,7 +2758,7 @@ sub get_ip {
# User fw-login should only have level 1 access to prevent # User fw-login should only have level 1 access to prevent
# password theft. This is pretty harmless. # password theft. This is pretty harmless.
my $queryif = opt('if', $h); my $queryif = opt('if', $h);
$skip = opt('fw-skip', $h) // ''; $skip = opt('fw-skip', $h);
# Convert slashes to protected value "\/" # Convert slashes to protected value "\/"
$queryif =~ s%\/%\\\/%g; $queryif =~ s%\/%\\\/%g;
@ -2781,7 +2781,7 @@ sub get_ip {
# User fw-login should only have level 1 access to prevent # User fw-login should only have level 1 access to prevent
# password theft. This is pretty harmless. # password theft. This is pretty harmless.
my $queryif = opt('if', $h); my $queryif = opt('if', $h);
$skip = opt('fw-skip', $h) // ''; $skip = opt('fw-skip', $h);
# Convert slashes to protected value "\/" # Convert slashes to protected value "\/"
$queryif =~ s%\/%\\\/%g; $queryif =~ s%\/%\\\/%g;
@ -2807,10 +2807,10 @@ sub get_ip {
# Note that --use=firewallname uses --fw=arg, not --firewallname=arg. # Note that --use=firewallname uses --fw=arg, not --firewallname=arg.
$arg = opt('fw', $h) // ''; $arg = opt('fw', $h) // '';
$url = $arg; $url = $arg;
$skip = opt('fw-skip', $h) // ''; $skip = opt('fw-skip', $h);
if (exists $builtinfw{$use}) { if (exists $builtinfw{$use}) {
$skip = $builtinfw{$use}->{'skip'} unless $skip; $skip //= $builtinfw{$use}->{'skip'};
$url = "http://${url}" . $builtinfw{$use}->{'url'} unless $url =~ /\//; $url = "http://${url}" . $builtinfw{$use}->{'url'} unless $url =~ /\//;
} }
@ -3152,7 +3152,7 @@ sub get_ipv4 {
my $ipv4 = undef; ## Found IPv4 address my $ipv4 = undef; ## Found IPv4 address
my $reply = ''; ## Text returned from various methods my $reply = ''; ## Text returned from various methods
my $url = ''; ## URL of website or firewall my $url = ''; ## URL of website or firewall
my $skip = ''; ## Regex of pattern to skip before looking for IP 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') { if ($usev4 eq 'ipv4') {
@ -3180,11 +3180,11 @@ sub get_ipv4 {
} elsif ($usev4 eq 'webv4') { } elsif ($usev4 eq 'webv4') {
## Obtain IPv4 address by accessing website at url in "webv4=<url>" ## Obtain IPv4 address by accessing website at url in "webv4=<url>"
$url = $arg; $url = $arg;
$skip = opt('webv4-skip', $h) // ''; $skip = opt('webv4-skip', $h);
if (exists $builtinweb{$url}) { if (exists $builtinweb{$url}) {
warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains'); warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains');
$skip = $builtinweb{$url}->{'skip'} unless $skip; $skip //= $builtinweb{$url}->{'skip'};
$url = $builtinweb{$url}->{'url'}; $url = $builtinweb{$url}->{'url'};
$arg = $url; $arg = $url;
} }
@ -3207,7 +3207,7 @@ sub get_ipv4 {
warning("'--fw-skip' is deprecated for '--usev4=$usev4'; use '--fwv4-skip' instead") warning("'--fw-skip' is deprecated for '--usev4=$usev4'; use '--fwv4-skip' instead")
if (!defined(opt('fwv4-skip', $h)) && defined(opt('fw-skip', $h))); if (!defined(opt('fwv4-skip', $h)) && defined(opt('fw-skip', $h)));
my $queryif = opt('ifv4', $h) // opt('if', $h); my $queryif = opt('ifv4', $h) // opt('if', $h);
$skip = opt('fwv4-skip', $h) // opt('fw-skip', $h) // ''; $skip = opt('fwv4-skip', $h) // opt('fw-skip', $h);
# Convert slashes to protected value "\/" # Convert slashes to protected value "\/"
$queryif =~ s%\/%\\\/%g; $queryif =~ s%\/%\\\/%g;
# Protect special HTML characters (like '?') # Protect special HTML characters (like '?')
@ -3239,10 +3239,10 @@ sub get_ipv4 {
# Note that --usev4=firewallname uses --fwv4=arg (or --fw=arg), not --firewallname=arg. # 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; $url = $arg;
$skip = opt('fwv4-skip', $h) // opt('fw-skip', $h) // ''; $skip = opt('fwv4-skip', $h) // opt('fw-skip', $h);
if (exists $builtinfw{$usev4}) { if (exists $builtinfw{$usev4}) {
$skip = $builtinfw{$usev4}->{'skip'} unless $skip; $skip //= $builtinfw{$usev4}->{'skip'};
$url = "http://${url}" . $builtinfw{$usev4}->{'url'} unless $url =~ /\//; $url = "http://${url}" . $builtinfw{$usev4}->{'url'} unless $url =~ /\//;
} }
if ($url) { if ($url) {
@ -3282,7 +3282,7 @@ sub get_ipv6 {
my $ipv6 = undef; ## Found IPv6 address my $ipv6 = undef; ## Found IPv6 address
my $reply = ''; ## Text returned from various methods my $reply = ''; ## Text returned from various methods
my $url = ''; ## URL of website or firewall my $url = ''; ## URL of website or firewall
my $skip = ''; ## Regex of pattern to skip before looking for IP 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') { if ($usev6 eq 'ipv6' || $usev6 eq 'ip') {
@ -3328,11 +3328,11 @@ sub get_ipv6 {
warning("'--web-skip' ignored for '--usev6=$usev6'; use '--webv6-skip' instead") warning("'--web-skip' ignored for '--usev6=$usev6'; use '--webv6-skip' instead")
if (!defined(opt('webv6-skip', $h)) && defined(opt('web-skip', $h))); if (!defined(opt('webv6-skip', $h)) && defined(opt('web-skip', $h)));
$url = $arg; $url = $arg;
$skip = opt('webv6-skip', $h) // ''; $skip = opt('webv6-skip', $h);
if (exists $builtinweb{$url}) { if (exists $builtinweb{$url}) {
warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains'); warning("googledomains is deprecated! See https://github.com/ddclient/ddclient/issues/622 for more info.") if ($url eq 'googledomains');
$skip = $builtinweb{$url}->{'skip'} unless $skip; $skip //= $builtinweb{$url}->{'skip'};
$url = $builtinweb{$url}->{'url'}; $url = $builtinweb{$url}->{'url'};
$arg = $url; $arg = $url;
} }

167
t/skip.pl Normal file
View file

@ -0,0 +1,167 @@
use Test::More;
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);
};
sub run_httpd {
my ($ipv6) = @_;
return undef if $ipv6 && (!$ipv6_supported || !$http_daemon_supports_ipv6);
my $httpd = ddclient::Test::Fake::HTTPD->new(
host => $ipv6 ? '::1' : '127.0.0.1',
scheme => 'http',
daemon_args => {V6Only => 1},
);
my $out = $ipv6 ? '::1 skip ::2' : '127.0.0.1 skip 127.0.0.2';
$httpd->run(sub {
return [200, ['Content-Type' => 'text/plain'], [$out]];
});
diag(sprintf("started IPv%s SSL server running at %s", $ipv6 ? '6' : '4', $httpd->endpoint()));
return $httpd;
}
my %httpd = (
'4' => run_httpd(0),
'6' => run_httpd(1),
);
my $builtinwebv4 = 't/skip.pl webv4';
my $builtinwebv6 = 't/skip.pl webv6';
my $builtinfw = 't/skip.pl fw';
$ddclient::builtinweb{$builtinwebv4} = {'url' => $httpd{'4'}->endpoint(), 'skip' => 'skip'};
$ddclient::builtinweb{$builtinwebv6} = {'url' => $httpd{'6'}->endpoint(), 'skip' => 'skip'}
if $httpd{'6'};
$ddclient::builtinfw{$builtinfw} = {name => 'test', skip => 'skip'};
%ddclient::builtinfw if 0; # suppress spurious warning "Name used only once: possible typo"
sub run_test_case {
my %tc = @_;
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;
my $h = 't/skip.pl';
$ddclient::config{$h} = $tc{cfg};
%ddclient::config if 0; # suppress spurious warning "Name used only once: possible typo"
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});
}
}
subtest "use=web web='$builtinwebv4'" => sub {
run_test_case(
desc => "web-skip='' cancels built-in skip",
cfg => {
'use' => 'web',
'web' => $builtinwebv4,
'web-skip' => '',
},
want => '127.0.0.1',
);
run_test_case(
desc => 'web-skip=undef uses built-in skip',
cfg => {
'use' => 'web',
'web' => $builtinwebv4,
'web-skip' => undef,
},
want => '127.0.0.2',
);
};
subtest "usev4=webv4 webv4='$builtinwebv4'" => sub {
run_test_case(
desc => "webv4-skip='' cancels built-in skip",
cfg => {
'usev4' => 'webv4',
'webv4' => $builtinwebv4,
'webv4-skip' => '',
},
want => '127.0.0.1',
);
run_test_case(
desc => 'webv4-skip=undef uses built-in skip',
cfg => {
'usev4' => 'webv4',
'webv4' => $builtinwebv4,
'webv4-skip' => undef,
},
want => '127.0.0.2',
);
};
subtest "usev6=webv6 webv6='$builtinwebv6'" => sub {
run_test_case(
desc => "webv6-skip='' cancels built-in skip",
cfg => {
'usev6' => 'webv6',
'webv6' => $builtinwebv6,
'webv6-skip' => '',
},
ipv6 => 1,
want => '::1',
);
run_test_case(
desc => 'webv6-skip=undef uses built-in skip',
cfg => {
'usev6' => 'webv6',
'webv6' => $builtinwebv6,
'webv6-skip' => undef,
},
ipv6 => 1,
want => '::2',
);
};
subtest "use='$builtinfw'" => sub {
run_test_case(
desc => "fw-skip='' cancels built-in skip",
cfg => {
'fw' => $httpd{'4'}->endpoint(),
'fw-skip' => '',
'use' => $builtinfw,
},
want => '127.0.0.1',
);
run_test_case(
desc => 'fw-skip=undef uses built-in skip',
cfg => {
'fw' => $httpd{'4'}->endpoint(),
'fw-skip' => undef,
'use' => $builtinfw,
},
want => '127.0.0.2',
);
};
subtest "usev4='$builtinfw'" => sub {
run_test_case(
desc => "fwv4-skip='' cancels built-in skip",
cfg => {
'fwv4' => $httpd{'4'}->endpoint(),
'fwv4-skip' => '',
'usev4' => $builtinfw,
},
want => '127.0.0.1',
);
run_test_case(
desc => 'fwv4-skip=undef uses built-in skip',
cfg => {
'fwv4' => $httpd{'4'}->endpoint(),
'fwv4-skip' => undef,
'usev4' => $builtinfw,
},
want => '127.0.0.2',
);
};
done_testing();