Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ayr-ton/f6db56f15ab083ab6b55 to your computer and use it in GitHub Desktop.
Save ayr-ton/f6db56f15ab083ab6b55 to your computer and use it in GitHub Desktop.
--- 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/[email protected]> 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__

Description

Dyn's free dynamic DNS service will be ending on Wednesday, May 7th, 2014.

CloudFlare, however, has a little known feature that will allow you to update your DNS records via API or a command line script called ddclient. This will give you the same result, and it's also free.

Unfortunately, ddclient does not work with CloudFlare out of the box. There is a patch available and here is how to hack[1] it up on Debian or Ubuntu, also works in Raspbian with Raspberry Pi.

Requirements

basic command line skills, and a domain name that you own.

CloudFlare

Sign up to CloudFlare and add your domain name. Follow the instructions, the default values it gives should be fine.

You'll be letting CloudFlare host your domain so you need to adjust the settings at your registrar.

If you'd like to use a subdomain, add an 'A' record for it. Any IP address will do for now.

Let's get to business...

Installation

$ sudo apt-get install ddclient

Patch

$ sudo apt-get install curl sendmail libjson-any-perl libio-socket-ssl-perl
$ curl -O http://blog.peter-r.co.uk/uploads/ddclient-3.8.0-cloudflare-22-6-2014.patch 
$ sudo patch /usr/sbin/ddclient < ddclient-3.8.0-cloudflare-22-6-2014.patch

Config

$ sudo vi /etc/ddclient.conf

Add:

##
### CloudFlare (cloudflare.com)
###
ssl=yes
use=web, web=dyndns
protocol=cloudflare, \
server=www.cloudflare.com, \
zone=domain.com, \
[email protected], \
password=api-key \
host.domain.com

Comment out:

#daemon=300

Your api-key comes from the account page
ssl=yes might already be in that file
use=web, web=dyndns will use dyndns to check IP (useful for NAT)

You're done. Log in to https://www.cloudflare.com and check that the IP listed for your domain matches http://checkip.dyndns.com

To verify your settings:

sudo ddclient -daemon=0 -debug -verbose -noquiet
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment