Get PLAT prefix from systemd-networkd, if possible
Makes clatd check if systemd-networkd is aware of any PLAT prefix (which it may have learned from the PREF64 Router Advertisement option, cf. RFC 8781). If a prefix is obtained from systemd-network, DNS64-based PLAT prefix discovery is skipped, as mandated by https://datatracker.ietf.org/doc/draft-ietf-v6ops-prefer8781/. However, if the dns64-servers config option is set, clatd will use DNS64-based PLAT prefix discovery towards the specified servers, and it will not query systemd-networkd at all. Closes #32
This commit is contained in:
4
Makefile
4
Makefile
@@ -20,8 +20,8 @@ install:
|
|||||||
|
|
||||||
installdeps:
|
installdeps:
|
||||||
# .deb/apt-get based distros
|
# .deb/apt-get based distros
|
||||||
if test -x "$(APT_GET)"; then $(APT_GET) -y install perl-base perl-modules libnet-ip-perl libnet-dns-perl iproute2 nftables tayga; fi
|
if test -x "$(APT_GET)"; then $(APT_GET) -y install perl-base perl-modules libnet-ip-perl libnet-dns-perl libjson-perl iproute2 nftables tayga; fi
|
||||||
# .rpm/DNF/YUM-based distros
|
# .rpm/DNF/YUM-based distros
|
||||||
if test -x "$(DNF_OR_YUM)"; then $(DNF_OR_YUM) -y install perl perl-IPC-Cmd perl-Net-IP perl-Net-DNS perl-File-Temp iproute nftables; fi
|
if test -x "$(DNF_OR_YUM)"; then $(DNF_OR_YUM) -y install perl perl-IPC-Cmd perl-Net-IP perl-Net-DNS perl-File-Temp perl-JSON iproute nftables; fi
|
||||||
# If necessary, try to install the TAYGA .rpm using dnf/yum. It is unfortunately not available in all .rpm based distros (in particular CentOS/RHEL).
|
# If necessary, try to install the TAYGA .rpm using dnf/yum. It is unfortunately not available in all .rpm based distros (in particular CentOS/RHEL).
|
||||||
if test -x "$(DNF_OR_YUM)" && test ! -x "$(TAYGA)"; then $(DNF_OR_YUM) -y install tayga || echo "ERROR: Failed to install TAYGA using dnf/yum, the package is probably not included in your distro. Try enabling the EPEL repo <URL: https://fedoraproject.org/wiki/EPEL> and try again, or install TAYGA <URL: http://www.litech.org/tayga> directly from source."; exit 1; fi
|
if test -x "$(DNF_OR_YUM)" && test ! -x "$(TAYGA)"; then $(DNF_OR_YUM) -y install tayga || echo "ERROR: Failed to install TAYGA using dnf/yum, the package is probably not included in your distro. Try enabling the EPEL repo <URL: https://fedoraproject.org/wiki/EPEL> and try again, or install TAYGA <URL: http://www.litech.org/tayga> directly from source."; exit 1; fi
|
||||||
|
|||||||
29
README.pod
29
README.pod
@@ -241,17 +241,32 @@ with using B<clatd> as a SIIT-DC Edge Relay (I<RFC 7756>).
|
|||||||
=item B<dns64-servers=srv1,[srv2,..]> (default: use system resolver)
|
=item B<dns64-servers=srv1,[srv2,..]> (default: use system resolver)
|
||||||
|
|
||||||
Comma-separated list of DNS64 servers to use when discovering the PLAT prefix
|
Comma-separated list of DNS64 servers to use when discovering the PLAT prefix
|
||||||
using the method described in RFC 7050. By default, the system resolver is
|
using the method described in I<RFC 7050>. By default, B<clatd> will first try
|
||||||
used, but it might be useful to override this in case your ISP doesn't provide
|
to determine if systemd-networkd is aware of a PLAT prefix (learned from the
|
||||||
you with a DNS64-enabled name server, and you want to test B<clatd> using any of
|
PREF64 Router Advertisement option, cf. I<RFC 8781>), falling back on using
|
||||||
the public DNS64/NAT64 instances on the internet. The first PLAT prefix
|
DNS64 discovery towards the system resolver if it isn't.
|
||||||
encountered will be used.
|
|
||||||
|
It might be useful to override this in case your network does not advertise the
|
||||||
|
PREF64 RA option, your ISP doesn't provide you with a DNS64-enabled name
|
||||||
|
server, and you want to test B<clatd> using any of the public DNS64/NAT64
|
||||||
|
instances on the internet. The first PLAT prefix encountered will be used.
|
||||||
|
|
||||||
=item B<cmd-ip=path> (default: assume in $PATH)
|
=item B<cmd-ip=path> (default: assume in $PATH)
|
||||||
|
|
||||||
Path to the B<ip> binary from the iproute2 package available at
|
Path to the B<ip> binary from the iproute2 package available at
|
||||||
L<https://www.kernel.org/pub/linux/utils/net/iproute2>. Required.
|
L<https://www.kernel.org/pub/linux/utils/net/iproute2>. Required.
|
||||||
|
|
||||||
|
=item B<cmd-networkctl=path> (default: assume in $PATH)
|
||||||
|
|
||||||
|
Path to the B<networkctl> binary from systemd-networkd. Required in order to
|
||||||
|
use any PLAT prefix discovered by systemd-networkd from the PREF64 Router
|
||||||
|
Advertisement option (see I<RFC 8781> and the I<UsePREF64> option in
|
||||||
|
I<systemd.network(5)> for more information). The first prefix returned is used,
|
||||||
|
any others are ignored.
|
||||||
|
|
||||||
|
To prevent PLAT prefix discovery via systemd-networkd from being attempted, set
|
||||||
|
this to an empty string.
|
||||||
|
|
||||||
=item B<cmd-nft=path> (default: assume in $PATH)
|
=item B<cmd-nft=path> (default: assume in $PATH)
|
||||||
|
|
||||||
Path to the B<nft> binary from the nftables package available at
|
Path to the B<nft> binary from the nftables package available at
|
||||||
@@ -493,9 +508,9 @@ SOFTWARE.
|
|||||||
|
|
||||||
=head1 SEE ALSO
|
=head1 SEE ALSO
|
||||||
|
|
||||||
ip(8), nft(8), tayga(8), tayga.conf(5)
|
ip(8), nft(8), systemd.network(5), tayga(8), tayga.conf(5)
|
||||||
|
|
||||||
RFC 6052, RFC 6145, RFC 6146, RFC 6877, RFC 7050, RFC 7335 RFC 7755, RFC 7756,
|
RFC 6052, RFC 6145, RFC 6146, RFC 6877, RFC 7050, RFC 7335 RFC 7755, RFC 7756,
|
||||||
RFC 7757
|
RFC 7757, RFC 8781
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|||||||
63
clatd
63
clatd
@@ -42,6 +42,7 @@ $CFG{"clat-v4-addr"} = "192.0.0.1"; # from RFC 7335
|
|||||||
$CFG{"clat-v6-addr"} = "shared"; # re-use primary address from host OS
|
$CFG{"clat-v6-addr"} = "shared"; # re-use primary address from host OS
|
||||||
$CFG{"dns64-servers"} = undef; # use system resolver by default
|
$CFG{"dns64-servers"} = undef; # use system resolver by default
|
||||||
$CFG{"cmd-ip"} = "ip"; # assume in $PATH
|
$CFG{"cmd-ip"} = "ip"; # assume in $PATH
|
||||||
|
$CFG{"cmd-networkctl"} = "networkctl"; # assume in $PATH
|
||||||
$CFG{"cmd-nft"} = "nft"; # assume in $PATH
|
$CFG{"cmd-nft"} = "nft"; # assume in $PATH
|
||||||
$CFG{"cmd-tayga"} = "tayga"; # assume in $PATH
|
$CFG{"cmd-tayga"} = "tayga"; # assume in $PATH
|
||||||
$CFG{"cmd-ufw"} = "ufw"; # assume in $PATH
|
$CFG{"cmd-ufw"} = "ufw"; # assume in $PATH
|
||||||
@@ -329,7 +330,7 @@ sub find_rfc7050_wka {
|
|||||||
# up to see if the well-known hostname 'ipv4only.arpa' resolves to an IPv6
|
# up to see if the well-known hostname 'ipv4only.arpa' resolves to an IPv6
|
||||||
# address, if so there is a high chance of DNS64 being used.
|
# address, if so there is a high chance of DNS64 being used.
|
||||||
#
|
#
|
||||||
sub get_plat_prefix {
|
sub get_plat_prefix_from_dns64 {
|
||||||
p("Performing DNS64-based PLAT prefix discovery (cf. RFC 7050)");
|
p("Performing DNS64-based PLAT prefix discovery (cf. RFC 7050)");
|
||||||
|
|
||||||
require Net::DNS;
|
require Net::DNS;
|
||||||
@@ -397,6 +398,62 @@ sub get_plat_prefix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function attempts request a PLAT prefix from systemd-networkd, which
|
||||||
|
# systemd-networkd will know about if the Router Advertisements contain the
|
||||||
|
# PREF64 option defined in RFC 8781, and systemd-networkd is configured with
|
||||||
|
# UsePREF64=true (not the default). The first prefix seen is used, subsequent
|
||||||
|
# ones are ignored.
|
||||||
|
#
|
||||||
|
sub get_plat_prefix_from_networkd {
|
||||||
|
if(!can_run(cfg("cmd-networkctl"))) {
|
||||||
|
d(cfg("cmd-networkctl"), " is not installed or not exectutable, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p("Attempting to query systemd-networkd for PLAT prefix (cf. RFC 8781)");
|
||||||
|
open(my $fd, '-|', cfg("cmd-networkctl"), qw(--json=short status))
|
||||||
|
or err(cfg("cmd-networkctl"), " failed to execute");
|
||||||
|
my @out = <$fd>;
|
||||||
|
if(!close($fd)) {
|
||||||
|
p("'networkctl status' failed, trying DNS64 PLAT prefix discovery");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require JSON;
|
||||||
|
my $status = JSON::decode_json("@out");
|
||||||
|
|
||||||
|
return unless($status->{"Interfaces"});
|
||||||
|
|
||||||
|
for my $interface (@{$status->{"Interfaces"}}) {
|
||||||
|
next if(!$interface->{"NDisc"}->{"PREF64"});
|
||||||
|
|
||||||
|
d2($interface->{"Name"}, " PREF64 bytes: ",
|
||||||
|
join(" ", @{$interface->{"NDisc"}->{"PREF64"}->[0]->{"Prefix"}}),
|
||||||
|
" / ", $interface->{"NDisc"}->{"PREF64"}->[0]->{"PrefixLength"});
|
||||||
|
|
||||||
|
# PREF64 is an array of bytes, convert to IPv6 string representation
|
||||||
|
my @bytes = @{$interface->{"NDisc"}->{"PREF64"}->[0]->{"Prefix"}};
|
||||||
|
my $ipstr;
|
||||||
|
for (my $i = 0; $i < @bytes;) {
|
||||||
|
$ipstr .= sprintf("%02x%02x", $bytes[$i++], $bytes[$i++]);
|
||||||
|
$ipstr .= ":" if($i < @bytes);
|
||||||
|
}
|
||||||
|
$ipstr .= "/" . $interface->{"NDisc"}->{"PREF64"}->[0]->{"PrefixLength"};
|
||||||
|
|
||||||
|
d2("String representation: $ipstr");
|
||||||
|
|
||||||
|
# Run the result through Net::IP to ensure we have a valid IPv6 string
|
||||||
|
# and also to convert it to compact format.
|
||||||
|
my $ip = Net::IP->new($ipstr, 6)
|
||||||
|
or err("Failed to convert PREF64 bytes array to IPv6 string format");
|
||||||
|
|
||||||
|
my $prefix = $ip->short() . "/" . $ip->prefixlen();
|
||||||
|
d("Obtained PLAT prefix $prefix from systemd-networkd");
|
||||||
|
return $prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This function figures out which network interface on the system faces the
|
# This function figures out which network interface on the system faces the
|
||||||
# PLAT/NAT64. We need this when generating an IPv6 address for the CLAT, when
|
# PLAT/NAT64. We need this when generating an IPv6 address for the CLAT, when
|
||||||
@@ -770,7 +827,9 @@ p("Starting clatd v$VERSION by Tore Anderson <tore\@fud.no>");
|
|||||||
#
|
#
|
||||||
# Step 1: Fill in any essential blanks in the configuration by auto-detecting
|
# Step 1: Fill in any essential blanks in the configuration by auto-detecting
|
||||||
# any missing values.
|
# any missing values.
|
||||||
$CFG{"plat-prefix"} ||= get_plat_prefix();
|
$CFG{"plat-prefix"} ||= get_plat_prefix_from_networkd()
|
||||||
|
unless($CFG{"dns64-servers"});
|
||||||
|
$CFG{"plat-prefix"} ||= get_plat_prefix_from_dns64();
|
||||||
if(!$CFG{"plat-prefix"}) {
|
if(!$CFG{"plat-prefix"}) {
|
||||||
w("No PLAT prefix was discovered or specified; 464XLAT cannot work.");
|
w("No PLAT prefix was discovered or specified; 464XLAT cannot work.");
|
||||||
exit 0;
|
exit 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user