But there are at most 2^16 TCP ports available on the other side. I think this doesn't theoretically prevent one from reusing an exterior port multiple times for multiple connections to different other IP addresses or ports, but that would be both rather tricky and inconsistent with some cultural expectations regarding the use of initiating ("client") ports, and so I doubt any current NAT stack in common use uses that approach (though I'd love to be proven wrong). It also fails naturally if all sixteen million hosts try to communicate with the same host/port on the other side. UDP has similar but nonidentical constraints.
I was originally thinking this would break things like IDENT, but then I remembered that they use the entire tuple (d'oh). I'll take your word for the pf behavior, and retract my bogus guess about kernel NAT. :-)
one-up-manship sucks, but correct information is beneficial. ;)
The problem with the term "NAT" as "Network Address Translation" is the
term is often misused/incorrect; most all modern "NAT" implementations
are actually "PNAT" ("Port and Network Address Translation") where the
translator system modifies both the source address and source port
rather than just modifying the source address.
For notes, the earliest translation implementations really were just
address modification, and hence, really were plain "NAT," but the
problem of conflicting port numbers is the reason why just about every
implementation moved to PNAT.
When running a PNAT implementation, you can exhaust the number of
available TCP ports with enough load from client systems. The number of
available TCP ports is typically, but incorrectly, stated as 2^16 ports,
but in practice, you can't use all of them.
Getting around the TCP port count limitation is entirely possible, and
regularly done in large scale networks. The early implementations were
standard "proxy systems/servers" (typically requiring client-side
configuration like, address, port, user/pass, etc.). More modern
implementations are "transparent proxies" and require no client-side
configuration. Transparent proxy implementations (typically) count on
PNAT in order to be "transparent" to the client systems and prevent the
need for client-side configuration.
The mental leap one needs to make in order to understand how to get past
the TCP port count limitation is, understanding that a single public IP
address can be shared by multiple systems simultaneously without
NAT/PNAT or proxies. There are many ways to do it from "load balancing
appliances," to CARP (Common Address Resolution Protocol - free in
OpenBSD), to VRRP (Virtual Router Redundancy Protocol - patented by
Cisco), to other methods. This is often combined with multiple stateful
firewalls where all of the firewalls share their state tables.
Similarly, pools of public IP addresses can also be shared amongst
multiple systems simultaneously. Let's say your shared state table
already has an entry with your source of "aaa.bbb.ccc.ddd port 1331",
with a pool of address, you now have your choice of changing either the
port number or the source address. --This isn't particularly precise,
but it is a good way to reason through it.
AOL used to (and maybe still does?) run some humongous transparent
proxies. If you search around, you'll find some (historic?) complaints
from sites about not being able to block trolls or malicious traffic
from jerks on AOL without blocking everyone on AOL. The only IP the site
owners got was the from the small block dedicated to the AOL transparent
proxies. I think this issue may have been resolved by the "proxy-for"
header being added eventually (i.e. often called a "non-anonymous
proxy"), but my recollection is a bit fuzzy.
The point to take away from this is, AOL, at its height, was able to
stuff all of it's millions of users behind a couple dozen proxies/IP's,
so the number of TCP ports is only a limitation in theory, but it's not
a limitation in practice.
Yogi Beara once said, "In theory, practice and theory are the same, but
in practice, they're not."
The number of available TCP ports is typically, but incorrectly, stated as 2^16 ports, but in practice, you can't use all of them.
That's mainly why I wrote “at most” instead of trying to compute the exact available number, yes.
You don't even theoretically need application-layer gateways to multiply the effective number of ports by a large factor for common loads, of course, as I mentioned; I just erroneously thought such technique was not in common use, per my reply to eggnet.