Understanding NAT traversal for WebRTC applications

Real-time peer-to-peer communications has become more important than ever before in the post-a̶p̶o̶c̶a̶l̶y̶p̶t̶i̶c̶ pandemic world. I’ve recently had to leverage WebRTC technology for an application and decided to share my experience with some of the difficulties with dealing with NATs in our existing network infrastructure.

Types of NAT

For the purpose of peer-to-peer (P2P) communications, be it real-time video streaming, phone calls or gaming, there are 2 main types NAT implementations: Cone and Symmetric NAT. Variants of each type depending on how incoming packets are filtered will be ignored for now.

The Cone NAT implementation will translate each outgoing packet’s address and port only based on the source port and address, for example:

In this example, both destinations see that the packet is sent from the same source (10.0.0.1:200) after NAT.

On the other hand, the Symmetric NAT implementation will translate each outgoing packet’s address and port based on both the source and destination, for example:

Here, the 2 destinations see packets coming from different sources after NAT even though they originate from the same source.

Methods of NAT Traversal

There are 2 main methods of performing P2P communications (STUN and TURN) across NAT firewalls due to the difference in constraints. For the purpose of demonstration I’ll assume both peers are behind the same NAT types and both use the same STUN/TURN server for simplicity; in practice peers can use different STUN/TURN servers.

When peers are behind Cone NATs, it is possible to establish a direct connection between them using STUN:

Because port mappings in Cone NATs are retained for different destinations, it’s possible to ask a 3rd party service (STUN server) for the external mapping of a given port and pass it along to the remote peer for direct communication.

When peers are behind Symmetric NATs, it is not possible to establish a direct connection between peers and traffic must go through an intermediate relay (TURN) server:

NATs in the Wild

In my personal tests on different networks, it seems that most home routers and cellular CG-NATs implement Cone NAT while enterprise firewalls or security appliances generally implement Symmetric NAT with rules to switch to Cone NAT for a host or specific network.

It is also common that 2 peers will have different NAT types, the article in reference [1] has a very comprehensive table for which method to use for each NAT combination of the peers.

For testing NAT types, I used a tool called stuntman [2] with following command:

$ stunclient --mode full stun.stunprotocol.org
Binding test: success
Local address: 10.0.0.13:59865
Mapped address: XX.XX.XX.XX:44798
Behavior test: success
Nat behavior: Address and Port Dependent Mapping
Filtering test: success
Nat filtering: Address and Port Dependent Filtering

The line “Address and Port Dependent Mapping” shows that I have a symmetric NAT in this case. Filtering determines what incoming packets are allowed after a mapping has been made, this is where the 4 commonly cited NAT types differ, see [3] for details.

Throughout this article I’ve also been making the assumption that the firewalls at play allow outgoing UDP traffic and support automatic rule generation for incoming packets (UDP hole-punching) but this is not always the case especially in restrictive corporate networks. In these scenarios, it’s possible to use the TURN method with a TCP transport ( via a commonly allowed port like 443).

References

[1] https://www.frozenmountain.com/developers/blog/webrtc-nat-traversal-methods-a-case-for-embedded-turn
[2] http://www.stunprotocol.org/
[3] https://en.wikipedia.org/wiki/Network_address_translation#Methods_of_translation