DNSExit update for ipv6.

- Support wantipv4 and wantipv6 configs automatically
- Remove manual record type setting
- Add support for hosts on your zone (subdomain)
- Update config examples
- Code/logic improvements
This commit is contained in:
jortkoopmans 2023-10-17 23:01:34 +02:00 committed by Reuben Thomas
parent 8ed2963b79
commit 9913e0ec29

View file

@ -535,9 +535,9 @@ my %variables = (
'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),
'path' => setv(T_STRING, 0, 0, '/dns/', undef),
'ttl' => setv(T_NUMBER, 1, 0, 5, 0),
'zone' => setv(T_STRING, 0, 0, undef, undef)
},
'regfishde-common-defaults' => {
'server' => setv(T_FQDNP, 1, 0, 'dyndns.regfish.de', undef),
@ -4050,24 +4050,29 @@ 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.
The 'dnsexit2' protocol is the updated protocol for the (free) dynamic hostname services
of 'DNSExit' (www.dnsexit.com). Their API is accepting JSON payload.
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.
zone='' ## defaults to empty, which assumes the zone is equal to the fully.qualified.host (is root of your DNSExit domain).
fully.qualified.host ## the host registered with the service.
Example ${program}.conf file entries:
## single host update
protocol=dnsexit2
password=YourAPIKey
fully.qualified.host
yourown.publicvm.com
## two hosts (which must be) on the same zone
protocol=dnsexit2
password=YourAPIKey
zone=yourown.publicvm.com
host1.yourown.publicvm.com,host2.yourown.publicvm.com
EoEXAMPLE
}
@ -4081,7 +4086,7 @@ EoEXAMPLE
sub nic_dnsexit2_update {
debug("\nnic_dnsexit2_update -------------------");
## Update each configured host
## Update each configured host (hosts cannot be grouped on this API)
foreach my $h (@_) {
# All the known status
my %status = (
@ -4094,25 +4099,45 @@ sub nic_dnsexit2_update {
'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);
my $ipv4 = delete $config{$h}{'wantipv4'};
my $ipv6 = delete $config{$h}{'wantipv6'};
# Updates for ipv4 and ipv6 need to be combined in a single API call, create Hash of Arrays for tracking
my %total_payload;
foreach my $ip ($ipv4, $ipv6){
next if (!$ip);
my $ipv = ($ip eq ($ipv6 // '')) ? '6' : '4';
my $type = ($ip eq ($ipv6 // '')) ? 'AAAA' : 'A';
info("Going to update IPv$ipv address to %s for %s.", $ip, $h);
$config{$h}{'status-ipv$ipv'} = 'failed';
# One key per ipv (4 or 6)
my %payload = (name => $h, type => $type, content => $ip, ttl => $config{$h}{'ttl'});
@total_payload{$ipv} = \%payload;
};
# 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";
my $header = "Content-Type: application/json\nAccept: application/json";
# Set the zone if empty
if ( not defined $config{$h}{'zone'}){
debug("Zone not defined, setting to default hostname: %s", $h);
$config{$h}{'zone'} = $h
} else {
debug("Zone is: %s", $config{$h}{'zone'});
}
# Build total JSON payload
my @payload_values = values %total_payload;
my $data = encode_json({
apikey => $config{$h}{'password'},
domain => $config{$h}{'zone'},
update => \@payload_values
});
# Make the call
my $reply = geturl(
@ -4120,32 +4145,27 @@ sub nic_dnsexit2_update {
url => $url,
headers => $header,
method => 'POST',
data => $data,
data => $data
);
# No reply, declare as failed
if (!defined($reply) || !$reply) {
unless ($reply && header_ok($h, $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);
if ( $http_status ne '200' ){
failed("Failed to update Host\n%s", $h);
failed("HTTP response code\n%s", $http_status);
failed("Full reply\n%s", $reply) unless opt('verbose');
$config{$h}{'status'} = 'failed';
last;
next;
}
# Strip HTTP response headers
@ -4182,31 +4202,30 @@ sub nic_dnsexit2_update {
# 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'}));
my $tracked_ipv;
foreach $tracked_ipv ( keys %total_payload ){
$config{$h}{"ipv$tracked_ipv"} = $total_payload{$tracked_ipv}{content};
$config{$h}{"status-ipv$tracked_ipv"} = 'good';
success("%s", $message);
success("Updated %s successfully to IPv$tracked_ipv address %s at time %s", $h, $total_payload{$tracked_ipv}{content}, 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';
}
}
}