← Tutti gli episodi

Stagione 94  /  Episodio 4

Il traghetto

Quando il ponte diretto è impossibile serve TURN: come funziona l'allocazione di un indirizzo di inoltro, quante chiamate ne hanno bisogno, come configurare coturn, le credenziali temporanee e le regole per non trasformare il traghetto in una porta aperta sulla vostra rete.

Note dell'episodio

Bentornati sulle due rive. Nell'episodio scorso abbiamo visto come ICE cerca un guado tra due città murate. Oggi parliamo di quello che succede quando il guado non c'è.

A volte le mura sono troppo alte. Il guardiano è di quelli ostili, che cambia porta per ogni destinazione. Oppure il firewall dell'azienda blocca tutto il traffico UDP e lascia uscire solo il web, sulla porta 443. In questi casi nessun pacchetto di prova arriva dall'altra parte, e il ponte diretto è impossibile.

Allora serve un traghetto: una barca vera, che sta in mezzo al fiume, raccoglie il carico da una riva e lo porta all'altra. Nel mondo WebRTC si chiama TURN.

TURN significa attraversamento con l'uso di inoltri attorno al NAT, ed è descritto nella RFC 8656. È un'estensione di STUN: stesso formato dei messaggi, stessa porta predefinita, la 3478.

Il funzionamento è questo. Il browser si collega al server TURN e chiede un'allocazione: per favore, riservami un indirizzo pubblico sul tuo server. Il server gliene assegna uno, una porta sul proprio indirizzo pubblico. Quell'indirizzo diventa un nuovo candidato, di tipo relay, e viene mandato all'altra riva come tutti gli altri.

Da quel momento il traghetto fa la spola. Tutto quello che arriva al server sull'indirizzo di inoltro viene inoltrato al browser, e tutto quello che il browser manda al server viene inoltrato all'altra riva. Il browser deve dire esplicitamente al server con quali indirizzi può parlare, creando dei permessi: il traghetto non carica chiunque si presenti al molo.

La cosa importante da capire è che il traghetto non si sostituisce a ICE. È solo un candidato in più, quello con la priorità più bassa. Se esiste un guado diretto, ICE lo preferisce. Il traghetto entra in gioco solo quando serve.

La domanda che tutti si fanno è: quanto spesso serve davvero il traghetto?

Le stime che circolano, pubblicate da chi gestisce servizi di videochiamata, parlano di solito di una quota tra il dieci e il venti per cento delle connessioni, con grandi differenze a seconda del pubblico. Un'applicazione usata da casa, con i router domestici, ne ha bisogno raramente. Un'applicazione usata nelle aziende, negli ospedali, nelle scuole, con reti molto chiuse, ne ha bisogno molto più spesso.

Ma il punto vero è un altro. Senza traghetto, quella minoranza di utenti non si collega affatto. E di solito è la minoranza più importante: il cliente aziendale, la sala riunioni dell'ufficio. Un'applicazione WebRTC in produzione senza TURN non è un'applicazione leggermente peggiore. È un'applicazione che per qualcuno non funziona.

Il traghetto può attraccare in modi diversi.

Il modo normale è UDP sulla porta 3478. È il più efficiente. Ma alcune reti bloccano UDP, e allora il browser può collegarsi al traghetto con TCP, sulla stessa porta.

Le reti più chiuse lasciano passare solo il traffico cifrato verso la porta 443, quella del web. Per loro esiste TURN su TLS: l'indirizzo comincia con turns, con la esse finale, e il traffico verso il traghetto è indistinguibile, per il firewall, da una normale navigazione in HTTPS. La porta standard per questa modalità è la 5349, ma in pratica molti la mettono sulla 443, proprio per passare da tutti i firewall.

Attenzione: TCP e TLS servono solo tra il browser e il traghetto. Dal traghetto all'altra riva il viaggio continua di solito su UDP. E il video sopra TCP soffre, perché TCP ritrasmette e aspetta, mentre il video preferirebbe perdere un pacchetto e andare avanti. È l'ultima risorsa dell'ultima risorsa, ma meglio di niente.

