From af1332264faf0af77e5f7301b0b1479c7e5bb122 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 1/6] Delete unnecessary address check `get_ip` is guaranteed to return a valid IP address or `undef`. --- ddclient.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 2491858..9a1313f 100755 --- a/ddclient.in +++ b/ddclient.in @@ -984,12 +984,6 @@ sub update_nics { if !$daemon || opt('verbose'); next; } - if (!is_ipv4($ip)) { - if (!extract_ipv6($ip)) { - warning("malformed IP address (%s)", $ip); - next; - } - } $iplist{$use}{$arg_ip}{$arg_fw}{$arg_if}{$arg_web}{$arg_cmd} = $ip; } $config{$h}{'wantip'} = $ip; From fe513f733d7ee87597700849d25483119408b17f Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 2/6] Use `is_ipv6`, not `extract_ipv6`, to validate IPv6 address --- ddclient.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9a1313f..36bda0d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -1930,9 +1930,7 @@ sub check_value { return undef if $value eq ""; } elsif ($type eq T_IP) { - if (!extract_ipv6($value)) { - return undef if !is_ipv4($value); - } + return undef if !is_ipv4($value) && !is_ipv6($value); } return $value; } From ab0a4597cee3632125aa14d72ead888e6596d7f5 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 3/6] Validate the `ip` setting --- ddclient.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ddclient.in b/ddclient.in index 36bda0d..d446146 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2212,6 +2212,10 @@ 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); + $ip = undef; + } $arg = 'ip'; } elsif ($use eq 'if') { From 5da22a8a6991ca6de15fd86196b2d1c8f2b947bd Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 4/6] Implement `is_ipv6` in terms of `extract_ivp6` --- ddclient.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddclient.in b/ddclient.in index d446146..2e2058d 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2347,12 +2347,12 @@ sub extract_ipv4 { } ###################################################################### -## is_ipv6() validates if string is valid IPv6 address +## is_ipv6() validates if string is valid IPv6 address with no preceding +## or trailing spaces/characters. ###################################################################### sub is_ipv6 { my ($value) = @_; - # This little gem from http://home.deds.nl/~aeron/regex/ - return $value =~ /^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/ai; + return (length($value // '') != 0) && ((extract_ipv6($value) // '') eq $value); } ###################################################################### From 0a999577c7005e76855b5acedc51fc4014cb7d24 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 5/6] Simplify the IPv4 regular expression --- ddclient.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 2e2058d..9883d31 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2342,7 +2342,7 @@ sub is_ipv4 { ## extract_ipv4() extracts the first valid IPv4 address from the given string ###################################################################### sub extract_ipv4 { - (shift // '') =~ /\b((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\b/ai; + (shift // '') =~ /\b((?:(?25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?&octet))\b/a; return $1; } From 36d8b511b37ec981700330ccc3dd795a8b708989 Mon Sep 17 00:00:00 2001 From: David Kerr Date: Tue, 30 Jun 2020 13:29:10 -0400 Subject: [PATCH 6/6] Move `un_zero_pad` into `extract_ipv4`, `extract_ipv6` This also causes `is_ipv4` to reject IPv4 addresses with leading zeros. --- ddclient.in | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9883d31..90a2f96 100755 --- a/ddclient.in +++ b/ddclient.in @@ -2181,26 +2181,7 @@ sub geturl { $reply =~ s/\r//g if defined $reply; return $reply; } -###################################################################### -## un_zero_pad -###################################################################### -sub un_zero_pad { - my $in_str = shift(@_); - my @out_str = (); - if ($in_str eq '0.0.0.0') { - return $in_str; - } - - foreach my $block (split /\./, $in_str) { - $block =~ s/^0+//; - if ($block eq '') { - $block = '0'; - } - push @out_str, $block; - } - return join('.', @out_str); -} ###################################################################### ## get_ip ###################################################################### @@ -2312,15 +2293,8 @@ sub get_ip { $skip =~ s/ /\\s/is; $reply =~ s/^.*?${skip}//is; } - if (defined($ip)) { - # no need to parse $reply - } elsif ($ip = extract_ipv4($reply)) { - $ip = un_zero_pad($ip); - } elsif ($ip = extract_ipv6($reply)) { - $ip = un_zero_pad($ip); - } else { - warning("found neither ipv4 nor ipv6 address"); - } + $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; } @@ -2330,8 +2304,9 @@ sub get_ip { } ###################################################################### -## is_ipv4() validates if string is valid IPv4 address and only -## a valid IPv4 address (no preceding or trailing spaces/characters) +## is_ipv4() validates if string is valid IPv4 address and only a +## valid address with no preceding or trailing spaces/characters +## and no embedded leading zeros. ###################################################################### sub is_ipv4 { my ($value) = @_; @@ -2339,11 +2314,14 @@ sub is_ipv4 { } ###################################################################### -## extract_ipv4() extracts the first valid IPv4 address from the given string +## extract_ipv4() extracts the first valid IPv4 address from given string. +## Accepts leading zeros in the address but removes them in returned value ###################################################################### sub extract_ipv4 { - (shift // '') =~ /\b((?:(?25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?&octet))\b/a; - return $1; + (shift // '') =~ /\b((?:(?25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?&octet))\b/a + or return undef; + (my $ip = $1) =~ s/\b0+\B//g; ## remove embedded leading zeros + return $ip; } ###################################################################### @@ -2352,11 +2330,13 @@ sub extract_ipv4 { ###################################################################### sub is_ipv6 { my ($value) = @_; - return (length($value // '') != 0) && ((extract_ipv6($value) // '') eq $value); + return (length($value // '') != 0) && + ((extract_ipv6($value) // '') eq (($value =~ s/\b0+\B//g) ? $value : $value)); } ###################################################################### -## extract_ipv6() extracts the first valid IPv6 address from the given string +## extract_ipv6() extracts the first valid IPv6 address from the given string. +## Accepts leading zeros in the address but removes them in returned value. ###################################################################### sub extract_ipv6 { my $content = shift; @@ -2378,6 +2358,7 @@ sub extract_ipv6 { next } } + $parsed =~ s/\b0+\B//g; ## remove embedded leading zeros return $parsed; } return;