clatd
clatd copied to clipboard
implement RFC 8781 (Discovering PREF64 in Router Advertisements)
Hi
RFC 8781 (https://www.rfc-editor.org/rfc/rfc8781.txt) is a nice way to get the plat-prefix direct by the router. So you don't need the dns64 server.
It is very unlikely that I would be able to implement this in clatd, because the receipt and parsing of ICMPv6 RAs are either done by the kernel or some user-space network management service like NetworkManager or systemd-networkd.
If they expose the prefix somewhere, like in sysfs or dbus, I guess it would be possible to look it up. I am not aware of any way to do it, though.
I'm currently writing a small C program to get the pref64 option. Would it be possible to include this with a plat-detector-script option (option name is just to have an example)?
Sure, I would be happy to include something like that!
In systemd Version 255 a UsePREF64 option was added to networkd:
https://www.freedesktop.org/software/systemd/man/latest/systemd.network.html#UsePREF64=
Not sure if there are already tools taking advantage of it to have an implementation example.
To me it seems hoewer sensible to rely on the network configuration utilities to get that information.
In systemd Version 255 a UsePREF64 option was added to networkd:
Could someone using this send me output from networkctl --json=pretty status $plat_dev?
Alternatively, add script-up=networkctl --json=pretty status $plat_dev to /etc/clatd.conf and send me output from starting clatd.
@toreanderson Here you go: https://gist.github.com/herbetom/e7a7eb380170d10b599ecc686689a2f1 :)
@herbetom I just realised that I can't do it like that, because the PLAT device isn't known at the time PLAT prefix discovery happens. I need to find the prefix first. Could you send me networkctl --json=pretty status (without specifying a device) instead?
@toreanderson Sure, here is another example of a VM with two network interfaces. One has the PREF64 Option, the other not.
https://gist.github.com/herbetom/7065d329cf545552f706c67202fab33e
But i guess helpful would also be an example with at least two networks with PREF64 and maybe a third that doesn't have it so that it can be tested that the correct one for the default route is selected? But that's something to set up after lunch.
I have just pushed a feature branch that adds support for this now. Could you please try it out and see if it works (and ideally also see if it fails gracefully over to DNS64-based prefix discovery in the cases where systemd-networkd is not in use, is unaware of a PREF64, and so on)?
The feature branch is available here: https://github.com/toreanderson/clatd/tree/rfc8781
Sorry, took me a while to get back to this. Tested it and discovery appears to be working.
But i didn't really test much in the form of corner cases. Only the single case shown below. Since i changed the used NAT64 Prefix (and DNS Server IP to one that doesn't provide DNS64) here is another paste of networkctl --json=pretty status: https://gist.github.com/herbetom/4bf57571b8d08cc7a064ae09ad0057aa
I've used NixOS (24.11) for testing with the following settings and adjustments if anyone else wants to give this a try (and also uses NixOS):
{ pkgs, lib, ... }:
{
networking = {
dhcpcd.enable = false;
useDHCP = false;
useHostResolvConf = false;
};
systemd.network = {
enable = true;
networks."50-enp5s0" = {
matchConfig.Name = "enp5s0";
networkConfig = {
DHCP = "ipv4";
IPv6AcceptRA = true;
};
linkConfig.RequiredForOnline = "routable";
ipv6AcceptRAConfig.UsePREF64 = true;
};
networks."50-enp6s0" = {
matchConfig.Name = "enp6s0";
networkConfig = {
DHCP = "ipv4";
IPv6AcceptRA = true;
};
linkConfig.RequiredForOnline = "routable";
ipv6AcceptRAConfig.UsePREF64 = true;
};
};
networking.nftables.enable = true;
networking.firewall.filterForward = true;
networking.firewall.checkReversePath = false;
services.clatd = {
enable = true;
package = pkgs.clatd.overrideAttrs (oldAttrs: {
version = "2.0.0-rfc8781-1";
src = pkgs.fetchFromGitHub {
owner = "toreanderson";
repo = "clatd";
rev = "f564300918a5007fb3eda0af0a7f59b9c79cfdfb"; # https://github.com/toreanderson/clatd/commits/rfc8781/
hash = "sha256-nDeB9GHzJFtlKmoocJVNDjVwALDN8mgBskli0O5izB4=";
};
buildInputs = with pkgs.perlPackages; [
JSON
] ++ oldAttrs.buildInputs;
postFixup = ''
patchShebangs $out/bin/clatd
wrapProgram $out/bin/clatd \
--set PERL5LIB $PERL5LIB \
--prefix PATH : ${
lib.makeBinPath [
pkgs.tayga
pkgs.iproute2
#pkgs.iptables
pkgs.nftables
]
}
'';
});
};
systemd.services.clatd.serviceConfig.RestrictAddressFamilies = [
"AF_UNIX"
];
}
The Log output with this is the following:
Feb 21 15:19:10 test23 systemd[1]: Started 464XLAT CLAT daemon.
Feb 21 15:19:11 test23 clatd[10039]: Starting clatd v2.0.0 by Tore Anderson <[email protected]>
Feb 21 15:19:11 test23 clatd[10039]: Attempting to query systemd-networkd for PLAT prefix (cf. RFC 8781)
Feb 21 15:19:11 test23 clatd[10039]: Using PLAT (NAT64) prefix: 2001:67c:2960:6464::/96
Feb 21 15:19:21 test23 clatd[10039]: Device facing the PLAT: enp6s0
Feb 21 15:19:21 test23 clatd[10039]: Using CLAT IPv4 address: 192.0.0.1
Feb 21 15:19:21 test23 clatd[10039]: Using CLAT IPv6 address: 2a0e:b107:eb0:300:216:3eff:fe69:5d3e
Feb 21 15:19:21 test23 clatd[10039]: Checking if this system already has IPv4 connectivity in 10 sec(s)
Feb 21 15:19:21 test23 clatd[10039]: Enabling IPv6 forwarding
Feb 21 15:19:21 test23 clatd[10039]: Creating and configuring up CLAT device 'clat'
Feb 21 15:19:21 test23 clatd[10046]: Created persistent tun device clat
Feb 21 15:19:21 test23 clatd[10039]: Adding clatd nftable, using conntrack mark 49575
Feb 21 15:19:21 test23 clatd[10039]: Adding IPv4 default route via the CLAT
Feb 21 15:19:21 test23 clatd[10039]: Starting up TAYGA, using config file '/tmp/gh1oHHuP4S'
Feb 21 15:19:21 test23 tayga[10058]: starting TAYGA 0.9.2
Feb 21 15:19:21 test23 tayga[10058]: Using tun device clat with MTU 1500
Feb 21 15:19:21 test23 tayga[10058]: TAYGA's IPv4 address: 192.0.0.2
Feb 21 15:19:21 test23 tayga[10058]: TAYGA's IPv6 address: 2001:67c:2960:6464::c000:2
Feb 21 15:19:21 test23 tayga[10058]: NAT64 prefix: 2001:67c:2960:6464::/96
It seems like the wrong "CLAT IPv6 address" is beeing used. That address belongs to a different Interface then the one where the PREF64 Option is received. It's still working but if this wouldn't be a Public NAT64 Prefix i'm not sure it would.
As discussed with Tore on IRC I have a design and (partial) implementation for facilitating access to RA options like PREF64 without systemd-networkd or NetworkManager. Currently only the [DESIGN] doc is public https://gist.github.com/DanielG/4d1cba309c9ed541038e2c2f7a346109 will work on getting the program published and uploaded to Debian also. Help welcome.
--Daniel
@herbetom What clatd does, is to perform a route lookup towards the NAT64 prefix in order to find the outgoing interface. In your case that would be ip route get 2001:67c:2960:6464::.
If I understand you correctly you are receiving a NAT64 prefix on interface X, but the outgoing route to that prefix is using interface Y. Therefore clatd picks an address from interface Y.
It's not necessarily the case that it would be any better to pick an address from interface X, because the Linux kernel would still route the packets towards the NAT64 out interface Y, but ISP Y might drop those packets as being spoofed (using a source address belonging to ISP X). Or, in the case of a non-public prefix (e.g., 64:ff9b::/96), ISP Y might not be able to reach the NAT64 instance at all.
In any case, this is no different from the DNS64 method of prefix discovery. Your system might have learned DNS servers both from ISPs X and Y, and the local resolver might give an answer for ipv4only.arpa that came from ISP X's DNS server, but you still might have the outgoing route to that prefix via ISP Y, so you end up in the same situation.
I don't really see how clatd could behave any different here.