Il server TURN open source più usato si chiama coturn. Si installa dai pacchetti di qualunque distribuzione, o con un'immagine Docker ufficiale.

La configurazione sta in un file solo, turnserver punto conf, e le voci essenziali sono poche. Le porte di ascolto. L'intervallo di porte da usare per le allocazioni, che deve essere aperto sul firewall. L'indirizzo pubblico del server, se il server stesso sta dietro a un NAT, come succede su molti servizi cloud. Il certificato, per la modalità cifrata. E il metodo di autenticazione.

Un consiglio pratico, se usate Docker: avviate il contenitore con la rete dell'host. Il traghetto usa centinaia, a volte migliaia di porte UDP, e pubblicarle una per una con Docker è lento e scomodo.

Un server TURN che chiunque può usare è un problema serio. È banda che pagate voi, usata da altri. Per questo ogni traghetto chiede le credenziali.

L'errore classico è scrivere un nome utente e una password fissi nel codice JavaScript. Chiunque apra gli strumenti per sviluppatori li vede, e può usare il vostro traghetto per sempre.

La soluzione corretta sono le credenziali temporanee. Il server TURN e il vostro backend condividono un segreto, che non esce mai dal server. Quando un utente autenticato apre una chiamata, il backend genera un nome utente che contiene la data di scadenza, per esempio tra un'ora, e calcola la password come firma HMAC di quel nome con il segreto. Il browser riceve queste credenziali e le passa a RTCPeerConnection. Il server TURN rifà lo stesso calcolo, verifica la firma e controlla che la scadenza non sia passata. Nessun database da sincronizzare, e le credenziali rubate scadono da sole. In coturn questa modalità si attiva con l'opzione use auth secret.

C'è un rischio meno ovvio, e molto concreto.

Il traghetto inoltra il traffico verso qualunque indirizzo il browser chieda. Se il server TURN sta nella stessa rete dei vostri altri server, un utente malintenzionato può chiedergli di inoltrare pacchetti verso un indirizzo interno: il database, un pannello di amministrazione, il servizio dei metadati del cloud. Il traghetto diventa una porta aperta dentro la vostra città.

Per questo coturn va configurato con un elenco di indirizzi vietati: tutte le reti private, l'indirizzo locale, gli indirizzi riservati. Ricercatori di sicurezza hanno mostrato più volte server TURN di grandi servizi usati proprio in questo modo. Nelle note trovate le righe da aggiungere.

Due ultime cose pratiche.

Per collaudare il traghetto, RTCPeerConnection accetta un'opzione chiamata iceTransportPolicy. Impostata su relay, costringe il browser a usare solo i candidati del traghetto. Se la chiamata funziona così, il traghetto funziona. È un test da fare prima di ogni rilascio.

E poi i costi. Tutta la banda delle chiamate che passano dal traghetto passa dal vostro server, nei due sensi. Un video a un megabit al secondo per un'ora sono circa quattrocentocinquanta megabyte per direzione. Moltiplicate per gli utenti. Conviene scegliere un fornitore con molto traffico incluso, e mettere il traghetto vicino agli utenti: un traghetto in un altro continente aggiunge decine di millisecondi a ogni pacchetto.

Quindi, ricapitolando: TURN è il traghetto che porta il carico quando il ponte diretto è impossibile. Serve a una minoranza di chiamate, ma senza di lui quella minoranza non si collega. Si configura con coturn, si protegge con credenziali temporanee e con il divieto di inoltrare verso le reti interne, e si collauda forzando il relay.

Adesso sappiamo da dove passa il ponte. Ma come fanno le due rive a essere sicure di parlare tra loro, e non con un impostore, magari proprio sul traghetto? Nel prossimo episodio: la parola d'ordine. Ci sentiamo lì.