• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer
webrtcHacks

webrtcHacks

Guides and information for WebRTC developers

  • Home
  • About
    • Chad Hart
    • Philipp Hancke
  • Subscribe
  • Contact
  • Show Search
Hide Search

Guide code, ICE, NAT, STUN, symmetric Philipp Hancke · May 15, 2017

Am I behind a Symmetric NAT?

NATs can be a nuisance for VoIP, particularly Symmetric NATs . Fortunately WebRTC includes tools for dealing with them. Image source: http://pinktentacle.com/

WebRTC establishes peer-to-peer connections between web browsers. To do that, it uses a set of techniques known as Interactive Connectivity Establishment or ICE. ICE allows clients behind certain types of routers that perform Network Address Translation, or NAT, to establish direct connections. (See the WebRTC glossary entry for a good introduction.) One of the first problems is for a client to find what its public IP address is. To do so, the client asks a STUN server for its IP address.

NATs are boxes (physical or virtual) that connect our local private networks to the public internet. They do so by translating the internal IP addresses we use to public ones. They work differently from one another, which ends up requiring WebRTC to rely on both STUN and TURN in order to connect calls. For background on these, check out some of our past posts on this topic like this one and this one.

While watching the “NAT Traversal” lesson of Tsahi Levent-Levi’s WebRTC Architecture course  I (re)learned the definition of a symmetric NAT from this slide:

If you ask two different STUN servers for your public IP address a symmetric NAT will give you the same IP address (hopefully) but different ports. We need a TURN server to get out of this mess as in general, symmetric NATs don’t allow the establishment of a direct connection.

 

A couple years ago I discussed some techniques for improving connectivity rates during a Tokbox talk (video and slides). Tsahi’s talk made me wonder if one could also test for the symmetric NAT scenario where you get a different port returned for each STUN binding?

After some tests I verified that yes, yes we can.

The first step is to ask two STUN servers for our IP address by passing it the following configuration:

JavaScript
1
2
3
4
5
6
   var pc = new RTCPeerConnection({iceServers: [
 
       {urls: ‘stun:stun1.l.google.com:19302’},
       {urls: ‘stun:stun2.l.google.com:19302’}
 
   ]})

We create a data channel to make the peer connection only generate a single local candidate.

JavaScript
1
   pc.createDataChannel("webrtchacks")

Then we look at the onicecandidate  event and parse any candidates we get (using a helper function from my SDP module). If the candidate is of type srflx  we note both the port  –  the port after translation by the NAT device – and the relatedPort  – the port before translation.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
pc.onicecandidate = function(e) {
 if (e.candidate && e.candidate.candidate.indexOf('srflx') !== -1) {
   var cand = parseCandidate(e.candidate.candidate);
   if (!candidates[cand.relatedPort]) candidates[cand.relatedPort] = [];
   candidates[cand.relatedPort].push(cand.port);
 } else if (!e.candidate) {
   if (Object.keys(candidates).length === 1) {
     var ports = candidates[Object.keys(candidates)[0]];
     console.log(ports.length === 1 ? 'cool nat' : 'symmetric nat');
 
   }
 }
};

Last but not least we call createOffer and setLocalDescription to start gathering:

JavaScript
1
2
   pc.createOffer()
   .then(offer => pc.setLocalDescription(offer))

Once we’re done gathering candidates we get an icecandidate  event with event.candidate  not being set. We then look at the candidates we got. There are only 3 options:

  1. If we only got a single candidate, the browser did not want to bother us with the response from the second STUN server as it contained the same port. Which means we are not behind a symmetric NAT.
  2. If we got two candidates with the same relatedPort  and different ports then we are behind a symmetric NAT.
  3. And if we did not get a srflx  candidate at all UDP is blocked. This means we need a TURN/TCP or TURN/TLS server (like this one).

How do you test it? The personal hotspot on the iPhone is doing symmetric NAT which helps a lot.  Test it online in this fiddle:

Does the knowledge that we’re behind a symmetric NAT help us? Probably not much. We can now build a NAT type detector. I am not sure if this has much practical use since WebRTC’s ICE mechanism is designed to find a connection without you worrying about the details, but who knows. Nonetheless, it is a fun hack that will help you understand the mysteries of NAT traversal in WebRTC.

{“author”: “Philipp Hancke“}

Guide code, ICE, NAT, STUN, symmetric

Related Posts

  • An Intro to WebRTC’s NAT/Firewall ProblemAn Intro to WebRTC’s NAT/Firewall Problem
  • How to stop a leak – the WebRTC notifierHow to stop a leak – the WebRTC notifier
  • ICE always tastes better when it trickles! (Emil Ivov)ICE always tastes better when it trickles! (Emil Ivov)
  • coturn: No Time to Die – Q&A with new project leadscoturn: No Time to Die – Q&A with new project leads

RSS Feed

Reader Interactions

Comments

  1. Aswath Rao says

    May 16, 2017 at 9:37 am

    As you point out the cost of symmetric NAT (at BOTH the ends) is the requirement of a TURN. At various times, people have proposed different ways to avoid use of a relay server. For example, https://tools.ietf.org/id/draft-takeda-symmetric-nat-traversal-00.txt proposes some heuristics to predict the rule the NAT uses for port mapping, thereby avoiding use of a relay. Like wise https://tools.ietf.org/html/rfc5780 suggests some other scheme.

    As far as I know, these efforts didn’t get much traction possibly because most are service providers and they see other benefits in routing the traffic through their infrastructure.

    Reply
    • Octavian says

      May 31, 2017 at 10:40 am

      I remember doing 2 way video/audio using Flash and FMS or Red5. All the traffic was relayed. We just estimated the usage and moved on.

      Reply
  2. Octavian says

    May 31, 2017 at 10:35 am

    >The personal hotspot on the iPhone is doing symmetric NAT which helps a lot.

    Out of curiosity I’ve connected an iMac to the Personal Hotspot of an iPhone 6S running iOS 10.3.2. I ran the jsfiddle and I only got “normal nat”.

    Maybe in your case it’s the 3G/4G network that’s going out to the Internet through a symmetric NAT ?

    Reply
  3. Mihály Mészáros says

    July 27, 2017 at 8:42 am

    It is great article thanks fippo & highly appreciated!

    In the fiddle there is a copy paste typo:
    One server is used twice, and so the fiddle gives back “normal nat” on consloe, even in case of symmetric NAT.

    Please correct this in the fiddle:
    {urls: ‘stun:stun2.l.google.com:19302’},
    {urls: ‘stun:stun2.l.google.com:19302’}
    to
    {urls: ‘stun:stun1.l.google.com:19302’},
    {urls: ‘stun:stun2.l.google.com:19302’}

    ( Or it was planned typo? Just a quick check that we really understand the article? 🙂 )

    Thanks!
    Misi

    Reply
    • Philipp Hancke says

      July 27, 2017 at 8:50 am

      Fixed, thanks Misi!

      Reply
  4. Misi says

    November 17, 2017 at 3:25 pm

    In the example Firefox 56 gives back false positive (symetric nat).

    My proposal is to replace in the fiddle
    candidates[cand.relatedPort].push(cand.port);

    With this simple udp protocol check.
    if (cand.protocol == “udp”) {
    candidates[cand.relatedPort].push(cand.port);
    }

    Reply
  5. michau says

    February 6, 2020 at 7:45 pm

    I’ve got two times ‘srflx’. What’s going on?

    Reply
    • Philipp Hancke says

      February 7, 2020 at 12:16 pm

      Hard to say without seeing the candidates. Maybe ipv4 and ipv6?

      Reply
      • michau says

        February 17, 2020 at 5:36 am

        RTCIceCandidate: candidate:1171761481 1 udp 1685987071 188.146.38.178 15017 typ srflx raddr 192.168.8.123 rport 55252 generation 0 ufrag OCBk network-id 1 network-cost 10 stun:64.233.165.127:19302″

        RTCIceCandidate: candidate: 1171761481 1 udp 1685987071 188.146.38.178 15023 typ srflx raddr 192.168.8.123 rport 62609 generation 0 ufrag OCBk network-id 1 network-cost 10 stun:64.233.165.127:19302″

        Reply
        • Harvinder says

          December 9, 2021 at 10:16 pm

          foundation property (in your case 1171761481) is a string which uniquely identifies the candidate across multiple transports. It seems that are actuall the same candidates

          Reply
  6. esser50k says

    December 13, 2021 at 8:31 am

    On a Mac I get normal nat on Chrome and Firefox.
    But then I get ‘symmetric nat’ on Safari..

    All these results are consistent regardless if it is my home wifi on iPhone hotspot.

    I don’t really understand these results. But it really does happen that Safari won’t establish a connection while other browsers do.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

  • Sponsored. Become a webtcHacks sponsor

Email Subscription

Subscribe to our mailing list

* indicates required

Twittering

Tweets by @webRTChacks
webrtcHacksguides and information for WebRTC developers

Footer

SITE

  • Post List
  • About
  • Contact

Categories

  • Guide
  • Other
  • Reverse-Engineering
  • Standards
  • Technology

Tags

apple Blackbox Exploration Brief camera Chrome code computer vision DataChannel debug e2ee Edge extension gateway getUserMedia ICE ims insertable streams ios ip leakage janus jitsi MCU Microsoft NAT opensource Opus ORTC Promo Q&A raspberry pi Safari SDES SDP sfu signaling simulcast standards TensorFlow TURN video vp8 Walkthrough Web Audio webrtc-internals wireshark

Follow

  • Twitter
  • YouTube
  • GitHub
  • RSS

webrtcHacks · copyright © 2023