RSSAmplifier

Rootknecht.net! on Rootknecht.net · Jul 9, 2025

Basic SNAT with nftables and iptables

0
Sign in to vote or save

Michael · Rootknecht.net

SNAT in a nutshell#

SNAT stands for Source Network Address Translation and is a type of Network Address Translation (NAT). SNAT replaces the client IP address (source), which might be dynamic, with a static IP address. Advantages include, for instance, that firewall rules can be applied to a known static IP, and network details can be hidden.

graph LR
A["`Client
172.20.0.2`"] e1@--> C["`Proxy
172.20.0.3`"]
e1@{ animate: slow }
C e2@--> D["`Server
172.20.0.4`"]
e2@{ animate: slow }
D e3@-- 172.20.0.3 --- A
e3@{ animate: slow }

A Client talks to the server via the Proxy’s IP address. The docker-example deploys this scenario.

IP forwarding#

IP forwarding must be enabled so that the proxy is capable of forwarding packets to other destinations.

Check if it is allready enabled with cat /proc/sys/net/ipv4/ip_forward.

Enable it with:

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sysctl -p

You also need to modify your client’s routing table so that traffic is routed through the proxy.

Example of a very basic setup with no other networking layers in between:

ip route add 172.20.0.4/32 via 172.20.0.3 dev eth0

iptables is the classic Linux programm to configure the Kernel’s firewall.

There might be some issues on systems where iptables actually refers to iptables-nft. The following code works with iptables-legacy.

SOURCE_NET=192.168.178.0/24
IP=$(ip -4 -o addr show dev eth0 | awk '{print $4}' | cut -d/ -f1)
sudo iptables -t nat -A POSTROUTING -s $SOURCE_NET -o eth0 -j SNAT --to-source $IP

This is not persistent. Have a look at iptables-save(8)

nftables#

nftables replaces iptables. The following code is equivalent to the iptables rule above.

SOURCE_NET=192.168.178.0/24
IP=$(ip -4 -o addr show dev eth0 | awk '{print $4}' | cut -d/ -f1)
sudo tee /etc/nftables.conf <<EOF
#!/usr/sbin/nft -f

flush ruleset

table ip nat {
    chain postrouting {
        type nat hook postrouting priority 100;
        ip saddr $SOURCE_NET oifname "eth0" snat to $IP
    }
}
EOF

sudo systemctl enable nftables
sudo systemctl start nftables

Docker example#

This Compose file starts three containers acting as a client, a proxy, and a server, illustrating the chart in SNAT in a nutshell

compose.yml
---
services:
  proxy:
    image: debian:12
    container_name: proxy
    hostname: proxy
    command: |
      bash -c "
        apt-get update && apt-get install -y nftables iproute2
        cat > /etc/nftables.conf << 'EOF'
      #!/usr/sbin/nft -f

      flush ruleset

      table ip nat {
          chain postrouting {
              type nat hook postrouting priority 100;
              ip saddr 172.20.0.0/24 oifname \"eth0\" snat to 172.20.0.3
          }
      }
      EOF
        nft -f /etc/nftables.conf
        tail -f /dev/null
      "
    privileged: true
    networks:
      frontend:
        ipv4_address: 172.20.0.3

  echo-server:
    image: allaman/gecho:main
    container_name: echo-server
    hostname: echo-server
    networks:
      frontend:
        ipv4_address: 172.20.0.4

  client:
    image: debian:12
    container_name: client
    hostname: client
    command: >
      bash -c "
        apt-get update && apt-get install -y iproute2 curl
        ip route add 172.20.0.4/32 via 172.20.0.3 dev eth0
        curl 172.20.0.4:8080
        tail -f /dev/null
      "
    privileged: true
    networks:
      frontend:
        ipv4_address: 172.20.0.2
    depends_on:
      - proxy
      - echo-server

networks:
  frontend:
    ipam:
      config:
        - subnet: 172.20.0.0/24
curl
Server sees the request coming from the proxy.

Reply by Email

Read the original on rootknecht.net

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.