[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [snowflake-webext/master] Make a test connection to determine NAT type
commit e1958c454de9e24f464efaf82837fa6da1270120
Author: Cecylia Bocovich <cohosh@xxxxxxxxxxxxxx>
Date: Wed Oct 14 11:32:29 2020 -0400
Make a test connection to determine NAT type
Make a test connection to the symmetrically NAT'd probe site to
determine NAT type. This replaces the previous method of getting
ICE candidates from two different STUN servers and more
definitively determines compatability with a symmetrically NAT'd
client.
---
config.js | 2 ++
init-badge.js | 7 ++++--
init-webext.js | 9 +++++---
util.js | 72 +++++++++++++++++++++++++++++++++++++++++-----------------
4 files changed, 64 insertions(+), 26 deletions(-)
diff --git a/config.js b/config.js
index d662013..b5db8b5 100644
--- a/config.js
+++ b/config.js
@@ -46,3 +46,5 @@ Config.prototype.pcConfig = {
}
]
};
+
+Config.PROBEURL = "https://snowflake-broker.torproject.net:8443/probe";
diff --git a/init-badge.js b/init-badge.js
index 4b432fc..6c4c7a7 100644
--- a/init-badge.js
+++ b/init-badge.js
@@ -150,10 +150,13 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, initNATType, s
initNATType = function() {
this.natType = "unknown";
(function loop(_this) {
- Util.checkNATType().then((type) => {
+ Util.checkNATType(config.datachannelTimeout).then((type) => {
console.log("Setting NAT type: " + type);
_this.natType = type;
- }).catch((e) => console.log(e));
+ }).catch((e) => {
+ console.log(e);
+ _this.natType = "unknown";
+ });
// reset NAT type every 24 hours in case proxy location changed
setTimeout(_this.initNATType, 24 * 60 * 60 * 1000);
})(this);
diff --git a/init-webext.js b/init-webext.js
index e38ab88..0a2c22b 100644
--- a/init-webext.js
+++ b/init-webext.js
@@ -13,7 +13,6 @@ class WebExtUI extends UI {
this.onMessage = this.onMessage.bind(this);
this.onDisconnect = this.onDisconnect.bind(this);
this.initStats();
- this.initNATType();
chrome.runtime.onConnect.addListener(this.onConnect);
}
@@ -29,10 +28,13 @@ class WebExtUI extends UI {
initNATType() {
this.natType = "unknown";
(function loop(_this) {
- Util.checkNATType().then((type) => {
+ Util.checkNATType(config.datachannelTimeout).then((type) => {
console.log("Setting NAT type: " + type);
_this.natType = type;
- }).catch((e) => console.log(e));
+ }).catch((e) => {
+ console.log(e);
+ _this.natType = "unknown";
+ });
// reset NAT type every 24 hours in case proxy location changed
setTimeout(_this.initNATType, 24 * 60 * 60 * 1000);
})(this);
@@ -200,6 +202,7 @@ var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotific
snowflake = new Snowflake(config, ui, broker);
log('== snowflake proxy ==');
ui.initToggle();
+ ui.initNATType();
};
update = function() {
diff --git a/util.js b/util.js
index ee36478..8ab65d9 100644
--- a/util.js
+++ b/util.js
@@ -1,5 +1,5 @@
/* exported Util, Params, DummyRateLimit */
-/* global PeerConnection */
+/* global PeerConnection, Config */
/*
A JavaScript WebRTC snowflake proxy
@@ -21,33 +21,63 @@ 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() {
+ // returns a promise that fullfills to "restricted" if we
+ // fail to make a test connection to a known restricted
+ // NAT, "unrestricted" if the test connection fails, and
+ // "unknown" if we fail to reach the probe test server
+ static checkNATType(timeout) {
return new Promise((fulfill, reject) => {
- let port = null;
+ let open = false;
let pc = new PeerConnection({iceServers: [
- {urls: 'stun:stun1.l.google.com:19302'},
- {urls: 'stun:stun2.l.google.com:19302'}
+ {urls: 'stun:stun1.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");
- }
+ let channel = pc.createDataChannel("NAT test");
+ channel.onopen = function() {
+ open = true;
+ fulfill("unrestricted");
+ channel.close();
+ pc.close();
};
- pc.createOffer().then((offer) => {
- pc.setLocalDescription(offer);
- }).catch((e) => {
+ pc.createOffer()
+ .then((offer) => pc.setLocalDescription(offer))
+ .then(() => Util.sendOffer(pc.localDescription))
+ .then((answer) => pc.setRemoteDescription(JSON.parse(answer)))
+ .catch((e) => {
console.log(e);
reject("Error checking NAT type");
});
+ setTimeout(() => {if(!open) fulfill("restricted");}, timeout);
+ });
+ }
+
+ // Assumes getClientOffer happened, and a WebRTC SDP answer has been generated.
+ // Sends it back to the broker, which passes it back to the original client.
+ static sendOffer(offer) {
+ return new Promise((fulfill, reject) => {
+ var xhr;
+ xhr = new XMLHttpRequest();
+ xhr.timeout = 10 * 1000;
+ xhr.onreadystatechange = function() {
+ if (xhr.DONE !== xhr.readyState) {
+ return;
+ }
+ switch (xhr.status) {
+ case 200:
+ var response = JSON.parse(xhr.responseText);
+ return fulfill(response.Answer); // Should contain offer.
+ default:
+ console.log('Probe ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText);
+ return reject('Failed to get answer from probe service');
+ }
+ };
+ var data = {"Status": "client match", "Offer": JSON.stringify(offer)};
+ try {
+ xhr.open('POST', Config.PROBEURL);
+ } catch (error) {
+ console.log('Signaling Server: exception while connecting: ' + error.message);
+ return reject('unable to connect to signaling server');
+ }
+ return xhr.send(JSON.stringify(data));
});
}
}
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits