Route traffic with NAT

Posted by Marcus Folkesson on Friday, February 17, 2023

Route traffic with NAT

Long time ago I wrota a blog post [1] about how to use NAT to route traffic to your embedded device via your host computer.

Back then we were using iptables to achieve it, nowadays nftables is the preferred successor, so it's time for an update.

What is NAT anyway?

/media/nat.png

Network Address Translation, or NAT, does map an address space into another by modifying the network address infromation in the IP header for each packet. This is how your router is able to route your local network out to internet.

To share an internet connection this way may sometimes be very practical when working with embedded devices. The network may have restrictions/authentications that stops you from plug in your device directly to a network, your traffic must go via a VPN connection that you host has configured, your device only has an USB interface available... use cases are many.

If your device does not have ethernet nor WiFi but USB with OTG support, you can still share internet by setup a RNDIS gadget device.

Setup

Host setup

  • eth0 has the IP address 192.168.1.50 and is connected to the internet
  • usb0 has IP address 10.2.234.1 and is connected to the target device via RNDIS

The best way to configure nftables is to do it by script. We will setup two rules;

  • A NAT chain for masquerade packages and
  • A forward rule to route packages between usb0 and eth0
#!/usr/sbin/nft -f

table ip imx8_table {
        chain imx8_nat {
                type nat hook postrouting priority 0; policy accept;
                oifname "eth0" masquerade
        }

        chain imx8_forward {
                type filter hook forward priority 0; policy accept;
                iifname "usb0" oifname "eth0" accept
        }
}

We also have to enable IP forwarding. This could be done in several ways:

  • Via sysctl on command line:

    sudo sysctl -w net.ipv4.ip_forward=1
    
  • Via sysctl configuration file:

    echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.conf
    sudo /sbin/sysctl -p
    
  • Via procfs:

    echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    

Target setup

  • usb0 has ip address 10.2.234.100 and is connected to the host.

You only need to make sure that all traffic is routed via usb0 by setting up a default route:

route add default gw 10.2.234.1 usb0

That is all. You should now be able to route your traffic out to the internet:

ping www.google.se

PING www.google.se (216.58.211.3) 56(84) bytes of data.
64 bytes from muc03s13-in-f3.1e100.net (216.58.211.3): icmp_seq=1 ttl=57 time=12.4 ms
64 bytes from muc03s13-in-f3.1e100.net (216.58.211.3): icmp_seq=2 ttl=57 time=12.4 ms
64 bytes from muc03s13-in-f3.1e100.net (216.58.211.3): icmp_seq=3 ttl=57 time=12.5 ms
64 bytes from muc03s13-in-f3.1e100.net (216.58.211.3): icmp_seq=4 ttl=57 time=12.5 ms