Added support for Cloudflare and multi domain support for namecheap

Pull request #7 from roberthawdon
See https://github.com/wimpunk/ddclient/pull/7 for more info.


git-svn-id: svn+ssh://svn.code.sf.net/p/ddclient/code/trunk@170 3873ddee-7413-0410-b6c4-c2c57c1ab35a
This commit is contained in:
wimpunk 2014-10-08 13:28:29 +00:00
parent a52ddf7492
commit e384564d12
3 changed files with 172 additions and 6 deletions

View file

@ -23,6 +23,7 @@ Dynamic DNS services currently supported include:
ChangeIP - See http://www.changeip.com/ for details ChangeIP - See http://www.changeip.com/ for details
dtdns - See http://www.dtdns.com/ for details dtdns - See http://www.dtdns.com/ for details
nsupdate - See nsupdate(1) and ddns-confgen(8) for details nsupdate - See nsupdate(1) and ddns-confgen(8) for details
CloudFlare - See https://www.cloudflare.com/ for defails
DDclient now supports many of cable/dsl broadband routers. DDclient now supports many of cable/dsl broadband routers.
@ -37,8 +38,9 @@ REQUIREMENTS:
- one or more accounts from one of the dynamic DNS services - one or more accounts from one of the dynamic DNS services
- Perl 5.004 or later - Perl 5.014 or later
(you need the IO::Socket::SSL perl library for ssl-support) (you need the IO::Socket::SSL perl library for ssl-support
and JSON::Any perl library for JSON support)
- Linux or probably any common Unix system - Linux or probably any common Unix system

162
ddclient
View file

@ -13,12 +13,19 @@
# Support for multiple IP numbers added by # Support for multiple IP numbers added by
# Astaro AG, Ingo Schwarze <ischwarze-OOs/4mkCeqbQT0dZR+AlfA@public.gmane.org> September 16, 2008 # Astaro AG, Ingo Schwarze <ischwarze-OOs/4mkCeqbQT0dZR+AlfA@public.gmane.org> September 16, 2008
# #
# Support for multiple domain support for Namecheap by Robert Ian Hawdon 2010-09-03: https://robertianhawdon.me.uk/
#
# Initial Cloudflare support by Ian Pye, updated by Robert Ian Hawdon 2012-07-16
# Further updates by Peter Roberts to support the new API 2013-09-26, 2014-06-22: http://blog.peter-r.co.uk/
#
#
###################################################################### ######################################################################
require 5.004; require 5.014;
use strict; use strict;
use Getopt::Long; use Getopt::Long;
use Sys::Hostname; use Sys::Hostname;
use IO::Socket; use IO::Socket;
use JSON::Any;
# my ($VERSION) = q$Revision$ =~ /(\d+)/; # my ($VERSION) = q$Revision$ =~ /(\d+)/;
@ -433,6 +440,14 @@ my %variables = (
'ttl' => setv(T_NUMBER, 0, 1, 0, 600, undef), 'ttl' => setv(T_NUMBER, 0, 1, 0, 600, undef),
'zone' => setv(T_STRING, 1, 1, 1, '', undef), 'zone' => setv(T_STRING, 1, 1, 1, '', 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 = ( my %services = (
'dyndns1' => { 'dyndns1' => {
@ -587,6 +602,17 @@ my %services = (
$variables{'service-common-defaults'}, $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{'merged'} = merge($variables{'global-defaults'},
$variables{'service-common-defaults'}, $variables{'service-common-defaults'},
@ -598,7 +624,7 @@ my @opt = (
"usage: ${program} [options]", "usage: ${program} [options]",
"options are:", "options are:",
[ "daemon", "=s", "-daemon delay : run as a daemon, specify delay as an interval." ], [ "daemon", "=s", "-daemon delay : run as a daemon, specify delay as an interval." ],
+ [ "foreground", "!", "-foreground : do not fork" ], [ "foreground", "!", "-foreground : do not fork" ],
[ "proxy", "=s", "-proxy host : use 'host' as the HTTP proxy" ], [ "proxy", "=s", "-proxy host : use 'host' as the HTTP proxy" ],
[ "server", "=s", "-server host : update DNS information on 'host'" ], [ "server", "=s", "-server host : update DNS information on 'host'" ],
[ "protocol", "=s", "-protocol type : update protocol used" ], [ "protocol", "=s", "-protocol type : update protocol used" ],
@ -3407,8 +3433,11 @@ sub nic_namecheap_update {
my $url; my $url;
$url = "http://$config{$h}{'server'}/update"; $url = "http://$config{$h}{'server'}/update";
$url .= "?host=$h"; my $domain = $config{$h}{'login'};
$url .= "&domain=$config{$h}{'login'}"; my $host = $h;
$host =~ s/(.*)\.$domain(.*)/$1$2/;
$url .= "?host=$host";
$url .= "&domain=$domain";
$url .= "&password=$config{$h}{'password'}"; $url .= "&password=$config{$h}{'password'}";
$url .= "&ip="; $url .= "&ip=";
$url .= $ip if $ip; $url .= $ip if $ip;
@ -3877,6 +3906,131 @@ EoINSTR3
} }
} }
######################################################################
######################################################################
## 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
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-secure-token \\
myhost.com
## multiple host update to the custom DNS service
protocol=cloudflare, \\
zone=dns.zone, \\
login=my-cloudflare.com-login, \\
password=my-cloudflare.com-secure-token \\
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';
}
}
}
###################################################################### ######################################################################
# vim: ai ts=4 sw=4 tw=78 : # vim: ai ts=4 sw=4 tw=78 :

View file

@ -196,3 +196,13 @@ ssl=yes # use ssl-support. Works with
# client=ddclient, # client=ddclient,
# password=my-dtdns.com-password # password=my-dtdns.com-password
# myhost.dtdns.net, otherhost.dtdns.net # myhost.dtdns.net, otherhost.dtdns.net
##
## CloudFlare (www.cloudflare.com)
##
#protocol=cloudflare, \
#zone=domain.tld, \
#server=www.cloudflare.com, \
#login=your-login-email, \
#password=APIKey \
#domain.tld,my.domain.tld