commit a2aa6acf51916e6000764dafce7197d6b85420a0 Author: Cecylia Bocovich cohosh@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; + } + }
tor-commits@lists.torproject.org