Computer Networking Cheatsheet

NAT and Port Forwarding

Use this Computer Networking reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

What NAT does

Network Address Translation rewrites addresses and ports in the IP header as packets cross a boundary, then keeps a table so replies can be mapped back. It exists because IPv4 ran out of addresses, and it is why one public IP can serve a whole house.

LAN                          router (203.0.113.9)              internet
192.168.1.37:51234  --->  203.0.113.9:61001  --->  93.184.216.34:443
192.168.1.42:51234  --->  203.0.113.9:61002  --->  93.184.216.34:443
                    translation table keyed by the full 5-tuple

The table entry holds protocol, original source IP and port, translated source IP and port, destination IP and port, and an idle timer. TCP entries commonly idle out at 5 days established or 120 s for half-open, UDP at 30-180 s.

NAT flavors

TypeRewritesDirectionTypical use
SNATsource IP (and port)outboundgive private hosts internet access, fixed public IP
Masqueradesource IP to whatever the egress IF hasoutbounddynamic WAN IP, dial-up and DHCP uplinks
DNATdestination IP (and port)inboundpublish an internal server, load balancer VIP
PAT · NAPTsource IP plus portoutbound, many to onethe "one public IP, many devices" case
1:1 · static NATwhole address, both waysbothDMZ hosts, cloud elastic IPs
Hairpin · NAT loopbacksource and destinationLAN to own public IPreach your own published service by its public name
CGNATsource, at the carrieroutboundISP-scale, 100.64.0.0/10

"NAT" in a home router means PAT. A pure SNAT that only changes the IP cannot support more hosts than it has public addresses.

Why NAT breaks inbound connections

A NAT table entry is created by an outbound packet. An unsolicited inbound packet has no entry, so the router does not know which private host to send it to and drops it. Consequences:

- Servers behind NAT are unreachable unless you add a static DNAT rule. - Peer-to-peer needs help: STUN to discover your mapped public address, hole punching so both sides create outbound entries at once, and TURN to relay when hole punching fails. That trio is what WebRTC ICE runs. - Protocols that carry IP addresses in the payload break, because NAT only rewrites headers. FTP active mode, SIP, and H.323 need application-layer gateways or helper modules. - CGNAT compounds it: you are behind your router's NAT and the ISP's, so no port forward you configure is reachable from outside. - IPsec AH cannot survive NAT (it authenticates the header), so ESP gets wrapped in UDP 4500 by NAT-T. - Idle mappings expire, so long-lived idle connections die silently. TCP keepalives or application pings keep the entry warm.

Port forwarding with nftables

# forward WAN :8080 to an internal web server (DNAT)
nft add table ip nat
nft 'add chain ip nat prerouting { type nat hook prerouting priority -100; }'
nft 'add chain ip nat postrouting { type nat hook postrouting priority 100; }'
nft add rule ip nat prerouting iif eth0 tcp dport 8080 \
  dnat to 192.168.1.50:80
nft add rule ip nat postrouting oif eth0 masquerade
sysctl -w net.ipv4.ip_forward=1
nft list table ip nat

Forwarding also needs a filter rule to permit the forwarded flow, since the default forward policy is usually drop.

Port forwarding with iptables

# DNAT: public 8080 → 192.168.1.50:80
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 \
  -j DNAT --to-destination 192.168.1.50:80
# allow the forwarded traffic
iptables -A FORWARD -p tcp -d 192.168.1.50 --dport 80 -j ACCEPT
# SNAT for the LAN, dynamic WAN address
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# SNAT with a fixed public address (cheaper, no per-packet lookup)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.9
# hairpin so LAN clients can use the public address
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.50 \
  -p tcp --dport 80 -j MASQUERADE
iptables -t nat -L -n -v --line-numbers
Table · chainWhen it runs
nat PREROUTINGbefore routing, do DNAT here
nat POSTROUTINGafter routing, do SNAT and masquerade here
nat OUTPUTlocally generated packets, DNAT
filter FORWARDrouted traffic, permit or drop

Inspecting and debugging translations

conntrack -L                                   # live translation table
conntrack -L -p tcp --dst 93.184.216.34
conntrack -E                                   # stream events as they happen
conntrack -D --orig-src 192.168.1.37           # drop a stuck entry
cat /proc/sys/net/netfilter/nf_conntrack_count  # entries in use
cat /proc/sys/net/netfilter/nf_conntrack_max    # ceiling
dmesg | grep -i 'conntrack table full'

Symptoms and causes worth memorizing:

SymptomLikely cause
New connections fail under load, existing ones fineconntrack table full
Works from LAN by private IP, fails by public nameno hairpin NAT rule
Port forward works from outside, not insidesame, hairpin missing
Forward configured but nothing arrivesISP CGNAT, or FORWARD policy drop
Long idle connection diesNAT mapping timed out, add keepalives
FTP or SIP connects then stallspayload carries the private IP, needs an ALG

IPv6 does not need NAT, and end-to-end addressing is the main reason to deploy it. NPTv6 exists for prefix translation but is a niche tool, not the default.