From b1ad547deb254d41f6aa49d9e3067edea0cfd626 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Thu, 10 Nov 2022 14:35:44 +0800 Subject: [PATCH] Documentation: add NAT description Signed-off-by: Zhe Weng --- Documentation/reference/os/nat.rst | 169 +++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 Documentation/reference/os/nat.rst diff --git a/Documentation/reference/os/nat.rst b/Documentation/reference/os/nat.rst new file mode 100644 index 0000000000..978eec60ce --- /dev/null +++ b/Documentation/reference/os/nat.rst @@ -0,0 +1,169 @@ +================================= +Network Address Translation (NAT) +================================= + +NuttX supports full cone NAT logic, which currently supports + +- TCP +- UDP +- ICMP ECHO (REQUEST & REPLY) + +Workflow +======== + +:: + + Local Network (LAN) External Network (WAN) + |----------------| + | | external port> peer port> + |----------------| + +- Outbound + + - **LAN** -> **Forward** -> **NAT** (only if targeting at WAN) -> **WAN** + + - All packets from **LAN** and targeting at **WAN** will be masqueraded + with ``local ip:port`` changed to ``external ip:port``. + +- Inbound + + - **WAN** -> **NAT** (only from WAN, change destination) -> **Forward** -> **LAN** + + - Packets from **WAN** will try to be changed back from + ``external ip:port`` to ``local ip:port`` and send to **LAN**. + +Configuration Options +===================== + +``CONFIG_NET_NAT`` + Enable or disable Network Address Translation (NAT) function. + Depends on ``CONFIG_NET_IPFORWARD``. +``CONFIG_NET_NAT_TCP_EXPIRE_SEC`` + The expiration time for idle TCP entry in NAT. + The default value 86400 is suggested by RFC2663, Section 2.6, + Page 5. But we may set it to shorter time like 240s for better + performance. +``CONFIG_NET_NAT_UDP_EXPIRE_SEC`` + The expiration time for idle UDP entry in NAT. +``CONFIG_NET_NAT_ICMP_EXPIRE_SEC`` + The expiration time for idle ICMP entry in NAT. + +Usage +===== + + - :c:func:`ipv4_nat_enable()` + - :c:func:`ipv4_nat_disable()` + +.. c:function:: int ipv4_nat_enable(FAR struct net_driver_s *dev); + + Enable NAT function on a network device, on which the outbound packets + will be masqueraded. + + Note that NAT is currently designed to be enabled on single device, it + may work when enabled on multiple devices, but external ports will not + be isolated between devices, so an external port used on one NAT device + will also be used by same local ip:port on another NAT device. + + :return: Zero is returned if NAT function is successfully enabled on + the device; A negated errno value is returned if failed. + +.. c:function:: int ipv4_nat_disable(FAR struct net_driver_s *dev); + + Disable NAT function on a network device. + + :return: Zero is returned if NAT function is successfully disabled on + the device; A negated errno value is returned if failed. + +Validation +========== + +Validated on Ubuntu 22.04 x86_64 with NuttX SIM by following steps: + +1. Configure NuttX with >=2 TAP devices (host route mode) and NAT enabled: + + .. code-block:: Kconfig + + CONFIG_NET_IPFORWARD=y + CONFIG_NET_NAT=y + # CONFIG_SIM_NET_BRIDGE is not set + CONFIG_SIM_NETDEV_NUMBER=2 + +2. Call ``ipv4_nat_enable`` on one dev on startup + + .. code-block:: c + + /* arch/sim/src/sim/up_netdriver.c */ + int netdriver_init(void) + { + ... + ipv4_nat_enable(&g_sim_dev[0]); + ... + } + +3. Set IP Address for NuttX on startup + + .. code-block:: shell + + ifconfig eth0 10.0.1.2 + ifup eth0 + ifconfig eth1 10.0.10.2 + ifup eth1 + +4. Configure IP & namespace & route on host side (maybe need to be root, then try ``sudo -i``) + + .. code-block:: bash + + IF_HOST="enp1s0" + IF_0="tap0" + IP_HOST_0="10.0.1.1" + IF_1="tap1" + IP_HOST_1="10.0.10.1" + IP_NUTTX_1="10.0.10.2" + + # add net namespace LAN for $IF_1 + ip netns add LAN + ip netns exec LAN sysctl -w net.ipv4.ip_forward=1 + ip link set $IF_1 netns LAN + ip netns exec LAN ip link set $IF_1 up + ip netns exec LAN ip link set lo up + + # add address and set default route + ip addr add $IP_HOST_0/24 dev $IF_0 + ip netns exec LAN ip addr add $IP_HOST_1/24 dev $IF_1 + ip netns exec LAN ip route add default dev $IF_1 via $IP_NUTTX_1 + + # nat to allow NuttX to access the internet + iptables -t nat -A POSTROUTING -o $IF_HOST -j MASQUERADE + iptables -A FORWARD -i $IF_HOST -o $IF_0 -j ACCEPT + iptables -A FORWARD -i $IF_0 -o $IF_HOST -j ACCEPT + sysctl -w net.ipv4.ip_forward=1 + +5. Do anything in the LAN namespace will go through NAT + + .. code-block:: shell + + # Host side + iperf -B 10.0.1.1 -s -i 1 + # LAN side + sudo ip netns exec LAN iperf -B 10.0.10.1 -c 10.0.1.1 -i 1 + + .. code-block:: shell + + # Host side + python3 -m http.server + # LAN side + for i in {1..20000}; do sudo ip netns exec LAN curl 'http://10.0.1.1:8000/' > /dev/null 2>1; done + + .. code-block:: shell + + # LAN side + sudo ip netns exec LAN ping 8.8.8.8 + + .. code-block:: shell + + # Host side + tcpdump -nn -i tap0 + # LAN side + sudo ip netns exec LAN tcpdump -nn -i tap1