While experimenting with WebRTC/ICE NAT traversal, I came across
a class of network configurations that currently does not result
in a direct P2P connection (but rather falls back to TURN), yet
could be in principle. I wanted to ask whether the limitation
for this kind of configurations is ''known to the WebRTC
community'', and if so what is the rationale behind not adding
the support for it.
Specifically, the configuration is where both peers are behind a
NAT which implements
* endpoint-independent mappings,
* endpoint-dependent filtering, and
* does not drop all unsolicited incoming packets, but rather generated
ICMP unreachable replies.
An example for such a configuration is Linux Iptables with a MASQUERADE
rule on the FORWARD chain, yet without a DROP rule on the INPUT chain.
In this configuration the following scenario can happen:
1. Both peers learn their external IP address and port from a
STUN server. Assume that Peer1 binds local
address/port (X1,x1), which gets mapped by NAT1 to (Y1,y1),
and for Peer2 binds (X2,x2), which gets mapped by NAT2 to (Y2,y2).
2. Peer 1 sends an outgoing UDP packet to (Y2,y2) (as part of the
hole punching), and this packet reaches NAT2 *before* Peer 2
sends an outgoing packet to (Y1,y1). In this case, since NAT2
implements endpoint-dependent filtering, NAT2 does not forward
the packet to Peer2 (this is expected). However, if NAT2 does not
drop the incoming packet, but rather generates an ICMP packet in
reply, the flow
(Y1,y1)<-->(Y2,y2) gets allocated (I beleive this is called a
Null Binding in Netfilter terminology).
3. Subsequently, when Peer2 sends its UDP packet (as part of the
hole punching) from (X2,x2) to (Y1,y1), NAT2 modifies the
external port of this packet to y3, since y2 is already allocated
due to the previous unsolicited packet. When this packet reaches
NAT1, it cannot traverse it since the source port y3, is
different than the port for which the hole in NAT1 has been
punched. Note that had the unsolicited packet not be previosly
received, the external port would not be modified, since the NAT
implements endpoint-independent mappings.
This prevents direct P2P connectivity.
I beleive one semi-standard solution to this approach is to begin
the hole punching by sending packets with short TTL numbers,
which would guarantee that a hole in each peer's NAT is punched
before any incoming packets arrive. This would prevent the above
scenario of unsolicited packets creating erroneous bindings in
the NAT that prevent succesfull hole punching.