Skip to main content


My effort during IETF 118 hackathon got merged. Now you can use clatd by @tore not only with TAYGA user-space translator but also with nat46 kernel-space translator: https://github.com/toreanderson/clatd/commit/6d2ad96c2f89c86d6d93e1dfc83fd03045754e54

We are still far from the universal availability of CLAT on Linux, but at least we started to move.

in reply to Ondřej Caletka

Thank you very much for your contribution, @Oskar456 ! 👌

It would have been much better if the functionality of clatd was included in the standard network management components like NetworkManager and systemd-networkd (honestly clatd is meant mostly as a proof of concept), but I doubt that will happen before there's a decent SIIT/NAT46 translation engine included in the upstream kernel.

in reply to Tore Anderson

definitely, that's the ultimate goal. But it still needs to be figured out what is going to do the actual packet translation.
During the hackathon, I also received a tip on how to make the clat least intrusive to the host OS - that means no forwarding enabled and no fiddling with firewall.

I have made a PoC and it seems to work quite well:
https://gist.github.com/oskar456/d898bf2e11b642757800a5ccdc2415aa

I would like to try to write a daemon to automate such a setup and eventually integrate to NM and similar.

in reply to Ondřej Caletka

Very nice! I've done something similar for a #k8s cluster that needed #NAT64 translation for its containers. One thing I did have to add was filtering within the namespace, since Jool was unexpectedly translating RFC1918 addresses when using the well-known prefix.

It was unclear to me why Jool was doing that, but all was easily fixed with some reject rules for each of the rfc1918 address subnets.

in reply to Ti Nguyen

@litchralee_v6
If I remember correctly android clat translates rfc1918 addresses too.(with the well known prefix)
in reply to Thomas Schäfer

@tschaefer What I had in mind was the restriction from RFC6053 section 3.1, where the well known prefix is supposed to reject non-global legacy IP addresses.

I suppose it's not a big issue if Android's CLAT tries to initiate traffic with such a destination, but the #NAT64 gateway is supposed to decline to translate that destination within the well known prefix, if I understand the RFC correctly.

in reply to Ti Nguyen

@litchralee_v6 @tschaefer To be honest, I don't get why this restriction even exists - Well-known prefix has only local validity, ie. same validity as private IPv4 addresses. It might make a lot of sense for someone to translate private IPv4 addresses using NAT64.
in reply to Ondřej Caletka

@tschaefer I agree there's definitely a use-case for translating private v4 addresses with NAT64, although there must be some reason this restriction exists for just the well-known prefix and no other prefix usable with NAT64. If I had to guess, it might have to do with the well-known prefix essentially being an anycast alias for v4 hosts, so all translators of that prefix should resolve to the same destination in the end, which would only work for global v4 addresses.
in reply to Ti Nguyen

@tschaefer That said, since Jool is permissive enough to translate the private addresses, and Android clat will request that translation, it seems that the restriction is effectively ignored and so far no ill consequences observed in the field. So it might not be such a big deal after all, despite the RFC.
This entry was edited (6 months ago)
in reply to Ti Nguyen

@litchralee_v6 @tschaefer I think the reason for that restriction is mostly the idea of the uniqueness of IPv6 addresses - the same reason why site-local addresses were deprecated. Basically it is considered beneficial that there is no case where one IPv6 address represents more than one node.

On the other hand, we have cases like NAT64 tethering on macOS which uses the same ULA prefix on every single host.

in reply to Ondřej Caletka

Now that systemd 255 includes support for respecting DHCP Op 108, I think the NAT64 space on Linux got a bit more interesting.

I’m no expert, but doesn’t it make the most sense for this to be done in netfilter in the kernel? That cuts down on it needing to be reimplemented multiple times in NetworkManager, networkd, Netplan etc, and opens the door for it to also work on embedded devices that don’t want to ship a full network management daemon.

in reply to Alex Haydock

Although I’m basing this on the fact that OpenBSD can do PLAT in a single line of pf config, but maybe that’s missing the fact that CLAT is probably harder since the 192.0.0.x interface and gateway do need to be instantiated by something…
in reply to Alex Haydock

@alexhaydock I am pretty sure it is too complex to be done completely in the kernel space.

Even OpenBSD requires some user space daemon to set this up, see https://codeberg.org/fobser/gelatod by @florian

The way this works with OpenBSD routing domains is basically the same solution using Linux network namespaces and Jool.

in reply to Ondřej Caletka

@alexhaydock @florian

What's missing in (vanilla) Linux is an in-kernel SIIT-EAM translation engine. (There are a couple of third party solutions but I doubt the systemd-networkd and NetworkManager developers are interested in supporting those until they are included upstream.)

NAT64 prefix discovery, CLAT interface provisioning and so on probably belongs in user space (prefix discovery should ideally be in a shared library that systemd-networkd and NetworkManager could both use).