FreeBSD IPFW NAT64LSN: Operate Stateful IPv6-to-IPv4 Translation
Configure FreeBSD IPFW NAT64LSN with DNS64, translation prefixes, state inspection, and firewall checks while preserving routing and protocol boundaries.
FreeBSD’s ipfw nat64lsn is an in-kernel, stateful translator for IPv6 clients that need to reach IPv4 servers. It is not a generic NAT switch: DNS64, an IPv6 Pref64, an IPv4 source pool, IPFW rule ordering, forwarding, and return-path state must agree. Treating those as separate layers makes it possible to diagnose whether a failure is name synthesis, routing, filtering, or translation.
nat64lsn is the stateful mode. FreeBSD also has nat64stl, which uses configured address mappings without per-flow state, and nat64clat, a client-side 464XLAT mode. They solve different topology problems. The example here is for an IPv6-only client network reaching IPv4-only services through a stateful translator; it does not make every IPv4 application reachable from IPv6.
The packet and name-resolution path
The IPv6 client first needs an IPv6 address for the IPv4-only destination. DNS64 synthesizes an AAAA record from the destination’s A record and the same IPv6 prefix configured on the translator. The client routes that synthesized address to the NAT64 gateway. FreeBSD extracts the embedded IPv4 address, creates translation state for the flow, chooses an address from its configured IPv4 pool, and forwards an IPv4 packet. Replies are translated back only when matching state exists.
That state boundary is important: in the ordinary case, the IPv6 endpoint initiates the flow. An unsolicited IPv4 packet does not acquire a mapping merely because it can reach the translator’s IPv4 interface. Static bindings or a separate NAT-traversal design are different mechanisms. RFC 6146 describes stateful NAT64 for unicast TCP, UDP, and ICMP; it does not define translation for every IP protocol. FreeBSD’s implementation follows the IPv4-embedded IPv6 address format in RFC 6052 and the IP/ICMP translation algorithm in RFC 7915.
The gateway must route both address families. FreeBSD’s ipfw(8) manual also warns that the normal NAT64 output path reinjects translated packets through the firewall, so a packet can encounter IPFW a second time. The ruleset must not translate the same packet repeatedly or accidentally deny the translated leg. Neighbor Discovery messages are IPv6 control traffic, not NAT64 payload; do not send ICMPv6 Neighbor Solicitation or Neighbor Advertisement through a translation action.
Match the DNS64 and translator prefixes
FreeBSD’s prefix6 option identifies the IPv4-embedded IPv6 addresses the translator accepts. The manual restricts this prefix to RFC 6052 lengths: /32, /40, /48, /56, /64, or /96. The Well-Known Prefix 64:ff9b::/96 must use /96. DNS64 must synthesize addresses using the same chosen prefix, or clients will send traffic the NAT64 instance cannot decode.
For a documentation-only example, pair 2001:db8:64::/96 with 192.0.2.0/24. Both ranges are reserved for examples; they are not usable production routes or public translator addresses. Replace them with a prefix and IPv4 pool actually assigned to the deployment, and configure DNS64 and routes consistently. RFC 6052 restricts use of the Well-Known Prefix for non-global IPv4 addresses. FreeBSD defaults to not processing mapped RFC 1918 destinations; its allow_private switch changes that policy and should be enabled only when the design intentionally translates private destinations.
Create an instance and connect it to IPFW
The NAT64 module must be present in the running kernel, either as ipfw_nat64 or through a kernel built with IPFIREWALL_NAT64. On a disposable FreeBSD test router, the shape of an instance configuration is:
# Example addresses only. Replace both prefixes before testing a real path.
kldload ipfw_nat64
ipfw nat64lsn edge create \
prefix4 192.0.2.0/24 \
prefix6 2001:db8:64::/96 \
log
prefix4 is the pool used as the translated IPv4 source; prefix6 is the embedded-address prefix also used by DNS64. The log option enables per-translator packet logging through the ipfwlog0 BPF pseudo-interface; it does not itself ensure that the interface exists or that a collector is attached. The FreeBSD 15.1 manual documents creating this interface after boot and capturing on it in an authorized lab. The tcpdump(1) manual defines -c 50 as a packet-count limit, not an elapsed-time limit; if traffic is quiet, the command can keep waiting until packets arrive or you interrupt it:
ifconfig ipfwlog0 create
tcpdump -ni ipfwlog0 -c 50
Check the exact release manual and current interface state before relying on these commands. This is distinct from generic IPFW rule logging through ipfw0. Translator captures can contain addresses and packet details; restrict access, cap collection, and do not leave an unreviewed capture process running. The manual documents an IPFW nat64lsn name action. A minimal rule shape must account for both the IPv6 request addressed to Pref64 and the IPv4 reply addressed to the translated pool:
# Illustrative matches only; integrate them into the reviewed ruleset.
ipfw add 120 nat64lsn edge ip6 from any to 2001:db8:64::/96
ipfw add 121 nat64lsn edge ip from any to 192.0.2.0/24
Rule numbers, directions, source scopes, interface names, and the surrounding allow/deny policy are deployment-specific. These examples are not a complete firewall policy. In particular, do not append them blindly to a remote host: first preserve the active ipfw -a list output, ensure a console or independent recovery path, and review the order in which the firewall sees original and translated packets. The return rule is not permission for every new IPv4 flow; the translator still checks its state table.
Verify state before tuning
Start with read-only observations. Confirm that the instance and options exist, then create one test connection from an IPv6-only client to a controlled IPv4-only service. Verify the DNS64 AAAA result, the IPv6 destination selected by the client, and the translator state:
ipfw nat64lsn edge show
ipfw nat64lsn edge show states
ipfw nat64lsn edge stats
ipfw -a list
An absent state entry can mean that the client did not use DNS64, the synthesized address used a different prefix, routing bypassed the gateway, the IPv6 rule did not match, or the kernel feature is unavailable. A state entry with no reply points further downstream: IPv4 routing, the server, upstream filtering, or the translated return rule. Preserve timestamps, counters, interface captures, and the exact ruleset so each conclusion can be reproduced. Do not infer success from a DNS answer alone.
State and memory capacity matter under load. ipfw(8) documents per-client host entries, IPv4 aliases, port groups, and connection states, as well as controls for state chunking and object lifetimes. Defaults are not a capacity plan. Measure the expected number of IPv6 clients and concurrent flows, review the manual for the exact FreeBSD release, and monitor instance statistics before changing limits. Shortening lifetimes to clear pressure can instead break idle but valid sessions.
Boundaries and safe change control
NAT64 does not provide DNS64, create an IPv6 default route, enable IP forwarding, or replace the firewall’s policy. It translates supported traffic that reaches a configured instance. DNS64 must be separately operated, and IPv6 clients need a route to Pref64 through the translator. Applications that embed IPv4 literals or use unsupported protocols may require a different adaptation strategy. NAT64 also changes the address family visible on each side, so logs and access-control policies must account for the translated source address rather than assuming the original client address survives unchanged.
Keep initial experiments in a VNET jail or disposable VM with a matched FreeBSD kernel and userland. Record the FreeBSD release, loaded module, prefixes, DNS64 resolver, exact rule counters, and state output. Test IPv4-only destinations, dual-stack destinations, DNS failures, expired states, and blocked replies independently. For a live migration, stage the instance and rules, maintain an out-of-band console, and prepare a rollback that restores the previously captured rules and resolver settings. Destroying the instance removes its translation state, so treat that operation as a session-disrupting change rather than harmless cleanup.
The operational advantage of nat64lsn is not that it erases IPv4 from the network. It creates a bounded compatibility edge: IPv6 clients can initiate supported sessions toward IPv4 services while the translator tracks return traffic. A correct deployment keeps the synthesized prefix, router path, translation pool, IPFW policy, and state diagnostics aligned.
Related:
- FreeBSD IPv6 Router Advertisements, SLAAC, and Neighbor Discovery Operations
- FreeBSD IPFW and Dummynet: Firewall Rules, Queues, and Traffic Emulation
Sources: