NATlab is a testbed for NAT traversal software. It intercepts packets before Linux's NAT implementation can process them, and does its own translation according to configurable policies. This enables NATlab to emulate any NAT behavior you desire.
Combined with something like docker-compose, you can construct complex network topologies, featuring multiple NAT gateways with different behaviors, and see how well your software is able to traverse them.
We write ip:port combinations as X:x
, X1:x1
, Y2:y2
and so
forth. We write a NAT mapping as X1:x1 <> X1':x1'
, meaning "the LAN
source ip:port X1:x1
is rewritten to X1':x1'
as packets go through
the NAT box".
NATlab implements a configurable NAT gateway, with configuration knobs for each of the behaviors identified by RFC 4787. By varying these knobs, you can emulate a wide variety of NAT devices.
In general, the questions we're trying to answer are:
The specific knobs offered by NATlab are as follows. We'll use REQ-x
to reference each behavior, although the RFC uses REQ-x
to specify
what a nice NAT box should do, we use it to describe all possible
behaviors.
When a LAN client sends packets from X1:x1
, the NAT box assigns a
NAT mapping that rewrites the source to X1':x1'
on the way out. The
LAN client then continues to send from X1:x1
, but varies the
destination IP and/or port.
Endpoint-Independent: The mapping X1:x1 <> X1':x1'
is reused
regardless of the destination address.
Address-Dependent: The mapping X1:x1 <> X1':x1
is reused as
long as the destination IP address is the same.
Address-And-Port-Dependent: The mapping X1:x1 <> X1':x1'
is
reused as long as both the destination IP and destination port are
the same.
RFC recommends Endpoint-Independent behavior.
Assume the NAT box has multiple public IP addresses it can choose from
when creating new NAT mappings. A LAN client sends packets from X1
,
on various source ports and to various destinations. What public IP(s)
will be used for mappings?
X1
may get different
public IPs X1'
, X2'
, ....X1
use a single public IP
X1'
. If X1'
has no free ports to use for a new mapping, new
sessions are dropped.X1
use a single public IP
X1'
. If X1'
has no free ports to use for a new mapping, ports
on other IPs may be used.RFC recommends Paired behavior, but notes that many enterprise NAT gateways use Arbitrary behavior "for security reasons" (i.e. wooly thinking).
When a new NAT mapping X1:x1 <> X1':x1'
needs to be created, how
does the NAT box pick x1'
?
x1' = x1
. If this
results in a collision, the previous mapping is deleted.x1' = x1
. In case of collision, the NAT box will pick some other x1'
.x1' = x1
at
all.REQ-3 does not specify what source IP to use. It's allowable to pick
x1'
on any available public IP, subject to the constraints of the
other settings.
RFC recommends anything but Port-Overloading, for the obvious reason that it breaks stuff hilariously.
When picking a port x1'
to map X1:x1
, does the NAT box attempt to
keep LSB(x1') == LSB(x1)
, i.e. map even ports to even ports and odd
ports to odd ports?
This is a silly distinction designed to placate ancient RTP clients, so NATlab doesn't implement it.
How long can a mapping go without seeing "qualifying traffic" (see REQ-6) before it gets deleted?
RFC recommends 5 minutes, and begs vendors to not set it lower than 2 minutes. Exceptions exist for certain types of traffic, e.g. DNS can have much shorter timeouts. NATlab doesn't (yet?) support overriding the timer by port.
What packets trigger a renewal of the NAT mapping's lease?
RFC recommends Outbound-Only at minimum, ideally Both (but points out that Both may enable a resource DoS on the NAT box, so "for security reasons" expect Outbound-Only to be the norm)
This specifies that if LAN and WAN have address collisions, the NAT box should handle this gracefully. NATlab doesn't implement this at all, as afaict this is a theoretical concern rather than a practical one.
When packets are traversing the NAT from WAN to LAN and match a NAT mapping, what packets are permitted to flow back to the LAN client?
Y:*
can only flow if the LAN
client has previously sent packets to Y
.Y:y
can only flow
if the LAN client has previously sent packets to Y:y
.RFC recommends either Endpoint-Independent or Address-Dependent, depending on paranoia levels.
If two clients X1:x1
and X2:x2
are on the same LAN, can they use
each other's public addresses X1':x1'
and X2':x2'
and hairpin
through the NAT box?
ip:port
as the source.ip:port
as the source.RFC requires External-Source behavior.
This requirement has to do with NATs having explicit behavioral support for certain protocols (e.g. VOIP). The RFC says to disable all ALGs, and NATlab doesn't implement any.
Roughly, this section says NATs shouldn't vary one REQ- behavior based on the outcome of another REQ- behavior. Some specific examples are given, but each one would have to be encoded as another sub-behavior of the appropriate REQ-.
For now, NATlab's implementation is deterministic according to this section.
Does the NAT box correctly rewrite and forward ICMP messages that pertain to an active NATed session?
RFC recommends Yes.
These are just a requirement that the NAT gateway should handle IP fragmentation correctly. DF=1 packets should result in ICMP Fragmentation Needed + drop, DF=0 should result in fragmentation.
NATlab relies on the linux kernel to do this right.
This isn't from the RFC, but there are a variety of "NAT helper" protocols that a client can use to explicitly create a port mapping. Eventually, we'd like NATlab to support them. They are: