vitlabuda / tundra-nat64

A minimal, user-space, stateless NAT64, CLAT and SIIT implementation for Linux
BSD 3-Clause "New" or "Revised" License
38 stars 4 forks source link
464xlat clat ipv6 nat64 siit

Tundra-NAT64

Tundra-NAT64 is an open-source IPv6-to-IPv4 & IPv4-to-IPv6 translator for Linux which operates entirely in user-space, can run in multiple threads (and thus make use of today's modern multicore CPUs) and uses either the TUN driver or inherited file descriptors to receive and send packets. It is written in pure C and translates packets according to the rules of SIIT (Stateless IP/ICMP Translation Algorithm; RFC 7915), while offering the following configurable address translation modes:

More information about the aforementioned address translation modes (including how to configure them) can be found in relevant sections of the example configuration file.

The SIIT/NAT64/CLAT translator offered by Tundra focuses on being minimal – features which are not necessary for SOHO-grade SIIT/NAT64/CLAT service are often omitted, and so are features which can be substituted by something else. One of the consequences of this design approach is that the program does not allocate any extra memory after it initializes.

Probably the most significant trait of this program, which makes it different from other NAT64/CLAT implementations, is that Tundra itself cannot act as a NAT64/CLAT translator for more than one host, as it lacks an internal dynamic address pool (or something similar) from which it would assign IP addresses to hosts needing its service – it uses a fixed single IP address specified in a configuration file instead (see the example config file for details). However, it can be used in cooperation with Linux's in-kernel NAT66/NAT44 translator and therefore translate traffic from any number of hosts/networks.

Tundra is, in certain aspects, similar to TAYGA (another stateless out-of-kernel NAT64 implementation, which can act as a CLAT translator in cooperation with clatd), but there are some differences. Tundra is multi-threaded, has configurable address translation modes (including the non-traditional external mode), can receive and send packets from inherited file descriptors, and lacks the aforementioned dynamic address pool. TAYGA also inspired this program's name - both "taiga" and "tundra" are subarctic biomes and the word "tundra" starts with "tun", the name of the driver which Tundra uses to exchange packets.

The reason why this program is named Tundra-NAT64 despite it offering other address translation modes than just NAT64 is that originally, it was meant to be only a stateless NAT64 translator and the other modes were added later. Since rebranding it would be quite difficult and could cause certain problems (due to, for example, permalinks pointing to this Git repository whose name/URL contains the nat64), I decided not to do it.

Tundra was the subject of a Czech-language talk I held at the Seminář IPv6: deset let poté conference on the 6th June 2022 in Prague – presentation, video. In addition, if you happen to be interested, you may have a look at this post on my English-language blog, in which the changes to this program made between the versions 4.1.6 and 5.0.1 are summed up.

Build

Tundra only depends on Linux's standard C library and libpthread - no other libraries are needed. The project uses CMake as its build system and GCC as its compiler. To build the program, run the following commands in the repository's root directory:

CC=gcc cmake -S. -Bbuild
make -Cbuild

The resulting binary will be located at ./build/tundra-nat64.

If desired, make -Cbuild install or cmake --install build may then be used to install the compiled binary and the example configuration file to your system.

Configuration & usage

Configuration file

Tundra loads its settings from a configuration file. This repository contains a sample configuration file with detailed comments: tundra-nat64.example.conf.

Command-line parameters

The output of ./tundra-nat64 --help is as follows:

Usage: ./tundra-nat64 [OPTION]... [MODE_OF_OPERATION]

Options:
  -h, --help
    Prints help and exits.
  -v, --version
    Prints version information and exits.
  -l, --license
    Prints license and exits.
  -c, --config-file=CONFIG_FILE_PATH
    Specifies the file from which the program's configuration will be loaded.
    DEFAULT: /etc/tundra-nat64/tundra-nat64.conf
    NOTE: To load configuration from the standard input, specify '-' as the path.
  -f, --io-inherited-fds=THREAD1_IN,THREAD1_OUT[;THREAD2_IN,THREAD2_OUT]...
    Specifies the file descriptors to be used in the 'inherited-fds' I/O mode. Ignored otherwise.
  -F, --addressing-external-inherited-fds=THREAD1_IN,THREAD1_OUT[;THREAD2_IN,THREAD2_OUT]...
    Specifies the file descriptors to be used for the 'inherited-fds' transport of the 'external' addressing mode. Ignored otherwise.

Modes of operation:
  translate
    The program will act as a stateless NAT64/CLAT/SIIT translator.
    This is the default mode of operation.
  mktun
    Creates a persistent TUN device according to the configuration file, then exits.
    Applicable only in the 'tun' I/O mode.
  rmtun
    Destroys a previously created persistent TUN device according to the configuration file, then exits.
    Applicable only in the 'tun' I/O mode.
  validate-config
    Tries to configure the program and prints an informational message if it succeeds, then exits.

Generic NAT64 configuration example

The following example shows how Tundra could be deployed as NAT64 translator for an IPv6-only network with the use of the example configuration file on a router which has access to both IPv4 and IPv6:

TUNDRA_CONFIG_FILE="./tundra-nat64.example.conf"
WAN_INTERFACE_NAME="eth0"  # Remember to adjust this!

# Create a new TUN network interface
./tundra-nat64 --config-file=$TUNDRA_CONFIG_FILE mktun

# Set up the TUN interface
ip link set dev tundra up
ip addr add 192.168.64.254/24 dev tundra  # The IP address should be different from 'translator.ipv4' and 'router.ipv4'!
ip -6 addr add fd00:6464::fffe/64 dev tundra  # The IP address should be different from 'translator.ipv6' and 'router.ipv6'!
ip -6 route add 64:ff9b::/96 dev tundra
ip6tables -t nat -A POSTROUTING -d 64:ff9b::/96 -o tundra -j SNAT --to-source=fd00:6464::2  # On some kernels, the support for NAT66 may need to be installed as a module
iptables -t nat -A POSTROUTING -o $WAN_INTERFACE_NAME -j MASQUERADE  # Perform NAT44 on all packets going to the internet, including the ones generated by Tundra

# Start the NAT64 translator (to terminate it, send SIGTERM, SIGINT or SIGHUP to the process)
./tundra-nat64 --config-file=$TUNDRA_CONFIG_FILE translate

# After the translator has terminated, remove the previously added NAT rules...
ip6tables -t nat -D POSTROUTING -d 64:ff9b::/96 -o tundra -j SNAT --to-source=fd00:6464::2
iptables -t nat -D POSTROUTING -o $WAN_INTERFACE_NAME -j MASQUERADE

# ... and remove the TUN interface
./tundra-nat64 --config-file=$TUNDRA_CONFIG_FILE rmtun

DNS64

To make hosts on IPv6-only networks use the NAT64 translator to access IPv4-only services, you will need to provide them with a DNS64 recursive resolver. You can either deploy your own one (all major recursive DNS servers, such as Unbound or Knot Resolver, nowadays support DNS64 natively), or, if your NAT64 deployment uses the well-known prefix of 64:ff9b::/96, use a public DNS64 resolver, such as the one provided by Google or Cloudflare.

Specific configuration examples

This repository contains the following configuration examples for specific platforms and translation modes:

Licensing

This project is licensed under the 3-clause BSD license – see the LICENSE file.

Programmed by Vít Labuda.