Add new protocol inwx
Adoption of protocol dyndns2 to support their custom URL: 'https://dyndns.inwx.com/nic/update?myip=<ipaddr>&myipv6=<ip6addr>'
This commit is contained in:
parent
f6e13f8003
commit
83ef1fa99a
4 changed files with 182 additions and 0 deletions
|
@ -77,6 +77,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master).
|
||||||
[#703](https://github.com/ddclient/ddclient/pull/703)
|
[#703](https://github.com/ddclient/ddclient/pull/703)
|
||||||
* `ddns.fm`: New `protocol` option for updating [DDNS.FM](https://ddns.fm/)
|
* `ddns.fm`: New `protocol` option for updating [DDNS.FM](https://ddns.fm/)
|
||||||
records. [#695](https://github.com/ddclient/ddclient/pull/695)
|
records. [#695](https://github.com/ddclient/ddclient/pull/695)
|
||||||
|
* `inwx`: New `protocol` option for updating [INWX](https://www.inwx.com/)
|
||||||
|
records. [#690](https://github.com/ddclient/ddclient/pull/690)
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ Dynamic DNS services currently supported include:
|
||||||
* [Google](https://domains.google)
|
* [Google](https://domains.google)
|
||||||
* [Hurricane Electric](https://dns.he.net)
|
* [Hurricane Electric](https://dns.he.net)
|
||||||
* [Infomaniak](https://faq.infomaniak.com/2376)
|
* [Infomaniak](https://faq.infomaniak.com/2376)
|
||||||
|
* [INWX](https://www.inwx.com/)
|
||||||
* [Loopia](https://www.loopia.se)
|
* [Loopia](https://www.loopia.se)
|
||||||
* [Mythic Beasts](https://www.mythic-beasts.com/support/api/dnsv2/dynamic-dns)
|
* [Mythic Beasts](https://www.mythic-beasts.com/support/api/dnsv2/dynamic-dns)
|
||||||
* [NameCheap](https://www.namecheap.com)
|
* [NameCheap](https://www.namecheap.com)
|
||||||
|
|
|
@ -404,3 +404,11 @@ pid=@runstatedir@/ddclient.pid # record PID in file.
|
||||||
# login=subdomain.domain.tld \
|
# login=subdomain.domain.tld \
|
||||||
# password=your_password \
|
# password=your_password \
|
||||||
# subdomain.domain.tld
|
# subdomain.domain.tld
|
||||||
|
|
||||||
|
##
|
||||||
|
## INWX
|
||||||
|
##
|
||||||
|
# protocol=inwx \
|
||||||
|
# login=my-inwx-DynDNS-account-username \
|
||||||
|
# password=my-inwx-DynDNS-account-password \
|
||||||
|
# myhost.example.org
|
||||||
|
|
171
ddclient.in
171
ddclient.in
|
@ -955,6 +955,16 @@ our %protocols = (
|
||||||
'zone' => setv(T_FQDN, 1, 0, undef, undef),
|
'zone' => setv(T_FQDN, 1, 0, undef, undef),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'inwx' => {
|
||||||
|
'force_update' => undef,
|
||||||
|
'update' => \&nic_inwx_update,
|
||||||
|
'examples' => \&nic_inwx_examples,
|
||||||
|
'variables' => {
|
||||||
|
%{$variables{'protocol-common-defaults'}},
|
||||||
|
'server' => setv(T_FQDNP, 0, 0, 'dyndns.inwx.com', undef),
|
||||||
|
'script' => setv(T_STRING, 0, 0, '/nic/update', undef),
|
||||||
|
},
|
||||||
|
},
|
||||||
'mythicdyn' => {
|
'mythicdyn' => {
|
||||||
'force_update' => undef,
|
'force_update' => undef,
|
||||||
'update' => \&nic_mythicdyn_update,
|
'update' => \&nic_mythicdyn_update,
|
||||||
|
@ -6459,6 +6469,167 @@ sub nic_hetzner_update {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
## nic_inwx_examples
|
||||||
|
######################################################################
|
||||||
|
sub nic_inwx_examples {
|
||||||
|
return <<"EoEXAMPLE";
|
||||||
|
o 'inwx'
|
||||||
|
|
||||||
|
The 'inwx' protocol is designed for DynDNS accounts at INWX
|
||||||
|
<https://www.inwx.com/>. It is similar to the 'dyndns2' protocol except IPv6
|
||||||
|
addresses are passed in a separate 'myipv6' URL parameter (rather than included
|
||||||
|
in the 'myip' parameter):
|
||||||
|
|
||||||
|
https://dyndns.inwx.com/nic/update?myip=<ipaddr>&myipv6=<ip6addr>
|
||||||
|
|
||||||
|
The 'inwx' protocol was designed around INWX's behavior as of June 2024:
|
||||||
|
- Omitting the IPv4 address (either no 'myip' URL parameter or '<ipaddr>' is
|
||||||
|
the empty string) will cause INWX to silently set the IPv4 address (A
|
||||||
|
record) to '127.0.0.1'. No error message is returned.
|
||||||
|
- Omitting the IPv6 address (either no 'myipv6' URL parameter or '<ip6addr>'
|
||||||
|
is the empty string) will cause INWX to delete the IPv6 address (AAAA
|
||||||
|
record) if it exists.
|
||||||
|
- INWX will automatically create an IPv6 AAAA record for your hostname if
|
||||||
|
necessary.
|
||||||
|
- 'dyndns.inwx.com' is not reachable via IPv6 (there is no AAAA record).
|
||||||
|
- GET 'https://dyndns.inwx.com/nic/update' without further parameters will set
|
||||||
|
the IPv4 A record to the public IP of the requesting host and delete the
|
||||||
|
IPv6 AAAA record.
|
||||||
|
- You can ask INWX support to manually convert a DynDNS account into an
|
||||||
|
IPv6-only account. No A record will be created in that case.
|
||||||
|
|
||||||
|
Configuration variables applicable to the 'inwx' protocol are:
|
||||||
|
protocol=inwx ##
|
||||||
|
server=fqdn.of.service ## defaults to dyndns.inwx.com
|
||||||
|
script=/path/to/script ## defaults to /nic/update
|
||||||
|
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=inwx \\
|
||||||
|
login=my-inwx-DynDNS-account-username \\
|
||||||
|
password=my-inwx-DynDNS-account-password \\
|
||||||
|
myhost.example.org
|
||||||
|
EoEXAMPLE
|
||||||
|
}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
## nic_inwx_update
|
||||||
|
######################################################################
|
||||||
|
sub nic_inwx_update {
|
||||||
|
debug("\nnic_inwx_update -------------------");
|
||||||
|
my %errors = (
|
||||||
|
'badauth' => 'Bad authorization (username or password)',
|
||||||
|
'badsys' => 'The system parameter given was not valid',
|
||||||
|
'notfqdn' => 'A Fully-Qualified Domain Name was not provided',
|
||||||
|
'nohost' => 'The hostname specified does not exist in the database',
|
||||||
|
'!yours' => 'The hostname specified exists, but not under the username currently being used',
|
||||||
|
'!donator' => 'The offline setting was set, when the user is not a donator',
|
||||||
|
'!active' => 'The hostname specified is in a Custom DNS domain which has not yet been activated.',
|
||||||
|
'abuse' => 'The hostname specified is blocked for abuse; you should receive an email notification which provides an unblock request link.',
|
||||||
|
'numhost' => 'System error: Too many or too few hosts found.',
|
||||||
|
'dnserr' => 'System error: DNS error encountered.',
|
||||||
|
'nochg' => 'No update required; unnecessary attempts to change to the current address are considered abusive',
|
||||||
|
);
|
||||||
|
my @group_by_attrs = qw(
|
||||||
|
login
|
||||||
|
password
|
||||||
|
server
|
||||||
|
script
|
||||||
|
wantipv4
|
||||||
|
wantipv6
|
||||||
|
);
|
||||||
|
for my $group (group_hosts_by(\@_, @group_by_attrs)) {
|
||||||
|
my @hosts = @{$group->{hosts}};
|
||||||
|
my %groupcfg = %{$group->{cfg}};
|
||||||
|
my $hosts = join(',', @hosts);
|
||||||
|
my $ipv4 = $groupcfg{'wantipv4'};
|
||||||
|
my $ipv6 = $groupcfg{'wantipv6'};
|
||||||
|
delete $config{$_}{'wantipv4'} for @hosts;
|
||||||
|
delete $config{$_}{'wantipv6'} for @hosts;
|
||||||
|
info("$hosts: setting IPv4 address to $ipv4") if $ipv4;
|
||||||
|
info("$hosts: setting IPv6 address to $ipv6") if $ipv6;
|
||||||
|
my $url = "$groupcfg{'server'}$groupcfg{'script'}?";
|
||||||
|
$url .= "myip=$ipv4" if $ipv4;
|
||||||
|
if ($ipv6) {
|
||||||
|
if (!$ipv4 && opt('usev4', $hosts) ne 'disabled') {
|
||||||
|
warning("Skipping IPv6 AAAA record update because INWX requires the IPv4 A record to be updated at the same time but the IPv4 address is unknown.");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$url .= "&" if $ipv4;
|
||||||
|
$url .= "myipv6=$ipv6";
|
||||||
|
}
|
||||||
|
my $reply = geturl(
|
||||||
|
proxy => opt('proxy'),
|
||||||
|
url => $url,
|
||||||
|
login => $groupcfg{'login'},
|
||||||
|
password => $groupcfg{'password'},
|
||||||
|
) // '';
|
||||||
|
if ($reply eq '') {
|
||||||
|
failed("$hosts: Could not connect to $groupcfg{'server'}");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
next if !header_ok($hosts, $reply);
|
||||||
|
# INWX can return 200 OK even if there is an error (e.g., bad authentication,
|
||||||
|
# updates too frequent) so the body of the response must also be checked.
|
||||||
|
(my $body = $reply) =~ s/^.*?\n\n//s;
|
||||||
|
my @reply = split(qr/\n/, $body);
|
||||||
|
if (!@reply) {
|
||||||
|
failed("$hosts: Could not connect to $groupcfg{'server'}");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
# From <https://help.dyn.com/remote-access-api/return-codes/>:
|
||||||
|
#
|
||||||
|
# If updating multiple hostnames, hostname-specific return codes are given one per line,
|
||||||
|
# in the same order as the hostnames were specified. Return codes indicating a failure
|
||||||
|
# with the account or the system are given only once.
|
||||||
|
#
|
||||||
|
# TODO: There is no mention of what happens if multiple IP addresses are supplied (e.g.,
|
||||||
|
# IPv4 and IPv6) for a host. If one address fails to update and the other doesn't, is that
|
||||||
|
# one error status line? An error status line and a success status line? Or is an update
|
||||||
|
# considered to be all-or-nothing and the status applies to the operation as a whole? If
|
||||||
|
# the IPv4 address changes but not the IPv6 address does that result in a status of "good"
|
||||||
|
# because the set of addresses for a host changed even if a subset did not?
|
||||||
|
#
|
||||||
|
# TODO: The logic below applies the last line's status to all hosts. Change it to apply
|
||||||
|
# each status to its corresponding host.
|
||||||
|
for my $line (@reply) {
|
||||||
|
# The IP address normally comes after the status, but we ignore it. We could compare
|
||||||
|
# it with the expected address and mark the update as failed if it differs, but (1)
|
||||||
|
# some services do not return the IP; and (2) comparison is brittle (e.g.,
|
||||||
|
# 192.000.002.001 vs. 192.0.2.1) and false errors could cause high load on the service
|
||||||
|
# (an update attempt every min-error-interval instead of every max-interval).
|
||||||
|
(my $status = $line) =~ s/ .*$//;
|
||||||
|
if ($status eq 'nochg') {
|
||||||
|
warning("$hosts: $status: $errors{$status}");
|
||||||
|
$status = 'good';
|
||||||
|
}
|
||||||
|
for my $h (@hosts) {
|
||||||
|
$config{$h}{'status-ipv4'} = $status if $ipv4;
|
||||||
|
$config{$h}{'status-ipv6'} = $status if $ipv6;
|
||||||
|
}
|
||||||
|
if ($status ne 'good') {
|
||||||
|
if (exists($errors{$status})) {
|
||||||
|
failed("$hosts: $status: $errors{$status}");
|
||||||
|
} else {
|
||||||
|
failed("$hosts: unexpected status: $line");
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
for my $h (@hosts) {
|
||||||
|
$config{$h}{'ipv4'} = $ipv4 if $ipv4;
|
||||||
|
$config{$h}{'ipv6'} = $ipv6 if $ipv6;
|
||||||
|
$config{$h}{'mtime'} = $now;
|
||||||
|
}
|
||||||
|
success("$hosts: IPv4 address set to $ipv4") if $ipv4;
|
||||||
|
success("$hosts: IPv6 address set to $ipv6") if $ipv6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
## nic_yandex_examples
|
## nic_yandex_examples
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
Loading…
Reference in a new issue