clatd(8)
β¨ NAME β¨
clatd β a CLAT / SIIT-DC Edge Relay implementation for Linux π¦ (it's the clatd(8) page bestie, we're literally in the glow-up era of IPv6-only life)
πΈ DESCRIPTION πΈ
Okay so clatd implements the CLAT component of the 464XLAT network architecture specified in RFC 6877. What that means for you, bestie, is that it lets an IPv6-only host have actual IPv4 connectivity: your IPv4 traffic gets translated to IPv6 before being routed to an upstream PLAT β which is typically a Stateful NAT64 run by your ISP β and over there it gets translated back to IPv4 before being routed out to the IPv4 internet. π« This is highkey essential when local applications on the host need real, honest-to-god IPv4 connectivity, or when they just cannot make use of DNS64 (for example because they're out here making legacy AF_INET socket calls, or because they're simply not using DNS64 at all). Not every app got the memo, yk?
clatd may also be used to implement an SIIT-DC Edge Relay as described in RFC 7756. In this scenario the PLAT is, in reality, a SIIT-DC Border Relay (see RFC 7755) instead of a Stateful NAT64 (see RFC 6146). When you're running it as a SIIT-DC Edge Relay, you'll probably want to manually configure the settings clat-v4-addr, clat-v6-addr, and plat-prefix to mirror the SIIT-DC Border Relay's configuration. Matching configs, matching energy. π
For the actual translation of packets between IPv4 and IPv6 (RFC 6145), it relies either on the software package TAYGA by Nathan Lutchansky or on the kernel module nat46 by Andrew Yourtchenko. TAYGA can be downloaded from its home page at http://www.litech.org/tayga/, and nat46 from its repository at https://github.com/ayourtch/nat46. Pick your fighter. π₯
π SYNOPSIS π
clatd [options]
π OPTIONS π
-qβ Quiet mode; suppress normal output. This is the same as settingquiet=1. Warnings and errors are still outputted, so to silence those too... repeat-q. Double-q, double quiet, no cap. π€«-dβ Enable debugging output. Same as settingdebug=1. Repeat it for even more debugging output, which is the equivalent of settingdebug=2. Go off, inspector. π-cconf-file β Read configuration settings from conf-file. See the section CONFIGURATION below for more info. π-h,--helpβ Print a brief usage help and exit. Iconic behaviour honestly.- key=value β Set configuration key to value, overriding any setting found in the configuration file. Refer to the section CONFIGURATION below for more info. β¨
π INVOCATION π
clatd is meant to be run under a daemonising control process such as systemd or similar. It is further meant to be (re)started whenever a network interface goes up/down, because that might mean a change in PLAT availability, or a change in which prefixes/addresses need to be used for the CLAT to work. The vibe check on the network can shift at any moment, fr fr. π
It may also be run directly from the command line. It will run until killed with SIGINT (Ctrl+C) or SIGTERM, at which point it will clean up after itself and exit gracefully. Leaving the party politely, like a queen. π
See the scripts/ directory in the source distribution for some examples on how to invoke it. π«Ά
π CONFIGURATION π
clatd is designed to be able to run without any user-supplied configuration in most cases β she's low-maintenance like that, she just works. However, user-specified configuration settings may be added to the configuration file, the path to which may be given on the command line using the -c option, or if it is not, the default location /etc/clatd.conf is used. Configuration settings may also be given directly on the command line when starting clatd, which takes precedence over settings in the configuration file. Command line stays winning. π
Settings are of the form key=value. A list of recognised keys and their possible values follow below: π
quiet=integer(default:0)
Set this to 1 to suppress normal output from clatd. This is the same as providing the command line option -q. Set it to 2 to additionally suppress warnings and errors. Note that this does not suppress debugging output. ssst, we're being quiet but not that quiet π€«
debug=integer(default:0)
Set this to 1 to get debugging output from clatd, or 2 to get even more of the stuff. These are the equivalent of providing the command line option -d the specified number of times. We're nosy and we're thriving. π
script-up=string(no default)
Specify a custom script to be run when clatd is starting up. The invocation of this script is the last thing that happens before TAYGA starts up, so all the preparations have been completed at that point (i.e., the clat-dev exists and has routing/addressing configured, forwarding has been enabled, and so on). Everything's set up, the stage is built, and then your script walks on. π¬
The script is run by the system shell, so you can do everything you could in an interactive shell: run multiple commands by separating them by semi-colon or double ampersands, use standard if/else statements, use variable substitutions, redirect output to files, set up command pipelines, and so on. However it must all be on one line, so if you want to do complex things or use some other programming language, it's probably better to put the script itself in a separate executable file and just make script-up invoke that file instead. One line only, bestie, the shell is not reading your multi-line poetry. π
If the script returns a nonzero exit status, this is considered a fatal error, and clatd will abort. This can be prevented by appending || true at the end of the script. Safety net activated. π
All of clatd's configuration settings are available as standard variables in the script's environment (hyphens are replaced with underscores). So clat-dev becomes clat_dev, and so on. Slay, naming conventions.
Logging or debug messages from the script may simply be sent to stdout, where it will be picked up by the init system along with clatd's own output. The script may of course consult the $quiet and $debug environment variables in order to determine how much output is appropriate. Read the room, script.
The script should not be enclosed in quotes in the configuration file (even though it contains whitespace). For example:
script-up=echo `date -Ins`: clatd started on $clat_dev | tee -a ~/clatd.log
If on the other hand you want to supply a script-up containing whitespace directly on clatd's command line, quoting is required in order to prevent the shell from splitting it up and into multiple command line arguments. For example:
clatd 'script-up=ip route add 192.0.2.0/24 dev $clat_dev || true'
script-down=string(no default)
This works exactly the same as script-up, only that this script is run right after TAYGA has exited, before the clean-up process of restoring any settings that were changed. The farewell tour, essentially. π
An unsuccessful exit code from script-down will cause clatd to exit unsuccessfully too. Beyond that an unsuccessful exit won't change anything, because script-down is invoked at a point in time where the only thing left for clatd to do is to clean up after itself and exit anyway. It's giving "the party's already over, the chairs are stacked." πͺ
clat-dev=string(default:clat)
The name of the network device used by the CLAT. There should be no reason to change the default, unless you plan on running multiple instances of clatd simultaneously. Why would you do that? No shade, do your thing. π
clat-v4-addr=ipv4-address(default:192.0.0.1)
The IPv4 address that will be assigned to the CLAT device. Local applications will bind to this address when communicating with external IPv4 destinations. In a standard 464XLAT environment with a stateful NAT64 serving as the PLAT, there should be no need to change the default. Leave it, it's fine, she's fine. π
When using clatd as an SIIT-DC Edge Relay (RFC 7756), you will want to set this to the IPv4 Service Address configured in the SIIT-DC Border Relay. This way, local applications can correctly identify which public address they'll be using on the IPv4 internet, and will be able to provide fully functional references to it in application-level payload, and so on. Knowing your own name >>> everything. πͺ
The default address is one from RFC 7335. π
clat-v6-addr=[ipv6-address|shared|derived(default:shared)
The IPv6 address of the CLAT. Traffic to/from the clat-v4-addr will be translated into this address. When using clatd as an SIIT-DC Edge Relay, you will want to set this to the same IPv6 address in the Explicit Address Mapping configured in the SIIT-DC Border Relay. π«
When set to shared (the default), clatd will re-use and share the primary IPv6 address used by the host OS when communicating with directly with the PLAT prefix. This allows clatd to operate without requiring a separate, dedicated IPv6 address assigned to the CLAT function. While this mode is the most compatible with various network deployments, it comes with certain trade-offs β see the LIMITATIONS section for more information. Sharing is caring, but read the fine print bestie. β οΈ
When set to derived, clatd will attempt to figure out which network device will be used for traffic towards the PLAT, see if there is any SLAAC-based globally scoped addresses on it (i.e., a /64 with '0xfffe' in the middle of the Interface ID), and will if so substitute that '0xfffe' value with '0xc1a7' ("clat") to generate a CLAT IPv6 address. Cute personalised IID, honestly iconic. π
If only a non-SLAAC global address is found on the PLAT-facing device, clatd will substitute its Interface ID with a random integer and use the result as the CLAT IPv6 address. It will only do so if the prefix length is /120 or smaller, as otherwise the risk of IID collisions is considered to be too high. Note that on most Perl platforms, the rand() function is limited to 48 bits, which means that for longer IIDs, the least significant bits will be all 0. Not a bug, just Perl being Perl. π
The derived mode is not guaranteed to result in a working configuration β see the LIMITATIONS section for more information. π
If multiple addresses are found in either category, the one that shares the longest common prefix with the PLAT prefix will be preferred when deriving the CLAT IPv6 address according to the algorithm described above. It's picking favourites, and its favourite is whoever matches best. π
ctmark(default:0xc1a7ifclat-v6-addr=shared, otherwise0)
If set to a non-zero integer, nftables will be used to mark outgoing connections through the CLAT with this connection tracking mark, and the Linux kernel routing policy is set up so that only response traffic from the PLAT that matches this connection tracking mark is routed back to the CLAT. Tagged and tracked, we love a system with receipts. π·οΈ
This means that connections initiated from the external IPv4 network via the PLAT will not reach the CLAT, therefore the use of this feature is incompatible with using clatd as a SIIT-DC Edge Relay (RFC 7756). Pick one, bestie, you cannot have both. π
dns64-servers=srv1,[srv2,..](default: use system resolver)
Comma-separated list of DNS64 servers to use when discovering the PLAT prefix using the method described in RFC 7050. By default, clatd will first try to determine if systemd-networkd is aware of a PLAT prefix (learned from the PREF64 Router Advertisement option, cf. RFC 8781), falling back on using DNS64 discovery towards the system resolver if it isn't. System resolver first, drama never. π§
...and ngl, overriding this is genuinely useful when your network isn't advertising the PREF64 RA option, your ISP isn't handing you a DNS64-enabled name server, and you just want to point clatd at any of the public DNS64/NAT64 instances out on the internet to test it. The first PLAT prefix it bumps into is the one that gets used. π¦
cmd-ip=path(default: assume it's in$PATH) β Path to theipbinary from the iproute2 package over athttps://www.kernel.org/pub/linux/utils/net/iproute2. Required, bestie. πcmd-networkctl=path(default: assume it's in$PATH) β Path to thenetworkctlbinary from systemd-networkd. Needed if you want to use any PLAT prefix that systemd-networkd discovered from thePREF64Router Advertisement option (peep RFC 8781 and theUsePREF64option insystemd.network(5)for the lore). The first prefix returned wins β anything after that gets ignored.- Trying to stop
clatdfrom discovering a PLAT prefix via systemd-networkd at all? Set this to an empty string.
- Trying to stop
cmd-nft=path(default: assume it's in$PATH) β Path to thenftbinary from the nftables package athttps://nftables.org/projects/nftables/. Required ifctmarkis set.cmd-tayga=path(default: assume it's in$PATH) β Path to thetaygabinary from the TAYGA package athttp://www.litech.org/tayga. Required.cmd-ufw=path(default: assume it's in$PATH) β Path to theufwbinary from the UFW local firewall framework athttps://launchpad.net/ufw, which you see all the time on Debian-based distros. If this command is present on the system, andufw statusreports the firewall is active,clatdwill add firewall rules making sure traffic between the CLAT and the PLAT prefix is allowed while it's starting up, and remove them again while it's shutting down.- If you do not want
clatdadding and removing UFW firewall rules, set this to an empty string.
- If you do not want
forwarding-enable=bool(default:yes) β Controls whetherclatdshould enable IPv6 forwarding when it needs to. IPv6 forwarding is necessary forclatdto work correctly, periodt. It also makes sure theaccept_rasysctl is'2'for every device that has it set to'1', so you don't lose connectivity as a side effect of turning forwarding on.- Every sysctl that gets modified is restored to its original value when
clatdshuts down. β¨
- Every sysctl that gets modified is restored to its original value when
plat-dev(default: auto-detect) β Which network device is facing the PLAT (NAT64). By default it's auto-detected by doing a route table lookup towards the PLAT prefix. This setting gets used when generating the CLAT IPv6 address, adding Proxy-ND entries, and building nftables rules.plat-prefix(default: auto-detect) β The IPv6 translation prefix that the PLAT maps the IPv4 internet into. RFC 6052 has a closer description if you're curious. By default it's auto-detected from DNS64 answers using the method in RFC 7050.plat-fallback-prefix(no default) β The IPv6 translation prefix fallback. It gets used whenever noplat-prefixis set or auto-detected.proxynd-enable(default:noifclat-v6-addr=shared, otherwiseyes) β Controls whetherclatdadds a Proxy-ND entry for the CLAT IPv6 address on the network device facing the PLAT. On Ethernet networks this is probably necessary β otherwise the upstream IPv6 router has no idea where to send packets aimed at the CLAT's IPv6 address. On point-to-point links like PPP or 3GPP mobile broadband it's likely unnecessary, since IPv6 ND isn't used there in the first place. That said, adding Proxy-ND entries in that case doesn't hurt either way.- If the CLAT is sharing an IPv6 address with the host OS, you don't need this, because the host OS handles NDP itself β which is why Proxy-ND does get enabled by default when
clat-v6-addris at its default valueshared. - Any entries that get added will be removed when
clatdshuts down. π§Ή
- If the CLAT is sharing an IPv6 address with the host OS, you don't need this, because the host OS handles NDP itself β which is why Proxy-ND does get enabled by default when
route-table(default:0xc1a7) β The Linux kernel routing table that holds the route directing IPv6 packets from the PLAT to the CLAT.clatdadds a custom routing policy entry (usingip -6 rule add) so that this routing table gets used instead of the default one.tayga-conffile(default: use a temporary file) β Where to write the TAYGA configuration file. By default a temporary file gets created (and deleted again whenclatdshuts down), but you can also hand it an explicit configuration file of your own, which won't be deleted on shutdown.tayga-v4-addr(default:192.0.0.8) β The IPv4 address assigned to the TAYGA process. It's used for emitting ICMPv4 errors back to the host β so it'll show up as the first hop when you traceroute to IPv4 destinations β and you can also ping it to check that the TAYGA process is still alive and thriving. π«Ά- The default is the IPv4 dummy address from RFC 7600, as suggested by draft-ietf-v6ops-icmpext-xlat-v6only-source.
v4-conncheck-enable=bool(default:yes) β Whether or not to check if the system already has IPv4 connectivity before starting the CLAT. If it does,clatdsimply exits without doing anything. This exists so you can always dropclatdinto your system startup scripts or network-up event scripts (like NetworkManager's dispatcher scripts) without it interfering with native IPv4 connectivity when that's present.- Want the CLAT to always start whenever possible, even though the system has IPv4 connectivity? Disable this. You can instead use the
v4-defaultroute-enableandv4-defaultroute-metricsettings to keepclatdfrom interfering with native IPv4 connectivity. - Heads up: enabling
v4-defaultroute-replaceoverridesv4-conncheck-enableand unconditionally disables IPv4 connectivity checking.
- Want the CLAT to always start whenever possible, even though the system has IPv4 connectivity? Disable this. You can instead use the
v4-conncheck-delay=seconds(default:10) β When running an IPv4 connectivity check, wait this many seconds before actually doing anything. This dodges a race condition where, say, IPv6 SLAAC finishes and fires off a network-up event script that startsclatdwhile IPv4 DHCPv4 is still running in the background. That's at least a likely scenario with NetworkManager, since it kicks off dispatcher scripts as soon as either IPv4 or IPv6 has completed β and IPv6 SLAAC is typically faster than IPv4 DHCPv4. β³- Set it to
0to run the check immediately.
- Set it to
v4-defaultroute-enable=bool(default:yes) β Whether or not to add an IPv4 default route pointing at the CLAT. In a typical 464XLAT environment you want this. But when you're runningclatdsomewhere native IPv4 connectivity is also present, you might want to disable it and manually control which IPv4 destinations reach through the CLAT and which don't.v4-defaultroute-replace=bool(default:no) β Tellsclatdto remove any pre-existing IPv4 default routes, replacing them with one pointing at the CLAT (assumingv4-defaultroute-enableisyes). The replacement is temporary β any pre-existing routes that got removed are restored whenclatdshuts down.- Real talk: nothing stops software like a connection manager or a DHCPv4 client daemon from re-adding any replaced routes while
clatdis running. - If you enable
v4-defaultroute-replacewhile simultaneously disablingv4-defaultroute-enable,clatdwill remove any pre-existing IPv4 default routes but not add any of its own. - Setting
v4-defaultroute-replacetoyesdisables the IPv4 connectivity check.
- Real talk: nothing stops software like a connection manager or a DHCPv4 client daemon from re-adding any replaced routes while
v4-defaultroute-metric=integer(default:2048) β The metric of the IPv4 default route pointing at the CLAT. The default was chosen because it's higher than the metric of a native IPv4 default route added by NetworkManager, which makes native IPv4 connectivity the preferred one whenever it's around.v4-defaultroute-mtu=integer(default:1260) β The MTU of the default route pointing at the CLAT. The default is the default IPv6 MTU that TAYGA uses (1280, which in turn comes from RFC 6145) minus20, to compensate for the difference in header size between IPv4 and IPv6. This keeps outbound packets from having to be fragmented by TAYGA, and it also makes local applications advertise a TCP MSS to their remote peers that stops those peers from sending us packets that would need fragmentation.- If you know the IPv6 Path MTU between the host and the PLAT is bigger than
1280, you may bump this up β but then you should also recompile TAYGA with a largeripv6_offlink_mtusetting inconffile.c.
- If you know the IPv6 Path MTU between the host and the PLAT is bigger than
v4-defaultroute-advmss=integer(default:v4-defaultroute-mtu - 40) β Theadvmssvalue assigned to the default route pointing at the CLAT. This controls the advertised TCP MSS value for TCP connections made through the CLAT.- You normally shouldn't need to set this. By default the value is calculated by taking
v4-defaultroute-mtuand subtracting40(20 bytes for the IPv4 header + 20 bytes for the TCP header). Ifv4-defaultroute-mtuis unset or0, there is no default.
- You normally shouldn't need to set this. By default the value is calculated by taking
π§ LIMITATIONS π§
okay bestie, real talk β clatd is iconic but she is not perfect, and here's exactly where the seams show π
- When you're using
clat-v6-addr=shared(or whenclat-v6-addris set to another address that's assigned to a local interface) andctmarkis set to0, the host OS literally cannot talk bi-directionally to IPv4 destinations directly through the PLAT β like, tryping6 64:ff9b::192.0.2.1and watch it flop π Why? Because the response traffic gets routed back to the CLAT, and it ultimately returns to the Linux kernel as an IPv4 packet, which does not match the outgoing IPv6 socket. Not the vibe. That said, direct communication like this is totally normal when you're using DNS64 synthesis for all queries (as opposed to justipv4only.arpa). - When you're using
clat-v6-addr=derivedand none of the IPv6 addresses on the PLAT-facing device are EUI-64-derived (think SLAAC with RFC 4941 or RFC 7217 privacy addressing, or static addresses), clatd will generate and use a CLAT IPv6 address with a random Interface ID from the same subnet prefix β but only if that prefix is/120or shorter. RFC 6877 suggests DHCPv6 IA_PD should be attempted in this case instead, but that isn't currently implemented. soz π - clatd will not attempt to perform Duplicate Address Detection for the IPv6 address it generates when you're using
clat-v6-addr=derived. This is a violation of RFC 6877. no cap, that's literally against the spec π - There is no guarantee that the generated CLAT IPv6 address is in fact usable, because the network might block its use. rude, but true π«
- If the upstream network is using DHCPv6, clatd will not be able to generate a CLAT IPv6 address at all, due to the fact that DHCPv6-assigned addresses do not carry a prefix length. it's giving "cannot compute" π§
- clatd will not attempt to perform a connectivity check to a discovered PLAT prefix before setting up the CLAT, as RFC 7050 suggests it should. vibe check skipped, unfortunately πΈ
π BUGS π
Spotted a bug? Got a feature request rattling around in your head? Head over to <https://github.com/toreanderson/clatd/issues> and submit a new issue β but only if someone else hasn't already done so, bestie, we don't need duplicates okay π
And PLEASE, when you report a bug, make sure to include logs with full debugging output β using -d -d on the command line, or debug=2 in the configuration file. Receipts, always π
Β©οΈ COPYRIGHT Β©οΈ
Copyright (c) 2014-2025 Tore Anderson <tore@fud.no>.
SPDX-License-Identifier: MIT
periodt. π
π SEE ALSO π
And the reading list, because she's well-read π:
okay that's the whole page bestie!! π this version came from perl v5.40.1, dated 2025-11-17, and it's the clatd(8) manual β go forth and NAT64 slay β¨π
π¦
π¦ where this page comes from
- ubuntu resolute: clatd 2.1.0-3 Β· MIT
- ubuntu stonking: clatd 2.1.0-3 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms