https://taoshu.in/unix/jool-nat64.html
IPv6-only Network based on Jool
Tao Shu 2025-01-05 [?]3.8 min(1.5k words) [?]
* Network Topology
* Jool vs TAYGA
* Install Jool
* Stateful-NAT64
* DNS64
* Port Mapping
* Persistence
In this post, I will share experiences of my experiment of how to
setting up the IPv6-only network on Linux using the Jool^1.
Network Topology
Here is the classical topology of home network. All the hosts can
access the Internet through one router. The router has dual stack of
v4/v6. And all the LAN hosts have one /64 IPv6 prefix.
Internet
|
+---+----+ 10.0.0.1/32
| Router | 2001:db8::/64
+---+----+
|
+-------+-------------------+
|2001:db8:1::/64 | 2001:db8:2::/64
+-----+-----+ +-----+-----+
| Host 1 | | Host 2 |
+-----+-----+ +-----+-----+
There are two problems we need to fix. Firstly, let the LAN hosts
access the IPv4 Internet without mutual interference. Secondly,
support IPv4-to-IPv6 port mapping so that the IPv4-only host in the
Internet can reach the services hosted on the IPv6-only LAN hosts.
Jool vs TAYGA
The two tasks mentioned above can be both achieved through Jool.
Besides the Jool, you may find the TAYGA^2. TAYGA is an out-of-kernel
stateless NAT64 implementation for Linux that uses the TUN driver to
exchange IPv4 and IPv6 packets with the kernel.
TAYGA is not the proper choice because it only support the stateless
NAT64, which means you need several public IPv4 addresses to to the
IPv4-to-IPv6 mapping. Another drawback of TAYGA is that it uses the
TUN devices, which may have performance issue.
Moreover, the latest release of TAYGA is published on 2011, which
means there are more than 15 years without new development.
On the contrary, the Jool is another Open Source Ipv4/IPv6 Translator
with active development. Jool support both stateless and stateful
NAT64.
Install Jool
Jool contains two parts, jool-dkms is for kernel modules, and
jool-tools for user space tools.
The Debian/Ubuntu user can install Jool by apt
apt install jool-dkms jool-tools
The OpenWrt user can install the jool-tools-netfilter package. This
will install kmod-jool-netfilter and other dependencies.
I am using the Arch Linux. So I have to build Jool from source.
Install the tools used by compiling
pacman -S base-devel linux-headers dkms tar
Get the source code
wget https://github.com/NICMx/Jool/releases/download/v4.1.13/jool-4.1.13.tar.gz
tar -xzf jool-4.1.13.tar.gz
Compiling the kernel modules
dkms install jool-4.1.13/
Compile and install the userspace applications
cd jool-4.1.13/
./configure
make
make install
We need to add the /etc/modules-load.d/jool.conf to let Arch Linux
load the jool module automatically after booting.
echo jool > /etc/modules-load.d/jool.conf
Now we can enable the stateful-nat64.
Stateful-NAT64
The NAT64 use the fixed prefix of 64:ff9b::/96. All the IPv4 address
should be embed into this prefix and be treated as normal IPv6
address in the LAN hosts.
In the router side, run the following command^3 to create the NAT64
instance named after z64.
jool instance add "z64" --netfilter --pool6 64:ff9b::/96
The name of instance is z64. And the IPv6 address pool is 64:ff9b::/
96. All packet with the destination address of prefix of 64:ff9b::/96
will be translated into IPv4 packet with the address of default
outing NIC. Jool will detect the outgoing network card automatically.
Then you need to enable the ip forwarding option of kernel.
sysctl -w net.ipv6.conf.all.forwarding=1
sysctl -w net.ipv6.conf.default.forwarding=1
sysctl -w net.ipv4.ip_forward=1
and run the below command to load them
sysctl --system
Now the router is ready to do the NAT64 translation.
In your LAN hosts, you can ping 1.1.1.1 with the following commands
ping -c1 64:ff9b::1.1.1.1
PING 64:ff9b::1.1.1.1 (64:ff9b::101:101) 56 data bytes
64 bytes from 64:ff9b::101:101: icmp_seq=1 ttl=56 time=1.42 ms
--- 64:ff9b::1.1.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.419/1.419/1.419/0.000 ms
The pseudo address of 64:ff9b::1.1.1.1 has been translated into
64:ff9b::101:101. And the ICMP echo package with destination address
of 64:ff9b::101:101 will be convert into 1.1.1.1 by Jool.
It works like charming.
DNS64
With the help of Jool, we can ping the pseudo ipv4 address. However,
we need to access the IPv4 services by the DNS name. It will be very
convenient if the DNS can convert the IPv4 address (A records) into
the pseudo IPv6 address. We can use the DNS64 service to do this job.
If one DNS resolver support DNS64, it will try to query the AAAA
records of the domain name. If there is only A records (IPv4
address), the resolver will return the pseudo IPv6 address with the
64:ff9b::/96 prefix as the AAAA record.
Both the Public DNS of Google and Cloudflare support the DNS64
service.
# google
2001:4860:4860::64
2001:4860:4860::6464
# cloudflare
2606:4700:4700::64
2606:4700:4700::6400
I recommend you to put both resolvers into your /etc/resolv.conf file
to obtain the high availability.
[?]Warning
Do not set the DNS64 resolver into the /etc/resolv.conf of Jool
host.
Because the Jool only hooks itself to PRE_ROUTING. It does not
attach itself to LOCAL_OUT. This means it can only translate
traffic that inbounds from some interface (physical or
otherwise). It does not intercept packets sourced from its own
network namespace.
And now you can ping github.com which is IPv4-only until 2024,
ping -c1 github.com
PING github.com (64:ff9b::8c52:7403) 56 data bytes
64 bytes from 64:ff9b::8c52:7403: icmp_seq=1 ttl=52 time=23.6 ms
--- github.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 23.624/23.624/23.624/0.000 ms
If you only want to let the LAN host access the IPv4 Internet, you
can finish here. But if you want to run service on you LAN host and
need to let the IPv4 host outside to access your service, you need
continue read next section.
Port Mapping
Suppose you are running web server on port of 3000 on Host 1. And you
need to let the client access your web server via IPv4 network. You
have to set the IPv4-to-IPv6 port mapping for your service.
By Jool, you can use the bib^4 command to do this job:
jool -i z64 bib add 2001:db8::1#3000 10.0.0.1#3000 --tcp
This will add one port mapping for tcp traffic. All traffic with
destination of 10.0.0.1 and port of 3000 will be translated into
2001:db8::1 and port of 3000 and be forwarded to Host 1.
However, if you try to run the aforementioned command, you will
encounter the following error:
Error: The kernel module returned error 22: Transport address '10.0.0.1#3000'
does not belong to pool4.
Please add it there first.
As it reads, the port of 10.0.0.1#3000 does not belong to pool4. So
what is in the pool4 currently? You can use the pool4 subcommand to
check it.
ip -i z64 pool4 display
You will see nothing. The pool4 is empty.
Every IPv6-to-IPv4 translation need the address pool of both v4 and
v6. We only setup the pool6 in the previous section. If the pool4 is
empty, how could Jool accomplish the traffic translation?
According the document of pool4^5, an empty pool4 behaves differently
from a populated pool4. Empty pool4 defaults to use ports 61001-65535
of whatever universe-scoped IPv4 addresses the node's interfaces
have.
Then Jool is behaving as if pool4 were configured as follows:
+------------+-------+--------------------+-----------------+-------------+
| Mark | Proto | Max iterations | Address | Ports |
+------------+-------+--------------------+-----------------+-------------+
| 0 | TCP | 1024 ( auto) | 10.0.0.1 | 61001-65535 |
+------------+-------+--------------------+-----------------+-------------+
| 0 | UDP | 1024 ( auto) | 10.0.0.1 | 61001-65535 |
+------------+-------+--------------------+-----------------+-------------+
| 0 | ICMP | 1024 ( auto) | 10.0.0.1 | 61001-65535 |
+------------+-------+--------------------+-----------------+-------------+
You can only mapping the port int the range of 61001-655535. Let's
adjust our bib command:
jool -i z64 bib add 2001:db8:1::#3000 10.0.0.1#63000 --tcp
Now you can access the web service on Host 1 via the destination
10.0.0.1:63000.
[?]Warning
The port range of pool4 should not overlap with the ephemeral
port range.
The default ephemeral port range is 32768-61000, this is why Jool
choose the 61001-65535 as it's default mapping range.
If you need to support more than 4534 simultaneous connections, you
have to adjust the port range of pool4 and the ephemeral port range
kernel.
sysctl -w net.ipv4.ip_local_port_range="32768 40000"
jool pool4 add 10.0.0.1 40001-61000 --tcp
jool pool4 add 10.0.0.1 40001-61000 --udp
jool pool4 add 10.0.0.1 40001-61000 --icmp
Persistence
All the above configurations will be reset after reboot. If you need
toe persist these functions, you need do add some configuration file.
First, load the jool module automatically.
echo jool > /etc/modules-load.d/jool.conf
Then enable the forwarding for both IPv6 and IPv4:
cat < /etc/sysctl.d/99-ipv6.conf
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.default.forwarding=1
net.ipv4.ip_forward=1
EOF
Third, setup the systemd service for Jool.
cat < /etc/systemd/system/jool.service
[Unit]
Description=Jool NAT64/SIIT Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/jool file handle /etc/jool/jool.conf
[Install]
WantedBy=multi-user.target
EOF
The Type of this unit is oneshot, which means it will be triggered
once. In the ExecStart part, we use the jool file handle to load the
/etc/jool/jool.conf.
{
"instance": "z64",
"framework": "netfilter",
"global": {
"pool6": "64:ff9b::/96"
},
"pool4": [
{
"protocol": "TCP",
"prefix": "10.0.0.1/32",
"port range": "50001-65535"
},
{
"protocol": "UDP",
"prefix": "10.0.0.1/32",
"port range": "50001-65535"
},
{
"protocol": "ICMP",
"prefix": "10.0.0.1/32",
"port range": "50001-65535"
}
],
"bib": [
{
"protocol": "TCP",
"ipv4 address": "10.0.0.1#53000",
"ipv6 address": "2001:db8:1::#3000"
}
]
}
Finally, enable the service unit:
systemctl enable --now jool
Then you can reboot the system. And all the NAT64 will work as plan.
Tip
More details of running IPv6 only network on OpenWRT can be found
at https://ripe87.ripe.net/wp-content/uploads/presentations/
8-IPv6-mostly_on_OpenWRT.pdf
OK, this post will finish here. With Jool, we can setup pure IPv6
network for both outgoing and ingoing traffic. If you have any
problem all advice, fell free to leave message to me.
---------------------------------------------------------------------
1. https://nicmx.github.io/Jool/en/index.html-[?]
2. http://www.litech.org/tayga/-[?]
3. https://nicmx.github.io/Jool/en/usr-flags-instance.html-[?]
4. https://nicmx.github.io/Jool/en/usr-flags-bib.html-[?]
5. https://nicmx.github.io/Jool/en/usr-flags-pool4.html-[?]
[ ] [ ] [ ]
[Submit]
Ben Zhan You Le Hu Qu Dong