Skip to content

Instantly share code, notes, and snippets.

@sjlu
Created August 16, 2014 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sjlu/f642da315be9751eee48 to your computer and use it in GitHub Desktop.
Save sjlu/f642da315be9751eee48 to your computer and use it in GitHub Desktop.
CloudFlare ddclient patch
--- ddclient.orig 2013-09-26 01:06:12.399990673 +0100
+++ ddclient 2013-09-26 06:25:36.768189452 +0100
@@ -13,12 +13,17 @@
# Support for multiple IP numbers added by
# Astaro AG, Ingo Schwarze <ischwarze-OOs/4mkCeqbQT0dZR+AlfA@public.gmane.org> September 16, 2008
#
+# Modified to work with Cloudflare by Robert Ian Hawdon 2012-07-16: http://robertianhawdon.me.uk/
+#
+# Further modified to work with Cloudflare by Peter Roberts 2013-9-26, 2014-6-22: blog.peter-r.co.uk
+#
######################################################################
-require 5.004;
+require 5.014;
use strict;
use Getopt::Long;
use Sys::Hostname;
use IO::Socket;
+use JSON::Any;
my $version = "3.8.0";
my $programd = $0;
@@ -416,6 +421,14 @@
'warned-min-interval' => setv(T_ANY, 0, 1, 0, 0, undef),
'warned-min-error-interval' => setv(T_ANY, 0, 1, 0, 0, undef),
},
+ 'cloudflare-common-defaults' => {
+ 'server' => setv(T_FQDNP, 1, 0, 1, 'www.cloudflare.com', 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),
+ 'mx' => setv(T_OFQDN, 0, 1, 1, '', undef),
+ 'backupmx' => setv(T_BOOL, 0, 1, 1, 0, undef),
+ },
);
my %services = (
'dyndns1' => {
@@ -529,6 +542,17 @@
$variables{'service-common-defaults'},
),
},
+ 'cloudflare' => {
+ 'updateable' => undef,
+ 'update' => \&nic_cloudflare_update,
+ 'examples' => \&nic_cloudflare_examples,
+ 'variables' => merge(
+ { 'server' => setv(T_FQDNP, 1, 0, 1, 'www.cloudflare.com', undef) },
+ { 'min-interval' => setv(T_DELAY, 0, 0, 1, interval('5m'), 0),},
+ $variables{'cloudflare-common-defaults'},
+ $variables{'service-common-defaults'},
+ ),
+ },
);
$variables{'merged'} = merge($variables{'global-defaults'},
$variables{'service-common-defaults'},
@@ -3386,7 +3410,128 @@
}
######################################################################
-# vim: ai ts=4 sw=4 tw=78 :
+######################################################################
+## nic_cloudflare_examples
+##
+## written by Ian Pye
+##
+######################################################################
+sub nic_cloudflare_examples {
+ return <<EoEXAMPLE;
+o 'cloudflare'
+
+The 'cloudflare' protocol is used by DNS service offered by www.cloudflare.com.
+
+Configuration variables applicable to the 'cloudflare' protocol are:
+ protocol=cloudflare ##
+ server=fqdn.of.service ## defaults to www.cloudflare.com
+ zone=dns.zone ## your domain
+ login=service-login ## login name and password registered with the service
+ password=service-password ##
+ fully.qualified.host ## the host registered with the service.
+
+Example ${program}.conf file entries:
+ ## single host update
+ protocol=cloudflare,
+ zone=dns-zone, \\
+ login=my-cloudflare.com-login, \\
+ password=my-cloudflare.com-api-key \\
+ myhost.com
+
+ ## multiple host update to the custom DNS service
+ protocol=cloudflare,
+ zone=dns.zone \\
+ login=my-cloudflare.com-login, \\
+ password=my-cloudflare.com-api-key \\
+ my-toplevel-domain.com,my-other-domain.com
+EoEXAMPLE
+}
+######################################################################
+## nic_cloudflare_update
+######################################################################
+sub nic_cloudflare_update {
+ debug("\nnic_cloudflare_update -------------------");
+
+ ## group hosts with identical attributes together
+ my %groups = group_hosts_by([ @_ ], [ qw(ssh login password server wildcard mx backupmx zone) ]);
+
+ ## update each set of hosts that had similar configurations
+ foreach my $sig (keys %groups) {
+ my @hosts = @{$groups{$sig}};
+ my $hosts = join(',', @hosts);
+ my $key = $hosts[0];
+ my $ip = $config{$key}{'wantip'};
+
+ # FQDNs
+ for my $domain (@hosts) {
+ my $hostname = $domain =~ s/\.$config{$key}{zone}$//r;
+ delete $config{$domain}{'wantip'};
+
+ info("setting IP address to %s for %s", $ip, $domain);
+ verbose("UPDATE:","updating %s", $domain);
+
+ # 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);
+ 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;
+ my $response = JSON::Any->jsonToObj($reply);
+ if ($response->{result} eq 'error') {
+ failed ("%s", $response->{msg});
+ next;
+ }
+
+ # 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);
+ next;
+ }
+
+ # 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;
+
+ $reply = geturl(opt('proxy'), $url);
+ unless ($reply) {
+ failed("updating %s: Could not connect to %s.", $domain, $config{$domain}{'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});
+ } else {
+ success ("%s -- Updated Successfully to %s", $domain, $ip);
+
+ }
+
+ # Cache
+ $config{$key}{'ip'} = $ip;
+ $config{$key}{'mtime'} = $now;
+ $config{$key}{'status'} = 'good';
+ }
+ }
+}
__END__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment