Je hebt één openbaar IP-adres en een dozijn apparaten achter je router. Je iPad zit op mobiel internet, drie netwerken verderop. Toch opent een app voor extern bureaublad in minder dan een seconde een directe verbinding van het ene naar het andere — meestal zonder relay ertussen. Zo werkt die magie echt: ICE, STUN, TURN, hole punching en de ongemakkelijke waarheid over symmetrische NAT.
Waarom dit belangrijk is
Stel je een dinsdagochtend voor. Je Mac mini staat thuis achter een router met één openbaar IPv4-adres. Je iPad zit in de trein, op het mobiele netwerk van een provider met eigen lagen van adresvertaling. Tussen de twee apparaten zitten minstens twee NAT's, waarschijnlijk drie. Geen van beide machines is standaard bereikbaar vanaf het open internet.
En toch open je Remio op de iPad, tik je op de Mac en een seconde later kijk je naar je bureaublad. Beeld en invoer lopen rechtstreeks tussen de twee apparaten — geen cloudrelay, geen proxy ertussen die je scherm opnieuw codeert.
De techniek die dit mogelijk maakt heeft een naam — NAT traversal — en een familie van duidelijk gedefinieerde protocollen erachter: STUN, TURN en ICE. Dit zijn dezelfde protocollen die WebRTC gebruikt voor videobellen in de browser, en ze zijn de reden dat elk modern P2P-extern bureaublad kan voorkomen dat je schermframes door het datacenter van een derde moeten. Dit artikel loopt door wat ze elk doen, waarom ze bestaan en hoe ze samen het pad met de laagste latentie vinden tussen twee apparaten die achter routers schuilen.
Het NAT-probleem in 60 seconden
Het internet is ontworpen zodat elk apparaat een eigen, openbaar routeerbaar adres had. Er zijn in de hele ruimte zo'n 4,3 miljard IPv4-adressen — ruim voldoende in 1981, en eind jaren negentig overduidelijk te weinig.
De oplossing was Network Address Translation. Je router krijgt van je provider één openbaar IPv4-adres. Binnen je huis krijgt elk apparaat een privéadres uit een gereserveerd bereik (meestal 192.168.x.x of 10.x.x.x). Wanneer je laptop een pakket verstuurt, herschrijft de router het bronadres naar zijn eigen openbare IP, onthoudt de koppeling en stuurt door. Komt het antwoord terug, dan zoekt de router de koppeling op en herschrijft hij het bestemmingsadres weer naar je laptop.
Precies daarom werken inkomende verbindingen standaard niet. Van buitenaf heeft je laptop geen adres; alleen de router heeft er een. Het pakket van een vreemde naar je-router-openbaar-ip:5060 komt bij een router zonder koppeling en wordt weggegooid.
Voor een P2P-app is dit het hele spel. Beide partijen zitten achter routers die alleen pakketten doorlaten als ze zich herinneren eerst zelf iets naar buiten te hebben gestuurd. Geen van beide kan de ander simpelweg "bellen" — ze moeten met hun routers samenwerken om tijdelijk een pad te openen.
Hole punching: de firewall je weer binnen laten
Dit is de truc. De NAT-tabel van je router werkt met een vijfvoud: bron-IP, bronpoort, bestemmings-IP, bestemmingspoort en protocol. Wanneer je apparaat een uitgaand UDP-pakket naar 1.2.3.4:5678 stuurt, maakt de router een tijdelijke regel: "als er een UDP-pakket van 1.2.3.4:5678 terugkomt naar mijn openbare IP op poort X, stuur het dan door naar dit apparaat op poort Y."
Die regel bestaat een tijdje — meestal 30 tot 60 seconden — en verloopt dan, tenzij iets hem ververst. In dat venster wordt elk pakket van het bestemmingsadres geaccepteerd.
Dit is het sleutelgat dat P2P-apps gebruiken. Als beide partijen elkaars openbare adres kennen, kunnen ze allebei tegelijk één uitgaand UDP-pakket naar de ander sturen. De router van elke kant opent een uitgaande koppeling. Het eerste pakket van elke kant wordt goed mogelijk weggegooid — de andere router heeft zijn koppeling nog niet geopend — maar het tweede pakket kan wel ergens heen. Vanaf dat moment denken beide routers dat ze een gewoon uitgaand gesprek doorsturen, en praten de twee apparaten rechtstreeks met elkaar.
Dit heet UDP hole punching. Het is een klein wonder, goed gedocumenteerd (RFC 5128) en werkt voor de overgrote meerderheid van consumenten-NAT's in het wild. De overige gevallen — symmetrische NAT, CGNAT, bedrijfsfirewalls — zijn de reden dat TURN bestaat.
Hole punching is geen hack. Het is precies het contract waaromheen NAT is ontworpen: een uitgaand pakket geeft inkomende toestemming. P2P-apps sturen dat uitgaande pakket alleen met opzet.
STUN: "wat is mijn openbare adres?"
Hole punching heeft één voorwaarde: elke partij moet haar eigen openbare adres kennen om de ander te kunnen vertellen waarheen pakketten moeten. Dat adres is van binnen het apparaat niet zichtbaar. Je iPad ziet zijn lokale wifi-adres (192.168.1.42). Wat de rest van het internet ziet nadat de router het pakket heeft herschreven, is iets heel anders.
STUN — Session Traversal Utilities for NAT, RFC 5389 — is het kleine protocol dat dit oplost. De werking is bijna beschamend simpel:
- De partij stuurt een UDP-pakket naar een openbare STUN-server. (Remio gebruikt voor redundantie zowel de openbare STUN-servers van Cloudflare als die van Google.)
- De STUN-server leest het bron-IP en de bronpoort van de lijn — wat per definitie het door NAT vertaalde openbare adres van de partij is.
- De STUN-server antwoordt met dat adres als inhoud: "Voor zover ik kan zien, ben jij
203.0.113.42:48291." - De partij weet nu welk adres ze aan de andere kant moet doorgeven.
Dat openbare adres heet in ICE-terminologie een server-reflexive candidate. Het kost vrijwel niets — één rondreis tijdens het opzetten van de verbinding, en geen extra bandbreedte of latentie nadat de verbinding er is. STUN heeft maar één taak: twee partijen aan elkaar voorstellen; zodra ze praten, speelt de STUN-server geen rol meer.
TURN: wanneer hole punching mislukt
Hole punching werkt voor de meeste NAT's, maar niet voor alle. De mislukkingen zijn echt, en een P2P-app die doet alsof ze niet bestaan, kan voor een aanzienlijk deel van de gebruikers simpelweg geen verbinding maken.
De belangrijkste boosdoeners:
- Symmetrische NAT. Een NAT die voor elke andere bestemming een andere openbare poort toewijst. STUN vertelt je gesprekspartner dat je op poort 48291 zit (want die poort zag de STUN-server), maar als je een pakket naar het adres van je gesprekspartner stuurt, kiest je router een andere poort — zeg 48317. De router van je gesprekspartner weigert het pakket omdat het van een onverwachte poort komt. Hole punching mislukt.
- Carrier-grade NAT (CGNAT). Mobiele en veel provider-netwerken leggen op providerniveau een tweede NAT. Je zit misschien achter twee NAT's zonder het te weten, en beide moeten meewerken. CGNAT is vaak symmetrisch, en je hebt er geen beheertoegang toe.
- Restrictieve bedrijfsfirewalls. Sommige bedrijfsnetwerken blokkeren al het uitgaande UDP, of staan het alleen naar specifieke bestemmingen toe. Hole punching heeft een UDP-pad nodig; is er geen, dan heeft het geen kans.
Voor deze gevallen is de terugvaloptie TURN — Traversal Using Relays around NAT, RFC 5766. Een TURN-server is een relay die beide partijen kunnen bereiken omdat hij een openbaar adres heeft dat altijd inkomend verkeer accepteert. Elke partij maakt een gewone uitgaande TLS-verbinding naar de TURN-server (die elke NAT toestaat), en de server stuurt bytes door tussen beide kanten.
TURN kost echt iets. Elk videopakket moet een extra netwerkstap nemen. Bij een regionale TURN-relay komt daar zo'n 30 tot 80 milliseconden rondreislatentie bij. Over regio's heen — zeg een relay in Frankfurt voor een partij in Tokio en een partij in São Paulo — kan het 80 tot 200 milliseconden zijn. De TURN-beheerder betaalt ook voor bandbreedte: elke bit van je stream gaat door zijn leidingen.
Daarom gebruikt een goed ontworpen app TURN alleen wanneer hole punching aantoonbaar is mislukt. ICE regelt die beslissing automatisch.
ICE: alle kandidaten tegelijk proberen
Interactive Connectivity Establishment, RFC 8445, is de choreografie die dit alles samenbindt. ICE kiest niet vooraf een strategie. Het verzamelt elk mogelijk kandidaatadres voor elke partij, wisselt de volledige lijst met de andere kant uit, en laat dan beide stacks elk kandidaatpaar tegelijk testen — een race om het eerste te vinden dat werkt.
Voor elke partij verzamelt ICE doorgaans:
- Host-kandidaten — elk lokaal IP-adres op elke netwerkinterface (Ethernet, wifi, virtuele interfaces, IPv4 en IPv6).
- Server-reflexive kandidaten — openbare adressen die van STUN-servers zijn geleerd.
- Relay-kandidaten — adressen die op een TURN-server zijn toegewezen.
De twee partijen wisselen deze lijsten uit via een signaleringskanaal — bij Remio is dat een kleine WebSocket-verbinding met relay.remio.net die de ICE-kandidaten en de WebRTC-sessiebeschrijving (de SDP) doorgeeft en daarna niets meer te doen heeft zodra de media gaan stromen.
Zodra beide lijsten binnen zijn, begint ICE met connectiviteitscontroles. Elke partij stuurt in volgorde van prioriteit een STUN-binding-request langs elk kandidaatpaar. De prioriteiten zijn zo ontworpen dat het pad met de laagste latentie de voorkeur krijgt:
- Host naar host — beide partijen op hetzelfde lokale netwerk. Dit is het droomgeval: een paar honderd microseconden latentie, geen router in het spel.
- Host naar server-reflexive, of server-reflexive naar server-reflexive — partijen op verschillende netwerken, via hole punching door hun eigen NAT's heen. Dit is in de praktijk meestal wat "P2P via internet" betekent.
- Alles met een relay — laatste redmiddel, alleen gebruikt als alle paden met hogere prioriteit hun connectiviteitscontroles niet doorstaan.
Het eerste kandidaatpaar waarbij beide richtingen slagen, wordt als winnaar benoemd en de media gaan over dat pad stromen. Het hele proces is doorgaans ruim binnen een seconde klaar.
ICE verzamelt kandidaten ook continu. Verschijnt er midden in een sessie een beter pad — bijvoorbeeld doordat je telefoon van mobiel internet op wifi overstapt — dan kan ICE naar het nieuwe pad overschakelen zonder het gesprek te verbreken.
Waarom Remio zo sterk de voorkeur geeft aan P2P
Remio is een app voor extern bureaublad, geen videogesprek. Het latentiebudget is moordend. Wil een sessie aanvoelen alsof je aan de hostmachine zit, dan moet de hele pijplijn — vastleggen, coderen, netwerk, decoderen, weergeven — piepklein zijn: op een lokaal netwerk kost het zo'n 8 ms, en de rest is de eigen verversingsfrequentie van 60 Hz van je scherm (ongeveer 16,7 ms per frame). Elke extra stap is een zonde.
Bij een directe P2P-verbinding op een lokaal netwerk is het netwerkdeel van dat budget zo'n 1 tot 5 milliseconden heen en terug. Er is geen relay; de bytes gaan rechtstreeks van het ene apparaat naar het andere. Met de pijplijn van Remio komt dat op zo'n 8 ms verwerking op een lokaal netwerk (intern gemeten; de rest is de eigen verversingsfrequentie van 60 Hz van je scherm) — je invoer landt vóór het volgende frame wordt getekend. De externe machine voelt niet te onderscheiden van een lokale.
Bij een verbinding via een TURN-relay — zelfs een regionale — springt het netwerkdeel naar 30 tot 80 milliseconden. De totale door de gebruiker ervaren latentie is dan 40 tot 100 ms. Nog steeds bruikbaar voor de meeste taken, maar je voelt het bij een snelle sleepbeweging of een snelle reeks klikken. Het trackpad voelt niet meer helemaal als van jou.
Dat verschil is waarom we zoveel moeite doen om sessies op P2P te houden. De WebRTC-stack van Remio verzamelt zowel IPv4- als IPv6-kandidaten, spreekt meerdere STUN-servers tegelijk aan en geeft bij de selectie van kandidaatparen door ICE sterk de voorkeur aan directe paden. Intern gebruiken we zelfs de gemeten rondreistijd van de verbinding om het netwerk te classificeren — onder 15 ms weten we dat het een lokaal netwerk is, zodat de encoder hoog begint en veel meer bandbreedte mag gebruiken. Alles wat trager is, wordt als WAN behandeld en voorzichtiger afgesteld.
En — dit is het deel dat concurrenten vaak stilzwijgend weglaten — de verbinding is end-to-end versleuteld, ongeacht het pad. Je scherm raakt onze servers nooit aan, en zelfs een TURN-relay ziet alleen cijfertekst: sleutels worden rechtstreeks tussen de twee partijen afgesproken tijdens de handshake, voordat er ook maar één pixel beweegt. Of de bytes nu via P2P of via TURN stromen, noch de signaleringsserver van Remio noch de TURN-beheerder kan ze lezen. P2P betekent alleen dat er helemaal geen derde partij op het datapad zit.
Wanneer een relay onvermijdelijk is (en dat is prima)
Soms zeggen de netwerkgoden nee. Symmetrische NAT aan beide kanten, dubbele CGNAT bij een mobiele provider met een strenge isp, een bedrijfsfirewall die alleen uitgaand TLS naar bekende cloudproviders toestaat — dit zijn echte, gangbare configuraties. In die gevallen moet de sessie via een relay lopen of het lukt helemaal niet.
De TURN-backend van Remio is Cloudflare Calls, dat ons een wereldwijd netwerk van relays dicht bij de meeste gebruikers geeft. Kiest ICE een relaypad, dan gaat de ervaring van "voelt lokaal" naar "voelt als Splashtop" — nog steeds goed bruikbaar, maar je merkt het. De extra latentie komt uit op 30 tot 80 ms bij een regionale relay; over regio's heen kan het 200 ms worden.
Het belangrijkste: de data blijft end-to-end versleuteld. Cloudflare ziet versleutelde UDP-pakketten de ene kant op en versleutelde UDP-pakketten de andere kant op. Het kan bytes tellen voor facturering. Het kan je scherm, je toetsaanslagen of enige sessie-inhoud niet zien. Ook aan de kant van Remio is er geen punt waar ontsleuteld wordt, want er zit geen Remio-cloud in de pijplijn — we beheren de TURN-dienst via Cloudflare en raken de payloads nooit aan.
Dit is de architectuur die ons beveiligingswhitepaper in meer detail beschrijft. Kort gezegd: P2P of relay, het dreigingsmodel is hetzelfde.
De IPv6-nooduitgang
IPv6 heeft 340 sextiljoen adressen (3,4 × 1038) — genoeg om elk zandkorrel op aarde een eigen openbaar IP te geven, met een paar biljoen over. In een wereld met alleen IPv6 is NAT grotendeels overbodig. Twee apparaten met IPv6 kunnen elkaar gewoon pakketten sturen, en het enige obstakel is de hostfirewall aan beide kanten.
Heb je IPv6 thuis en bij je mobiele provider, dan is je misschien opgevallen dat sommige apps sneller verbinden wanneer beide kanten IPv6 hebben — omdat de hele dans van "kandidaten verzamelen, paren testen" dan minder obstakels kent. Er is geen NAT-vertaling te ontdekken, geen STUN-rondje nodig, alleen directe adressen.
Maar dit is het addertje: in 2026 is de wereldwijde uitrol nog niet af. Veel thuisrouters ondersteunen IPv6 slecht of helemaal niet. Veel bedrijfsnetwerken blokkeren inkomend IPv6 standaard. Sommige providers bieden IPv6 aan de radiozijde aan maar bruggen elders naar IPv4. Pure IPv6-naar-IPv6-paden bestaan, maar je kunt er niet op vertrouwen als enig mechanisme.
Dus verzamelt Remio — net als elke serieuze P2P-stack — zowel IPv4- als IPv6-kandidaten en laat ICE ze tegen elkaar racen. Bestaat er een direct IPv6-pad en werkt het, dan wint het meestal op latentie. Zo niet, dan neemt IPv4 met hole punching het over. Mislukken beide, dan relay. De gebruiker ziet hier niets van; de verbinding komt gewoon tot stand.
Zo weet je welk pad je sessie gebruikt
Benieuwd op welk pad je sessie terecht is gekomen? De verbindingsindicator van Remio toont het type in gewone taal — "Direct" voor P2P, "Relay" voor TURN. Het statistiekenpaneel voor ontwikkelaars toont de volledige WebRTC-status, inclusief de kandidaattypen van het gekozen paar (host, srflx, relay) en de gemeten RTT.
Een paar snelle interpretaties:
- RTT onder 5 ms, Direct — je zit op hetzelfde lokale netwerk als de host. Het beste geval. Zo'n 8 ms verwerking (de rest is de eigen verversingsfrequentie van 60 Hz van je scherm) is haalbaar.
- RTT 5 tot 15 ms, Direct — hetzelfde wifinetwerk maar met een extra toegangspunt of mesh-stap. Nog steeds uitstekend.
- RTT 15 tot 80 ms, Direct — je zit op een ander netwerk dan de host, hole punching is gelukt. P2P via internet werkt.
- RTT 30 tot 80 ms, Relay (regionaal) — symmetrische NAT of carrier-grade NAT versloeg de hole punch. Een Cloudflare TURN in de buurt nam het over.
- RTT 80 tot 200 ms, Relay — TURN over een grotere geografische afstand, of jij en de host zitten in zeer verschillende regio's.
Val je betrouwbaar terug op een relay, zelfs thuis, dan zijn de gebruikelijke verdachten een isp-modem die symmetrische NAT doet, IPv4-CGNAT op je thuisverbinding (vaker dan je denkt bij wederverkopers van glasvezel), of een overijverige firewall die inkomend UDP blokkeert. Onze gids om vertraging op extern bureaublad te verminderen loopt de gangbare boosdoeners langs, en de pagina over directe verbinding op het lokale netwerk is de snelle route als beide apparaten op jouw netwerk zitten.
Prestatiecijfers uit de praktijk
Alles bij elkaar zijn dit de latentiecijfers die we in productie meten over de verschillende paden die een Remio-sessie kan nemen:
- Direct P2P op lokaal netwerk: 1–5 ms netwerk-RTT. End-to-end (invoergebeurtenis tot pixelupdate): zo'n 8 ms verwerking (de rest is de eigen verversingsfrequentie van 60 Hz van je scherm) als de rest van de pijplijn meewerkt.
- Wifi op hetzelfde netwerk met extra stappen: 5–10 ms netwerk-RTT.
- TURN-relay, regionaal: 30–80 ms netwerk-RTT.
- TURN-relay, tussen regio's: 80–200 ms netwerk-RTT.
- 4G/5G mobiel, P2P via hole punching: 40–100 ms netwerk-RTT.
Dit komt overeen met de cijfers in de benchmarks van Remio en verklaart waarom we de grens tussen lokaal netwerk en WAN op 15 ms RTT leggen — die scheidt directe paden netjes van elke relay (minimaal 30 ms) of mobiel pad (minimaal 40 ms), met zeer weinig valse positieven.
NAT traversal is zo'n onderwerp waarbij de protocollen afzonderlijk simpel zijn maar de combinatoriek lastig. De meeste gebruikers hoeven nooit te weten dat ICE, STUN en TURN bestaan — ze merken alleen een app die snel verbindt van overal naar overal. De protocollen doen hun werk als je ze niet opmerkt. Merk je ze wel op — een sessie duurt net te lang, of "Direct" wordt "Relay" — dan heb je nu het mentale model.
Lees voor meer over de native pijplijn van Remio en de keuzes die 1–5 ms netwerklatentie omzetten in zo'n 8 ms verwerking (de rest is de eigen verversingsfrequentie van 60 Hz van je scherm) waarom native ertoe doet. Voor het dreigingsmodel van relaypaden, zie het beveiligingswhitepaper. Of bekijk de functies en download Remio om het te voelen werken.