Package: ddclient Version: 3.8.3-1.1 Severity: wishlist Tags: patch CloudFlare has announced that the old API that is used by standard ddclient is going and everyone needs to go to API version 4. There is a patch in a fork for ddclient that does this new API[1]
I've merely merged this into the Debian package, full credit to Harry Xue. I've applied it and it seems to be doing the right thing. I'd send the output from ddclient in foreground but I'm not sure what is key material. - Craig 1: https://github.com/wimpunk/ddclient/pull/42 -- System Information: Debian Release: stretch/sid APT prefers unstable APT policy: (500, 'unstable') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 4.6.0-1-amd64 (SMP w/6 CPU cores) Locale: LANG=en_AU.UTF-8, LC_CTYPE=en_AU.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages ddclient depends on: ii debconf [debconf-2.0] 1.5.59 ii lsb-base 9.20160629 ii perl 5.22.2-3 Versions of packages ddclient recommends: ii libio-socket-ssl-perl 2.033-1 ddclient suggests no packages. -- debconf information excluded -- debsums errors found: debsums: changed file /usr/sbin/ddclient (from ddclient package)
diff --git a/debian/changelog b/debian/changelog index 1268b2e..e6e7ea9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,9 @@ ddclient (3.8.3-2) UNRELEASED; urgency=medium * Bump Standards-Version to 3.9.8 (no changes required) * Update Vcs-Browser, Vcd-Git to use https URLs + [ Craig Small ] + * Update CloudFlare API to v4 + -- Martin Pitt <[email protected]> Wed, 22 Jun 2016 17:44:54 +0200 ddclient (3.8.3-1) unstable; urgency=medium diff --git a/debian/patches/cloudflare-api-v4.diff b/debian/patches/cloudflare-api-v4.diff new file mode 100644 index 0000000..9f46575 --- /dev/null +++ b/debian/patches/cloudflare-api-v4.diff @@ -0,0 +1,152 @@ +Description: Update CloudFlare API to v4 +Author: Harry-Xue on Github +Origin: upstream, https://github.com/wimpunk/ddclient/pull/42 +Reviewed-by: Craig Small <[email protected]> +Last-Update: 2016-08-01 +--- a/ddclient ++++ b/ddclient +@@ -448,7 +448,7 @@ + 'zone' => setv(T_STRING, 1, 1, 1, '', undef), + }, + 'cloudflare-common-defaults' => { +- 'server' => setv(T_FQDNP, 1, 0, 1, 'www.cloudflare.com', undef), ++ 'server' => setv(T_FQDNP, 1, 0, 1, 'api.cloudflare.com/client/v4', undef), + 'zone' => setv(T_FQDN, 1, 0, 1, '', undef), + 'static' => setv(T_BOOL, 0, 1, 1, 0, undef), + 'wildcard' => setv(T_BOOL, 0, 1, 1, 0, undef), +@@ -621,7 +621,7 @@ + 'update' => \&nic_cloudflare_update, + 'examples' => \&nic_cloudflare_examples, + 'variables' => merge( +- { 'server' => setv(T_FQDNP, 1, 0, 1, 'www.cloudflare.com', undef) }, ++ { 'server' => setv(T_FQDNP, 1, 0, 1, 'api.cloudflare.com/client/v4', undef) }, + { 'min-interval' => setv(T_DELAY, 0, 0, 1, interval('5m'), 0),}, + $variables{'cloudflare-common-defaults'}, + $variables{'service-common-defaults'}, +@@ -1924,6 +1924,9 @@ + my $url = shift || ''; + my $login = shift || ''; + my $password = shift || ''; ++ my $headers = shift || ''; ++ my $method = shift || 'GET'; ++ my $data = shift || ''; + my ($peer, $server, $port, $default_port, $use_ssl); + my ($sd, $rq, $request, $reply); + +@@ -1964,7 +1967,7 @@ + my $to = sprintf "%s%s", $server, $proxy ? " via proxy $peer:$port" : ""; + verbose("CONNECT:", "%s", $to); + +- $request = "GET "; ++ $request = "$method "; + $request .= "http://$server" if $proxy; + $request .= "/$url HTTP/1.0\n"; + $request .= "Host: $server\n"; +@@ -1973,7 +1976,10 @@ + $request .= "Authorization: Basic $auth\n" if $login || $password; + $request .= "User-Agent: ${program}/${version}\n"; + $request .= "Connection: close\n"; ++ $request .= "$headers\n"; ++ $request .= "Content-Length: ".length($data)."\n" if $data; + $request .= "\n"; ++ $request .= $data; + + ## make sure newlines are <cr><lf> for some pedantic proxy servers + ($rq = $request) =~ s/\n/\r\n/g; +@@ -4102,7 +4108,7 @@ + + Configuration variables applicable to the 'cloudflare' protocol are: + protocol=cloudflare ## +- server=fqdn.of.service ## defaults to www.cloudflare.com ++ server=fqdn.of.service ## defaults to api.cloudflare.com/client/v4 + login=service-login ## login name and password registered with the service + password=service-password ## + fully.qualified.host ## the host registered with the service. +@@ -4139,6 +4145,10 @@ + my $key = $hosts[0]; + my $ip = $config{$key}{'wantip'}; + ++ my $headers = "X-Auth-Email: $config{$key}{'login'}\n"; ++ $headers .= "X-Auth-Key: $config{$key}{'password'}\n"; ++ $headers .= "Content-Type: application/json"; ++ + # FQDNs + for my $domain (@hosts) { + (my $hostname = $domain) =~ s/\.$config{$key}{zone}$//; +@@ -4146,14 +4156,11 @@ + + info("setting IP address to %s for %s", $ip, $domain); + verbose("UPDATE:","updating %s", $domain); ++ # Get zone ID ++ my $url = "https://$config{$key}{'server'}/zones?"; ++ $url .= "name=".$config{$key}{'zone'}; + +- # Get domain ID +- my $url = "https://$config{$key}{'server'}/api_json.html?a=rec_load_all"; +- $url .= "&z=".$config{$key}{'zone'}; +- $url .= "&email=".$config{$key}{'login'}; +- $url .= "&tkn=".$config{$key}{'password'}; +- +- my $reply = geturl(opt('proxy'), $url); ++ my $reply = geturl(opt('proxy'), $url, undef, undef, $headers); + unless ($reply) { + failed("updating %s: Could not connect to %s.", $domain, $config{$key}{'server'}); + last; +@@ -4169,23 +4176,44 @@ + } + + # Pull the ID out of the json, messy +- my ($id) = map { $_->{name} eq $domain ? $_->{rec_id} : () } @{ $response->{response}->{recs}->{objs} }; +- unless($id) { +- failed("updating %s: No domain ID found.", $domain); ++ my ($zone_id) = map { $_->{name} eq $config{$key}{'zone'} ? $_->{id} : () } @{ $response->{result} }; ++ unless($zone_id) { ++ failed("updating %s: No zone ID found.", $config{$key}{'zone'}); + next; + } ++ info("zone ID is $zone_id"); + +- # Set domain +- $url = "https://$config{$key}{'server'}/api_json.html?a=rec_edit&type=A&ttl=1"; +- $url .= "&name=$hostname"; +- $url .= "&z=".$config{$key}{'zone'}; +- $url .= "&id=".$id; +- $url .= "&email=".$config{$key}{'login'}; +- $url .= "&tkn=".$config{$key}{'password'}; +- $url .= "&content="; +- $url .= "$ip" if $ip; ++ # Get DNS record ID ++ $url = "https://$config{$key}{'server'}/zones/$zone_id/dns_records?"; ++ $url .= "type=A&name=$domain"; + +- $reply = geturl(opt('proxy'), $url); ++ $reply = geturl(opt('proxy'), $url, undef, undef, $headers); ++ unless ($reply) { ++ failed("updating %s: Could not connect to %s.", $domain, $config{$key}{'server'}); ++ last; ++ } ++ last if !header_ok($domain, $reply); ++ ++ # Strip header ++ $reply =~ s/^.*?\n\n//s; ++ $response = JSON::Any->jsonToObj($reply); ++ if ($response->{result} eq 'error') { ++ failed ("%s", $response->{msg}); ++ next; ++ } ++ ++ # Pull the ID out of the json, messy ++ my ($dns_rec_id) = map { $_->{name} eq $domain ? $_->{id} : () } @{ $response->{result} }; ++ unless($dns_rec_id) { ++ failed("updating %s: No DNS record ID found.", $domain); ++ next; ++ } ++ info("DNS record ID is $dns_rec_id"); ++ ++ # Set domain ++ $url = "https://$config{$key}{'server'}/zones/$zone_id/dns_records/$dns_rec_id"; ++ my $data = "{\"content\":\"$ip\"}"; ++ $reply = geturl(opt('proxy'), $url, undef, undef, $headers, "PATCH", $data); + unless ($reply) { + failed("updating %s: Could not connect to %s.", $domain, $config{$domain}{'server'}); + last; diff --git a/debian/patches/series b/debian/patches/series index d096468..0fe4a5e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,3 +2,4 @@ smc-barricade-fw-alt.diff config_path.diff maxinterval.diff usev6.diff +cloudflare-api-v4.diff

