nat

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package nat implements IPv4 network address translation between two L3 networks.

Unlike the slirp package (which NATs to the real host network via net.Dial), this NAT operates entirely within the pktkit virtual network, translating addresses between an inside (private) and outside (public) L3 interface.

It handles TCP, UDP, and ICMP (echo + error messages), including proper rewriting of embedded headers in ICMP error payloads.

NAT64 translates between IPv6 and IPv4 packets, allowing IPv6-only clients to reach IPv4 destinations via IPv4-mapped IPv6 addresses (::ffff:x.x.x.x).

Inside() faces the IPv6 network; Outside() faces the IPv4 network.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Defragger

type Defragger struct {
	// contains filtered or unexported fields
}

Defragger reassembles fragmented IPv4 packets.

func (*Defragger) Close

func (d *Defragger) Close()

Close stops the defragger cleanup goroutine.

func (*Defragger) Process

func (d *Defragger) Process(pkt pktkit.Packet) pktkit.Packet

Process handles an IPv4 packet. If it's not fragmented, returns it as-is. If fragmented, buffers it and returns nil until all fragments arrive, then returns the reassembled packet.

type Expectation

type Expectation struct {
	Proto      uint8      // expected protocol (TCP/UDP)
	RemoteIP   netip.Addr // expected remote IP (zero = any)
	RemotePort uint16     // expected remote port (0 = any)
	InsideIP   netip.Addr // where to forward
	InsidePort uint16     // inside destination port
	Expires    time.Time
}

Expectation describes a future connection that the NAT should accept and translate automatically. Helpers create expectations for related connections (e.g., FTP data channels, RTP media streams).

type FTPHelper

type FTPHelper struct{}

FTPHelper is an Application Layer Gateway for FTP (RFC 959). It rewrites PORT/EPRT commands in outbound traffic and 227/229 responses in inbound traffic so that active and passive mode data connections work through the NAT.

func NewFTPHelper

func NewFTPHelper() *FTPHelper

NewFTPHelper returns a new FTP ALG helper.

func (*FTPHelper) Close

func (h *FTPHelper) Close() error

func (*FTPHelper) MatchOutbound

func (h *FTPHelper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for TCP connections to port 21 (FTP control).

func (*FTPHelper) Name

func (h *FTPHelper) Name() string

func (*FTPHelper) ProcessInbound

func (h *FTPHelper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound inspects inbound TCP payload for 227 and 229 responses, rewrites passive-mode addresses, and creates expectations.

func (*FTPHelper) ProcessOutbound

func (h *FTPHelper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound inspects outbound TCP payload for PORT and EPRT commands, rewrites the embedded IP:port to the NAT's outside address, and creates expectations for the resulting inbound data connections.

type H323Helper

type H323Helper struct{}

H323Helper is a simplified ALG for the H.323 VoIP protocol suite.

H.323 uses ASN.1 PER (Packed Encoding Rules) for its signaling messages, which makes full parsing extremely complex. This implementation uses a heuristic approach: it searches for 4-byte IPv4 address patterns and 6-byte transport address patterns (4-byte IP + 2-byte port) in the TCP payload, replacing inside addresses with outside addresses. While imperfect, this covers the majority of real-world H.323 NAT traversal cases where the addresses appear as contiguous binary values.

func NewH323Helper

func NewH323Helper() *H323Helper

NewH323Helper returns a new H.323 ALG helper.

func (*H323Helper) Close

func (h *H323Helper) Close() error

func (*H323Helper) MatchOutbound

func (h *H323Helper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for TCP traffic to port 1720 (Q.931/H.225).

func (*H323Helper) Name

func (h *H323Helper) Name() string

func (*H323Helper) ProcessInbound

func (h *H323Helper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound searches the TCP payload for binary representations of the outside IP address and replaces them with the inside IP.

func (*H323Helper) ProcessOutbound

func (h *H323Helper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound searches the TCP payload for binary representations of the inside IP address and replaces them with the outside IP. When a 6-byte transport address (IP + port) is found, it creates NAT expectations for the associated H.245 or RTP channels.

type Helper

type Helper interface {
	Name() string
	Close() error
}

Helper is an optional NAT module loaded via NAT.AddHelper.

type IRCHelper

type IRCHelper struct {
	// contains filtered or unexported fields
}

IRCHelper is an Application Layer Gateway for IRC DCC (Direct Client-to-Client).

DCC commands embed the sender's IP address (as a 32-bit decimal integer) and a TCP port in the PRIVMSG payload. This helper rewrites those values to the NAT's outside address and an allocated outside port, and creates expectations so the incoming DCC connection is forwarded correctly.

func NewIRCHelper

func NewIRCHelper(ports ...uint16) *IRCHelper

NewIRCHelper returns a new IRC DCC ALG helper. If no ports are specified, the default IRC port 6667 is used.

func (*IRCHelper) Close

func (h *IRCHelper) Close() error

func (*IRCHelper) MatchOutbound

func (h *IRCHelper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for TCP connections to any of the configured IRC ports.

func (*IRCHelper) Name

func (h *IRCHelper) Name() string

func (*IRCHelper) ProcessInbound

func (h *IRCHelper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound is a no-op for IRC DCC. Incoming DCC connections are handled by the expectations registered in ProcessOutbound.

func (*IRCHelper) ProcessOutbound

func (h *IRCHelper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound inspects outbound TCP payload for DCC SEND and DCC CHAT commands, rewrites the embedded IP and port to the NAT's outside address, and creates expectations for incoming DCC connections.

type LocalHelper

type LocalHelper interface {
	Helper
	HandleLocal(n *NAT, pkt pktkit.Packet) bool
}

LocalHelper handles packets destined for the NAT's own inside IP address (e.g., UPnP control requests, SSDP discovery). Returns true if the packet was consumed and should not be processed further.

type NAT

type NAT struct {
	// contains filtered or unexported fields
}

NAT performs IPv4 network address translation between two L3 networks. Inside() faces the private network (acts as default gateway). Outside() faces the upstream network (uses a public IP).

For multi-tenant use (e.g. WireGuard), call ConnectL3 to create namespace-isolated inside L3Devices. Each namespace's connections are tracked independently, allowing overlapping inside IPs.

func New

func New(insideAddr, outsideAddr netip.Prefix) *NAT

New creates a NAT with the given inside (private) and outside (public) addresses.

func (*NAT) AddExpectation

func (n *NAT) AddExpectation(e Expectation)

AddExpectation registers an expected future connection.

func (*NAT) AddHelper

func (n *NAT) AddHelper(h Helper)

AddHelper registers a helper module with the NAT.

func (*NAT) AddPortForward

func (n *NAT) AddPortForward(pf PortForward) error

AddPortForward creates a static port mapping. Inbound connections to outsidePort are forwarded to insideIP:insidePort. Returns an error if the outside port is already forwarded to a different inside IP.

func (*NAT) AllocOutsidePort

func (n *NAT) AllocOutsidePort(proto uint8) uint16

AllocOutsidePort allocates an outside port for use by helpers. Returns 0 if no ports are available.

func (*NAT) Close

func (n *NAT) Close() error

Close shuts down the NAT and stops the maintenance goroutine.

func (*NAT) ConnectL3

func (n *NAT) ConnectL3(dev pktkit.L3Device) (func() error, error)

ConnectL3 implements pktkit.L3Connector. It creates a namespace-isolated inside L3Device. Packets from the device are tracked with a unique namespace ID, so multiple devices can use overlapping inside IPs without conflict. The returned cleanup function removes the namespace and its mappings.

func (*NAT) CreateMapping

func (n *NAT) CreateMapping(proto uint8, insideIP netip.Addr, insidePort uint16) uint16

CreateMapping creates a NAT mapping for use by helpers. Returns the allocated outside port.

func (*NAT) EnableDefrag

func (n *NAT) EnableDefrag()

EnableDefrag activates IP defragmentation on the NAT.

func (*NAT) EnableUPnP

func (n *NAT) EnableUPnP(cfg UPnPConfig) error

EnableUPnP creates and registers a UPnP IGD helper on this NAT. Clients on the inside network can discover the NAT via SSDP and manage port forwarding through SOAP requests.

func (*NAT) Inside

func (n *NAT) Inside() pktkit.L3Device

Inside returns the L3Device facing the private network.

func (*NAT) InsideAddr

func (n *NAT) InsideAddr() netip.Addr

InsideAddr returns the NAT's inside IP address.

func (*NAT) ListPortForwards

func (n *NAT) ListPortForwards() []PortForward

ListPortForwards returns all active static port mappings.

func (*NAT) Outside

func (n *NAT) Outside() pktkit.L3Device

Outside returns the L3Device facing the upstream network.

func (*NAT) OutsideAddr

func (n *NAT) OutsideAddr() netip.Addr

OutsideAddr returns the NAT's outside IP address. Useful for helpers that need to know the public IP.

func (*NAT) RemovePortForward

func (n *NAT) RemovePortForward(proto uint8, outsidePort uint16) error

RemovePortForward removes a static port mapping.

func (*NAT) SendInside

func (n *NAT) SendInside(pkt pktkit.Packet)

SendInside sends a raw IP packet out through the inside interface. Used by helpers (e.g., UPnP) that need to send responses to inside clients.

type NAT64

type NAT64 struct {
	// contains filtered or unexported fields
}

NAT64 performs IPv6-to-IPv4 network address translation. Inside() faces the IPv6 network; Outside() faces the IPv4 network.

func NewNAT64

func NewNAT64(insideAddr, outsideAddr netip.Prefix) *NAT64

NewNAT64 creates a NAT64 with the given inside (IPv6) and outside (IPv4) addresses.

func (*NAT64) Close

func (n *NAT64) Close() error

Close shuts down the NAT64 and stops the maintenance goroutine.

func (*NAT64) Inside

func (n *NAT64) Inside() pktkit.L3Device

Inside returns the L3Device facing the IPv6 network.

func (*NAT64) Outside

func (n *NAT64) Outside() pktkit.L3Device

Outside returns the L3Device facing the IPv4 network.

type NATMapping

type NATMapping struct {
	Proto       uint8
	InsideIP    netip.Addr
	InsidePort  uint16
	OutsidePort uint16
}

NATMapping provides a read-only view of a NAT mapping for use by helpers.

type PPTPHelper

type PPTPHelper struct {
	// contains filtered or unexported fields
}

PPTPHelper is an ALG for the Point-to-Point Tunneling Protocol (PPTP). It tracks PPTP control channel messages (TCP port 1723) to extract Call-IDs used in the associated GRE data tunnel, and creates NAT expectations for the GRE traffic.

Note: GRE traffic uses IP protocol 47 (not TCP or UDP). Full PPTP NAT traversal requires the NAT core to handle GRE packets, including rewriting the Call-ID in the GRE key field (bytes 4-5 of the GRE header for PPTP enhanced GRE). This helper only handles the control signaling; GRE data forwarding is beyond its scope.

func NewPPTPHelper

func NewPPTPHelper() *PPTPHelper

NewPPTPHelper returns a new PPTP ALG helper.

func (*PPTPHelper) Close

func (h *PPTPHelper) Close() error

func (*PPTPHelper) MatchOutbound

func (h *PPTPHelper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for TCP traffic to port 1723.

func (*PPTPHelper) Name

func (h *PPTPHelper) Name() string

func (*PPTPHelper) ProcessInbound

func (h *PPTPHelper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound parses PPTP control messages from the server side, tracking Call-IDs in reply messages for proper GRE forwarding.

func (*PPTPHelper) ProcessOutbound

func (h *PPTPHelper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound parses PPTP control messages and tracks Call-IDs. For Outgoing-Call-Request messages, it extracts the Call-ID and creates GRE expectations.

type PacketHelper

type PacketHelper interface {
	Helper
	// MatchOutbound returns true if this helper handles connections to the
	// given protocol and destination port.
	MatchOutbound(proto uint8, dstPort uint16) bool
	// ProcessOutbound may modify an outbound packet after NAT translation.
	// It may call [NAT.AddExpectation] to register expected related connections.
	ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet
	// ProcessInbound may modify an inbound packet after reverse-NAT translation.
	ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet
}

PacketHelper inspects and modifies packets flowing through the NAT. Used by ALGs (FTP, SIP, etc.) that need to rewrite embedded addresses in application-layer protocols.

type PortForward

type PortForward struct {
	Proto       uint8
	OutsidePort uint16
	InsideIP    netip.Addr
	InsidePort  uint16
	Description string
	Expires     time.Time // zero = permanent
}

PortForward is a static port mapping configured on the NAT.

type SIPHelper

type SIPHelper struct{}

SIPHelper is an ALG for the Session Initiation Protocol (SIP), used in VoIP. It rewrites embedded IP addresses and ports in SIP headers (Via, Contact) and SDP bodies (c= connection, m= media lines), and creates expectations for the resulting RTP/RTCP media streams.

func NewSIPHelper

func NewSIPHelper() *SIPHelper

NewSIPHelper returns a new SIP ALG helper.

func (*SIPHelper) Close

func (h *SIPHelper) Close() error

func (*SIPHelper) MatchOutbound

func (h *SIPHelper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for UDP or TCP traffic to port 5060.

func (*SIPHelper) Name

func (h *SIPHelper) Name() string

func (*SIPHelper) ProcessInbound

func (h *SIPHelper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound rewrites outside addresses back to inside addresses in SIP headers and SDP bodies.

func (*SIPHelper) ProcessOutbound

func (h *SIPHelper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound rewrites inside addresses to outside addresses in SIP headers and SDP bodies. It creates NAT expectations for RTP/RTCP streams found in SDP media lines.

type TFTPHelper

type TFTPHelper struct{}

TFTPHelper is an Application Layer Gateway for TFTP (RFC 1350).

TFTP uses a well-known port (69) only for the initial request. The server replies from a random ephemeral port, so the NAT needs an expectation to allow the response through. This helper creates that expectation when it sees an outbound RRQ or WRQ.

func NewTFTPHelper

func NewTFTPHelper() *TFTPHelper

NewTFTPHelper returns a new TFTP ALG helper.

func (*TFTPHelper) Close

func (h *TFTPHelper) Close() error

func (*TFTPHelper) MatchOutbound

func (h *TFTPHelper) MatchOutbound(proto uint8, dstPort uint16) bool

MatchOutbound returns true for UDP connections to port 69 (TFTP).

func (*TFTPHelper) Name

func (h *TFTPHelper) Name() string

func (*TFTPHelper) ProcessInbound

func (h *TFTPHelper) ProcessInbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessInbound is a no-op for TFTP. The server's response is handled by the expectation registered in ProcessOutbound.

func (*TFTPHelper) ProcessOutbound

func (h *TFTPHelper) ProcessOutbound(n *NAT, pkt pktkit.Packet, m *NATMapping) pktkit.Packet

ProcessOutbound creates an expectation for the TFTP server's reply. The server will respond from its IP on a random ephemeral port to the client's mapped outside port.

type UPnPConfig

type UPnPConfig struct {
	ControlPort   uint16        // TCP port for the SOAP control server (default 5000)
	AllowedPorts  [][2]uint16   // allowed outside port ranges; empty means all
	MaxMappings   int           // max total port forwards (0 = unlimited)
	MaxPerClient  int           // max port forwards per inside IP (0 = unlimited)
	LeaseDuration time.Duration // max lease duration (0 = permanent allowed)
}

UPnPConfig configures the UPnP IGD helper.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL