Skip to content

Commit

Permalink
Add support to ionos.com
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonjr committed Sep 9, 2024
1 parent 1c0ba9a commit 2017e71
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ handwritten_tests = \
t/protocol_directnic.pl \
t/protocol_dnsexit2.pl \
t/protocol_dyndns2.pl \
t/protocol_ionos.pl \
t/read_recap.pl \
t/skip.pl \
t/ssl-validate.pl \
Expand Down
73 changes: 73 additions & 0 deletions ddclient.in
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,15 @@ our %protocols = (
'max-interval' => setv(T_DELAY, 0, 'inf', 0),
},
),
'ionos' => ddclient::Protocol->new(
'update' => \&nic_ionos_update,
'examples' => \&nic_ionos_examples,
'cfgvars' => {
%{$cfgvars{'protocol-common-defaults'}},
'server' => setv(T_FQDNP, 0, 'ipv4.api.hosting.ionos.com', undef),
'login' => undef,
},
),
);
$cfgvars{'merged'} = {
map({ %{$protocols{$_}{'cfgvars'}} } keys(%protocols)),
Expand Down Expand Up @@ -7641,6 +7650,70 @@ Example ${program}.conf file entries:
EoEXAMPLE
}

######################################################################
## nic_ionos_examples
######################################################################
sub nic_ionos_examples {
my $self = shift;
return <<EoEXAMPLE;
o 'ionos'
The 'ionos' protocol is used by DNS service offered by ionos.com.
Configuration variables applicable to the 'ionos' protocol are:
protocol=ionos ##
password=dyndns-update-key ## the key created to update the host below
fully.qualified.host ## the host registered with the service.
Example ${program}.conf file entries:
## single host update
protocol=ionos,
password=dyndns-update-key
myhost.com
Getting the DynDNS key (only available via Ionos API):
1. Create an API key
2. Enable DynDNS for your host using the /dns/v1/dyndns API
(documentation @ https://developer.hosting.ionos.es/docs/dns)
3. In the API response, get the key value. The key is a long string
from the "q=" parameter. The URL looks like this:
https://ipv4.api.hosting.ionos.com/dns/v1/dyndns?q=XXXXXXXXXXXXXXX
(in the example above the key is "XXXXXXXXXXXXXXX").
Note: Because the key is individual for each host, you cannot update
multiple hosts with the same key.
EoEXAMPLE
}

######################################################################
## nic_ionos_update
## response contains "code 200" on succesfull completion
######################################################################
sub nic_ionos_update {
my $self = shift;
## update each configured host
## should improve to update in one pass
for my $h (@_) {
local $_l = pushlogctx($h);
my $ip = delete $config{$h}{'wantip'};
info("setting IP address to $ip");
my $url = opt('server', $h) . "/dns/v1/dyndns?q=" . opt('password', $h);
my $reply = geturl(proxy => opt('proxy'), url => $url);
last if !header_ok($reply);

if ($reply =~ /code = 200/) {
$recap{$h}{'ip'} = $ip;
$recap{$h}{'mtime'} = $now;
$recap{$h}{'status'} = 'good';
success("IP address set to $ip");
} else {
$recap{$h}{'status'} = 'failed';
failed("server said: $reply");
}
}
}

# Execute main() if this file is run as a script or run via PAR (https://metacpan.org/pod/PAR),
# otherwise do nothing. This "modulino" pattern makes it possible to import this file as a module
# and test its functions directly; there's no need for test-only command-line arguments or stdout
Expand Down
39 changes: 39 additions & 0 deletions t/protocol_ionos.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use Test::More;
# Your test dependencies go here.

SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
eval { require 'ddclient'; } or BAIL_OUT($@);
BEGIN {
eval { require ddclient::t::HTTPD; 1; } or plan(skip_all => $@);
ddclient::t::HTTPD->import();
}

httpd()->run(sub {
my ($req) = @_;
diag('==============================================================================');
diag("Test server received request:\n" . $req->as_string());
return undef if $req->uri()->path() eq '/control';
return [401, [@$textplain, 'www-authenticate' => 'Basic realm="realm", charset="UTF-8"'],
['authentication required']] if ($req->header('authorization') // '') ne $wantauthn;
return [400, $textplain, ['invalid method: ' . $req->method()]] if $req->method() ne 'GET';
return undef;
});

local %ddclient::config = (
'host.my.example.com' => {
'protocol' => 'ionos',
'password' => 'mytestingpassword',
'server' => httpd()->endpoint(),
'wantip' => '1.2.3.4',
});

ddclient::nic_ionos_update(undef, 'host.my.example.com');

my @requests = httpd()->reset();
is(scalar(@requests), 1, "$tc->{desc}: single update request");

my $req = shift(@requests);
is($req->uri()->path(), '/dns/v1/dyndns', "$tc->{desc}: request path");
is($req->uri()->query(), 'q=mytestingpassword', "$tc->{desc}: request query");

done_testing();

0 comments on commit 2017e71

Please sign in to comment.