Introduction to Jool
Jool is an Open Source implementation of IPv4/IPv6 Translation on Linux. Until version 3.2.x, it used to be only a Stateful NAT64; starting from 3.3.0, it also supports SIIT mode.
As far as we know, this is the compliance status of Jool 4:
|RFC 6052||IP address translation||Fully compliant.|
|RFC 6144||IPv4/IPv6 Translation Framework||Fully compliant.|
|RFC 7915||SIIT||Compliant, except for
|RFC 6146||Stateful NAT64||Fully compliant.|
|RFC 6384||FTP over NAT64||Not yet compliant.|
|RFC 6791||ICMP quirks||In short, this RFC wants two things: A pool of IPv4 addresses and an ICMP header extension. Jool implements the former but not the latter.|
|RFC 6877||464XLAT||Rather implemented as SIIT-DC-DTM; see below.|
|RFC 7755||SIIT-DC||Fully compliant.|
|RFC 7756||SIIT-DC: Dual Translation Mode||Fully compliant.|
|RFC 8021||Atomic Fragment Deprecation||Fully compliant.|
|RFC 7757||EAM||Fully compliant.|
|RFC 7422||Deterministic port allocations||Deterministic port allocations (sequential algorithm only) can be achieved using the pool4’s
Please let us know if you find additional compliance issues or RFCs/drafts we’ve missed.
|Jool version||Supported Linux kernels (mainline)||Supported Linux kernels (RHEL)|
|master||3.13 - 3.19,
4.0 - 4.20,
5.0 - 5.4
|RHEL 7.0 - RHEL 7.7,
|4.0.7||3.13 - 3.19,
4.0 - 4.20,
5.0 - 5.4
|RHEL 7.0 - RHEL 7.7,
|3.5.8||3.2 - 3.19,
4.0 - 4.18
|RHEL 7.0 - RHEL 7.4|
If you’re using a non-RHEL distribution (eg. Debian derivatives), execute
uname -r to print the kernel version you’re running. Suffixes rarely matter. Here’s an example from my running machine, which states that my running kernel is 4.15:
user@T:~$ /bin/uname -r 4.15.0-36-generic
RHEL-based distributions (such as Red Hat and CentOS) do not follow the normal kernel versioning conventions; use the third column instead.
A Jool instance can be attached to one of two different traffic-intercepting, plugin-enabling, kernel-based frameworks: Netfilter and iptables. Despite some documentation out there, these two are not the same thing; at least not from Jool’s point of view.
Netfilter is a bunch of hooks (
POSTROUTING) in the Linux kernel where modules can inject code. Whenever a packet reaches a hook, the kernel runs it through all the corresponding registered modules. Netfilter Jool instances hook themselves to
PREROUTING and as such intercept all incoming traffic (“pre”vious to “routing”) with the intent of translating it.
Netfilter Jool instances are simple to configure. However, they are also greedy. This is, since there is no matching conditional (other than “packets need to match the network namespace the instance exists in”), translation has overwhelming priority. Only packets that meet failure during translation are left untouched by a Netfilter instance. Jool attempts to translate everything, and the rest of the network subsystem gets the leftovers. Because of this, a careless Netfilter Jool configuration could deprive its own namespace of external network traffic.
There can only be one Netfilter SIIT Jool instance and one Netfilter NAT64 instance per network namespace.
Netfilter Jool instances start packet translation as soon as they are created. They drop packets deemed corrupted, translate packets which can be translated (according to their configuration) and return everything else to the kernel.
Netfilter plugins are not allowed to change the network protocol of their packets. Additionally, the kernel API does not export a means to post packets in the
FORWARD chain. For these reasons, successfully translated packets skip
FORWARD, going straight to
Be aware that this means that, because filtering normally happens during
FORWARD, if you want to firewall forwarding traffic, you should probably enclose Jool in a network namespace and filter during the
FORWARD boxes outside of it:
Alternatively, if you know what you’re doing, you can filter on mangle.
Until Jool 3.5, Netfilter used to be the only available operation mode.
iptables is another packet-handling framework. It is built on top of Netfiter, and is mostly known for its NAT’ing and firewalling capabilities. In regards to this discussion, its most relevant feature is its match system–A means to specify which packets are handled by some “target” plugin.
If you’re familiar with the
iptables utility, you might be accustomed to the following syntax:
# iptables -t filter -A PREROUTING --destination 192.0.2.0/24 -j DROP
For anyone not in the knowing, that command adds a rule to iptables’ filter table, which “DROP”s all packets headed towards the
192.0.2 network. This happens during
PREROUTING. (Which is the same concept from Netfilter.)
iptables Jool is implemented as an ordinary iptables target. Thus,
# iptables -t mangle -A PREROUTING --destination 192.0.2.0/24 -j JOOL --instance potato
adds a rule to iptables’s mangle table, which “Jools” all packets headed towards the
192.0.2 network. This happens during
PREROUTING. Of all the Jool instances available in the current namespace, the translation is done by the one whose name is
There can be any number of iptables Jool instances in any namespace, and any number of iptables rules can reference them.
iptables Jool instances sit idle until some iptables rule sends packets to them. (Of course, only packets that match the rule’s conditions are sent.) As of version 4.0.6, iptables instances function the same as Netfilter instances: They drop packets deemed corrupted, translate packets which can be translated (according to their configuration) and return everything else to the kernel. (In this context, “return to the kernel” means that the packet will go back to the iptables chain, right after the Jool rule that matched it.)
iptables Jool has a quirk similar to Netfilter Jool that you should be aware of: iptables rules are also not allowed to change the network protocol of their packets, so iptables Jool rules also send their matched and successfully translated packets straight to
POSTROUTING. Packets which do not match the rule continue through the chain normally.
iptables Jool first became available in Jool 4.0.0.
As of version 4.0.6, both Netfilter Jool and iptables Jool return the packet to the kernel if any of these conditions are met:
- An iptables rule’s
--instanceparameter does not match any existing iptables instances. (ie. user created the iptables rule but hasn’t yet created the instance.)
- The packet was translated successfully, but the translated packet cannot be routed. (Most of the time, this is because its destination address does not match any entries in the routing table.)
- The translator is disabled by configuration.
SIIT Jool also returns the packet to the kernel when at least one of these conditions are met:
- The packet is IPv4 and at least one of its addresses cannot be translated. An IPv4 address cannot be translated when
- it’s subnet-scoped,
- belongs to one of the translator’s interfaces,
- is blacklist4ed, or
- cannot be translated by any of the populated address translation strategies (EAMT, pool6 and rfc6791).
- The packet is IPv6 and at least one of its addresses cannot be translated. An IPv6 address cannot be translated when
- it cannot be translated by any of the populated address translation strategies (EAMT, pool6 and rfc6791),
- its IPv4 counterpart is blacklist4ed,
- its IPv4 counterpart is subnet-scoped, or
- its IPv4 counterpart belongs to a local interface.
Stateful NAT64 Jool also returns the packet to the kernel when at least one of these conditions are met:
- The packet’s transport protocol is unsupported. (NAT64 Jool only supports TCP, UDP and ICMP as of now.)
- The packet is IPv6 and its destination address does not match pool6. (ie. packet is not meant to be translated.)
- The packet is IPv4 and its destination transport address (address + port) does not match any BIB entries. (ie. packet lacks IPv6 destination.)
- Untranslatable/unknown ICMPv4 and ICMPv6 types.