Skip to content

5.5 NAT and PAT

SNMP monitors the network, but it does not solve a fundamental addressing problem: the internet ran out of IPv4 addresses. NAT provides the workaround.

NAT and PAT — Network Address Translation

Section titled “NAT and PAT — Network Address Translation”

NAT (Network Address Translation) maps private IP addresses (RFC 1918: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to public IP addresses. It exists because the IPv4 address space (4.3 billion addresses) is exhausted. Without NAT, every device would need a globally unique public IP.

PAT (Port Address Translation), also called NAT overload, maps many private addresses to a single public address by using different source port numbers to distinguish connections.

The router maintains a NAT translation table that maps each internal IP:port pair to an external IP:port pair. Return traffic is matched against this table and forwarded to the correct internal host.

NAT breaks protocols that embed IP addresses in the application payload. Modbus TCP works through NAT because it does not embed addresses. EtherNet/IP (CIP) breaks because the CIP layer carries IP addresses inside the payload, and NAT does not inspect or rewrite CIP data. OPC UA works through NAT when using TCP transport, but discovery services that return internal addresses fail.

The following script reads the Linux NAT connection tracking table, showing active translations. Run it on a Linux router or firewall to see which internal hosts have active NAT sessions.

import re
from pathlib import Path
def read_nat_table() -> list[dict]:
conntrack = Path("/proc/net/nf_conntrack")
if not conntrack.exists():
conntrack = Path("/proc/net/ip_conntrack")
entries = []
for line in conntrack.read_text().splitlines():
m = re.search(r"src=(\S+) dst=(\S+) sport=(\d+) dport=(\d+).*"
r"src=(\S+) dst=(\S+) sport=(\d+) dport=(\d+)", line)
if m:
entries.append({
"orig_src": m.group(1), "orig_dst": m.group(2),
"orig_sport": m.group(3), "orig_dport": m.group(4),
"reply_src": m.group(5), "reply_dst": m.group(6),
})
return entries
for entry in read_nat_table()[:10]:
print(f"{entry['orig_src']}:{entry['orig_sport']} -> "
f"{entry['orig_dst']}:{entry['orig_dport']} "
f"(reply from {entry['reply_src']})")

Each line shows the original source, destination, and the reply path. If the reply source differs from the original destination, NAT is rewriting addresses.

PAT maps many hosts to one public IP

Port numbers distinguish connections. The NAT table tracks every active mapping.

NAT breaks EtherNet/IP and OPC UA discovery

Protocols that embed IP addresses in the payload fail through NAT. Use routed VLANs with firewall rules in OT networks.

NAT solves the address exhaustion problem, but it does not solve the gateway redundancy problem. If the default gateway fails, all devices on the subnet lose connectivity. The next page covers FHRP, the protocol family that provides gateway redundancy.

  • RFC 3022 — Traditional IP Network Address Translator (IETF, 2001)
  • RFC 1918 — Address Allocation for Private Internets (IETF, 1996)