Skip to content
ydahhrk edited this page Oct 7, 2013 · 2 revisions

The configuration in the previous tutorial was designed with speed and low resources in mind. Though several commands were issued to Linux, Jool was modprobed with no arguments and then it wasn't further tweaked. Also, the Jool machine was a stock laptop, and I don't expect to see many of those deployed as border nodes.

In this second tutorial a slightly more realistic scenario will be covered, along with more thorough insight and control.

Fig.1 - Network design

I dropped the wireless interface (for realism and to clear the tutorial of iwconfig), threw in more sensible addresses (in particular, the IPv4 pool is no longer an alien), and made each network more than one node each (but they will all be Linux, since I'm more comfortable with its routing than anything else's). Also, I will assume that you have no control over the IPv4 nodes so we can no longer configure them in unnatural ways (In the previous tutorial, Jool was the IPv4 node's default gateway, which made no sense). If the IPv6 side is your network and the IPv4 side is your ISP, then this is probably the case.

In case it isn't obvious, the name "J" comes from "Jool", but the "J" in the diagram is not Jool; it is the node wearing Jool. When you read "J" think of the actual computer, and when you read "Jool" think of the kernel module.

We will still configure everything statically. If your distribution features a network manager, you probably want to turn if off before you issue any commands mentioned below.

Configuring the routers

Long story short: If a packet's destination address belongs to one of the pools, then Jool translates the packet. Otherwise Linux handles it normally.

Router-wise, you have to think of the NAT64 as a normal NAT where the IPv6 internet is the hidden network. Nodes in network 6:2::/96 can perceive J as their default gateway, so you might run this on R:

ifconfig eth0 add 6:1::1/96 up
ifconfig eth1 add 6:2::1/96 up
# Turn R into router.
sysctl -w net.ipv6.conf.all.forwarding=1
# Forward unknown traffic to J.
# (We know the entire IPv6 Internet, so unknown traffic is probably headed to IPv4.)
ip -6 route add default via 6:2::2 dev eth1

But better yet: If you want more control and security, you know that only packets whose prefix is 64::/96 are meant to be translated, so you can drop everything else:

# Use this instead of the default gateway instruction.
ip -6 route add 64::/96 via 6:2::2 dev eth1

IPv4 routers simply need to be aware of J's IPv4 addresses. In this case, the pool address belongs to the network, so no magic is needed here.

The configuration of S (your ISP's router) will probably look something like this. Note the complete unawareness of the fact that J holds Jool:

ifconfig eth0 4.1.0.1 netmask 255.255.255.0 up
ifconfig eth1 4.2.0.1 netmask 255.255.255.0 up
sysctl -w net.ipv4.conf.all.forwarding=1

Configuring the leaves

Again, when a IPv6 node wants to talk to a IPv4 one, it will append the 64::/96 prefix to the real IPv4 address. This means that the entire IPv4 universe can be seen as just a network named 64::/96.

So, just issue this on C and D:

ifconfig eth0 add 6:2::10/96 up # or 6:2::11/96.
ip -6 route add 6:1::/96 via 6:2::1 dev eth0
ip -6 route add 64::/96 via 6:2::2 dev eth0

A and B are even easier; they only have one gateway, and they don't see the NAT64, so they don't even need to know it exists.

ifconfig eth0 add 6:1::10/96 up # or 6:1::11/96.
ip -6 route add default via 6:1::1 dev eth0

(The whole point of me bothering with this network is to show that you can also have IPv6 nodes completely unaware of the NAT64's existence.)

Yet again, Jool masks the IPv6 internet so IPv4 nodes cannot start conversations with IPv6 nodes; they can only respond. To them, J is just another node:

# E and F.
ifconfig eth0 4.1.0.10 netmask 255.255.255.0 up # or 4.1.0.11.
ip route add 4.2.0.0/24 via 4.1.0.1 dev eth0
# G and H.
ifconfig eth0 4.2.0.10 netmask 255.255.255.0 up # or 4.2.0.11.
ip route add 4.1.0.0/24 via 4.2.0.1 dev eth0

Configuring the NAT64

ifconfig eth0 add 6:2::2/96 up
ifconfig eth1 add 4.1.0.2 netmask 255.255.255.0 up
ip -6 route add 6:1::/96 via 6:2::1 dev eth0
sysctl -w net.ipv4.conf.all.forwarding=1
sysctl -w net.ipv6.conf.all.forwarding=1
  • 6:2::2 is J's address in the 6:2::/96 network. For the most part, there is nothing unusual about this: J itself (not the NAT64 mechanism) uses it to communicate with other IPv6 nodes. Again: Jool never touches this address.
  • 4.1.0.2 is more odd. Technically, it is J's address in the 4.1.0.0/24 network, but J doesn't use it to chat the IPv4 nodes. Rather, Jool hogs it up and uses it as source address for all outgoing traffic originated from the IPv6 side. Though it is only used by Jool, we have to ifconfig it so Linux answers ARP requests for it.
  • 64::/96 is a range of addresses. It belongs to Jool, and J can be otherwise unaware of it. Linux doesn't have to ARP reply it because the 6:2::/96 nodes already know to forward prefixed packets to 6:2::2's machine (see the previous sections).

Since the IPv4 address is completely monopolized by Jool, you might wonder if it is possible for J to chat IPv4 nodes. The answer is yes, but a bug currently prevents it from being as elegant as we'd like (TODO: clarify).

You tell Jool its pool addresses during module insertion. To override the default values, say them out loud:

# remember to turn offloads off and log martians.
modprobe jool pool6=64::/96 pool4=4.1.0.2

And booya:

Fig.2 - IPv4 access from IPv6

A bigger IPv4 pool

Here's a theoretical packet that might travel from C to E:

Source: Address 6:2::10, port 1234 (random)  
Destination: Address 64::4.1.0.10, port 80 (i. e. trying to reach a website)

Regarding the source port field: It is well known that a port is a two-byte value, which means that you can run out of them. This is normally not an issue, since 65536 (minus reserved ones) per node is at least a fairly reasonable amount.

The above packet might be translated by J into something like this:

Source: 4.1.0.3#1234  
Destination: 4.1.0.10#80

And Jool will memorize that 6:2::10#1234 is related to 4.1.0.3#1234. E will answer

Source: 4.1.0.10#80  
Destination: 4.1.0.3#1234

And by virtue of its memory, Jool will know it has to translate that into

Source: 64::4.1.0.10#80  
Destination: 6:2::10#1234

But what if D generates the following packet?

Source: 6:2::11#1234
Destination: 64::4.1.0.10#80

Jool cannot translate it into

Source: 4.1.0.3#1234  
Destination: 4.1.0.10#80

Because it will then have two contradictory mappings. Which one will it use when E's answer shows its face?

  1. 6:2::10#1234 <-> 4.1.0.3#1234
  2. 6:2::11#1234 <-> 4.1.0.3#1234

The solution is to mask not only addresses, but ports as well. Instead of generating the aforementioned packet, Jool will generate this:

Source: 4.1.0.3#6326  
Destination: 4.1.0.10#80

And the Binding Information Base (BIB) will look like this:

  1. 6:2::10#1234 <-> 4.1.0.3#1234
  2. 6:2::11#1234 <-> 4.1.0.3#6326

To what I'm getting is, all IPv6 nodes share the same IPv4 address (as opposed to stateless NAT64). This is good because you don't need one IPv4 address per IPv6 node, but at the same time you need to be aware that Jool might run out of ports.

C and D used one port each (and they even happened to be the same one), but Jool still had to use two. Each IPv6 node has 65536 ports to work with, but because they all share the same IPv4 address, as a group, they can use up to 65536 ports via the translator. The more IPv6 nodes you have, the faster J will run out of ports.

How do you make up for this? You can give Jool more addresses. You will get 64k fresh ports for each IPv4 address you throw in. If the IPv4 side is indeed an ISP, do remember that it will the one who'll provide the addresses.

You can specify up to 5 addresses during module insertion:

modprobe jool pool4="4.1.0.3, 4.1.0.4, 4.1.0.5, 4.1.0.6, 4.1.0.7"

If you need more, you can add them using the userspace application:

./jool --pool4 --add --address 4.1.0.8
./jool --pool4 --add --address 4.1.0.9
# etc.

And remember that Linux might have to answer ARP requests for them:

ifconfig eth1 add 4.1.0.3 netmask 255.255.255.0 up
ifconfig eth1 add 4.1.0.4 netmask 255.255.255.0 up
ifconfig eth1 add 4.1.0.5 netmask 255.255.255.0 up
ifconfig eth1 add 4.1.0.6 netmask 255.255.255.0 up
# etc

Have something to say? jool@nic.mx or post an issue.