commit e77baabdcfd742d6dbc4dbf2a74f21ba6d36ad36 Author: Cecylia Bocovich cohosh@torproject.org Date: Wed Jul 24 10:52:33 2019 -0400
Add a timeout to check if datachannel opened
This is similar to the deadlock bug in the proxy-go instances. If the proxy-pair sends an answer to the broker, it previously assumed that the datachannel would be opened and the pair reused only once the datachannel closed. However, sometimes the datachannel never opens due to ICE errors or a misbehaving/buggy client causing the proxy to infinitely loop and the proxy-pair to remain active.
This commit reuses the pair.running attribute to indicate whether or not the datachannel has been opened and sets a timeout to close the proxy-pair if it has not been opened by that time. --- proxy/proxypair.js | 6 ++++-- proxy/snowflake.js | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/proxy/proxypair.js b/proxy/proxypair.js index 6ffa9e5..703ac27 100644 --- a/proxy/proxypair.js +++ b/proxy/proxypair.js @@ -85,6 +85,7 @@ class ProxyPair { prepareDataChannel(channel) { channel.onopen = () => { log('WebRTC DataChannel opened!'); + this.running = true; snowflake.state = Snowflake.MODE.WEBRTC_READY; snowflake.ui.setActive(true); // This is the point when the WebRTC datachannel is done, so the next step @@ -176,7 +177,6 @@ class ProxyPair { clearTimeout(this.timer); this.timer = 0; } - this.running = false; if (this.webrtcIsReady()) { this.client.close(); } @@ -186,6 +186,8 @@ class ProxyPair { } this.relay = null; this.onCleanup(); + this.active = false; + this.running = false; }
flush() { @@ -245,7 +247,7 @@ ProxyPair.prototype.relay = null; // websocket
ProxyPair.prototype.timer = 0;
-ProxyPair.prototype.running = true; +ProxyPair.prototype.running = false; // Whether a datachannel is opened
ProxyPair.prototype.active = false; // Whether serving a client.
diff --git a/proxy/snowflake.js b/proxy/snowflake.js index ae7aa2c..7a242db 100644 --- a/proxy/snowflake.js +++ b/proxy/snowflake.js @@ -74,10 +74,16 @@ class Snowflake { this.ui.setStatus(msg); recv = this.broker.getClientOffer(pair.id); recv.then((desc) => { - if (pair.running) { + if (pair.active) { if (!this.receiveOffer(pair, desc)) { return pair.active = false; } + //set a timeout for channel creation + return setTimeout((() => { + log('proxypair datachannel timed out waiting for open'); + pair.close(); + return pair.active = false; + }), 20000); // 20 second timeout } else { return pair.active = false; }
tor-commits@lists.torproject.org