Package: ddclient Version: 3.8.0-11.3 Severity: wishlist Tags: ipv6 patch A patch for 3.8.1 to support IPv6 on the two services I know that can handle it. Both dyndns and freedns automatically recognize the type of address being passed to them and use it to update the A or the AAAA record.
I added the "usev6" variable, that works exactly as the "use" one. So, if you are using dynds and use "usev6" instead of "use" on your existing definition *and* you have a global IPv6 address, then you're all set. For "usev6" only the "ip" and "if" strategies are implemented and the "if" one uses "ip -6 addr list" instead of "ifconfig" because I found it easier to parse. But upstream was concerned about portability so "ifconfig" should be used in the future. The patch has been in use for a year and a half in many installations with no problems reported. -- System Information: Debian Release: 6.0.6 APT prefers stable APT policy: (500, 'stable') Architecture: i386 (i686) Kernel: Linux 3.4.1 (SMP w/1 CPU core) Locale: LANG=es_UY.utf8, LC_CTYPE=es_UY.utf8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages ddclient depends on: ii debconf [debconf-2 1.5.36.1 Debian configuration management sy ii initscripts 2.88dsf-13.1+squeeze1 scripts for initializing and shutt ii lsb-base 3.2-23.2squeeze1 Linux Standard Base 3.2 init scrip ii perl [perl5] 5.10.1-17squeeze3 Larry Wall's Practical Extraction Versions of packages ddclient recommends: ii libio-socket-ssl-perl 1.33-1+squeeze1 Perl module implementing object or ddclient suggests no packages. -- debconf information excluded
--- ddclient 2011-07-11 18:04:21.000000000 -0300 +++ /usr/sbin/ddclient 2011-09-10 01:47:43.721029588 -0300 @@ -55,6 +55,7 @@ sub T_FQDNP {'fully qualified host name and optional port number'}; sub T_PROTO {'protocol'} sub T_USE {'ip strategy'} +sub T_USEV6 {'ipv6 strategy'} sub T_IF {'interface'} sub T_PROG {'program name'} sub T_IP {'ip'} @@ -325,6 +326,7 @@ 'protocol' => setv(T_PROTO, 0, 0, 1, 'dyndns2', undef), 'use' => setv(T_USE, 0, 0, 1, 'ip', undef), + 'usev6' => setv(T_USEV6, 0, 0, 1, undef, undef), 'ip' => setv(T_IP, 0, 0, 1, undef, undef), 'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef), 'if-skip' => setv(T_STRING,1, 0, 1, '', undef), @@ -365,6 +367,7 @@ 'host' => setv(T_STRING, 1, 1, 1, '', undef), 'use' => setv(T_USE, 0, 0, 1, 'ip', undef), + 'usev6' => setv(T_USE, 0, 0, 1, undef, undef), 'if' => setv(T_IF, 0, 0, 1, 'ppp0', undef), 'if-skip' => setv(T_STRING,0, 0, 1, '', undef), 'web' => setv(T_STRING,0, 0, 1, 'dyndns', undef), @@ -583,6 +586,7 @@ [ "pid", "=s", "-pid path : record process id in 'path'" ], "", [ "use", "=s", "-use which : how the should IP address be obtained." ], + [ "usev6", "=s", "-usev6 which : how the should IPv6 address be obtained." ], &ip_strategies_usage(), "", [ "ip", "=s", "-ip address : set the IP address to 'address'" ], @@ -769,11 +773,19 @@ my (@hosts, %ips) = (); my $updateable = $services{$s}{'updateable'}; my $update = $services{$s}{'update'}; + my $ipv6 = 0; foreach my $h (sort keys %config) { next if $config{$h}{'protocol'} ne lc($s); $examined{$h} = 1; - my $use = $config{$h}{'use'} || opt('use'); + my $use = ''; + $ipv6 = 1 if (defined $config{$h}{'usev6'}); + if ($ipv6) { + $use = $config{$h}{'usev6'} || opt('usev6'); + } + else { + $use = $config{$h}{'use'} || opt('use'); + } local $opt{$use} = $config{$h}{$use} if $config{$h}{$use}; # bug #13: we should only do this once # use isn't enough, we have to save the origin to. @@ -783,16 +795,21 @@ if (defined $iplist{$use}) { $ip = $iplist{$use}; } else { - $ip = get_ip($use, $h); + $ip = get_ip($use, $h) if !$ipv6; + $ip = get_ipv6($use, $h) if $ipv6; if (!defined $ip || !$ip) { warning("unable to determine IP address") if !$daemon || opt('verbose'); next; } - if ($ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { + if (!$ipv6 and $ip !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { warning("malformed IP address (%s)", $ip); next; } + if ($ipv6 and $ip !~ /^[0-9a-f:]+$/) { + warning("malformed IPv6 address (%s)", $ip); + next; + } $iplist{$use} = $ip; } $config{$h}{'wantip'} = $ip; @@ -933,7 +950,7 @@ my ($c, $name, $value); my ($escape, $quote) = (0, ''); - if ($rest =~ /^\s*([a-z][a-z_-]*)=(.*)/i) { + if ($rest =~ /^\s*([a-z][0-9a-z_-]*)=(.*)/i) { ($name, $rest, $value) = ($1, $2, ''); while (length($c = substr($rest,0,1))) { @@ -1111,6 +1128,11 @@ $opt{'use'} = 'if' if !define($opt{'use'}) && defined($opt{'if'}); $opt{'use'} = 'web' if !define($opt{'use'}) && defined($opt{'web'}); + ## infer the IPv6 strategy if possible + $opt{'usev6'} = 'ip' if !define($opt{'usev6'}) && defined($opt{'ip'}); + $opt{'usev6'} = 'if' if !define($opt{'usev6'}) && defined($opt{'if'}); + $opt{'usev6'} = 'web' if !define($opt{'usev6'}) && defined($opt{'web'}); + ## sanity check $opt{'max-interval'} = min(interval(opt('max-interval')), interval(default('max-interval'))); $opt{'min-interval'} = max(interval(opt('min-interval')), interval(default('min-interval'))); @@ -1720,6 +1742,10 @@ $value = lc $value; return undef if ! exists $ip_strategies{$value}; + } elsif ($type eq T_USEV6) { + $value = lc $value; + return undef if ! exists $ip_strategies{$value}; + } elsif ($type eq T_FILE) { return undef if $value eq ""; @@ -1736,7 +1762,7 @@ # return undef if $value =~ /:/; } elsif ($type eq T_IP) { - return undef if $value !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; + return undef if $value !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ and $value !~ /^[0-9a-f:]+$/; } return $value; } @@ -2020,6 +2046,42 @@ $ip = $1; } if (($use ne 'ip') && (define($ip,'') eq '0.0.0.0')) { + $ip = undef; + } + + debug("get_ip: using %s, %s reports %s", $use, $arg, define($ip, "<undefined>")); + return $ip; +} + +###################################################################### +## get_ipv6 +###################################################################### +sub get_ipv6 { + my $use = lc shift; + my $h = shift; + my ($ip, $arg, $reply, $url, $skip) = (undef, opt($use), ''); + $arg = '' unless $arg; + + if ($use eq 'ip') { + $ip = opt('ip', $h); + $arg = 'ip'; + + } elsif ($use eq 'if') { + $skip = opt('if-skip', $h) || ''; + $reply = `ip -6 addr list dev $arg | grep "scope.global" 2> /dev/null`; + $reply = '' if $?; + } + if (!defined $reply) { + $reply = ''; + } + if ($skip) { + $skip =~ s/ /\\s/is; + $reply =~ s/^.*?${skip}//is; + } + if ($reply =~ /.*? ([0-9:][^\/]*)/i) { + $ip = $1; + } + if (($use ne 'ip') && (define($ip,'') eq '0.0.0.0')) { $ip = undef; }