added Peter Roberts's cloudflare modifications, cleaned up code, updated README.md

This commit is contained in:
Robert Ian Hawdon 2014-10-03 21:04:02 +01:00
parent 354c72e8df
commit 1d42008821
4 changed files with 4302 additions and 87 deletions

View file

@ -23,6 +23,7 @@ Dynamic DNS services currently supported include:
ChangeIP - See http://www.changeip.com/ for details
dtdns - See http://www.dtdns.com/ 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.
@ -37,8 +38,9 @@ REQUIREMENTS:
- one or more accounts from one of the dynamic DNS services
- Perl 5.004 or later
(you need the IO::Socket::SSL perl library for ssl-support)
- Perl 5.014 or later
(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

182
README.md~ Normal file
View file

@ -0,0 +1,182 @@
===============================================================================
# DDCLIENT v3.8.2
ddclient is a Perl client used to update dynamic DNS entries for accounts
on many dynamic DNS services.
===============================================================================
Dynamic DNS services currently supported include:
DynDNS.com - See http://www.dyndns.com for details on obtaining a free account.
Hammernode - See http://www.hn.org for details on obtaining a free account.
Zoneedit - See http://www.zoneedit.com for details.
EasyDNS - See http://www.easydns.com for details.
NameCheap - See http://www.namecheap.com for details
ConCont - See http://www.dydns.za.net for details
DnsPark - See http://www.dnspark.com for details
DslReports - See http://www.dslreports.com for details
Sitelutions - See http://www.sitelutions.com for details
Loopia - See http://www.loopia.se for details
Noip - See http://www.noip.com/ for details
Freedns - See http://freedns.afraid.org/ for details
ChangeIP - See http://www.changeip.com/ for details
dtdns - See http://www.dtdns.com/ for details
nsupdate - See nsupdate(1) and ddns-confgen(8) for details
DDclient now supports many of cable/dsl broadband routers.
Comments, suggestions and requests: use the forums on
http://sourceforge.net/projects/ddclient/
The code was originally written by Paul Burry and is now hosted and maintained
through sourceforge.net. Please check out http://ddclient.sf.net
-------------------------------------------------------------------------------
REQUIREMENTS:
- one or more accounts from one of the dynamic DNS services
- Perl 5.004 or later
(you need the IO::Socket::SSL perl library for ssl-support)
- Linux or probably any common Unix system
-------------------------------------------------------------------------------
INSTALLATION:
cp ddclient /usr/sbin/
mkdir /etc/ddclient
mkdir /var/cache/ddclient
cp sample-etc_ddclient.conf /etc/ddclient/ddclient.conf
vi /etc/ddclient/ddclient.conf
-- and change hostnames, logins, and passwords appropriately
## For those using Redhat style rc files and using daemon-mode:
cp sample-etc_rc.d_init.d_ddclient /etc/rc.d/init.d/ddclient
## enable automatic startup when booting
## check your distribution
/sbin/chkconfig --add ddclient
## start the first time by hand
/etc/rc.d/init.d/ddclient start
## For those using Alpine style rc files and using daemon-mode:
cp sample-etc_rc.d_init.d_ddclient.alpine /etc/init.d/ddclient
## enable automatic startup when booting
rc-update add ddclient
## make sure you have perl installed
apk add perl
## start the first time by hand
rc-service ddclient start
## If you are not using daemon-mode, configure cron and dhcp or ppp
## as described below.
-------------------------------------------------------------------------------
TROUBLESHOOTING:
1. enable debugging and verbose messages.
``$ ddclient -daemon=0 -debug -verbose -noquiet``
2. Do you need to specify a proxy?
If so, just add a
``proxy=your.isp.proxy``
to the ddclient.conf file.
3. Define the IP address of your router with ``fw=xxx.xxx.xxx.xxx`` in
``/etc/ddclient/ddclient.conf`` and then try
``$ ddclient -daemon=0 -query``
to see if the router status web page can be understood.
4. Need support for another router/firewall?
Define the router status page yourself with:
``fw=url-to-your-router``'s-status-page
``fw-skip=any-string-preceding-your-IP-address``
ddclient does something like this to provide builtin support for
common routers.
For example, the Linksys routers could have been added with:
fw=192.168.1.1/Status.htm
fw-skip=WAN.*?IP Address
OR
Send me the output from:
$ ddclient -geturl {fw-ip-status-url} [-login login [-password password]]
and I'll add it to the next release!
ie. for my fw/router I used:
$ ddclient -geturl 192.168.1.254/status.htm
5. Some broadband routers require the use of a password when ddclient
accesses its status page to determine the router's WAN IP address.
If this is the case for your router, add
fw-login=your-router-login
fw-password=your-router-password
to the beginning of your ddclient.conf file.
Note that some routers use either 'root' or 'admin' as their login
while some others accept anything.
-------------------------------------------------------------------------------
USING DDCLIENT WITH ppp
If you are using a ppp connection, you can easily update your DynDNS
entry with each connection, with:
## configure pppd to update DynDNS with each connection
cp sample-etc_ppp_ip-up.local /etc/ppp/ip-up.local
Alternatively, you may just configure ddclient to operate as a daemon
and monitor your ppp interface.
-------------------------------------------------------------------------------
USING DDCLIENT WITH cron
If you have not configured ddclient to use daemon-mode, you'll need to
configure cron to force an update once a month so that the dns entry will
not become stale.
## configure cron to force an update twice a month
cp sample-etc_cron.d_ddclient /etc/cron.d/ddclient
vi /etc/cron.d/ddclient
-------------------------------------------------------------------------------
USING DDCLIENT WITH dhcpcd-1.3.17
If you are using dhcpcd-1.3.17 or thereabouts, you can easily update
your DynDNS entry automatically every time your lease is obtained
or renewed by creating an executable file named:
/etc/dhcpc/dhcpcd-{your-interface}.exe
ie.:
cp sample-etc_dhcpc_dhcpcd-eth0.exe /etc/dhcpc/dhcpcd-{your-interface}.exe
In my case, it is named dhcpcd-eth0.exe and contains the lines:
#!/bin/sh
PATH=/usr/sbin:/root/bin:${PATH}
logger -t dhcpcd IP address changed to $1
ddclient -proxy fasthttp.sympatico.ca -wildcard -ip $1 | logger -t ddclient
exit 0
Other DHCP clients may have another method of calling out to programs
for updating DNS entries.
Alternatively, you may just configure ddclient to operate as a daemon
and monitor your ethernet interface.
-------------------------------------------------------------------------------
USING DDCLIENT WITH dhclient
If you are using the ISC DHCP client (dhclient), you can update
your DynDNS entry automatically every time your lease is obtained
or renewed by creating an executable file named:
/etc/dhclient-exit-hooks
ie.:
cp sample-etc_dhclient-exit-hooks /etc/dhclient-exit-hooks
Edit /etc/dhclient-exit-hooks to change any options required.
Alternatively, you may just configure ddclient to operate as a daemon
and monitor your ethernet interface.
-------------------------------------------------------------------------------

169
ddclient
View file

@ -13,14 +13,19 @@
# 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/
# 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 Getopt::Long;
use Sys::Hostname;
use IO::Socket;
use JSON::ANY;
# my ($VERSION) = q$Revision: 161 $ =~ /(\d+)/;
@ -436,7 +441,8 @@ my %variables = (
'zone' => setv(T_STRING, 1, 1, 1, '', undef),
},
'cloudflare-common-defaults' => {
'server' => setv(T_FQDNP, 1, 0, 1, 'www.cloudflare.com', undef),
'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),
@ -618,7 +624,7 @@ my @opt = (
"usage: ${program} [options]",
"options are:",
[ "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" ],
[ "server", "=s", "-server host : update DNS information on 'host'" ],
[ "protocol", "=s", "-protocol type : update protocol used" ],
@ -3907,8 +3913,6 @@ EoINSTR3
##
## written by Ian Pye
##
## https://www.cloudflare.com/api.html?a=DIUP&u=myemail@mydomain.com&tkn=SecretPass&ip=192.168.10.4&hosts=example.com
##
######################################################################
sub nic_cloudflare_examples {
return <<EoEXAMPLE;
@ -3941,93 +3945,88 @@ EoEXAMPLE
## nic_cloudflare_update
######################################################################
sub nic_cloudflare_update {
debug("\nnic_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) ]);
## group hosts with identical attributes together
my %groups = group_hosts_by([ @_ ], [ qw(ssh login password server wildcard mx backupmx zone) ]);
## each host is in a group by itself
##my %groups = map { $_ => [ $_ ] } @_;
## 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'};
my %errors = (
'E_NOUPDATE' => 'No changes made to the hostname(s). Continual updates with no changes lead to blocked clients.',
'E_NOHOST' => 'No valid FQDN (fully qualified domain name) was specified',
'E_INVLDHST'=> 'An invalid hostname was specified. This may be due to the fact the hostname has not been created in the system. Creating new host names via clients is not supported.',
'E_UNAUTH' => 'The username specified is not authorized to update this hostname and domain.',
'E_INVLDIP' => 'The IP address given is not valid.',
'E_DUPHST' => 'Duplicate values exist for a record. Only single values for records are supported currently.',
);
# FQDNs
for my $domain (@hosts) {
my $hostname = $domain =~ s/\.$config{$key}{zone}$//r;
delete $config{$domain}{'wantip'};
## update each set of hosts that had similar configurations
foreach my $sig (keys %groups) {
info("setting IP address to %s for %s", $ip, $domain);
verbose("UPDATE:","updating %s", $domain);
my @hosts = @{$groups{$sig}};
my $hosts = join(',', @hosts);
my $h = $hosts[0];
my $ip = $config{$h}{'wantip'};
# 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'};
delete $config{$_}{'wantip'} foreach @hosts;
info("setting IP address to %s for %s", $ip, $hosts);
verbose("UPDATE:","updating %s", $hosts);
my $url;
$url = "https://$config{$h}{'server'}/api.html?a=DIUP";
$url .= "&hosts=$hosts";
$url .= "&u=".$config{$h}{'login'};
$url .= "&tkn=".$config{$h}{'password'};
$url .= "&ip=";
$url .= "$ip" if $ip;
my $reply = geturl(opt('proxy'), $url);
if (!defined($reply) || !$reply) {
failed("updating %s: Could not connect to %s.", $hosts, $config{$h}{'server'});
last;
}
last if !header_ok($hosts, $reply);
my @reply = split /\n/, $reply;
my @body = ();
my $in_header = 1;
foreach my $line (@reply) {
if ($line eq "") {
$in_header = 0;
} elsif (!$in_header) {
push(@body, $line);
}
}
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);
if ($reply =~ /E_UNAUTH/) {
failed ("%s", $errors{"E_UNAUTH"});
} elsif ($reply =~ /E_NOHOST/) {
failed ("%s", $errors{"E_NOHOST"});
} elsif ($reply =~ /E_INVLDHST/) {
failed ("%s", $errors{"E_INVLDHST"});
} elsif ($reply =~ /E_INVLDIP/) {
failed ("%s", $errors{"E_INVLDIP"});
} elsif ($reply =~ /E_DUPHST/) {
failed ("%s", $errors{"E_DUPHST"});
} else {
foreach my $line (@body) {
my @res = split / /, $line;
if ($res[1] eq "E_NOUPDATE") {
$config{$res[0]}{'ip'} = $ip;
$config{$res[0]}{'mtime'} = $now;
$config{$res[0]}{'status'} = 'good';
warning ("%s -- %s", $res[0], $errors{"E_NOUPDATE"});
} elsif ($res[1] eq "OK") {
$config{$res[0]}{'ip'} = $ip;
$config{$res[0]}{'mtime'} = $now;
$config{$res[0]}{'status'} = 'good';
success ("%s -- Updated Successfully to %s", $res[0], $ip);
}
}
}
}
# 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 :
__END__

4032
ddclient~ Executable file

File diff suppressed because it is too large Load diff