Add a document describing a design for comprehensive IPv6 support. The ddclient maintainers agreed to this design, and it should be used to guide the implementation of full IPv6 support.
16 KiB
Design Doc: IPv6 Support
Author: @rhansen
Date: 2020-06-09
Signed off by:
@SuperSandro2000
Objective
Add full IPv6 support to ddclient, including support for dual-stack systems.
Background
ddclient's current IPv6 support is limited:
- Users can update either an IPv6 record or an IPv4 record for a host, not both.
- If SSL is used for an HTTP request, IPv6 will be used if the
remote host has a AAAA record, even if the user would rather use
IPv4. This breaks
use=webfor IPv4 if thewebURL's host has a AAAA record. - The
use=ifmethod only works if the user setsif-skipto something that skips over all IPv4 addresses in the output ofifconfig(orip). If the output contains an IPv4 address after the IPv6 address thenuse=ifcannot be used for IPv6. - There is no support for falling back to IPv4 if an IPv6 connection fails.
use=ifdoes not filter out locally scoped or temporary IPv6 addresses.
Some attempts have been made to add more robust IPv6 support:
- Debian's ddclient package applies a
patch
that adds a new
usev6option. Theusev6option can be set toiporif, but not any of the other strategies currently available for theuseoption (web,cmd,fw,cisco,cisco-asa). When set toiporif, only IPv6 addresses are considered; IPv4 addresses are ignored. The patch does not change the behavior of theuseoption, souse=weboruse=cmdcan be used for IPv6 if pointed at something that only outputs an IPv6 address. - ddclient-curl is a fork of ddclient that uses curl as the HTTP client (instead of ddclient's own homemade client) for more robust IPv6 support.
- PR #40 is perhaps the most comprehensive attempt at adding full IPv6 support, but it was never merged and has since bit-rotted. There is renewed effort to rebase the changes and get them merged in. PR #40 adds new options and changes some existing options. The approach taken is to completely isolate IPv4 address detection from IPv6 address detection and require the update protocol callbacks to handle each type of address appropriately.
Requirements
- The mechanism for determining the current IPv4 address (the
useoption) must be independently configurable from the mechanism used to determine the current IPv6 address. - The user must be able to disable IPv4 address updates without affecting IPv6 updates.
- The user must be able to disable IPv6 address updates without affecting IPv4 updates.
- If HTTP polling is used for both IPv4 and IPv6 address discovery,
the URL used to determine the IPv4 address (the
weboption) must be independently configurable from the URL used to determine the IPv6 address. - The use of IPv4 or IPv6 to update a record must be independent of the type of record being updated (IPv4 or IPv6).
- The callback for the update protocol must be given both addresses, even if only one of the two addresses has changed.
- The callback for the update protocol must be told which addresses have changed.
- There must be IPv6 equivalents to
use=ip,use=if,use=web, anduse=cmd. For the IPv6 equivalent touse=if, it is acceptable to ignore non-global and temporary addresses (the user can always use the IPv6 equivalent touse=cmdto get non-global or temporary addresses). - Existing support for updating IPv6 records must not be lost.
- Some dynamic DNS service providers use separate credentials for the IPv4 and IPv6 records. These providers must be supported, either by accepting both sets of credentials in a single host's configuration or by allowing the user to specify the same host twice, once for IPv4 and once for IPv6.
Nice-to-Haves
- The user should be able to force the update protocol to use IPv4 or IPv6.
- Unless configured otherwise, ddclient should first attempt to update via IPv6 and fall back to IPv4 if the IPv6 connection fails. This behavior can be added later; for now it is acceptable to keep the current behavior (use IPv6 without IPv4 fallback if there is a AAAA record, use IPv4 if there is no AAAA record).
- Full backwards compatibility with existing config files and flags. The trade-offs between migration burden, long-term usability, and code maintenance should be carefully considered.
- IPv6 equivalents to
use=fw,use=cisco, anduse=cisco-asa. - Add IPv6 support in protocol callbacks where IPv6 support is currently missing. (This can be done later.)
Proposal
Configuration changes
- Add new
usev4andusev6settings that are like the currentusesetting except they only apply to IPv4 and IPv6, respectively.usev4can be set to one of the following values:disabled,ipv4,webv4,fwv4,ifv4,cmdv4,ciscov4,cisco-asav4usev6can be set to one of the following values:disabled,ipv6,webv6,fwv6,ifv6,cmdv6,ciscov6,cisco-asav6
- Add a new
usestrategy:disabled. - The
disabledvalue foruse,usev4, andusev6causes ddclient to act as if it was never set. This is useful for overriding the global value for a particular host. - For compatibility with ddclient-curl,
nois a deprecated alias ofdisabled. - Add new
ipv4,ipv6,webv4,webv4-skip,webv6,webv6-skip,ifv4,ifv6,cmdv4,cmdv6, etc. settings that behave like their versionless counterparts except they only apply to IPv4 or IPv6. Deprecate the versionless counterparts, and change their behavior so that they also influence the default value of the versioned options. (Example: Supposeusev4=ifv4. Ififv4is not set thenifis used.) Special notes:- The value of
ipwill only serve as the default foripv4(oripv6) if it contains an IPv4 (or IPv6) address. - There is currently an
ipv6boolean setting. To preserve backward compatibility with existing configs,ipv6set to a boolean value is ignored (other than a warning). - There is no
ifv4-skiporifv6-skipbecause it's ddclient's responsibility to properly parse the output of whatever tool it uses to read the interface's addresses. - For now there is no
cmdv4-skiporcmdv6-skip. Anyone who already knows how to write a regular expression can probably write a wrapper script. These may be added in the future if users request them, especially if it facilitates migration away from the deprecatedcmd-skipsetting. - For
usev6=ifv6, interfaces are likely to have several IPv6 addresses (unlike IPv4). Choosing the "right" IPv6 address is not trivial. Fortunately, we don't have to solve this perfectly right now; we can choose something that mostly works and let user bug reports guide future refinements. For the first iteration, we will try the following:- Ignore addresses that are not global unicast.
(Unfortunately, the
ipcommand from iproute2 does not provide a way to filter out ULA addresses so we will have to do this ourselves.) - Ignore temporary addresses.
- If no addresses remain, log a warning and don't update the IPv6 record.
- Otherwise, if one of the remaining addresses matches the previously selected address, continue to use it.
- Otherwise, select one arbitrarily.
- Ignore addresses that are not global unicast.
(Unfortunately, the
- The value of
- Deprecate the
usesetting (print a loud warning) but keep its existing semantics with an exception: If there is a conflict withusev4orusev6then those take priority:- If
use,usev4, andusev6are all set then a warning is logged and theusesetting is ignored. - If
useandusev4are both set and theusestrategy discovers an IPv4 address that differs from the address discovered by theusev4strategy, then the address fromusev4is used and a warning is logged. - If
useandusev6are both set and theusestrategy discovers an IPv6 address that differs from the address discovered by theusev6strategy, then the address fromusev6is used and a warning is logged.
- If
- If
usev4(usev6) is not set:- If
ipv4(usev6) is set, ddclient acts as ifusev4(usev6) was set toipv4(ipv6). - Otherwise, if
ifv4(ifv6) is set, ddclient acts as ifusev4(usev6) was set toifv4(ifv6). - Otherwise, if
cmdv4(cmdv6) is set, ddclient acts as ifusev4(usev6) was set tocmdv4(cmdv6). - Otherwise, if
fwv4(fwv6) is set, ddclient acts as ifusev4(usev6) was set tofwv4(fwv6). - Otherwise,
usev4(usev6) remains unset.
- If
- To support separate credentials for IPv4 vs. IPv6 updates, users can specify the same host multiple times, each time with different options.
Internal API changes
-
Add two new entries to the
$config{$host}hash:$config{$host}{'wantipv4'}is set to:- If
usev4is enabled, the IPv4 address discovered by theusev4strategy. - Otherwise, if
useis enabled and theusestrategy discovered an IPv4 address, the IPv4 address discovered by theusestrategy. - Otherwise,
undef.
- If
$config{$host}{'wantipv6'}is set to:- If
usev6is enabled, the IPv6 address discovered by theusev6strategy. - Otherwise, if
useis enabled and theusestrategy discovered an IPv6 address, the IPv6 address discovered by theusestrategy. - Otherwise,
undef.
- If
-
Deprecate the existing
$config{$host}{'wantip'}entry, to be removed after all update protocol callbacks have been updated to use the above new entries. In the meantime, this entry's value depends on which ofuse,usev4, andusev6is enabled, and what type of IP address is discovered by theusestrategy (if enabled), according to the following table:useusev4usev6resulting value ✔(IPv4) ✖ ✖ the IPv4 address discovered by the usestrategy✔(IPv6) ✖ ✖ the IPv6 address discovered by the usestrategy✖ ✔ ✖ the IPv4 address discovered by the usev4strategy✖ ✖ ✔ the IPv6 address discovered by the usev6strategy✔(IPv4) ✔ ✖ the IPv4 address discovered by the usev4strategy (and log another warning if it doesn't match the IPv4 address found by theusestrategy)✔(IPv6) ✔ ✖ the IPv6 address discovered by the usestrategy✔(IPv4) ✖ ✔ the IPv4 address discovered by the usestrategy✔(IPv6) ✖ ✔ the IPv6 address discovered by the usev6strategy (and log another warning if it doesn't match the IPv6 address found by theusestrategy) -
To support separate credentials for IPv4 vs. IPv6 updates, convert the
%confighash of host configs into a list of host configs. A second definition for the same host adds a second entry rather than overwrites the existing entry.
Alternatives Considered
Repurpose the existing settings for v4
Rather than create new usev4, ifv4, cmdv4, etc. settings,
repurpose the existing use, if, cmd, etc. settings for IPv4.
Why this was rejected:
- There is a usability advantage to the symmetry with the
v6settings. - It is easier to remain compatible with existing configurations.
Let use set the default for usev4
Rather than three separate IP discovery mechanisms (use, usev4,
and usev6), have just two (usev4 and usev6) and let the old
use setting control the default for usev4: If usev4 is not set,
then use=foo is equivalent to usev4=foov4.
Why this was rejected: Backwards incompatibility. Specifically, configurations that previously updated an IPv6 record would instead (attempt to) update an IPv4 record.
Let use set the default for usev4 and usev6
Rather than three separate IP discovery mechanisms (use, usev4,
and usev6), have just two (usev4 and usev6) and let the old
use setting control the default for usev4 and usev6:
- If neither
usev4norusev6is set, thenuse=foois equivalent tousev4=foov4,usev6=foov6. - If
usev4is set but notusev6, thenuse=foois equivalent tousev6=foov6. - If
usev6is set but notusev4, thenuse=foois equivalent tousev4=foov4. - If both
usev4andusev6are set, thenuse=foois ignored.
Why this was rejected: The new design would cause existing configurations to trigger surprising, and possibly undesired (e.g., timeouts or update errors), new behavior:
- Configurations that previously updated only an IPv4 record would also update an IPv6 record.
- Similarly, configurations that previously updated only an IPv6 record would also update an IPv4 record.
Replace uses of 'wantip' with 'wantipv4'
Rather than support 'wantip', 'wantipv4', and 'wantipv6', just
replace all 'wantip' references to 'wantipv4'.
Why this was rejected: This would break compatibility for users that
are currently updating IPv6 addresses. (Compatibility would be
restored once the update protocol callbacks are updated to honor
'wantipv6'.)
Single if setting for both usev4=if and usev6=if
The proposed design calls for separate ifv4 and ifv6 settings. If
the user sets usev4=if,usev6=if, then the user most likely wants to
use the same interface for both IPv4 and IPv6. Rather than create
separate ifv4 and ifv6 settings, have a single if setting used
for both usev4 and usev6.
Why this was rejected:
- Separate
v4andv6settings adds consistency to the configuration. - There are cases where a user will want to use a different interface. In particular, an IPv6 over IPv4 tunnel (e.g., https://tunnelbroker.net) involves creating a separate interface that is used only for IPv6.
Separate IPv4 and IPv6 credentials
In order to support providers that use separate credentials for IPv4 and IPv6 updates, the proposed design allows the user to define the same host twice. We could instead add additional options so that the user can provide both sets of credentials in a single host definition.
Why this was rejected:
-
The proposed design is easier to implement, as it does not require any modifications to existing protocol implementations.
-
The proposed design is less likely to cause problems for users that rely on globals instead of host-specific options. For example, a configuration file like the following might not do what the user expects:
ssl=true, use=if, if=eth0 protocol=foo login=username-for-ipv4 password=password-for-ipv4 loginv6=username-for-ipv6 passwordv6=password-for-ipv6 myhost.example.com protocol=bar login=username password=password # This host definition will use loginv6, passwordv6 from above # because the user didn't end each setting with a line # continuation: my-other-host.example.com -
The proposed design provides some bonus functionality:
- Users can smoothly transition between different providers by updating both providers simultaneously until the domain registration switches to the new registrar.
- Users can take advantage of providers that support multiple A or multiple AAAA records for the same hostname, assuming each record has independent credentials.