Stateless Network Address Translation (NAT)

Stateless Network Address Translation (NAT), also known as static NAT, establishes a permanent mapping between a private IP address and a single public address.

To configure stateless NAT, the tc iproute2 tool is utilized, along with the tc-nat action. This action is combined with the flower filter rule and ingress qdisc to enable static NAT entry offloading. Below is the command format:

tc ... flower ... action nat { ingress | egress } <OLD> <NEW>

Where:

  • <OLD> represents the IP address to be translated.
  • <NEW> represents the IP address to translate to.
  • ingress translates destination addresses (performs DNAT).
  • egress translates source addresses (performs SNAT).

To implement NAT one-to-one mapping, two rules are required: one for private-to-public direction and another for public-to-private direction.

Example Configuration

Configure the private host (Assume it to be PC1):

ip 192.168.0.2/24 192.168.0.1

Configure the public host (Assume it to be PC2):

ip 91.245.77.2/24

Configure IP on the interfaces and set up a default gateway:

ip addr add dev swp23 192.168.0.1/24
ip addr add dev swp24 91.245.77.1/24
ip route add default via 91.245.77.1

Ensure that the interfaces are up. You can bring up the interfaces using the following commands:

ip link set dev swp23 up
ip link set dev swp24 up

Stateless-NAT

This setup ensures PC1 (the private host) is on the private network, and PC2 (the public host) is on the public network, with the DENT VM managing the connection tracking and Stateless NAT between these networks.

Configure ACL rules for NAT offloading:

tc qdisc add dev swp23 clsact

NAT connection tracking on swp23 for egress traffic:

tc filter add dev swp23 protocol ip egress flower ip_proto tcp src_ip 192.168.0.2 action nat egress 192.168.0.2 91.245.77.1
filter protocol ip pref 49152 flower chain 0
filter protocol ip pref 49152 flower chain 0 handle 0x1
  eth_type ipv4
  ip_proto tcp
  src_ip 192.168.0.2
  not_in_hw
        action order 1:  nat egress 192.168.0.2/32 91.245.77.1 pass
         index 1 ref 1 bind 1

NAT connection tracking on swp23 for ingress traffic:

tc filter add dev swp23 protocol ip ingress flower ip_proto tcp dst_ip 91.245.77.1 action nat ingress 91.245.77.1 192.168.0.2
filter protocol ip pref 49152 flower chain 0
filter protocol ip pref 49152 flower chain 0 handle 0x1
  eth_type ipv4
  ip_proto tcp
  dst_ip 91.245.77.1
  in_hw in_hw_count 1
        action order 1:  nat ingress 91.245.77.1/32 192.168.0.2 pass
         index 2 ref 1 bind 1
        used_hw_stats delayed

To create only HW rule on swp24:

tc qdisc add dev swp24 clsact
tc filter add dev swp24 protocol ip ingress flower skip_sw ip_proto tcp src_ip 192.168.0.2 action nat egress 192.168.0.2 91.245.77.1
filter protocol ip pref 49152 flower chain 0
filter protocol ip pref 49152 flower chain 0 handle 0x1
  eth_type ipv4
  ip_proto tcp
  src_ip 192.168.0.2
  skip_sw
  in_hw in_hw_count 1
        action order 1:  nat egress 192.168.0.2/32 91.245.77.1 pass
         index 3 ref 1 bind 1
        used_hw_stats delayed

Verify Connectivity:

From PC1 to DENT:

PC1> ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 192.168.0.1: icmp_seq=4 ttl=64 time=0.045 ms

From PC2 to DENT:

PC1> ping 91.245.77.1
PING 91.245.77.1 (91.245.77.1) 56(84) bytes of data.
64 bytes from 91.245.77.1: icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from 91.245.77.1: icmp_seq=2 ttl=64 time=0.058 ms
64 bytes from 91.245.77.1: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 91.245.77.1: icmp_seq=4 ttl=64 time=0.041 ms

From PC1 to PC2:

PC1> ping 91.245.77.2
PING 91.245.77.2 (91.245.77.2) 56(84) bytes of data.
64 bytes from 91.245.77.2: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 91.245.77.2: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 91.245.77.2: icmp_seq=3 ttl=64 time=0.040 ms
64 bytes from 91.245.77.2: icmp_seq=4 ttl=64 time=0.035 ms

Since all three pings are successful, it indicates that the network is configured correctly and connectivity is established.

Private to Private Flow

To skip NAT for packets designated as a private subnet or hosts:

tc filter add dev swp24 protocol ip ingress flower skip_sw ip_proto tcp dst_ip 192.168.0.1/24 action pass
filter protocol ip pref 49152 flower chain 0
filter protocol ip pref 49152 flower chain 0 handle 0x1
  eth_type ipv4
  ip_proto tcp
  dst_ip 192.168.0.1/24
  skip_sw
  in_hw in_hw_count 1
        action order 1: gact action pass
         random type none pass val 0
         index 5 ref 1 bind 1
        used_hw_stats delayed

Note: The last added rule has a higher priority, so the priority can be skipped in the rule.