Forked from klittlepage/ddclient-3.8.1-cloudflare-30-10-2013.patch
Created
February 19, 2014 12:49
-
-
Save illucent/9091298 to your computer and use it in GitHub Desktop.
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-3.8.1/ddclient 2011-07-11 15:04:21.000000000 -0600 | |
+++ ddclient 2013-10-30 19:51:54.056629680 -0600 | |
@@ -1,4 +1,3 @@ | |
-#!/usr/bin/perl -w | |
#!/usr/local/bin/perl -w | |
###################################################################### | |
# $Id: ddclient 130 2011-07-11 21:02:07Z wimpunk $ | |
@@ -13,12 +12,18 @@ | |
# 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-09-26: blog.peter-r.co.uk | |
+# | |
###################################################################### | |
-require 5.004; | |
+require 5.014; | |
use strict; | |
use Getopt::Long; | |
use Sys::Hostname; | |
use IO::Socket; | |
+use POSIX 'setsid'; | |
+use JSON::Any; | |
my ($VERSION) = q$Revision: 130 $ =~ /(\d+)/; | |
@@ -29,9 +34,9 @@ | |
$program =~ s/d$//; | |
my $now = time; | |
my $hostname = hostname(); | |
-my $etc = ($program =~ /test/i) ? './' : '/etc/ddclient/'; | |
-my $cachedir = ($program =~ /test/i) ? './' : '/var/cache/ddclient/'; | |
-my $savedir = ($program =~ /test/i) ? 'URL/' : '/tmp/'; | |
+my $etc = ($program =~ /test/i) ? './' : '/usr/local/etc/'; | |
+my $cachedir = ($program =~ /test/i) ? './' : '/var/tmp/'; | |
+my $savedir = ($program =~ /test/i) ? 'URL/' : '/var/tmp/'; | |
my $msgs = ''; | |
my $last_msgs = ''; | |
@@ -39,7 +44,7 @@ | |
local $file = ''; | |
local $lineno = ''; | |
-$ENV{'PATH'} = (exists($ENV{PATH}) ? "$ENV{PATH}:" : "") . "/sbin:/usr/sbin:/bin:/usr/bin:/etc:/usr/lib:"; | |
+$ENV{'PATH'} = (exists($ENV{PATH}) ? "$ENV{PATH}:" : "") . "/sbin:/usr/local/sbin:/bin:/usr/local/bin:"; | |
sub T_ANY {'any'}; | |
sub T_STRING {'string'}; | |
@@ -429,6 +434,14 @@ | |
'login' => setv(T_LOGIN, 0, 0, 0, 'unused', undef), | |
'client' => setv(T_STRING, 0, 1, 1, $program, 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' => { | |
@@ -563,6 +576,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'}, | |
@@ -668,6 +692,9 @@ | |
; | |
} elsif (opt('daemon')) { | |
$SIG{'CHLD'} = 'IGNORE'; | |
+ chdir '/'; | |
+ open(STDIN, "</dev/null"); | |
+ open(STDOUT, ">/dev/null"); | |
my $pid = fork; | |
if ($pid < 0) { | |
print STDERR "${program}: can not fork ($!)\n"; | |
@@ -675,10 +702,9 @@ | |
} elsif ($pid) { | |
exit 0; | |
} | |
+ setsid; | |
$SIG{'CHLD'} = 'DEFAULT'; | |
- open(STDOUT, ">/dev/null"); | |
- open(STDERR, ">/dev/null"); | |
- open(STDIN, "</dev/null"); | |
+ open(STDERR, "&STDOUT"); | |
} | |
# write out the pid file if we're daemon'ized | |
@@ -1463,17 +1489,17 @@ | |
## execute the command. | |
local *FD; | |
if (! open(FD, $cmd)) { | |
- printf STDERR "$program: cannot execute command %s.\n", $cmd; | |
+ warning("$program: cannot execute command %s.\n", $cmd); | |
} elsif ($stdin && (! print FD "$stdin\n")) { | |
- printf STDERR "$program: failed writting to %s.\n", $cmd; | |
+ warning("$program: failed writing to %s.\n", $cmd); | |
close(FD); | |
} elsif (! close(FD)) { | |
- printf STDERR "$program: failed closing %s.($@)\n", $cmd; | |
+ warning("$program: failed closing %s.($@)\n", $cmd); | |
} elsif (opt('exec') && $?) { | |
- printf STDERR "$program: failed %s. ($@)\n", $cmd; | |
+ warning("$program: failed %s. ($@)\n", $cmd); | |
} else { | |
$ok = 1; | |
@@ -1861,6 +1887,7 @@ | |
Proto => 'tcp', | |
MultiHomed => 1, | |
Timeout => opt('timeout'), | |
+ SSL_verify_mode => SSL_VERIFY_NONE(), | |
); | |
defined $sd or warning("cannot connect to $peer:$port socket: $@ " . IO::Socket::SSL::errstr()); | |
} else { | |
@@ -3672,7 +3699,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) ]); | |
+ | |
+ ## 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