NFTables.NAT (NFTables v0.8.2)
View SourceHigh-level Network Address Translation (NAT) operations.
This module provides convenient functions for common NAT scenarios like internet sharing (masquerade), port forwarding (DNAT), and source NAT.
All functions follow a builder-first pattern, taking a Builder as the first parameter and returning a modified Builder. This allows composing multiple NAT rules before submitting them in a single transaction.
Quick Examples
{:ok, pid} = NFTables.start_link()
# Single rule
Builder.new()
|> NFTables.NAT.setup_masquerade("wan0")
|> NFTables.submit(pid: pid)
# Compose multiple NAT rules
Builder.new()
|> NFTables.NAT.setup_masquerade("wan0", table: "nat")
|> NFTables.NAT.port_forward(80, "192.168.1.100", 8080, table: "nat")
|> NFTables.NAT.static_nat("203.0.113.1", "192.168.1.100", table: "nat")
|> NFTables.submit(pid: pid)Prerequisites
NAT operations require a NAT table and appropriate chains:
# Create NAT table and chains using Builder
Builder.new()
|> NFTables.add(table: "nat", family: :inet)
|> NFTables.add(
table: "nat",
chain: "prerouting",
family: :inet,
type: :nat,
hook: :prerouting,
priority: -100,
policy: :accept
)
|> NFTables.add(
table: "nat",
chain: "postrouting",
family: :inet,
type: :nat,
hook: :postrouting,
priority: 100,
policy: :accept
)
|> NFTables.submit(pid: pid)
Summary
Functions
Set up destination NAT for incoming traffic.
Forward a port to an internal host (DNAT).
Redirect a port to a different port on the same host (local port redirect).
Set up internet sharing (masquerade) on an interface.
Set up source NAT for a specific source IP or subnet.
Set up static (1:1) NAT between two IP addresses.
Types
Functions
@spec destination_nat(NFTables.Builder.t(), String.t(), String.t(), keyword()) :: NFTables.Builder.t()
Set up destination NAT for incoming traffic.
Parameters
builder- Builder to add the rule to (defaults to new builder)dest- Destination IP to matchnat_ip- IP to NAT toopts- Options::table- NAT table name (default: "nat"):chain- Chain name (default: "prerouting"):family- Protocol family (default: :inet):interface- Limit to specific interface (optional)
Examples
# Redirect traffic to virtual IP to actual server
Builder.new()
|> NFTables.NAT.destination_nat("203.0.113.100", "192.168.1.100")
|> NFTables.submit(pid: pid)
# With interface restriction
Builder.new()
|> NFTables.NAT.destination_nat("203.0.113.100", "192.168.1.100", interface: "wan0")
|> NFTables.submit(pid: pid)
@spec port_forward( NFTables.Builder.t(), non_neg_integer(), String.t(), non_neg_integer(), keyword() ) :: NFTables.Builder.t()
Forward a port to an internal host (DNAT).
This redirects incoming traffic on a specific port to an internal host and optionally a different port.
Parameters
builder- Builder to add the rule to (defaults to new builder)external_port- Port to listen oninternal_ip- Destination IP addressinternal_port- Destination port (defaults to external_port)opts- Options::protocol- :tcp or :udp (default: :tcp):table- NAT table name (default: "nat"):chain- Chain name (default: "prerouting"):family- Protocol family (default: :inet):interface- Limit to specific interface (optional)
Examples
# Forward external port 80 to internal web server
Builder.new()
|> NFTables.NAT.port_forward(80, "192.168.1.100", 8080)
|> NFTables.submit(pid: pid)
# Forward SSH to internal host
Builder.new()
|> NFTables.NAT.port_forward(2222, "192.168.1.10", 22)
|> NFTables.submit(pid: pid)
# Forward UDP DNS
Builder.new()
|> NFTables.NAT.port_forward(53, "192.168.1.1", 53, protocol: :udp)
|> NFTables.submit(pid: pid)
# Compose multiple port forwards
Builder.new()
|> NFTables.NAT.port_forward(80, "192.168.1.100", 8080, table: "nat")
|> NFTables.NAT.port_forward(443, "192.168.1.100", 8443, table: "nat")
|> NFTables.submit(pid: pid)
@spec redirect_port( NFTables.Builder.t(), non_neg_integer(), non_neg_integer(), keyword() ) :: NFTables.Builder.t()
Redirect a port to a different port on the same host (local port redirect).
Useful for transparent proxying.
Parameters
builder- Builder to add the rule to (defaults to new builder)from_port- Port to redirect fromto_port- Port to redirect toopts- Options::protocol- :tcp or :udp (default: :tcp):table- NAT table name (default: "nat"):chain- Chain name (default: "prerouting"):family- Protocol family (default: :inet)
Examples
# Redirect HTTP to local proxy
Builder.new()
|> NFTables.NAT.redirect_port(80, 3128)
|> NFTables.submit(pid: pid)
# Redirect HTTPS to local proxy
Builder.new()
|> NFTables.NAT.redirect_port(443, 8443)
|> NFTables.submit(pid: pid)
# Multiple redirects
Builder.new()
|> NFTables.NAT.redirect_port(80, 3128, table: "nat")
|> NFTables.NAT.redirect_port(443, 8443, table: "nat")
|> NFTables.submit(pid: pid)
@spec setup_masquerade(NFTables.Builder.t(), String.t(), keyword()) :: NFTables.Builder.t()
Set up internet sharing (masquerade) on an interface.
This enables NAT for all outgoing traffic on the specified interface, allowing internal hosts to share a single public IP address.
Parameters
builder- Builder to add the rule to (defaults to new builder)interface- Outgoing interface name (e.g., "eth0", "wan0")opts- Options::table- NAT table name (default: "nat"):chain- Chain name (default: "postrouting"):family- Protocol family (default: :inet)
Examples
# Share internet connection via eth0
Builder.new()
|> NFTables.NAT.setup_masquerade("eth0")
|> NFTables.submit(pid: pid)
# Compose with other rules
Builder.new()
|> NFTables.NAT.setup_masquerade("wan0", table: "nat")
|> NFTables.NAT.source_nat("10.0.0.0/24", "203.0.113.1", table: "nat")
|> NFTables.submit(pid: pid)
@spec source_nat(NFTables.Builder.t(), String.t(), String.t(), keyword()) :: NFTables.Builder.t()
Set up source NAT for a specific source IP or subnet.
Parameters
builder- Builder to add the rule to (defaults to new builder)source- Source IP or CIDR (e.g., "192.168.1.0/24")nat_ip- IP to NAT toopts- Options::table- NAT table name (default: "nat"):chain- Chain name (default: "postrouting"):family- Protocol family (default: :inet):interface- Limit to specific interface (optional)
Examples
# NAT internal subnet to public IP
Builder.new()
|> NFTables.NAT.source_nat("192.168.1.0/24", "203.0.113.1")
|> NFTables.submit(pid: pid)
# NAT specific host
Builder.new()
|> NFTables.NAT.source_nat("192.168.1.100", "203.0.113.1")
|> NFTables.submit(pid: pid)
# With interface restriction
Builder.new()
|> NFTables.NAT.source_nat("10.0.0.0/24", "203.0.113.1", interface: "wan0")
|> NFTables.submit(pid: pid)
@spec static_nat(NFTables.Builder.t(), String.t(), String.t(), keyword()) :: NFTables.Builder.t()
Set up static (1:1) NAT between two IP addresses.
Maps all traffic for a public IP to a private IP and vice versa. This function adds both DNAT (prerouting) and SNAT (postrouting) rules.
Parameters
builder- Builder to add the rules to (defaults to new builder)public_ip- External IP addressprivate_ip- Internal IP addressopts- Options::table- NAT table name (default: "nat"):family- Protocol family (default: :inet)
Examples
# Map public IP to DMZ host
Builder.new()
|> NFTables.NAT.static_nat("203.0.113.100", "192.168.1.100")
|> NFTables.submit(pid: pid)
# Multiple static NAT mappings
Builder.new()
|> NFTables.NAT.static_nat("203.0.113.100", "192.168.1.100", table: "nat")
|> NFTables.NAT.static_nat("203.0.113.101", "192.168.1.101", table: "nat")
|> NFTables.submit(pid: pid)