Created
August 16, 2014 21:02
-
-
Save sjlu/f642da315be9751eee48 to your computer and use it in GitHub Desktop.
CloudFlare ddclient patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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