Commit 99035eb7 authored by Kathleen Brade's avatar Kathleen Brade
Browse files

Bug 29627: Moat: add support for obfsproxy's meek_lite

Recognize "meek_lite" as a transport in addition to "meek".
Use SOCKS args instead of command line parameters to pass the
  "url" (BridgeDB reflector) and "front" (BridgeDB front end)
   parameters to the PT binary.
parent a40e5e1b
// Copyright (c) 2018, The Tor Project, Inc. // Copyright (c) 2019, The Tor Project, Inc.
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// vim: set sw=2 sts=2 ts=8 et syntax=javascript: // vim: set sw=2 sts=2 ts=8 et syntax=javascript:
...@@ -542,18 +542,22 @@ function onOpenBridgeDBRequestPrompt() ...@@ -542,18 +542,22 @@ function onOpenBridgeDBRequestPrompt()
return; return;
let meekClientPath; let meekClientPath;
let meekTransport; // We support both "meek" and "meek_lite".
let meekClientArgs; let meekClientArgs;
reply.lineArray.forEach(aLine => reply.lineArray.forEach(aLine =>
{ {
let tokens = aLine.split(' '); let tokens = aLine.split(' ');
if ((tokens.length > 2) && (tokens[0] == "meek") && (tokens[1] == "exec")) if ((tokens.length > 2) &&
((tokens[0] == "meek") || (tokens[0] == "meek_lite")) &&
(tokens[1] == "exec"))
{ {
meekTransport = tokens[0];
meekClientPath = tokens[2]; meekClientPath = tokens[2];
meekClientArgs = tokens.slice(3); meekClientArgs = tokens.slice(3);
} }
}); });
if (!meekClientPath) if (!meekTransport)
{ {
reportMoatError(TorLauncherUtil.getLocalizedString("no_meek")); reportMoatError(TorLauncherUtil.getLocalizedString("no_meek"));
return; return;
...@@ -578,7 +582,8 @@ function onOpenBridgeDBRequestPrompt() ...@@ -578,7 +582,8 @@ function onOpenBridgeDBRequestPrompt()
resetBridgeDBRequestPrompt(); resetBridgeDBRequestPrompt();
setBridgeDBRequestState("fetchingCaptcha"); setBridgeDBRequestState("fetchingCaptcha");
overlay.hidden = false; overlay.hidden = false;
requestMoatCaptcha(proxySettings, meekClientPath, meekClientArgs); requestMoatCaptcha(proxySettings, meekTransport, meekClientPath,
meekClientArgs);
} }
} }
...@@ -2508,7 +2513,8 @@ function createColonStr(aStr1, aStr2) ...@@ -2508,7 +2513,8 @@ function createColonStr(aStr1, aStr2)
} }
function requestMoatCaptcha(aProxySettings, aMeekClientPath, aMeekClientArgs) function requestMoatCaptcha(aProxySettings, aMeekTransport,
aMeekClientPath, aMeekClientArgs)
{ {
function cleanup(aMoatRequestor, aErr) function cleanup(aMoatRequestor, aErr)
{ {
...@@ -2543,7 +2549,7 @@ function requestMoatCaptcha(aProxySettings, aMeekClientPath, aMeekClientArgs) ...@@ -2543,7 +2549,7 @@ function requestMoatCaptcha(aProxySettings, aMeekClientPath, aMeekClientArgs)
}; };
addBridgeDBRequestEventListener(kCaptchaCancelEventType, cancelListener); addBridgeDBRequestEventListener(kCaptchaCancelEventType, cancelListener);
moatRequestor.init(proxyURLFromSettings(aProxySettings), moatRequestor.init(proxyURLFromSettings(aProxySettings), aMeekTransport,
aMeekClientPath, aMeekClientArgs) aMeekClientPath, aMeekClientArgs)
.then(()=> .then(()=>
{ {
......
// Copyright (c) 2018, The Tor Project, Inc. // Copyright (c) 2019, The Tor Project, Inc.
// See LICENSE for licensing information. // See LICENSE for licensing information.
// //
// vim: set sw=2 sts=2 ts=8 et syntax=javascript: // vim: set sw=2 sts=2 ts=8 et syntax=javascript:
...@@ -61,7 +61,6 @@ function _MoatRequestor() ...@@ -61,7 +61,6 @@ function _MoatRequestor()
_MoatRequestor.prototype = _MoatRequestor.prototype =
{ {
kMaxResponseLength: 1024 * 400, kMaxResponseLength: 1024 * 400,
kTransport: "meek",
kMoatContentType: "application/vnd.api+json", kMoatContentType: "application/vnd.api+json",
kMoatVersion: "0.1.0", kMoatVersion: "0.1.0",
kPrefBridgeDBFront: "extensions.torlauncher.bridgedb_front", kPrefBridgeDBFront: "extensions.torlauncher.bridgedb_front",
...@@ -74,6 +73,9 @@ _MoatRequestor.prototype = ...@@ -74,6 +73,9 @@ _MoatRequestor.prototype =
kMoatCheckRequestType: "moat-solution", kMoatCheckRequestType: "moat-solution",
kMoatCheckResponseType: "moat-bridges", kMoatCheckResponseType: "moat-bridges",
kMozProxyTypeSocks4: "socks4",
kMozProxyTypeSocks5: "socks",
kStateIdle: 0, kStateIdle: 0,
kStateWaitingForVersion: 1, kStateWaitingForVersion: 1,
kStateWaitingForProxyDone: 2, kStateWaitingForProxyDone: 2,
...@@ -83,19 +85,22 @@ _MoatRequestor.prototype = ...@@ -83,19 +85,22 @@ _MoatRequestor.prototype =
mState: this.kStateIdle, mState: this.kStateIdle,
mMeekTransport: undefined,
mLocalProxyURL: undefined, mLocalProxyURL: undefined,
mMeekFront: undefined, // Frontend server, if we are using one. mMeekFront: undefined, // Frontend server, if we are using one.
mMeekClientEscapedArgs: undefined,
mMeekClientProcess: undefined, mMeekClientProcess: undefined,
mMeekClientStdoutBuffer: undefined, mMeekClientStdoutBuffer: undefined,
mMeekClientProxyType: undefined, // contains Mozilla names such as socks4 mMeekClientProxyType: undefined, // kMozProxyTypeSocks4 or kMozProxyTypeSocks5
mMeekClientIP: undefined, mMeekClientIP: undefined,
mMeekClientPort: undefined, mMeekClientPort: undefined,
mMoatResponseListener: undefined, mMoatResponseListener: undefined,
mUserCanceled: false, mUserCanceled: false,
// Returns a promise. // Returns a promise.
init: function(aProxyURL, aMeekClientPath, aMeekClientArgs) init: function(aProxyURL, aMeekTransport, aMeekClientPath, aMeekClientArgs)
{ {
this.mMeekTransport = aMeekTransport;
this.mLocalProxyURL = aProxyURL; this.mLocalProxyURL = aProxyURL;
return this._startMeekClient(aMeekClientPath, aMeekClientArgs); return this._startMeekClient(aMeekClientPath, aMeekClientArgs);
}, },
...@@ -208,21 +213,24 @@ _MoatRequestor.prototype = ...@@ -208,21 +213,24 @@ _MoatRequestor.prototype =
meekClientPath = f.path; meekClientPath = f.path;
} }
// Construct the args array. // Construct the per-connection arguments.
let args = aMeekClientArgs.slice(); // make a copy this.mMeekClientEscapedArgs = "";
let meekReflector = TorLauncherUtil.getCharPref(this.kPrefBridgeDBReflector); let meekReflector = TorLauncherUtil.getCharPref(this.kPrefBridgeDBReflector);
if (meekReflector) if (meekReflector)
{ {
args.push("-url"); this.mMeekClientEscapedArgs += "url=";
args.push(meekReflector); this.mMeekClientEscapedArgs += this._escapeArgValue(meekReflector);
} }
this.mMeekFront = TorLauncherUtil.getCharPref(this.kPrefBridgeDBFront); this.mMeekFront = TorLauncherUtil.getCharPref(this.kPrefBridgeDBFront);
if (this.mMeekFront) if (this.mMeekFront)
{ {
args.push("-front"); if (this.mMeekClientEscapedArgs.length > 0)
args.push(this.mMeekFront); this.mMeekClientEscapedArgs += ';';
this.mMeekClientEscapedArgs += "front=";
this.mMeekClientEscapedArgs += this._escapeArgValue(this.mMeekFront);
} }
// Setup environment and start the meek client process.
let ptStateDir = TorLauncherUtil.getTorFile("tordatadir", false); let ptStateDir = TorLauncherUtil.getTorFile("tordatadir", false);
let meekHelperProfileDir = TorLauncherUtil.getTorFile("pt-profiles-dir", let meekHelperProfileDir = TorLauncherUtil.getTorFile("pt-profiles-dir",
true); true);
...@@ -238,17 +246,19 @@ _MoatRequestor.prototype = ...@@ -238,17 +246,19 @@ _MoatRequestor.prototype =
let envAdditions = { TOR_PT_MANAGED_TRANSPORT_VER: "1", let envAdditions = { TOR_PT_MANAGED_TRANSPORT_VER: "1",
TOR_PT_STATE_LOCATION: ptStateDir.path, TOR_PT_STATE_LOCATION: ptStateDir.path,
TOR_PT_EXIT_ON_STDIN_CLOSE: "1", TOR_PT_EXIT_ON_STDIN_CLOSE: "1",
TOR_PT_CLIENT_TRANSPORTS: this.kTransport, TOR_PT_CLIENT_TRANSPORTS: this.mMeekTransport,
TOR_BROWSER_MEEK_PROFILE: meekHelperProfileDir.path }; TOR_BROWSER_MEEK_PROFILE: meekHelperProfileDir.path };
if (this.mLocalProxyURL) if (this.mLocalProxyURL)
envAdditions.TOR_PT_PROXY = this.mLocalProxyURL; envAdditions.TOR_PT_PROXY = this.mLocalProxyURL;
TorLauncherLogger.log(3, "starting " + meekClientPath + " in " TorLauncherLogger.log(3, "starting " + meekClientPath + " in "
+ workDir.path); + workDir.path);
TorLauncherLogger.log(3, "args " + JSON.stringify(args)); TorLauncherLogger.log(3, "args " + JSON.stringify(aMeekClientArgs));
TorLauncherLogger.log(3, "env additions " + JSON.stringify(envAdditions)); TorLauncherLogger.log(3, "env additions " + JSON.stringify(envAdditions));
TorLauncherLogger.log(3, "per-connection args \"" +
this.mMeekClientEscapedArgs + "\"");
let opts = { command: meekClientPath, let opts = { command: meekClientPath,
arguments: args, arguments: aMeekClientArgs,
workdir: workDir.path, workdir: workDir.path,
environmentAppend: true, environmentAppend: true,
environment: envAdditions, environment: envAdditions,
...@@ -271,6 +281,21 @@ _MoatRequestor.prototype = ...@@ -271,6 +281,21 @@ _MoatRequestor.prototype =
}); });
}, // _startMeekClient }, // _startMeekClient
// Escape aValue per section 3.5 of the PT specification:
// First the "<Key>=<Value>" formatted arguments MUST be escaped,
// such that all backslash, equal sign, and semicolon characters
// are escaped with a backslash.
_escapeArgValue: function(aValue)
{
if (!aValue)
return "";
let rv = aValue.replace(/\\/g, "\\\\");
rv = rv.replace(/=/g, "\\=");
rv = rv.replace(/;/g, "\\;");
return rv;
},
// Returns a promise that is resolved when the PT handshake finishes. // Returns a promise that is resolved when the PT handshake finishes.
_meekClientHandshake: function(aMeekClientProc) _meekClientHandshake: function(aMeekClientProc)
{ {
...@@ -389,7 +414,7 @@ _MoatRequestor.prototype = ...@@ -389,7 +414,7 @@ _MoatRequestor.prototype =
{ {
errMsg = "Invalid CMETHOD response (too few parameters)."; errMsg = "Invalid CMETHOD response (too few parameters).";
} }
else if (tokens[1] != this.kTransport) else if (tokens[1] != this.mMeekTransport)
{ {
errMsg = "Unexpected transport " + tokens[1] errMsg = "Unexpected transport " + tokens[1]
+ " in CMETHOD response."; + " in CMETHOD response.";
...@@ -399,11 +424,11 @@ _MoatRequestor.prototype = ...@@ -399,11 +424,11 @@ _MoatRequestor.prototype =
let proxyType = tokens[2]; let proxyType = tokens[2];
if (proxyType == "socks5") if (proxyType == "socks5")
{ {
this.mMeekClientProxyType = "socks"; this.mMeekClientProxyType = this.kMozProxyTypeSocks5;
} }
else if ((proxyType == "socks4a") || (proxyType == "socks4")) else if ((proxyType == "socks4a") || (proxyType == "socks4"))
{ {
this.mMeekClientProxyType = "socks4"; this.mMeekClientProxyType = this.kMozProxyTypeSocks4;
} }
else else
{ {
...@@ -466,12 +491,49 @@ _MoatRequestor.prototype = ...@@ -466,12 +491,49 @@ _MoatRequestor.prototype =
// Based on meek/firefox/components/main.js // Based on meek/firefox/components/main.js
_sendMoatRequest: function(aRequestObj, aIsCheck) _sendMoatRequest: function(aRequestObj, aIsCheck)
{ {
// Include arguments per section 3.5 of the PT specification:
// Lastly the arguments are transmitted when making the outgoing
// connection using the authentication mechanism specific to the
// SOCKS protocol version.
//
// - In the case of SOCKS 4, the concatenated argument list is
// transmitted in the "USERID" field of the "CONNECT" request.
//
// - In the case of SOCKS 5, the parent process must negotiate
// "Username/Password" authentication [RFC1929], and transmit
// the arguments encoded in the "UNAME" and "PASSWD" fields.
//
// If the encoded argument list is less than 255 bytes in
// length, the "PLEN" field must be set to "1" and the "PASSWD"
// field must contain a single NUL character.
let userName = "";
let password = undefined;
if (this.mMeekClientProxyType == this.kMozProxyTypeSocks4)
{
userName = this.mMeekClientEscapedArgs;
}
else
{
if (this.mMeekClientEscapedArgs.length <= 255)
{
userName = this.mMeekClientEscapedArgs;
password = "\x00";
}
else
{
userName = this.mMeekClientEscapedArgs.substring(0, 255);
password = this.mMeekClientEscapedArgs.substring(255);
}
}
let proxyPS = Cc["@mozilla.org/network/protocol-proxy-service;1"] let proxyPS = Cc["@mozilla.org/network/protocol-proxy-service;1"]
.getService(Ci.nsIProtocolProxyService); .getService(Ci.nsIProtocolProxyService);
let flags = Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST; let flags = Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST;
let noTimeout = 0xFFFFFFFF; // UINT32_MAX let noTimeout = 0xFFFFFFFF; // UINT32_MAX
let proxyInfo = proxyPS.newProxyInfo(this.mMeekClientProxyType, let proxyInfo = proxyPS.newProxyInfoWithAuth(this.mMeekClientProxyType,
this.mMeekClientIP, this.mMeekClientPort, this.mMeekClientIP, this.mMeekClientPort,
userName, password,
flags, noTimeout, undefined); flags, noTimeout, undefined);
let uriStr = TorLauncherUtil.getCharPref(this.kPrefMoatService); let uriStr = TorLauncherUtil.getCharPref(this.kPrefMoatService);
if (!uriStr) if (!uriStr)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment