Pārlūkot izejas kodu

Improve TURN pairing (#910)

Add random prefixes to TURN servers and disable IPv6 TURN relaying

Previously, all TURN server IPs had been used which was unnecessary.
Furthermore, IPv6 relaying is not deemed necessary as IPv6 should not
need any relaying and clients will pretty much always have a valid
IPv4 address anyway.

Replaceable prefixes have been introduced in the config file.
Lennart Grahl 5 gadi atpakaļ
vecāks
revīzija
1b1705c9d2
5 mainītis faili ar 24 papildinājumiem un 50 dzēšanām
  1. 5 2
      README.md
  2. 4 6
      src/config.ts
  3. 1 1
      src/services/peerconnection.ts
  4. 13 38
      src/services/webclient.ts
  5. 1 3
      src/threema.d.ts

+ 5 - 2
README.md

@@ -125,8 +125,9 @@ The configuration of Threema Web can be tweaked in `src/config.ts`:
 **SaltyRTC**
 
 - `SALTYRTC_HOST`: Set this to the hostname of the SaltyRTC server that you
-  want to use. If set to `null`, the hostname will be constructed based on the
-  `SALTYRTC_HOST_PREFIX` and the `SALTYRTC_HOST_SUFFIX` values.
+  want to use. If supplied, the substring `{prefix}` will be replaced by the
+  first byte of the initiator's public key, represented as a lowercase
+  hexadecimal value.
 - `SALTYRTC_PORT`: The port of the SaltyRTC server to be used.
 - `SALTYRTC_SERVER_KEY`: The public permanent key of the SaltyRTC server. Set
   this value to `null` if your server does not provide a public permanent key,
@@ -135,6 +136,8 @@ The configuration of Threema Web can be tweaked in `src/config.ts`:
 **ICE**
 
 - `ICE_SERVERS`: Configuration object for the WebRTC STUN and ICE servers.
+  Each URL may contain the substring `{prefix}`, which will be replaced by a
+  random byte represented as a lowercase hexadecimal value. 
 
 **Push**
 

+ 4 - 6
src/config.ts

@@ -19,18 +19,16 @@ export default {
     GIT_BRANCH: 'master',
 
     // SaltyRTC
-    SALTYRTC_HOST: null,
-    SALTYRTC_HOST_PREFIX: 'saltyrtc-',
-    SALTYRTC_HOST_SUFFIX: '.threema.ch',
+    SALTYRTC_HOST: 'saltyrtc-{prefix}.threema.ch',
     SALTYRTC_PORT: 443,
     SALTYRTC_SERVER_KEY: 'b1337fc8402f7db8ea639e05ed05d65463e24809792f91eca29e88101b4a2171',
 
     // ICE
     ICE_SERVERS: [{
         urls: [
-            'turn:ds-turn.threema.ch:443?transport=udp',
-            'turn:ds-turn.threema.ch:443?transport=tcp',
-            'turns:ds-turn.threema.ch:443',
+            'turn:turn-{prefix}.threema.ch:443?transport=udp',
+            'turn:turn-{prefix}.threema.ch:443?transport=tcp',
+            'turns:turn-{prefix}.threema.ch:443',
         ],
         username: 'threema-angular',
         credential: 'Uv0LcCq3kyx6EiRwQW5jVigkhzbp70CjN2CJqzmRxG3UGIdJHSJV6tpo7Gj7YnGB',

+ 1 - 1
src/services/peerconnection.ts

@@ -62,7 +62,7 @@ export class PeerConnectionHelper {
     ) {
         this.log = logService.getLogger('PeerConnection', 'color: #fff; background-color: #3333ff');
         this.log.info('Initialize WebRTC PeerConnection');
-        this.log.debug('ICE servers used:', [].concat(...iceServers.map((c) => c.urls)));
+        this.log.debug('ICE servers used:', [].concat(...iceServers.map((server) => server.urls)));
         this.$q = $q;
         this.$rootScope = $rootScope;
         this.config = config;

+ 13 - 38
src/services/webclient.ts

@@ -23,11 +23,12 @@ import {StateService as UiStateService} from '@uirouter/angularjs';
 import {Logger} from 'ts-log';
 
 import * as msgpack from 'msgpack-lite';
+import * as nacl from 'tweetnacl';
 import {
     arraysAreEqual,
     base64ToU8a,
     bufferToUrl,
-    copyDeepOrReference,
+    copyDeepOrReference, copyShallow,
     hasFeature,
     hasValue,
     hexToU8a,
@@ -527,16 +528,8 @@ export class WebClientService {
             keyStore = new saltyrtcClient.KeyStore();
         }
 
-        // Determine SaltyRTC host
-        if (this.config.SALTYRTC_HOST !== null) {
-            // Static URL
-            this.saltyRtcHost = this.config.SALTYRTC_HOST;
-        } else {
-            // Construct URL using prefix and suffix
-            this.saltyRtcHost = this.config.SALTYRTC_HOST_PREFIX
-                + keyStore.publicKeyHex.substr(0, 2)
-                + this.config.SALTYRTC_HOST_SUFFIX;
-        }
+        // Determine SaltyRTC host, replace the inner prefix (if any)
+        this.saltyRtcHost = this.config.SALTYRTC_HOST.replace('{prefix}', keyStore.publicKeyHex.substr(0, 2));
 
         // Create SaltyRTC client
         let builder = new saltyrtcClient.SaltyRTCBuilder()
@@ -889,16 +882,20 @@ export class WebClientService {
         if (this.chosenTask === threema.ChosenTask.WebRTC) {
             const browser = this.browserService.getBrowser();
 
-            // Safari does not support our dual-stack TURN servers.
-            if (browser.isSafari(false)) {
-                this.skipIceDs();
-            }
+            // Determine ICE servers and replace random prefix (if any)
+            const prefix = u8aToHex(nacl.randomBytes(1));
+            const iceServers = this.config.ICE_SERVERS.map((server) => {
+                server = copyShallow(server) as RTCIceServer;
+                const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
+                server.urls = urls.map((url) => url.replace('{prefix}', prefix));
+                return server;
+            });
 
             // Create peer connection
             this.pcHelper = new PeerConnectionHelper(
                 this.$q, this.$rootScope,
                 this.config, this.logService, this.timeoutService,
-                task as saltyrtc.tasks.webrtc.WebRTCTask, this.config.ICE_SERVERS);
+                task as saltyrtc.tasks.webrtc.WebRTCTask, iceServers);
 
             // On state changes in the PeerConnectionHelper class, let state service know about it
             this.pcHelper.onConnectionStateChange = (state: threema.TaskConnectionState) => {
@@ -1436,28 +1433,6 @@ export class WebClientService {
         }
     }
 
-    /**
-     * Safari has issues with dual-stack TURN servers:
-     * https://bugs.webkit.org/show_bug.cgi?id=173307#c13
-     * As a workaround, replace ds-turn.threema.ch servers
-     * in the ICE_SERVERS configuration with turn.threema.ch.
-     */
-    public skipIceDs(): void {
-        this.arpLog.debug('Requested to replace DS servers in ICE configuration');
-        const allUrls = [].concat(...this.config.ICE_SERVERS.map((conf) => conf.urls));
-        if (allUrls.some((url) => url.includes('ds-turn.threema.ch'))) {
-            for (const server of this.config.ICE_SERVERS) {
-                // Replace dual stack entries
-                const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
-                server.urls = urls.map((url) => {
-                    return url.replace('ds-turn.threema.ch', 'turn.threema.ch');
-                });
-            }
-        } else {
-            this.arpLog.debug('No ds-turn ICE server present');
-        }
-    }
-
     /**
      * Mark a component as initialized
      */

+ 1 - 3
src/threema.d.ts

@@ -664,9 +664,7 @@ declare namespace threema {
         GIT_BRANCH: string;
 
         // SaltyRTC
-        SALTYRTC_HOST: string | null;
-        SALTYRTC_HOST_PREFIX: string | null;
-        SALTYRTC_HOST_SUFFIX: string | null;
+        SALTYRTC_HOST: string;
         SALTYRTC_PORT: number;
         SALTYRTC_SERVER_KEY: string | null;