Add support for new DNSExit API (adding protocol dnsexit2).
This commit is contained in:
parent
a4eab34ab4
commit
ec4d83bc3f
3 changed files with 196 additions and 1 deletions
|
@ -45,6 +45,7 @@ Dynamic DNS services currently supported include:
|
||||||
dinahosting - See https://dinahosting.com
|
dinahosting - See https://dinahosting.com
|
||||||
Gandi - See https://gandi.net
|
Gandi - See https://gandi.net
|
||||||
dnsexit - See https://dnsexit.com/ for details
|
dnsexit - See https://dnsexit.com/ for details
|
||||||
|
dnsexit2 - See https://dnsexit.com/dns/dns-api/ for details
|
||||||
1984.is - See https://www.1984.is/product/freedns/ for details
|
1984.is - See https://www.1984.is/product/freedns/ for details
|
||||||
Njal.la - See https://njal.la/docs/ddns/
|
Njal.la - See https://njal.la/docs/ddns/
|
||||||
regfish.de - See https://www.regfish.de/domains/dyndns/ for details
|
regfish.de - See https://www.regfish.de/domains/dyndns/ for details
|
||||||
|
|
|
@ -317,6 +317,13 @@ ssl=yes # use ssl-support. Works with
|
||||||
#password=mypassword, \
|
#password=mypassword, \
|
||||||
#subdomain-1.domain.com,subdomain-2.domain.com
|
#subdomain-1.domain.com,subdomain-2.domain.com
|
||||||
|
|
||||||
|
##
|
||||||
|
## dnsexit2 (API method www.dnsexit.com)
|
||||||
|
##
|
||||||
|
#protocol=dnsexit2
|
||||||
|
#password=MyAPIKey
|
||||||
|
#subdomain-1.domain.com,subdomain-2.domain.com
|
||||||
|
|
||||||
##
|
##
|
||||||
## domeneshop (www.domeneshop.no)
|
## domeneshop (www.domeneshop.no)
|
||||||
##
|
##
|
||||||
|
|
189
ddclient.in
189
ddclient.in
|
@ -548,6 +548,13 @@ my %variables = (
|
||||||
'script' => setv(T_STRING, 0, 1, '/RemoteUpdate.sv', undef),
|
'script' => setv(T_STRING, 0, 1, '/RemoteUpdate.sv', undef),
|
||||||
'min-error-interval' => setv(T_DELAY, 0, 0, interval('8m'), 0),
|
'min-error-interval' => setv(T_DELAY, 0, 0, interval('8m'), 0),
|
||||||
},
|
},
|
||||||
|
'dnsexit2-common-defaults' => {
|
||||||
|
'ssl' => setv(T_BOOL, 0, 0, 1, undef),
|
||||||
|
'server' => setv(T_FQDNP, 1, 0, 'api.dnsexit.com', undef),
|
||||||
|
'path' => setv(T_STRING, 0, 1, '/dns/', undef),
|
||||||
|
'record-type' => setv(T_STRING, 1, 0, 'A', undef),
|
||||||
|
'ttl' => setv(T_NUMBER, 1, 0, 5, 0),
|
||||||
|
},
|
||||||
'regfishde-common-defaults' => {
|
'regfishde-common-defaults' => {
|
||||||
'server' => setv(T_FQDNP, 1, 0, 'dyndns.regfish.de', undef),
|
'server' => setv(T_FQDNP, 1, 0, 'dyndns.regfish.de', undef),
|
||||||
'login' => setv(T_LOGIN, 0, 0, 0, 'unused', undef),
|
'login' => setv(T_LOGIN, 0, 0, 0, 'unused', undef),
|
||||||
|
@ -959,6 +966,19 @@ my %services = (
|
||||||
$variables{'service-common-defaults'},
|
$variables{'service-common-defaults'},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
'dnsexit2' => {
|
||||||
|
'updateable' => undef,
|
||||||
|
'update' => \&nic_dnsexit2_update,
|
||||||
|
'examples' => \&nic_dnsexit2_examples,
|
||||||
|
'variables' => {
|
||||||
|
%{$variables{'service-common-defaults'}},
|
||||||
|
%{$variables{'dnsexit2-common-defaults'}},
|
||||||
|
# nic_updateable() assumes that every service uses a username/login but that is
|
||||||
|
# not true for the DNSExit API. Silence warnings by redefining the username variable
|
||||||
|
# as non-required with value unused.
|
||||||
|
'login' => setv(T_STRING, 0, 0, 'unused', undef),
|
||||||
|
},
|
||||||
|
},
|
||||||
'regfishde' => {
|
'regfishde' => {
|
||||||
'updateable' => undef,
|
'updateable' => undef,
|
||||||
'update' => \&nic_regfishde_update,
|
'update' => \&nic_regfishde_update,
|
||||||
|
@ -1815,7 +1835,7 @@ sub init_config {
|
||||||
$proto = opt('protocol') if !defined($proto);
|
$proto = opt('protocol') if !defined($proto);
|
||||||
|
|
||||||
load_sha1_support($proto) if (grep (/^$proto$/, ("freedns", "nfsn")));
|
load_sha1_support($proto) if (grep (/^$proto$/, ("freedns", "nfsn")));
|
||||||
load_json_support($proto) if (grep (/^$proto$/, ("1984", "cloudflare", "digitalocean", "gandi", "godaddy", "hetzner", "yandex", "nfsn", "njalla", "porkbun")));
|
load_json_support($proto) if (grep (/^$proto$/, ("1984", "cloudflare", "digitalocean", "gandi", "godaddy", "hetzner", "yandex", "nfsn", "njalla", "porkbun", "dnsexit2")));
|
||||||
|
|
||||||
if (!exists($services{$proto})) {
|
if (!exists($services{$proto})) {
|
||||||
warning("skipping host: %s: unrecognized protocol '%s'", $h, $proto);
|
warning("skipping host: %s: unrecognized protocol '%s'", $h, $proto);
|
||||||
|
@ -4352,6 +4372,173 @@ sub nic_dnsexit_update {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
######################################################################
|
######################################################################
|
||||||
|
## nic_dnsexit2_examples
|
||||||
|
######################################################################
|
||||||
|
sub nic_dnsexit2_examples {
|
||||||
|
return <<"EoEXAMPLE";
|
||||||
|
o 'dnsexit2'
|
||||||
|
|
||||||
|
The 'dnsexit2' protocol is the new API protocol used by the dynamic hostname services
|
||||||
|
of the 'DNSExit' dns services. This is currently used by the free
|
||||||
|
dynamic DNS service offered by www.dnsexit.com.
|
||||||
|
|
||||||
|
Configuration variables applicable to the 'dnsexit2' protocol are:
|
||||||
|
protocol=dnsexit2 ##
|
||||||
|
password=YourAPIKey ## API Key of your account.
|
||||||
|
server=api.dnsexit.com ## defaults to api.dnsexit.com.
|
||||||
|
path=/dns/ ## defaults to /dns/.
|
||||||
|
record-type=A ## defaults to A record.
|
||||||
|
ttl=5 ## defaults to 5 minutes.
|
||||||
|
fully.qualified.host ## the host registered with the service.
|
||||||
|
|
||||||
|
Example ${program}.conf file entries:
|
||||||
|
## single host update
|
||||||
|
protocol=dnsexit2
|
||||||
|
password=YourAPIKey
|
||||||
|
fully.qualified.host
|
||||||
|
|
||||||
|
EoEXAMPLE
|
||||||
|
}
|
||||||
|
######################################################################
|
||||||
|
## nic_dnsexit2_update
|
||||||
|
##
|
||||||
|
## by @jortkoopmans
|
||||||
|
## based on https://dnsexit.com/dns/dns-api/
|
||||||
|
##
|
||||||
|
######################################################################
|
||||||
|
sub nic_dnsexit2_update {
|
||||||
|
debug("\nnic_dnsexit2_update -------------------");
|
||||||
|
|
||||||
|
## Update each configured host
|
||||||
|
foreach my $h (@_) {
|
||||||
|
# All the known status
|
||||||
|
my %status = (
|
||||||
|
'0' => [ 'good', 'Success! Actions got executed successfully.' ],
|
||||||
|
'1' => [ 'warning', 'Some execution problems. May not indicate actions failures. Some action may got executed fine and some may have problems.' ],
|
||||||
|
'2' => [ 'badauth', 'API Key Authentication Error. The API Key is missing or wrong.' ],
|
||||||
|
'3' => [ 'error', 'Missing Required Definitions. Your JSON file may missing some required definitions.' ],
|
||||||
|
'4' => [ 'error', 'JSON Data Syntax Error. Your JSON file has syntax error.' ],
|
||||||
|
'5' => [ 'error', 'JSON Defined Record Type not Supported. Your JSON may try to update some record type not supported by our system.' ],
|
||||||
|
'6' => [ 'error', 'System Error. Our system problem. May not be your problem. Contact our support if you got such error.' ],
|
||||||
|
'7' => [ 'error', 'Error getting post data. Our server has problem to receive your JSON posting.' ],
|
||||||
|
);
|
||||||
|
my $ip = delete $config{$h}{'wantip'};
|
||||||
|
info("Going to update IP address to %s for %s.", $ip, $h);
|
||||||
|
# Set the URL of the API endpoint
|
||||||
|
my $url = "https://$config{$h}{'server'}$config{$h}{'path'}";
|
||||||
|
|
||||||
|
# Set JSON payload
|
||||||
|
my $data = encode_json({
|
||||||
|
apikey => $config{$h}{'password'},
|
||||||
|
domain => $h,
|
||||||
|
update => {
|
||||||
|
type => $config{$h}{'record-type'},
|
||||||
|
name => $h,
|
||||||
|
content => $ip,
|
||||||
|
ttl => $config{$h}{'ttl'}},
|
||||||
|
});
|
||||||
|
|
||||||
|
# Set additional headers
|
||||||
|
my $header = "Content-Type: application/json\n";
|
||||||
|
$header .= "Accept: application/json";
|
||||||
|
|
||||||
|
# Make the call
|
||||||
|
my $reply = geturl(
|
||||||
|
proxy => opt('proxy'),
|
||||||
|
url => $url,
|
||||||
|
headers => $header,
|
||||||
|
method => 'POST',
|
||||||
|
data => $data,
|
||||||
|
);
|
||||||
|
|
||||||
|
# No reply, declare as failed
|
||||||
|
if (!defined($reply) || !$reply) {
|
||||||
|
failed("updating %s: Could not connect to %s%s.", $h, $config{$h}{'server'}, $config{$h}{'path'});
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Reply found
|
||||||
|
debug("%s", $reply);
|
||||||
|
# $ok is mandatory?
|
||||||
|
my $ok = header_ok($h, $reply);
|
||||||
|
|
||||||
|
# Extract the HTTP response code
|
||||||
|
(my $http_status) = ($reply =~ m%^s*HTTP/.*\s+(\d+)%i);
|
||||||
|
debug("HTTP response code: %s", $http_status);
|
||||||
|
|
||||||
|
# If not 200, bail
|
||||||
|
if ( $http_status != "200"){
|
||||||
|
failed("Failed to update Host\n%s to IP:%s", $h, $ip);
|
||||||
|
failed("HTTP response code\n%s", $http_status);
|
||||||
|
failed("Full reply\n%s", $reply) unless opt('verbose');
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Strip HTTP response headers
|
||||||
|
(my $strip_status) = ($reply =~ s/^[\s\S]*?(?=\{"code":)//);
|
||||||
|
debug("strip_status");
|
||||||
|
debug("%s", $strip_status);
|
||||||
|
if ($strip_status) {
|
||||||
|
debug("HTTP headers are stripped.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warning("Unexpected: no HTTP headers stripped!");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Decode the remaining reply, it should be JSON.
|
||||||
|
my $response = decode_json($reply);
|
||||||
|
|
||||||
|
# It should at least have a 'code' and 'message'.
|
||||||
|
if (defined($response->{'code'}) and defined($response->{'message'})) {
|
||||||
|
if (exists $status{$response->{'code'}}) {
|
||||||
|
# Add the server response data to the applicable array
|
||||||
|
push( @{ $status {$response->{'code'} } }, $response->{'message'});
|
||||||
|
if (defined($response->{'details'})) {
|
||||||
|
push ( @{ $status {$response->{'code'} } }, $response->{'details'}[0]);
|
||||||
|
} else {
|
||||||
|
# Keep it symmetrical for simplicity
|
||||||
|
push ( @{ $status {$response->{'code'} } }, "no details received");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set data from array
|
||||||
|
my ($status, $message, $srv_message, $srv_details) = @{ $status {$response->{'code'} } };
|
||||||
|
info("Status: %s -- Message: %s", $status, $message);
|
||||||
|
info("Server Message: %s -- Server Details: %s", $srv_message, $srv_details);
|
||||||
|
$config{$h}{'status'} = $status;
|
||||||
|
|
||||||
|
# Handle statuses
|
||||||
|
if ($status eq 'good') {
|
||||||
|
$config{$h}{'ip'} = $ip;
|
||||||
|
$config{$h}{'mtime'} = $now;
|
||||||
|
$config{$h}{'status'} = 'good';
|
||||||
|
success("%s", $message);
|
||||||
|
success("Updated %s successfully to IP address %s at time %s", $h, $ip, prettytime($config{$h}{'mtime'}));
|
||||||
|
} elsif ($status eq 'warning') {
|
||||||
|
warning("%s", $message);
|
||||||
|
warning("Server response: %s", $srv_message);
|
||||||
|
} elsif ($status =~ m'^(badauth|error)$') {
|
||||||
|
failed("%s", $message);
|
||||||
|
failed("Server response: %s", $srv_message);
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
} else {
|
||||||
|
failed("This should not be possible");
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
failed("Status code %s is unknown!", $response->{'code'});
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
failed("Did not receive expected \"code\" and \"message\" keys in server response.");
|
||||||
|
failed("Response:");
|
||||||
|
failed("%s", $response);
|
||||||
|
$config{$h}{'status'} = 'failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
######################################################################
|
||||||
## nic_noip_update
|
## nic_noip_update
|
||||||
## Note: uses same features as nic_dyndns2_update, less return codes
|
## Note: uses same features as nic_dyndns2_update, less return codes
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
Loading…
Reference in a new issue