1 Commits

Author SHA1 Message Date
Tore Anderson
f564300918 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
2025-02-14 19:26:51 +01:00
2 changed files with 13 additions and 45 deletions

View File

@@ -7,11 +7,9 @@ DNF_OR_YUM:=$(shell which dnf || which yum)
SYSTEMCTL:=$(shell which systemctl)
TAYGA:=$(shell which tayga)
all:
install:
# Install the main script
install -D -m0755 clatd $(DESTDIR)$(PREFIX)/sbin/clatd
install -m0755 clatd $(DESTDIR)$(PREFIX)/sbin/clatd
# Install manual page if pod2man is installed
pod2man --name clatd --center "clatd - a CLAT implementation for Linux" --section 8 README.pod $(DESTDIR)$(PREFIX)/share/man/man8/clatd.8 && gzip -f9 $(DESTDIR)$(PREFIX)/share/man/man8/clatd.8 || echo "pod2man is required to generate manual page"
# Install systemd service file if applicable for this system

54
clatd
View File

@@ -27,7 +27,7 @@ use strict;
use IPC::Cmd qw(can_run);
use Net::IP;
my $VERSION = "2.1.0";
my $VERSION = "2.0.0";
#
# Populate the global config hash with the default values
@@ -42,7 +42,6 @@ $CFG{"clat-v4-addr"} = "192.0.0.1"; # from RFC 7335
$CFG{"clat-v6-addr"} = "shared"; # re-use primary address from host OS
$CFG{"dns64-servers"} = undef; # use system resolver by default
$CFG{"cmd-ip"} = "ip"; # assume in $PATH
$CFG{"cmd-ipxlat-ctl"} = "ipxlat-ctl"; # assume in $PATH
$CFG{"cmd-networkctl"} = "networkctl"; # assume in $PATH
$CFG{"cmd-nft"} = "nft"; # assume in $PATH
$CFG{"cmd-tayga"} = "tayga"; # assume in $PATH
@@ -63,7 +62,6 @@ $CFG{"v4-defaultroute-replace"} = 0; # replace existing v4 defaultroute?
$CFG{"v4-defaultroute-metric"} = 2048; # metric for the IPv4 defaultroute
$CFG{"v4-defaultroute-mtu"} = 1260; # MTU for the IPv4 defaultroute
$CFG{"v4-defaultroute-advmss"} = 0; # TCP MSS for the IPv4 defaultroute
$CFG{"xlat-engine"} = undef; # which translation engine to use
#
@@ -359,8 +357,7 @@ sub get_plat_prefix_from_dns64 {
$res->nameservers(map {
Net::IP->new($_)->version() == 4 ? "::ffff:$_" : $_;
} $res->nameservers);
d2("Nameservers after Net::DNS bug workaround: ",
join(" ", $res->nameservers));
d2("Nameservers after Net::DNS bug workaround: ", $res->nameservers);
my $pkt = $res->query('ipv4only.arpa', 'AAAA');
if(!$pkt) {
@@ -394,7 +391,7 @@ sub get_plat_prefix_from_dns64 {
p("No PLAT prefix could be discovered, using fallback");
return $CFG{"plat-fallback-prefix"};
} else {
p("No PLAT prefix could be discovered. Your connection probably doesn't provide",
p("No PLAT prefix could be discovered. Your ISP probably doesn't provide",
" NAT64/DNS64 PLAT service. Exiting.");
cleanup_and_exit(0);
}
@@ -668,7 +665,6 @@ sub get_clat_v6_addr {
#
my $cleanup_remove_tayga_clat_dev; # true if having created it
my $cleanup_remove_nat46_clat_dev; # true if having created it
my $cleanup_remove_ipxlat_clat_dev; # true if having created it
my $cleanup_delete_taygaconf; # true if having made a temp confile
my $cleanup_zero_forwarding_sysctl; # zero forwarding sysctl if set
my @cleanup_accept_ra_sysctls; # accept_ra sysctls to be reset to '1'
@@ -700,9 +696,6 @@ sub cleanup_and_exit {
print $nat46_control_fh "del ", cfg("clat-dev"), "\n";
close($nat46_control_fh) or err("close($nat46_control_fh: $!");
}
if(defined($cleanup_remove_ipxlat_clat_dev)) {
cmd(\&w, cfg("cmd-ip"), qw(link delete dev), cfg("clat-dev"));
}
if(defined($cleanup_zero_forwarding_sysctl)) {
d("Cleanup: Resetting forwarding sysctl to 0");
sysctl("net/ipv6/conf/all/forwarding", 0);
@@ -913,31 +906,17 @@ if(cfgbool("v4-conncheck-enable") and !cfgbool("v4-defaultroute-replace")) {
d("Skipping IPv4 connectivity check at user request");
}
# Let's figure out if there's nat46 kernel module loaded
my $nat46_controlfile = "/proc/net/nat46/control";
my $use_nat46 = (-e $nat46_controlfile);
#
# Auto-detect which translation engine to use if not specified in config
if(!cfg("xlat-engine") and (-e $nat46_controlfile)) {
p("Using translation engine: nat46");
$CFG{"xlat-engine"} = "nat46";
} elsif(!cfg("xlat-engine") and can_run(cfg("cmd-ipxlat-ctl"))) {
p("Using translation engine: ipxlat");
$CFG{"xlat-engine"} = "ipxlat";
} elsif(!cfg("xlat-engine") and can_run(cfg("cmd-tayga"))) {
p("Using translation engine: TAYGA");
$CFG{"xlat-engine"} = "tayga";
} elsif(!cfg("xlat-engine")) {
err("No supported translation engine available. Please install TAYGA or ensure ",
"either the nat46 or ipxlat kernel modules is loaded.");
}
#
# Write out the TAYGA config file, either to the user-specified location,
# or to a temporary file (which we'll delete later)
#
if(cfg("xlat-engine") eq "tayga") {
unless($use_nat46) {
my $tayga_conffile = cfg("tayga-conffile");
my $tayga_conffile_fh;
if(!$tayga_conffile) {
@@ -1047,17 +1026,14 @@ close($fd) or err("'ip -6 rule show prio 0 table local' failed");
# route to the corresponding IPv6 address, and possibly an IPv4 default route
#
p("Creating and configuring up CLAT device '", cfg("clat-dev"), "'");
if(cfg("xlat-engine") eq "nat46") {
if($use_nat46) {
my $nat46_control_fh;
open($nat46_control_fh, ">$nat46_controlfile") or
err("Could not open nat46 control socket for writing");
print $nat46_control_fh "add ", cfg("clat-dev"), "\n";
close($nat46_control_fh) or err("close($nat46_control_fh: $!");
$cleanup_remove_nat46_clat_dev = 1;
} elsif(cfg("xlat-engine") eq "ipxlat") {
cmd(\&err, cfg("cmd-ip"), qw(link add name), cfg("clat-dev"), qw(type ipxlat));
$cleanup_remove_ipxlat_clat_dev = 1;
} elsif(cfg("xlat-engine") eq "tayga") {
} else {
cmd(\&err, cfg("cmd-tayga"), "--config", cfg("tayga-conffile"), "--mktun",
cfgint("debug") ? "-d" : "");
$cleanup_remove_tayga_clat_dev = 1;
@@ -1079,13 +1055,13 @@ if(cfgint("ctmark")) {
or err("'nft -f-' failed to execute");
print $fd "add table ip6 clatd\n";
print $fd "add chain ip6 clatd prerouting ",
"{ type filter hook prerouting priority mangle; }\n";
"{ type filter hook prerouting priority 0; }\n";
print $fd "add rule ip6 clatd prerouting",
" iif ", cfg("clat-dev"),
" ip6 saddr ", cfg("clat-v6-addr"),
" ip6 daddr ", cfg("plat-prefix"),
" ct mark set ", cfgint("ctmark"),
# set meta mark as well, to placate firewalld's IPv6_rpfilter and NixOS' rpfilter rules
# set meta mark as well, to placate firewalld's IPv6_rpfilter
" meta mark set ", cfgint("ctmark"), " counter\n";
print $fd "add rule ip6 clatd prerouting",
" iif ", cfg("plat-dev"),
@@ -1139,7 +1115,7 @@ if(cfg("script-up")) {
# All preparation done! We can now start nat46 or TAYGA, which will handle the actual
# translation of IP packets.
#
if(cfg("xlat-engine") eq "nat46") {
if($use_nat46){
p("Setting up nat46 kernel module");
my $nat46_control_fh;
open($nat46_control_fh, ">$nat46_controlfile") or
@@ -1155,13 +1131,7 @@ if(cfg("xlat-engine") eq "nat46") {
$SIG{'INT'} = \&cleanup_handler;
$SIG{'TERM'} = \&cleanup_handler;
sleep();
} elsif(cfg("xlat-engine") eq "ipxlat") {
cmd(\&err, cfg("cmd-ipxlat-ctl"), cfg("clat-dev"), "pool6", cfg("plat-prefix"));
# Nothing more to do here, we just set up a cleanup handler and sleep forever.
$SIG{'INT'} = \&cleanup_handler;
$SIG{'TERM'} = \&cleanup_handler;
sleep();
} elsif(cfg("xlat-engine") eq "tayga") {
} else {
my $tayga_conffile = cfg("tayga-conffile");
p("Starting up TAYGA, using config file '$tayga_conffile'");