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

Reply via email to