[tor-commits] [tor-launcher/master] Bug 29627: Moat: add support for obfsproxy's meek_lite

gk at torproject.org gk at torproject.org
Wed May 8 21:12:09 UTC 2019


commit 99035eb7b6069c60fe4f97291abbea5af4fee886
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Fri Mar 1 10:09:16 2019 -0500

    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.
---
 src/chrome/content/network-settings.js | 18 ++++---
 src/modules/tl-bridgedb.jsm            | 96 ++++++++++++++++++++++++++++------
 2 files changed, 91 insertions(+), 23 deletions(-)

diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js
index 1599c28..fad89e5 100644
--- a/src/chrome/content/network-settings.js
+++ b/src/chrome/content/network-settings.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2019, The Tor Project, Inc.
 // See LICENSE for licensing information.
 //
 // vim: set sw=2 sts=2 ts=8 et syntax=javascript:
@@ -542,18 +542,22 @@ function onOpenBridgeDBRequestPrompt()
     return;
 
   let meekClientPath;
+  let meekTransport;  // We support both "meek" and "meek_lite".
   let meekClientArgs;
   reply.lineArray.forEach(aLine =>
   {
     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];
       meekClientArgs = tokens.slice(3);
     }
   });
 
-  if (!meekClientPath)
+  if (!meekTransport)
   {
     reportMoatError(TorLauncherUtil.getLocalizedString("no_meek"));
     return;
@@ -578,7 +582,8 @@ function onOpenBridgeDBRequestPrompt()
     resetBridgeDBRequestPrompt();
     setBridgeDBRequestState("fetchingCaptcha");
     overlay.hidden = false;
-    requestMoatCaptcha(proxySettings, meekClientPath, meekClientArgs);
+    requestMoatCaptcha(proxySettings, meekTransport, meekClientPath,
+                       meekClientArgs);
   }
 }
 
@@ -2508,7 +2513,8 @@ function createColonStr(aStr1, aStr2)
 }
 
 
