[tor-commits] [snowflake-webext/master] Perform a test for symmetric NATs on startup

cohosh at torproject.org cohosh at torproject.org
Wed Aug 12 14:35:36 UTC 2020


commit a2aa6acf51916e6000764dafce7197d6b85420a0
Author: Cecylia Bocovich <cohosh at torproject.org>
Date:   Tue Aug 4 13:26:23 2020 -0400

    Perform a test for symmetric NATs on startup
---
 init-badge.js     | 16 +++++++++++++++-
 init-webext.js    | 12 ++++++++----
 package.json      |  2 +-
 spec/util.spec.js | 24 ++++++++++++++++++++++++
 util.js           | 42 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/init-badge.js b/init-badge.js
index b627806..4b432fc 100644
--- a/init-badge.js
+++ b/init-badge.js
@@ -105,7 +105,7 @@ function getLang() {
   return defaultLang;
 }
 
-var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotifications, query, tryProbe;
+var debug, snowflake, config, broker, ui, log, dbg, init, update, initNATType, silenceNotifications, query, tryProbe;
 
 (function() {
 
@@ -147,6 +147,18 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific
     );
   };
 
+  initNATType = function() {
+    this.natType = "unknown";
+    (function loop(_this) {
+      Util.checkNATType().then((type) => {
+        console.log("Setting NAT type: " + type);
+        _this.natType = type;
+      }).catch((e) => console.log(e));
+      // reset NAT type every 24 hours in case proxy location changed
+      setTimeout(_this.initNATType, 24 * 60 * 60 * 1000);
+    })(this);
+  };
+
   update = function() {
     const cookies = Parse.cookie(document.cookie);
     if (cookies[COOKIE_NAME] !== '1') {
@@ -181,6 +193,8 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific
     snowflake = new Snowflake(config, ui, broker);
     log('== snowflake proxy ==');
     update();
+
+    initNATType();
   };
 
   // Notification of closing tab with active proxy.
diff --git a/init-webext.js b/init-webext.js
index 3d7b1ea..e38ab88 100644
--- a/init-webext.js
+++ b/init-webext.js
@@ -28,10 +28,14 @@ class WebExtUI extends UI {
 
   initNATType() {
     this.natType = "unknown";
-    // reset NAT type every 24 hours in case proxy location changed
-    setInterval((() => {
-      this.natType = "unknown";
-    }), 24 * 60 * 60 * 1000);
+    (function loop(_this) {
+      Util.checkNATType().then((type) => {
+        console.log("Setting NAT type: " + type);
+        _this.natType = type;
+      }).catch((e) => console.log(e));
+      // reset NAT type every 24 hours in case proxy location changed
+      setTimeout(_this.initNATType, 24 * 60 * 60 * 1000);
+    })(this);
   }
 
   tryProbe() {
diff --git a/package.json b/package.json
index 4dd6a00..601675a 100644
--- a/package.json
+++ b/package.json
@@ -32,4 +32,4 @@
     "ws": "^3.3.1",
     "xmlhttprequest": "^1.8.0"
   }
-}
\ No newline at end of file
+}
diff --git a/spec/util.spec.js b/spec/util.spec.js
index 6eb5be4..a15c201 100644
--- a/spec/util.spec.js
+++ b/spec/util.spec.js
@@ -210,7 +210,31 @@ describe('Parse', function() {
     });
 
   });
+  describe('portFromCandidate', function() {
 
+    var testCases = [
+      {
+        candidate: "candidate:0 1 UDP 2122252543 aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.local 54297 typ host",
+        expected: null
+      },
+      {
+        candidate: "candidate:1 1 UDP 1686052863 1.2.3.4 54297 typ srflx raddr 0.0.0.0 rport 0",
+        expected: "54297"
+      },
+      {
+        candidate: "candidate:1 1 UDP 1686052863 2a07:2e47:ffff:ffff:ffff:ffff:ffff:ffff 54297 typ srflx raddr 0.0.0.0 rport 0",
+        expected: "54297"
+      }
+    ];
+    it('parses port', function() {
+      var i, len, ref, ref1, results, test;
+      results = [];
+      for (i = 0, len = testCases.length; i < len; i++) {
+        test = testCases[i];
+        expect(Parse.portFromCandidate(test.candidate)).toEqual(test.expected);
+      }
+    });
+  });
 });
 
 describe('Params', function() {
diff --git a/util.js b/util.js
index 42843d7..0199ae8 100644
--- a/util.js
+++ b/util.js
@@ -1,4 +1,5 @@
 /* exported Util, Params, DummyRateLimit */
+/* global PeerConnection */
 
 /*
 A JavaScript WebRTC snowflake proxy
@@ -20,6 +21,35 @@ class Util {
     return navigator.cookieEnabled;
   }
 
+  // returns a promise that fullfills to "restricted" if the
+  // mapping is symmetric, and we know it's a restrictive NAT,
+  // and fullfills to "unknown" if the mapping is not
+  // symmetric.
+  static checkNATType() {
+    return new Promise((fulfill, reject) => {
+      let port = null;
+      let pc = new PeerConnection({iceServers: [
+        {urls: 'stun:stun1.l.google.com:19302'},
+        {urls: 'stun:stun2.l.google.com:19302'}
+      ]});
+      pc.createDataChannel("NAT test");
+      pc.onicecandidate = function(e) {
+        if (e.candidate) {
+          let p = Parse.portFromCandidate(e.candidate.candidate);
+          if (port == null) port = p;
+          else if (p != null && p != port) fulfill("restricted");
+        } else { // done parsing candidates
+          fulfill("unknown");
+        }
+      };
+      pc.createOffer().then((offer) => {
+        pc.setLocalDescription(offer);
+      }).catch((e) => {
+        console.log(e);
+        reject("Error checking NAT type");
+      });
+    });
+  }
 }
 
 
@@ -118,6 +148,18 @@ class Parse {
     }
   }
 
+  // Parse the mapped port out of an ice candidate returned from the
+  // onicecandidate callback
+  static portFromCandidate(c) {
+    var m, pattern;
+    pattern = /(?:[\d.]+|[0-9A-Fa-f:.]+) (\d+) typ srflx/m;
+    m = pattern.exec(c);
+    if (m != null) {
+      return m[1];
+    }
+    return null;
+  }
+
 }
 
 



More information about the tor-commits mailing list