Pier Angelo Vendrame pushed to branch tor-browser-128.4.0esr-14.5-1 at The Tor Project / Applications / Tor Browser

Commits:

6 changed files:

Changes:

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
    ... ... @@ -220,12 +220,18 @@ public class TorIntegrationAndroid implements BundleEventListener {
    220 220
         if (previousProcess != null) {
    
    221 221
           Log.w(TAG, "We still have a running process: " + previousProcess.getHandle());
    
    222 222
         }
    
    223
    -    mTorProcess = new TorProcess(handle);
    
    223
    +
    
    224
    +    boolean tcpSocks = message.getBoolean("tcpSocks", false);
    
    225
    +    mTorProcess = new TorProcess(handle, tcpSocks);
    
    224 226
     
    
    225 227
         GeckoBundle bundle = new GeckoBundle(3);
    
    226 228
         bundle.putString("controlPortPath", mIpcDirectory + CONTROL_PORT_FILE);
    
    227
    -    bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
    
    228 229
         bundle.putString("cookieFilePath", mIpcDirectory + COOKIE_AUTH_FILE);
    
    230
    +    if (tcpSocks) {
    
    231
    +      bundle.putInt("socksPort", 0);
    
    232
    +    } else {
    
    233
    +      bundle.putString("socksPath", mIpcDirectory + SOCKS_FILE);
    
    234
    +    }
    
    229 235
         callback.sendSuccess(bundle);
    
    230 236
       }
    
    231 237
     
    
    ... ... @@ -254,10 +260,12 @@ public class TorIntegrationAndroid implements BundleEventListener {
    254 260
         private static final String EVENT_TOR_START_FAILED = "GeckoView:Tor:TorStartFailed";
    
    255 261
         private static final String EVENT_TOR_EXITED = "GeckoView:Tor:TorExited";
    
    256 262
         private final String mHandle;
    
    263
    +    private final boolean mTcpSocks;
    
    257 264
         private Process mProcess = null;
    
    258 265
     
    
    259
    -    TorProcess(String handle) {
    
    266
    +    TorProcess(String handle, boolean tcpSocks) {
    
    260 267
           mHandle = handle;
    
    268
    +      mTcpSocks = tcpSocks;
    
    261 269
           setName("tor-process-" + handle);
    
    262 270
           start();
    
    263 271
         }
    
    ... ... @@ -273,8 +281,13 @@ public class TorIntegrationAndroid implements BundleEventListener {
    273 281
           args.add("1");
    
    274 282
           args.add("+__ControlPort");
    
    275 283
           args.add("unix:" + ipcDir + CONTROL_PORT_FILE);
    
    284
    +      final String socksFlags = " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth";
    
    276 285
           args.add("+__SocksPort");
    
    277
    -      args.add("unix:" + ipcDir + SOCKS_FILE + " IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth");
    
    286
    +      args.add("unix:" + ipcDir + SOCKS_FILE + socksFlags);
    
    287
    +      if (mTcpSocks) {
    
    288
    +        args.add("+__SocksPort");
    
    289
    +        args.add("auto " + socksFlags);
    
    290
    +      }
    
    278 291
           args.add("CookieAuthentication");
    
    279 292
           args.add("1");
    
    280 293
           args.add("CookieAuthFile");
    

  • toolkit/components/tor-launcher/TorControlPort.sys.mjs
    ... ... @@ -298,6 +298,12 @@ class AsyncSocket {
    298 298
      * @property {string} [options] Optional options passed to the binary (only for
    
    299 299
      * exec)
    
    300 300
      */
    
    301
    +/**
    
    302
    + * @typedef {object} SocksListener
    
    303
    + * @property {string} [ipcPath] path to a Unix socket to use for an IPC proxy
    
    304
    + * @property {string} [host] The host to connect for a TCP proxy
    
    305
    + * @property {number} [port] The port number to use for a TCP proxy
    
    306
    + */
    
    301 307
     /**
    
    302 308
      * @typedef {object} OnionAuthKeyInfo
    
    303 309
      * @property {string} address The address of the onion service
    
    ... ... @@ -746,6 +752,32 @@ export class TorController {
    746 752
         return this.#getInfo(`ip-to-country/${ip}`);
    
    747 753
       }
    
    748 754
     
    
    755
    +  /**
    
    756
    +   * Ask tor which ports it is listening to for SOCKS connections.
    
    757
    +   *
    
    758
    +   * @returns {Promise<SocksListener[]>} An array of addresses. It might be
    
    759
    +   * empty (e.g., when DisableNetwork is set)
    
    760
    +   */
    
    761
    +  async getSocksListeners() {
    
    762
    +    const listeners = await this.#getInfo("net/listeners/socks");
    
    763
    +    return Array.from(
    
    764
    +      listeners.matchAll(/\s*("(?:[^"\\]|\\.)*"|\S+)\s*/g),
    
    765
    +      m => {
    
    766
    +        const listener = TorParsers.unescapeString(m[1]);
    
    767
    +        if (listener.startsWith("unix:/")) {
    
    768
    +          return { ipcPath: listener.substring(5) };
    
    769
    +        }
    
    770
    +        const idx = listener.lastIndexOf(":");
    
    771
    +        const host = listener.substring(0, idx);
    
    772
    +        const port = parseInt(listener.substring(idx + 1));
    
    773
    +        if (isNaN(port) || port <= 0 || port > 65535 || !host || !port) {
    
    774
    +          throw new Error(`Could not parse the SOCKS listener ${listener}.`);
    
    775
    +        }
    
    776
    +        return { host, port };
    
    777
    +      }
    
    778
    +    );
    
    779
    +  }
    
    780
    +
    
    749 781
       /**
    
    750 782
        * Ask Tor a list of circuits.
    
    751 783
        *
    

  • toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs
    ... ... @@ -449,7 +449,7 @@ export const TorLauncherUtil = Object.freeze({
    449 449
        *   If network.proxy.socks contains a file: URL, a default value of
    
    450 450
        *     "127.0.0.1" is used instead.
    
    451 451
        *   If the network.proxy.socks_port value is not valid (outside the
    
    452
    -   *     (0; 65535] range), a default value of 9150 is used instead.
    
    452
    +   *     (0; 65535] range), we will let the tor daemon choose a port.
    
    453 453
        *
    
    454 454
        * The SOCKS configuration will not influence the launch of a tor daemon and
    
    455 455
        * the configuration of the control port in any way.
    
    ... ... @@ -458,13 +458,6 @@ export const TorLauncherUtil = Object.freeze({
    458 458
        * This also applies to TOR_TRANSPROXY (at least for now): tor will be
    
    459 459
        * launched with its defaults.
    
    460 460
        *
    
    461
    -   * TODO: add a preference to ignore the current configuration, and let tor
    
    462
    -   * listen on any free port. Then, the browser will prompt the daemon the port
    
    463
    -   * to use through the control port (even though this is quite dangerous at the
    
    464
    -   * moment, because with network disabled tor will disable also the SOCKS
    
    465
    -   * listeners, so it means that we will have to check it every time we change
    
    466
    -   * the network status).
    
    467
    -   *
    
    468 461
        * @returns {SocksSettings}
    
    469 462
        */
    
    470 463
       getPreferredSocksConfiguration() {
    
    ... ... @@ -491,7 +484,7 @@ export const TorLauncherUtil = Object.freeze({
    491 484
           }
    
    492 485
           if (Services.env.exists("TOR_SOCKS_PORT")) {
    
    493 486
             const port = parseInt(Services.env.get("TOR_SOCKS_PORT"), 10);
    
    494
    -        if (Number.isInteger(port) && port > 0 && port <= 65535) {
    
    487
    +        if (Number.isInteger(port) && port >= 0 && port <= 65535) {
    
    495 488
               socksPortInfo.port = port;
    
    496 489
               useIPC = false;
    
    497 490
             }
    
    ... ... @@ -522,20 +515,32 @@ export const TorLauncherUtil = Object.freeze({
    522 515
             socksPortInfo.host = socksAddrHasHost ? socksAddr : "127.0.0.1";
    
    523 516
           }
    
    524 517
     
    
    525
    -      if (!socksPortInfo.port) {
    
    518
    +      if (socksPortInfo.port === undefined) {
    
    526 519
             let socksPort = Services.prefs.getIntPref(
    
    527 520
               "network.proxy.socks_port",
    
    528
    -          0
    
    521
    +          9150
    
    529 522
             );
    
    530
    -        // This pref is set as 0 by default in Firefox, use 9150 if we get 0.
    
    531
    -        socksPortInfo.port =
    
    532
    -          socksPort > 0 && socksPort <= 65535 ? socksPort : 9150;
    
    523
    +        if (socksPort > 0 && socksPort <= 65535) {
    
    524
    +          socksPortInfo.port = socksPort;
    
    525
    +        } else {
    
    526
    +          // Automatic port number, we have to query tor over the control port
    
    527
    +          // every time we change DisableNetwork.
    
    528
    +          socksPortInfo.port = 0;
    
    529
    +        }
    
    533 530
           }
    
    534 531
         }
    
    535 532
     
    
    536 533
         return socksPortInfo;
    
    537 534
       },
    
    538 535
     
    
    536
    +  /**
    
    537
    +   * Apply our proxy configuration to the browser.
    
    538
    +   *
    
    539
    +   * Currently, we try to configure the Tor daemon to match the browser's
    
    540
    +   * configuration, but this might change in the future (tor-browser#42062).
    
    541
    +   *
    
    542
    +   * @param {SocksSettings} socksPortInfo The configuration to apply
    
    543
    +   */
    
    539 544
       setProxyConfiguration(socksPortInfo) {
    
    540 545
         if (socksPortInfo.transproxy) {
    
    541 546
           Services.prefs.setBoolPref("network.proxy.socks_remote_dns", false);
    
    ... ... @@ -556,7 +561,7 @@ export const TorLauncherUtil = Object.freeze({
    556 561
           if (socksPortInfo.host) {
    
    557 562
             Services.prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
    
    558 563
           }
    
    559
    -      if (socksPortInfo.port) {
    
    564
    +      if (socksPortInfo.port > 0 && socksPortInfo.port <= 65535) {
    
    560 565
             Services.prefs.setIntPref(
    
    561 566
               "network.proxy.socks_port",
    
    562 567
               socksPortInfo.port
    

  • toolkit/components/tor-launcher/TorProcess.sys.mjs
    ... ... @@ -53,13 +53,16 @@ export class TorProcess {
    53 53
           throw new Error("Unauthenticated control port is not supported");
    
    54 54
         }
    
    55 55
     
    
    56
    -    const checkPort = port =>
    
    56
    +    const checkPort = (port, allowZero) =>
    
    57 57
           port === undefined ||
    
    58
    -      (Number.isInteger(port) && port > 0 && port < 65535);
    
    59
    -    if (!checkPort(controlSettings?.port)) {
    
    58
    +      (Number.isInteger(port) &&
    
    59
    +        port < 65535 &&
    
    60
    +        (port > 0 || (allowZero && port === 0)));
    
    61
    +    if (!checkPort(controlSettings?.port, false)) {
    
    60 62
           throw new Error("Invalid control port");
    
    61 63
         }
    
    62
    -    if (!checkPort(socksSettings.port)) {
    
    64
    +    // Port 0 for SOCKS means automatic port.
    
    65
    +    if (!checkPort(socksSettings.port, true)) {
    
    63 66
           throw new Error("Invalid port specified for the SOCKS port");
    
    64 67
         }
    
    65 68
     
    
    ... ... @@ -296,10 +299,12 @@ export class TorProcess {
    296 299
         let socksPortArg;
    
    297 300
         if (this.#socksSettings.ipcFile) {
    
    298 301
           socksPortArg = this.#socksSettings.ipcFile;
    
    299
    -    } else if (this.#socksSettings.port != 0) {
    
    302
    +    } else if (this.#socksSettings.port > 0) {
    
    300 303
           socksPortArg = this.#socksSettings.host
    
    301 304
             ? `${this.#socksSettings.host}:${this.#socksSettings.port}`
    
    302 305
             : this.#socksSettings.port.toString();
    
    306
    +    } else {
    
    307
    +      socksPortArg = "auto";
    
    303 308
         }
    
    304 309
         if (socksPortArg) {
    
    305 310
           const socksPortFlags = Services.prefs.getCharPref(
    

  • toolkit/components/tor-launcher/TorProcessAndroid.sys.mjs
    ... ... @@ -77,6 +77,10 @@ export class TorProcessAndroid {
    77 77
           config = await lazy.EventDispatcher.instance.sendRequestForResult({
    
    78 78
             type: TorOutgoingEvents.start,
    
    79 79
             handle: this.#processHandle,
    
    80
    +        tcpSocks: Services.prefs.getBoolPref(
    
    81
    +          "extensions.torlauncher.socks_port_use_tcp",
    
    82
    +          false
    
    83
    +        ),
    
    80 84
           });
    
    81 85
           logger.debug("Sent the start event.");
    
    82 86
         } catch (e) {
    

  • toolkit/components/tor-launcher/TorProvider.sys.mjs
    ... ... @@ -27,23 +27,23 @@ const logger = console.createInstance({
    27 27
      * @typedef {object} ControlPortSettings An object with the settings to use for
    
    28 28
      * the control port. All the entries are optional, but an authentication
    
    29 29
      * mechanism and a communication method must be specified.
    
    30
    - * @property {Uint8Array=} password The clear text password as an array of
    
    30
    + * @property {Uint8Array} [password] The clear text password as an array of
    
    31 31
      * bytes. It must always be defined, unless cookieFilePath is
    
    32
    - * @property {string=} cookieFilePath The path to the cookie file to use for
    
    32
    + * @property {string} [cookieFilePath] The path to the cookie file to use for
    
    33 33
      * authentication
    
    34
    - * @property {nsIFile=} ipcFile The nsIFile object with the path to a Unix
    
    34
    + * @property {nsIFile} [ipcFile] The nsIFile object with the path to a Unix
    
    35 35
      * socket to use for control socket
    
    36
    - * @property {string=} host The host to connect for a TCP control port
    
    37
    - * @property {number=} port The port number to use for a TCP control port
    
    36
    + * @property {string} [host] The host to connect for a TCP control port
    
    37
    + * @property {number} [port] The port number to use for a TCP control port
    
    38 38
      */
    
    39 39
     /**
    
    40 40
      * @typedef {object} SocksSettings An object that includes the proxy settings to
    
    41 41
      * be configured in the browser.
    
    42
    - * @property {boolean=} transproxy If true, no proxy is configured
    
    43
    - * @property {nsIFile=} ipcFile The nsIFile object with the path to a Unix
    
    42
    + * @property {boolean} [transproxy] If true, no proxy is configured
    
    43
    + * @property {nsIFile} [ipcFile] The nsIFile object with the path to a Unix
    
    44 44
      * socket to use for an IPC proxy
    
    45
    - * @property {string=} host The host to connect for a TCP proxy
    
    46
    - * @property {number=} port The port number to use for a TCP proxy
    
    45
    + * @property {string} [host] The host to connect for a TCP proxy
    
    46
    + * @property {number} [port] The port number to use for a TCP proxy
    
    47 47
      */
    
    48 48
     /**
    
    49 49
      * @typedef {object} LogEntry An object with a log message
    
    ... ... @@ -345,6 +345,25 @@ export class TorProvider {
    345 345
        */
    
    346 346
       async connect() {
    
    347 347
         await this.#controller.setNetworkEnabled(true);
    
    348
    +    if (this.#socksSettings.port === 0) {
    
    349
    +      // Enablign/disabling network resets also the SOCKS listener.
    
    350
    +      // So, every time we do it, we need to update the browser's configuration
    
    351
    +      // to use the updated port.
    
    352
    +      const settings = structuredClone(this.#socksSettings);
    
    353
    +      for (const listener of await this.#controller.getSocksListeners()) {
    
    354
    +        // When set to automatic port, ignore any IPC listener, as the intention
    
    355
    +        // was to use TCP.
    
    356
    +        if (listener.ipcPath) {
    
    357
    +          continue;
    
    358
    +        }
    
    359
    +        // The tor daemon can have any number of SOCKS listeners (see SocksPort
    
    360
    +        // in man 1 tor). We take for granted that any TCP one will work for us.
    
    361
    +        settings.host = listener.host;
    
    362
    +        settings.port = listener.port;
    
    363
    +        break;
    
    364
    +      }
    
    365
    +      TorLauncherUtil.setProxyConfiguration(settings);
    
    366
    +    }
    
    348 367
         this.#lastWarning = {};
    
    349 368
         this.retrieveBootstrapStatus();
    
    350 369
       }
    
    ... ... @@ -569,14 +588,24 @@ export class TorProvider {
    569 588
         logger.debug("Trying to start the tor process.");
    
    570 589
         const res = await this.#torProcess.start();
    
    571 590
         if (TorLauncherUtil.isAndroid) {
    
    591
    +      logger.debug("Configuration from TorProcessAndriod", res);
    
    572 592
           this.#controlPortSettings = {
    
    573 593
             ipcFile: new lazy.FileUtils.File(res.controlPortPath),
    
    574 594
             cookieFilePath: res.cookieFilePath,
    
    575 595
           };
    
    576 596
           this.#socksSettings = {
    
    577 597
             transproxy: false,
    
    578
    -        ipcFile: new lazy.FileUtils.File(res.socksPath),
    
    579 598
           };
    
    599
    +      if (res.socksPath) {
    
    600
    +        this.#socksSettings.ipcFile = new lazy.FileUtils.File(res.socksPath);
    
    601
    +      } else if (res.socksPort !== undefined) {
    
    602
    +        this.#socksSettings.host = res.socksHost ?? "127.0.0.1";
    
    603
    +        this.#socksSettings.port = res.socksPort;
    
    604
    +      } else {
    
    605
    +        throw new Error(
    
    606
    +          "TorProcessAndroid did not return a valid SOCKS configuration."
    
    607
    +        );
    
    608
    +      }
    
    580 609
         }
    
    581 610
         logger.info("Started a tor process");
    
    582 611
       }