-function requestMoatCaptcha(aProxySettings, aMeekClientPath, aMeekClientArgs)
+function requestMoatCaptcha(aProxySettings, aMeekTransport,
+                            aMeekClientPath, aMeekClientArgs)
 {
   function cleanup(aMoatRequestor, aErr)
   {
@@ -2543,7 +2549,7 @@ function requestMoatCaptcha(aProxySettings, aMeekClientPath, aMeekClientArgs)
   };
   addBridgeDBRequestEventListener(kCaptchaCancelEventType, cancelListener);
 
-  moatRequestor.init(proxyURLFromSettings(aProxySettings),
+  moatRequestor.init(proxyURLFromSettings(aProxySettings), aMeekTransport,
                      aMeekClientPath, aMeekClientArgs)
     .then(()=>
     {
diff --git a/src/modules/tl-bridgedb.jsm b/src/modules/tl-bridgedb.jsm
index 8b7a1d6..bc9b300 100644
--- a/src/modules/tl-bridgedb.jsm
+++ b/src/modules/tl-bridgedb.jsm
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, The Tor Project, Inc.
+// Copyright (c) 2019, The Tor Project, Inc.
 // See LICENSE for licensing information.
 //
 // vim: set sw=2 sts=2 ts=8 et syntax=javascript:
@@ -61,7 +61,6 @@ function _MoatRequestor()
 _MoatRequestor.prototype =
 {
   kMaxResponseLength: 1024 * 400,
-  kTransport: "meek",
   kMoatContentType: "application/vnd.api+json",
   kMoatVersion: "0.1.0",
   kPrefBridgeDBFront: "extensions.torlauncher.bridgedb_front",
@@ -74,6 +73,9 @@ _MoatRequestor.prototype =
   kMoatCheckRequestType: "moat-solution",
   kMoatCheckResponseType: "moat-bridges",
 
+  kMozProxyTypeSocks4: "socks4",
+  kMozProxyTypeSocks5: "socks",
+
   kStateIdle: 0,
   kStateWaitingForVersion: 1,
   kStateWaitingForProxyDone: 2,
@@ -83,19 +85,22 @@ _MoatRequestor.prototype =
 
   mState: this.kStateIdle,
 
+  mMeekTransport: undefined,
   mLocalProxyURL: undefined,
   mMeekFront: undefined,  // Frontend server, if we are using one.
+  mMeekClientEscapedArgs: undefined,
   mMeekClientProcess: undefined,
   mMeekClientStdoutBuffer: undefined,
-  mMeekClientProxyType: undefined,  // contains Mozilla names such as socks4
+  mMeekClientProxyType: undefined,  // kMozProxyTypeSocks4 or kMozProxyTypeSocks5
   mMeekClientIP: undefined,
   mMeekClientPort: undefined,
   mMoatResponseListener: undefined,
   mUserCanceled: false,
 
   // Returns a promise.
-  init: function(aProxyURL, aMeekClientPath, aMeekClientArgs)
+  init: function(aProxyURL, aMeekTransport, aMeekClientPath, aMeekClientArgs)
   {
+    this.mMeekTransport = aMeekTransport;
     this.mLocalProxyURL = aProxyURL;
     return this._startMeekClient(aMeekClientPath, aMeekClientArgs);
   },
@@ -208,21 +213,24 @@ _MoatRequestor.prototype =
       meekClientPath = f.path;
     }
 
-    // Construct the args array.
-    let args = aMeekClientArgs.slice(); // make a copy
+    // Construct the per-connection arguments.
+    this.mMeekClientEscapedArgs = "";
     let meekReflector = TorLauncherUtil.getCharPref(this.kPrefBridgeDBReflector);
     if (meekReflector)
     {
-      args.push("-url");
-      args.push(meekReflector);
+      this.mMeekClientEscapedArgs += "url=";
+      this.mMeekClientEscapedArgs += this._escapeArgValue(meekReflector);
     }
     this.mMeekFront = TorLauncherUtil.getCharPref(this.kPrefBridgeDBFront);
     if (this.mMeekFront)
     {
-      args.push("-front");
-      args.push(this.mMeekFront);
+      if (this.mMeekClientEscapedArgs.length > 0)
+        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 meekHelperProfileDir = TorLauncherUtil.getTorFile("pt-profiles-dir",
                                                           true);
@@ -238,17 +246,19 @@ _MoatRequestor.prototype =
     let envAdditions = { TOR_PT_MANAGED_TRANSPORT_VER: "1",
                          TOR_PT_STATE_LOCATION: ptStateDir.path,
                          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 };
     if (this.mLocalProxyURL)
       envAdditions.TOR_PT_PROXY = this.mLocalProxyURL;
 
     TorLauncherLogger.log(3, "starting " + meekClientPath + " in "
                           + 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, "per-connection args \"" +
+                             this.mMeekClientEscapedArgs + "\"");
     let opts = { command: meekClientPath,
-                 arguments: args,
+                 arguments: aMeekClientArgs,
                  workdir: workDir.path,
                  environmentAppend: true,
                  environment: envAdditions,
@@ -271,6 +281,21 @@ _MoatRequestor.prototype =
       });
   }, // _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.
   _meekClientHandshake: function(aMeekClientProc)
   {
@@ -389,7 +414,7 @@ _MoatRequestor.prototype =
             {
               errMsg = "Invalid CMETHOD response (too few parameters).";
             }
-            else if (tokens[1] != this.kTransport)
+            else if (tokens[1] != this.mMeekTransport)
             {
               errMsg = "Unexpected transport " + tokens[1]
                        + " in CMETHOD response.";
@@ -399,11 +424,11 @@ _MoatRequestor.prototype =
               let proxyType = tokens[2];
               if (proxyType == "socks5")
               {
-                this.mMeekClientProxyType = "socks";
+                this.mMeekClientProxyType = this.kMozProxyTypeSocks5;
               }
               else if ((proxyType == "socks4a") || (proxyType == "socks4"))
               {
-                this.mMeekClientProxyType = "socks4";
+                this.mMeekClientProxyType = this.kMozProxyTypeSocks4;
               }
               else
               {
@@ -466,12 +491,49 @@ _MoatRequestor.prototype =
   // Based on meek/firefox/components/main.js
   _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"]
                   .getService(Ci.nsIProtocolProxyService);
     let flags = Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST;
     let noTimeout = 0xFFFFFFFF; // UINT32_MAX
-    let proxyInfo = proxyPS.newProxyInfo(this.mMeekClientProxyType,
+    let proxyInfo = proxyPS.newProxyInfoWithAuth(this.mMeekClientProxyType,
                               this.mMeekClientIP, this.mMeekClientPort,
+                              userName, password,
                               flags, noTimeout, undefined);
     let uriStr = TorLauncherUtil.getCharPref(this.kPrefMoatService);
     if (!uriStr)





More information about the tor-commits mailing list