IPsec was een goed idee. Leg de versleuteling op de netwerklaag, onder alles, en elk protocol dat over IP loopt erft vertrouwelijkheid en integriteit zonder dat het iets hoeft te weten. Geen bibliotheek om te linken. Geen certificaat per applicatie. Niets herschrijven aan wat je al hebt uitgeleverd. Het pakket vertrekt beschermd en komt beschermd aan, en de routers ertussen vervoeren het zonder te weten of te willen weten wat erin zit.
Dat ontwerp rust op één aanname, en die staat in de standaard in plaats van dat hij wordt geïmpliceerd: het adres van een pakket identificeert de machine waar het vandaan kwam. Een security association wordt opgezocht op het bestemmingsadres, het protocolnummer en de SPI1. De Authentication Header gaat verder en ondertekent de IP-header zelf, bron en bestemming inbegrepen2. Voor IPsec is het adres geen routeringsmetadata. Het is onderdeel van de identiteit en onderdeel van de integriteitscontrole.
Daarna heeft deze branche dertig jaar besteed aan het wegnemen van het adres.
Eerst NAT, om een kantoor achter één lijn te laten passen. Toen carrier-grade NAT, om enkele honderden huizen achter één adres te laten passen, omdat IPv6 aanzetten werk was en een doos kopen inkoop — wat het hele onderwerp is van We Zijn Nooit Zonder Adressen Geraakt. We Zijn Zonder Moeite Geraakt. en dat doe ik hier niet nog eens over. Wat voor deze post telt, is het gevolg. Precies het ene ding waarop IPsec gebouwd is, levert het moderne toegangsnetwerk niet meer.
Dus werd IPsec opgelapt. Verpak het versleutelde pakket in UDP zodat een vertaler een poort heeft om te herschrijven. Zet de checksum op nul zodat niemand hem opnieuw controleert. Stuur elke twintig seconden een pakket van één byte, voor altijd, zodat een tabel in andermans apparatuur niet vergeet dat je bestaat. Haal de identiteit van het adres af en hang hem aan een naam. Geef de Authentication Header op, want die kan een herschreven header per constructie niet overleven. En als een hotel UDP blokkeert, verpak het geheel er ook nog eens in TCP bij3.
Elk daarvan is een echte, gestandaardiseerde, door leveranciers ondersteunde oplossing. Samen zijn ze een protocol dat overeind wordt gehouden door zijn eigen steigers. En die steigers zijn het argument: je stut niet een kwart eeuw lang iets omdat het in de kern gezond is.
De conclusie waar ik op uitgekomen ben, is dat IPsec volledig uitgefaseerd hoort te worden. Niet bijgeschaafd, niet opnieuw voorgesteld met betere cijfers, niet bewaard voor site-to-site omdat dat stuk nog werkt. Uitgefaseerd, met datums, zoals PPTP tien jaar eerder had moeten gebeuren dan het moment waarop iemand er eindelijk aan toekwam. Wat volgt is het bewijs, de diagrammen, de leveranciersdocumentatie die dit alles in hun eigen woorden zegt, en — omdat de meesten die dit lezen die dingen maandag toch draaiend moeten houden — een werkbare methode om IPsec-storingen intussen te diagnosticeren.
Wat het je werkelijk kost, in tickets
Vóór de standaarden hier de rekening, in de volgorde waarin je hem tegenkomt.
De tunnel valt op de klok uit. Elk uur, of elke acht uur, of na twintig minuten zonder verkeer. Hij komt terug zodra iemand een bestand opent, dus de helft van de gebruikers meldt het nooit en de andere helft meldt het als “het VPN is traag”. Niemand heeft iets veranderd.
Twee mensen in hetzelfde huis kunnen niet allebei verbinden. De tweede komt op, de eerste valt eruit. Ze bellen apart naar de servicedesk, dus de tickets komen elkaar nooit tegen en veertien dagen lang ziet niemand het patroon.
Kleine dingen werken en grote dingen blijven hangen. Inloggen werkt. Teams werkt. Ping werkt. Een bestand kopiëren stokt elke keer op dezelfde plek, en een grote pagina in een interne applicatie blijft staan tot hij verloopt.
De tunnel staat en er gaat geen verkeer doorheen. Beide kanten zeggen “established”. Beide kanten zijn tevreden over zichzelf. Er beweegt niets.
Van buiten komt er niets binnen. Site-to-site naar het filiaal dat naar een glasvezel-altnet is overgestapt komt niet meer tot stand in de richting waarin dat vroeger ging, en niemand kan zeggen waarom, alleen dat “hun IP is veranderd”.
QoS aanzetten heeft de versleuteling gesloopt. Iemand heeft spraak geprioriteerd, en nu gooit de andere kant pakketten weg als replays.
Geen van deze gevallen is een configuratiefout in de gewone zin. Elk ervan is IPsec dat het netwerk tegenkomt zoals het nu is. De rest van deze post is het waarom, op volgorde, en hoe je aantoont welk geval jij hebt.
IPsec wordt niet door het netwerk gedragen. Het ís het netwerk.
Begin bij wat het was, want het ontwerp is werkelijk goed en de storingen krijgen alleen daartegen betekenis.
ESP is geen protocol dat over TCP of UDP loopt. Het is een transportprotocol, IP-protocolnummer 50, direct op IP, in precies dezelfde plek waar TCP en UDP zitten. AH is protocol 51. Geen van beide heeft een poortveld, want geen van beide heeft er een nodig: op het internet waarvoor IPsec ontworpen is, benoemt het bestemmingsadres al precies één machine, en de SPI in de ESP-header benoemt welke security association op die machine. Adres plus protocol plus SPI. Dat drietal is de opzoeking1.
Kijk wat dat oplevert. Geen handshake-poort om bloot te stellen, geen sessielaag om fout te doen, geen applicatie die mee moet doen. Elk van beide kanten kan beginnen. Het midden van het netwerk is dom, en dat is precies wat het midden van een netwerk moet zijn. Een router stuurt protocol 50 door zoals hij protocol 6 doorstuurt, en dat hij de payload niet kan lezen is het doel en geen beperking.
Een schoon ontwerp. En tegelijk, in 2026, de beschrijving van een internet dat de meesten die dit lezen niet kunnen kopen.
Toen zette iemand in elk pad een vertaler
Een NAT herschrijft het bronadres, en vaak de bronpoort, zodat meerdere machines één adres delen. Meer doet het niet. Tegen IPsec is dat bijna een volledige sloop, en de IETF was eerlijk genoeg om er een heel document over te publiceren dat de stukken opsomt: RFC 3715, IPsec-Network Address Translation (NAT) Compatibility Requirements4. Zestien aparte onverenigbaarheden. Dit zijn de belangrijke.
AH is klaar, per constructie. In de eigen woorden van RFC 3715: “Since the AH header incorporates the IP source and destination addresses in the keyed message integrity check, NAT or reverse NAT devices making changes to address fields will invalidate the message integrity check.”4 — de AH-header neemt bron- en bestemmingsadres op in de integriteitscontrole, dus elke adreswijziging maakt die ongeldig. Daar is geen oplossing voor, en die zou er ook nooit komen. Een protocol dat de header ondertekent komt niet door een doos wiens hele taak het herschrijven van de header is. AH is niet omzeild. Het is opgegeven.
Er zijn geen poorten om te vertalen. Een NAT die poortvertaling doet heeft een poort nodig. ESP heeft er geen. Cisco schrijft het onomwonden in de Catalyst-configuratiehandleiding: “If PAT found a legislative IP address and port, it would drop the Encapsulating Security Payload (ESP) packet.”5 Het pakket wordt niet op beleid afgewezen. Het wordt weggegooid omdat de doos nergens heeft om te schrijven wat hij moet schrijven.
De identiteit past niet meer bij het pakket. Opnieuw uit RFC 3715: “Where IP addresses are used as identifiers in Internet Key Exchange Protocol (IKE) Phase 1 or Phase 2, modification of the IP source or destination addresses by NATs or reverse NATs will result in a mismatch between the identifiers and the addresses in the IP header.”4 — worden adressen als identificatie gebruikt, dan klopt na de vertaling de identificatie niet meer met de header. Een identiteitsschema dat machines bij adres benoemt overleeft geen apparaat dat machines beroepshalve hernoemt.
Twee machines kunnen dezelfde SPI kiezen. De SPI wordt door de ontvanger gekozen en hoeft alleen bij hem uniek te zijn. Zet twee hosts achter één adres en de vertaler heeft twee associations zonder iets om ze uit elkaar te houden.
Van buiten kan niets beginnen. Een NAT bouwt zijn tabel op uit uitgaande pakketten. Er is geen uitgaand pakket tot iemand begint, en op een NAT-lijn kan alleen de binnenkant beginnen. De halve symmetrie van het protocol is weg.
De oplossing was echt, en elk onderdeel ervan heeft iets gekost
NAT-traversal werkt. Dat wordt niet betwist en ik doe ook niet alsof. Ik heb genoeg tunnels door genoeg NAT’s gedraaid. Wat ik vastgelegd wil hebben is de rekening, want die wordt elke dag door iedereen betaald en bijna niemand specificeert hem.
Het mechanisme is RFC 3948: detecteer tijdens de sleuteluitwisseling een vertaler, en stop dan het hele ESP-pakket in een UDP-datagram op poort 4500 zodat de vertaler iets heeft dat hij begrijpt6. Cisco’s beschrijving van het wire-formaat is precies: na versleuteling worden “a UDP header and a non-IKE marker (which is 8 bytes in length) are inserted between the original IP header and ESP header”5 — een UDP-header en een acht byte lange niet-IKE-markering tussen de oorspronkelijke IP-header en de ESP-header gezet. Die van Juniper is korter en zegt hetzelfde: “NAT-T encapsulates both IKE and ESP traffic within UDP with port 4500 used as both the source and destination port.”7
Nu de gespecificeerde rekening.
De Authentication Header is weg. Niet beleefd afgeschaft. Onbruikbaar. RFC 8221 zegt inmiddels helder dat ESP samen met AH NOT RECOMMENDED is8, en de eerlijke reden is dat het ene dat AH deed en ESP niet doet, precies het ene is dat NAT vernietigt.
De UDP-checksum wordt opzettelijk op nul gezet. RFC 3948 eist het: met herschreven adressen zou een daarover berekende checksum falen, dus het antwoord van de standaard is hem niet meer te berekenen. “If the protocol header after the ESP header is a UDP header, set the checksum field to zero in the UDP header.”6 Een laag foutdetectie weggehaald zodat een laag adresherschrijving blijft werken.
Je stuurt nu pakketten om een tabel warm te houden. RFC 3948 definieert een keepalive als één byte, 0xFF, verstuurd als er verder niets is uitgegaan gedurende een instelbaar interval met standaard twintig seconden6. Juniper noemt de reden zonder opsmuk: “Because NAT devices age out stale UDP translations, keepalive messages are required between the peers.”7 Een laptop in de trein die helemaal niets doet, zendt dus elke twintig seconden, voor altijd, omdat een tabel in een doos die van geen van beide kanten is anders vergeet dat hij bestaat. Vermenigvuldig dat met een vloot. Dat is de radio die wakker wordt, de accu die leegloopt, en het mobiele netwerk dat verkeer draagt waarvan het enige doel is vergeten te voorkomen.
Je firewallt nu twee poorten in plaats van één protocol, en Cisco’s eigen beperkingenlijst eist statische vertaalregels voor zowel 500 als 4500 voordat er ook maar iets van werkt5.
En lees de rest van die beperkingenlijst, want daar vertelt de leverancier je de vorm van het ding. Dynamisch NAT-beleid: niet ondersteund. IPv6-verkeer: onverenigbaar met de functie. IPsec en NAT op hetzelfde apparaat: die kunnen niet allebei werken5. Dat is geen configuratiehandleiding. Dat is een lijst van plekken waar de steigers niet komen.
Elegant is er niets aan, en het is ook niemands schuld in het bijzonder. Het is wat er gebeurt als je een laag-3-protocol in leven houdt op een netwerk dat is opgehouden laag 3 te eerbiedigen.
Carrier-grade NAT nam weg wat er over was
Gewoon NAT nam het adres van de machine af en gaf het aan de locatie. De vertaler was nog van jou, dus je kon een poort doorsturen, een mapping vastzetten, een timer verlengen of de concentrator ervoor zetten.
Carrier-grade NAT neemt het adres van de locatie af en geeft het aan enkele honderden vreemden, en de vertaler is van je provider. Alles wat je er vroeger aan kon doen, kan nu niet meer.
En wees duidelijk over wat er werkelijk in het pad staat, want dit is het stuk dat mensen fout hebben. De router in huis doet nog steeds NAT. Die is niet uitgezet. Hij vertaalt je laptop op 192.168.1.20 nog altijd naar het adres dat de lijn houdt — alleen houdt de lijn nu 100.64.12.7, gedeelde ruimte, geen publiek adres. De carrier vertaalt dat vervolgens nog een keer. Het pakket passeert dus twee vertalers voor het het internet bereikt, en dat is het gewone geval, niet iets bijzonders.
Je zit achter dubbel NAT, en maar één van de tabellen is van jou. Twee vertalingen betekent twee mappingtabellen, twee verouderingstimers en twee kansen dat de mapping verdwijnt. Je keepalive moet die verslaan die het eerst verloopt, en je kunt er precies één lezen. Erger nog, de twee grijpen in elkaar: de router in huis heeft mogelijk eigen ideeën over IPsec en probeert te helpen met een application gateway, zodat de bronpoort die je client denkt te gebruiken niet die is die het huis verlaat, en ook niet die is die de carrier verlaat.
Poortdoorsturing werkt nog steeds, en levert helemaal niets op. Dit is het ticket dat de meeste tijd opeet. Iemand stuurt UDP 500 en 4500 door op de thuisrouter, de router accepteert het, de instellingenpagina zegt dat de regel actief is — en niets kan hem gebruiken, want hij stuurt door vanaf een adres dat het internet niet kan bereiken. UPnP en PCP gedragen zich net zo: de client vraagt om een mapping, de router verleent die, en de poort opent op een gang. Alles meldt succes en niets werkt. De doos vertelt je wat je horen wilt.
De snelste manier om het te beslechten kost niets. Lees het WAN-adres in de router. Begint dat met 100.64, dan is dat de gedeelde ruimte die in RFC 6598 is gereserveerd, zit je achter carrier-grade NAT, en is de halve instellingenpagina decoratie.
De responderrol bestaat niet meer. Een apparaat achter CGNAT kan niet de kant zijn die iemand belt. Site-to-site tussen twee filialen op consumentenglasvezel — normaal, goedkoop, en precies wat een klein bedrijf wil — vereist dat minstens één kant een echt adres houdt, of een derde partij in het midden die ze aan elkaar voorstelt. Die derde partij is een bedrijf waarvan je nu afhankelijk bent omdat je provider je geen adres wilde geven.
De timer is van iemand anders. RFC 4787 zegt NAT-beheerders dat een UDP-mapping “MUST NOT expire in less than two minutes”, en beveelt vijf of meer aan9. Dat is de ondergrens en het advies, geen belofte, en wat jouw carrier werkelijk doet kun je niet nakijken. Als zodanig houdt de keepalive op een afstelknop te zijn. Hij is dragend, op een timer die je raadt.
De identiteit van je peer kan niet zijn adres zijn. Meerdere abonnees bereiken de andere kant als één adres. Wat de concentrator ook gebruikt om ze uit elkaar te houden, het is niet de IP-header — en juist die zou IPsec gebruiken.
Er is een harde bovengrens, en de leveranciers publiceren hem. Juniper legt voor SRX5400, SRX5600 en SRX5800 vast: “the total number of tunnels from a given public translated IP cannot exceed 1000 tunnels”7. Lees dat als beheerder en niet als specificatieregel. Je VPN-concentrator heeft een limiet per gedeeld adres, het delen wordt gedaan door een carrier waarmee je geen contract hebt, en hoe dicht je bij die limiet zit hangt af van hoeveel van je gebruikers toevallig achter dezelfde zitten. Er is geen teller om in te kijken. Er is alleen de dag waarop het voor sommigen begint te falen en voor anderen niet.
Alles in dit hoofdstuk vloeit voort uit één beslissing die dit land genomen heeft en bleef nemen. Die zaak heb ik elders volledig uitgeschreven en herhaal ik niet. Het punt is hier smaller: de kernaanname van IPsec is door het toegangsnetwerk geschrapt, en IPsec leeft sindsdien van noodoplossingen.
En het IPv6-only-netwerk redt het ook niet
Hier moet ik eerlijk zijn tegen mijn eigen betoog, want het voor de hand liggende antwoord op alles hierboven is: goed, geef dan elke machine een echt IPv6-adres en IPsec werkt weer zoals gespecificeerd.
Dat klopt, tussen twee kanten die er allebei een hebben. Dat is niet het netwerk waar de meeste mensen op zitten.
De IPv6-only-toegangsnetwerken die werkelijk bestaan, mobiel voorop, bereiken het IPv4-internet via NAT64, en dat is in de gewone zin helemaal geen NAT. Het is een protocolvertaler, die een IPv6-pakket herschrijft tot een IPv4-pakket. En RFC 6146 benoemt wat het vervoert, en benoemt wat het niet vervoert, zonder enige dubbelzinnigheid:
“The current specification only defines how stateful NAT64 translates unicast packets carrying TCP, UDP, and ICMP traffic. Multicast packets and other protocols, including the Stream Control Transmission Protocol (SCTP), the Datagram Congestion Control Protocol (DCCP), and IPsec, are out of the scope of this specification.”10
IPsec, bij naam, buiten het bereik. En pakketten die iets buiten die lijst dragen “SHOULD be discarded”10.
Op een IPv6-only-telefoon of -laptop die een IPv4-concentrator wil bereiken — en dat zijn de meeste concentratoren — wordt natief ESP dus niet door een firewall weggegooid of door een vertaler verminkt. Het wordt om te beginnen nooit vervoerd. De vertaler doet precies wat zijn standaard hem voorschrijft.
Het antwoord van de branche daarop is onvermijdelijk nog een laag: 464XLAT, dat het apparaat een lokale IPv4-stack geeft en twee keer vertaalt, uit IPv4 en terug, zodat wat NAT64 niet kan dragen toch werkt11. Het staat al op de lijst met aanbouwsels in de IPv6-post en ik ga het niet opnieuw beargumenteren. Wat hier het vermelden waard is, is de vorm: een protocol dat in 2004 op NAT brak, breekt ook op de vertaling die in 2011 voor de IPv6-overgang is gebouwd, en beide keren is het antwoord het in iets anders te verpakken.
Dat is de toets die een protocol in 2026 moet doorstaan. Werkt het op het netwerk dat mensen werkelijk hebben — achter het gedeelde adres van een carrier, op een IPv6-only-mobielnetwerk, door een hotel dat alleen TCP 443 doorlaat? Alles dat op een UDP-poort gebouwd is doorstaat alle drie zonder dat je het hoeft te zeggen. IPsec heeft voor elk een andere noodoplossing nodig, en voor de derde bovendien TCP-encapsulatie3.
Geen poorten betekent ook geen tweede lijn
Hier een storing die niets met NAT te maken heeft, puur modern is, en bijna geen aandacht krijgt.
Routers en switches verdelen verkeer over parallelle paden. Link aggregation, equal-cost multipath: die werken hetzelfde, door het vijftal te hashen. Bronadres, bestemmingsadres, protocol, bronpoort, bestemmingspoort. ESP heeft geen poorten. Elk pakket van een tunnel tussen dezelfde twee adressen hasht dus identiek, en de hele tunnel landt op één lid van de bundel, hoeveel je er ook gekocht hebt.
Twee 10G-lijnen en één IPsec-tunnel geven je 10G. Vier geven je 10G. De apparatuur werkt precies zoals ontworpen.
De noodoplossing heeft de gebruikelijke vorm. Sommig silicium kan in plaats daarvan op de SPI hashen, want elke SPI benoemt één association en dus één stroom, maar dat is een functie die je gekocht moet hebben en niet iets dat je kunt aannemen van een pad dat niet van jou is. Er loopt een IETF-concept waarvan het enige doel is ESP in nog een UDP-header te verpakken zodat gewone routers het kunnen hashen, en het zegt in één zin waarom: “Although the ESP SPI field within the IPsec packets can be used as the load-balancing key, but it cannot be used by legacy switches and routers.”12 De probleemstelling is net zo onomwonden over wat mensen in plaats daarvan doen: “Many cloud service providers allow customers to establish multiple IPsec VPN tunnels in parallel to enable ECMP and increase aggregate bandwidth. However, this approach is not ideal, as each tunnel typically requires its own public IP address, leading to higher public IP consumption and increased operational overhead.”12
Laat dat even bezinken. De aanbevolen manier om een versleutelde verbinding sneller te maken, is er meerdere bouwen, elk met een verbrand publiek IPv4-adres — tijdens een adressenschaarste — omdat het protocol geen poortnummer heeft om op te hashen. Een op UDP gebouwde tunnel krijgt multipath intussen gratis, van apparatuur die vijftien jaar geleden is uitgeleverd, omdat hij een poort heeft zoals al het andere op het moderne internet.
Dat is geen erfenisprobleem dat vanzelf uitdooft. Dat is een levende grens voor nieuwbouw, vandaag, bij precies de snelheden die mensen nu kopen.
De MTU-belasting, en wie hem betaalt
Elke tunnel kost bytes. IPsec kost er meer dan de meeste, en de manier waarop het faalt als het krap wordt is de ergste soort storing: onregelmatig, afhankelijk van de grootte, en onzichtbaar voor elke test die je als eerste draait.
Reken het voor één configuratie door in plaats van te zwaaien. ESP in tunnelmodus over IPv4 met AES-GCM: 20 byte buitenste IP-header, 8 ESP-header, 8 nonce, minimaal 2 trailer, 16 integriteitswaarde. 54 byte voordat er iets van je pakket in gaat. Verpak het voor NAT-traversal en de UDP-header maakt er 62 van. Op een pad van 1500 byte blijft 1438 over, en zodra er ergens ervoor PPPoE op 1492 loopt zit je er weer onder.
En dan het stuk dat er een storing van maakt in plaats van een rekensom. Een verzender komt er alleen achter dat een pakket te groot was doordat er een ICMP-fout terugkomt — Fragmentation Needed bij IPv4, Packet Too Big bij IPv6. Gooit iets in het pad die fouten weg, dan komt de verzender er nooit achter en blijft hij pakketten sturen die blijven sterven. Dat is het klassieke zwarte gat: de handshake komt erdoor omdat handshakes klein zijn, en de overdracht blijft hangen omdat overdrachten dat niet zijn.
Cisco onderhoudt hierover sinds het GRE-en-IPsec-tijdperk een heel document, en het is nog altijd een van de betere verklaringen van dit samenspel in wiens bibliotheek dan ook13. Het moet onderhouden worden omdat mensen ICMP in zijn geheel blijven blokkeren en zich dan afvragen waarom tunnels zich vreemd gedragen.
De twee helften van dat betoog heb ik al uitgeschreven en ze gelden hier zonder herhaling: welke ICMP-berichten dragend zijn en welk niet, in Ping: het diagnosegereedschap dat een heleboel meer opent, en hoe je de precieze hop vindt die je verkeer opeet, in De firewall is elf hops ver. De korte versie voor deze post: de fouten zijn het mechanisme, echo niet, en een grensbeleid dat heel ICMP weggooit heeft je VPN gesloopt op een manier die het VPN aangerekend wordt.
En je eigen quality of service kan het slopen
Nog eentje, want die pakt goede ingenieurs die het juiste doen.
ESP draagt een volgnummer en de ontvanger houdt een replayvenster van standaard 64 pakketten op Cisco-platformen14. Prioriteer nu spraak op de verzendende router. Low latency queueing doet wat je vroeg en herschikt pakketten ten opzichte van de volgorde waarin ze versleuteld zijn. Valt een pakket bij aankomst buiten het venster, dan gooit de andere kant het weg als replay, en de teller die oploopt is een beveiligingsteller.
Cisco’s eigen woorden: “Certain QoS features, such as Low Latency Queueing (LLQ), could cause IPsec packet delivery to become out-of-order and dropped by the receiving endpoint due to a replay check failure.”14 Hun antwoord is het venster te verbreden naar 1024 waar het platform dat toelaat, of een uitbreiding met meerdere volgnummerruimtes te nemen die QoS-klassen op gescheiden volgnummerruimtes binnen één association afbeeldt14.
Dus: een standaardfunctie van je eigen netwerk aanzetten sloopt je eigen tunnel, en het middel is nog een protocoluitbreiding. Dezelfde vorm als alles hierboven.
L2TP: inbel-framing, versleuteld, in 2026
L2TP is geen beveiligingsprotocol en heeft dat nooit beweerd. RFC 2661 is een tunnelprotocol om PPP-sessies te vervoeren, gepubliceerd in 1999, zonder eigen vertrouwelijkheid — de eigen beveiligingsparagraaf verwijst je voor bescherming op pakketniveau naar IPsec15. Die koppeling is RFC 3193, en het resultaat is de stapel uit het diagram hierboven: een buitenste IP-header, een UDP-header voor NAT-traversal, ESP, dan binnen de versleuteling nog een UDP-header op poort 1701, een L2TP-header en een PPP-header.
PPP. De framing van inbelmodems, vervoerd in een versleutelde tunnel, over het internet, in 2026, omdat L2TP daar nu eenmaal voor geschreven is.
Reken uit wat dat kost aan een voorbeeld — buitenste IP 20, UDP 8, ESP-header en IV 24, binnenste UDP 8, L2TP 6, PPP 4, trailer en waarde 18 — en je geeft ongeveer 88 byte per pakket uit om gegevens te verplaatsen die natief ESP voor 54 verplaatst. Vierendertig byte, op elk pakket, voor een sessielaag die niets toevoegt wat je wilde en een verbindingslaag die voor een telefoonlijn ontworpen is.
De overhead is nog het minste.
Het vermenigvuldigt het NAT-probleem in plaats van het te delen. L2TP/IPsec gebruikt gewoonlijk ESP in transportmodus, de modus waar NAT het meeste pijn doet, en het bekende resultaat is dat veel implementaties twee clients achter één adres helemaal niet ondersteunen. Twee mensen in één huis, of veertig in één kantoor, of enkele honderden achter het gedeelde adres van een carrier. De andere kant ziet één adres en kan de sessies niet uit elkaar houden, dus vervangt de tweede verbinding de eerste. Dat is het ticket van bovenaan deze post, en het is in niemands product een fout — het is het identiteit-via-adres-probleem dat aankomt op de plek waar de meeste mensen het tegenkomen.
En in het veld wordt het meestal uitgerold met één gedeeld geheim voor iedereen. Doordat het geheim in het clientprofiel wordt gezet en met de installatie-instructies wordt uitgedeeld, staat de pre-shared key in het onboardingdocument, op de wikipagina, in de e-mail aan nieuwe collega’s, en op elke laptop die ooit het pand verliet. Het is geen tweede factor. Het is een wachtwoord dat de gateway tegenover niemand in het bijzonder authenticeert en dat nog nooit gewisseld is.
L2TP is geen protocol dat slecht verouderd is. Het is een protocol dat vanaf dag één het verkeerde vervoerde, en aan IPsec is vastgeschroefd om goed te maken wat het helemaal niet kon.
PPTP was nooit veilig, en wordt nog steeds verkocht
PPTP verdient twee alinea’s, geen hoofdstuk, en krijgt ze alleen omdat mensen het nog steeds uitleveren.
Het was nooit een standaard. RFC 2637 is Informational. Een opgeschreven leveranciersprotocol, niets dat de IETF ooit heeft aanbevolen. Het vervoert PPP in GRE, IP-protocol 47, dat net als ESP geen poorten heeft, dus het heeft in elke NAT op het pad een eigen uitzonderingsbehandeling nodig — het vinkje “PPTP passthrough”, dat op heel veel thuisrouters precies één sessie tegelijk ondersteunt.
De beveiliging eindigde publiekelijk in 2012. Marlinspike en Hulton lieten zien dat de beveiliging van MS-CHAPv2 zich ongeacht de wachtwoordlengte terugbrengt tot één DES-bewerking, bouwden chapcrack om de handshake eruit te halen, en koppelden dat aan een kraakdienst die de sleutel binnen een dag voor twintig dollar teruggaf — een slaagkans van 100 %, geen waarschijnlijkheid16. Hun conclusie was dat PPTP-verkeer als onversleuteld beschouwd moet worden. Apple stemde met de voeten en haalde PPTP in 2016 uit de ingebouwde client van macOS Sierra en iOS 10, en publiceert de waarschuwing nog steeds17.
Tien jaar later is PPTP nog altijd een menu-item op routers die dit jaar verkocht worden, nog altijd in handleidingen van leveranciers, nog altijd wat iemand aanzet omdat het de enige is die meteen werkt. Het werkt meteen omdat het de klus niet doet.
Alles wat zich IPsec-VPN noemt
“IPsec-VPN” is geen protocol. Het is een familie, en de lengte van de lijst hieronder is het argument, want geen twee producten implementeren dezelfde deelverzameling, en in de gaten tussen die deelverzamelingen woont elke interopklus die je ooit gehaat hebt.
| Onderdeel | Wat het toevoegt | Waar het staat |
|---|---|---|
| ESP, IP-protocol 50 | De versleuteling en integriteit zelf | RFC 4303 — actueel18 |
| AH, IP-protocol 51 | Integriteit ook over de IP-header | RFC 4302 — door NAT onbruikbaar2 |
| IKEv1 | De oorspronkelijke sleuteluitwisseling | Afgeschaft, RFC’s op Historic gezet19 |
| IKEv2 | De huidige sleuteluitwisseling | RFC 729620 |
| IPComp, IP-protocol 108 | Comprimeert voor het versleutelen, met eigen associations | RFC 317321 |
| PF_KEY v2 | Een kernel-API zodat een daemon de sleutels kan laden | RFC 236722 |
| NAT-traversal | Verpakt ESP in UDP 4500 zodat een vertaler ermee overweg kan | RFC 3947 / 39486 |
| TCP-encapsulatie | Voor netwerken die ook UDP blokkeren | RFC 9329, vervangt RFC 82293 |
| IKEv2-fragmentatie | Omdat de sleuteluitwisseling zelf de MTU ontgroeid is | RFC 738323 |
| MOBIKE | Zodat de tunnel een adreswisseling overleeft | RFC 455524 |
| Dead peer detection | Een hartslag, want verder zegt niets het je | RFC 370625 |
| XAUTH | Gebruikersauthenticatie — wachtwoord, token, RADIUS | Nooit een RFC. Verlopen concept, 200126 |
| Mode-Config | Geeft de client adres, DNS en routes | Ook nooit een RFC26 |
| L2TP/IPsec | Vervoert PPP in de tunnel | RFC 2661 + RFC 319327 |
| GRE of VTI over IPsec | Geeft je een routeerbare interface om een protocol op te draaien | Leveranciersarchitectuur op ESP |
| DMVPN | mGRE plus NHRP plus IPsec, zodat spokes elkaar vinden | Leveranciersarchitectuur, NHRP RFC 233228 |
| GETVPN | Groepssleutels, helemaal zonder tunnel per paar | GDOI, RFC 640729 |
| PPTP | Wat IPsec moest vervangen | RFC 2637 — Informational, nooit een standaard30 |
Kijk nu naar de twee vetgedrukte regels, want dat zijn de regels die je moeten tegenhouden.
Bijna twee decennia lang was de normale manier om een gebruiker op een zakelijk IPsec-VPN aan te melden XAUTH — je gebruikersnaam en wachtwoord, je token, je RADIUS-server — met Mode-Config dat de client zijn adres, DNS-servers en routes geeft. Samen zijn ze de hele ervaring van toegang op afstand. Elke “Cisco IPsec”-client, elk VPN-pictogram in een balk, elke aansluitinstructie.
Geen van beide is een standaard. XAUTH was een individueel internetconcept dat in 2001 verliep en gearchiveerd werd zonder ooit een RFC te worden26. De opgegeven reden is het lezen waard, want daar legt een commissie uit waarom het zijn werk niet wilde doen: het concept legt vast dat de IPSRA-werkgroep geen protocol zou aanvaarden dat ISAKMP of IKE uitbreidt, en dat de IPsec-werkgroep alles weigerde wat met toegang op afstand te maken had26. Het meest uitgerolde deel van het meest uitgerolde VPN-protocol bleef dus dakloos, werd toch door elke leverancier naar eigen lezing van een verlopen concept geïmplementeerd, en aan miljoenen gebruikers uitgeleverd.
IKEv2 heeft beide uiteindelijk rechtgezet, en dat mag gezegd worden: de authenticatie ging naar EAP en de configuratiepayloads voor de client kwamen in de kernspecificatie20. Maar lees de jaartallen. De meest gebruikte functie van het meest gebruikte VPN-protocol liep ongeveer een decennium op een verlopen concept voordat er überhaupt een standaard was, en de geïnstalleerde basis draaide daarna nog jaren door op de conceptversie. Een protocolfamilie krijgt geen krediet voor het uiteindelijk standaardiseren van het deel dat iedereen toch al gebruikte.
Dat is de familie die je draait. Een deel ervan is Standards Track en actueel. Een deel is Historic. Een deel is nooit iets geworden. En een product waarvan het datablad “IPsec-VPN” zegt, heeft je ongeveer niets verteld over welke van deze achttien dingen het kan — en daarom kost twee ervan aan elkaar knopen veertien dagen, een spreadsheet met proposals en een telefoontje naar iemand die het eerder gedaan heeft.
Het Fisher-Price OS (Windows) heeft nooit echt samengewerkt
Dit is het stuk waar iemand zegt dat het probleem eigenlijk Linux is, dus doen we het met bronnen.
Standaard verbindt de Windows-client helemaal niet met een IPsec-server die achter NAT staat. Niet “heeft moeite”. Weigert. De oplossing is een registerwaarde met de naam AssumeUDPEncapsulationContextOnSendRule onder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgent, op 1 gezet als de server achter een vertaler staat of op 2 als beide kanten dat doen, op elke client en op de server, gevolgd door een herstart31. Microsofts eigen woorden: “By default, Windows Vista and Windows Server 2008 don’t support Internet Protocol security (IPsec) network address translation (NAT) Traversal (NAT-T) security associations to servers that are located behind a NAT device.”31
Twee dingen daarover. Ten eerste heeft Microsoft de NAT-traversalstandaard die het weigert te gebruiken mede geschreven. Hun naam staat op RFC 3947 en RFC 39486. Ten tweede is de pagina die je zegt het register te bewerken voor het laatst herzien in februari 202631. Twintig jaar later is een registeringreep op elk eindpunt nog altijd het antwoord, en wordt het nog altijd als antwoord onderhouden.
En lees de zin die Microsoft er direct boven zet: “If you must use IPsec for communication, use public IP addresses for all servers that you can connect to from the Internet.”31
Dat is deze hele post, in de documentatie van de leverancier. Zet IPsec niet achter NAT. Geef elke machine een echt adres. Ze hebben het opgeschreven, en daarna heeft de branche twee decennia het tegenovergestelde gedaan en het verschil in rekening gebracht.
Bij NAT houdt het niet op. Lees wat een opensourcegateway moet vastleggen om een Windows-client te accepteren.
- Het gatewaycertificaat heeft een extended key usage nodig die hiervoor en voor niets anders bestaat. serverAuth, OID 1.3.6.1.5.5.7.3.1, plus IP Security IKE Intermediate, OID 1.3.6.1.5.5.8.2.232. Je CA moet geleerd worden een OID uit te geven waarvan de meeste gereedschappen nog nooit gehoord hebben, anders faalt de verbinding op een beleidsfout zonder bruikbare melding.
- Een tweede registerwaarde is nodig voordat de client fatsoenlijke cryptografie aanbiedt. strongSwan documenteert het toevoegen van
NegotiateDH2048_AES256onderRasman\Parametersom AES-256-CBC en een 2048-bits groep te krijgen33. Lees dat andersom, want zo telt het: zonder registeringreep is het standaardaanbod zwakker dan dat. - Door de server gestart hersleutelen wordt door clients achter NAT geweigerd, en de gedocumenteerde noodoplossing is hersleutelen op de gateway uit te zetten en de client te laten beginnen33.
- Standaard IKEv2-uitbreidingen ontbreken simpelweg — geen IKE-omleiding, geen meervoudige authenticatierondes33.
Niets daarvan is een fout van Linux. Elk punt is een opensourceproject dat opschrijft wat het moet doen om tegemoet te komen aan de lezing die één leverancier geeft aan een standaard die die leverancier mede geschreven heeft.
Dat is het patroon, en het is dertig jaar oud. PPTP was Microsofts protocol, als Informational opgeschreven en nooit gestandaardiseerd30. MS-CHAPv2 en MPPE waren Microsofts authenticatie en versleuteling, en beide zijn in het openbaar gebroken16. SSTP is een Microsoft-tunnel die niemand anders termineert. DirectAccess was IPsec, en was aan beide kanten Windows bij ontwerp — en is inmiddels afgeschaft en wordt verwijderd, waarbij klanten naar Always On VPN worden geduwd34. Geen daarvan is ooit een protocol geweest waarbij de rest van ons elkaar halverwege kon treffen. Het was een protocol waar je je bij aansloot, en draaide je aan beide kanten niet het juiste besturingssysteem, dan kreeg je de registeringreep, de rare OID en de pagina met noodoplossingen.
Dus zeg ik het onomwonden, het is tenslotte mijn blog. Het Fisher-Price OS (Windows) is in een open protocolstapel nooit een echte gelijke geweest, want daar was het nooit voor bedoeld. Het verbergt de machine voor de persoon die hem gebruikt, en wel als ontwerpdoel, en een stapel die je niet kunt zien is een stapel die je niet interoperabel kunt maken. Als dat het enige besturingssysteem is dat je ooit beheerd hebt, zullen de hoofdstukken hierboven over kerneltellers en meelezen op de lijn als een vreemde taal geklonken hebben, en dát is het gat — geen voorkeur, een gat.
Niets daarvan hoeft de lezer iets te kosten. Elke diagnose in deze post draait vanaf elke Unix in het netwerk, gericht op wat kapot is, en het maakt haar volstrekt niet uit wat er aan de andere kant draait. En als dat besturingssysteem het enige is dat je hebt, draagt het diagnosedeel hieronder ook zijn eigen gereedschap — de capture, de twee cmdlets en de foutcodes met wat elk daarvan werkelijk zegt. Een kapotte tunnel moet maandag toch gerepareerd worden. De vervanger waar ik aan het eind voor pleit heeft dan één client, die zich op elk platform hetzelfde gedraagt, dat platform inbegrepen — voor het eerst in dertig jaar geldt dat voor een VPN.
Het afschaffingsdossier leest als een overlijdensbericht
Zet de noodoplossingen opzij en lees gewoon wat de standaardisatieorganen deze familie door de jaren heen hebben aangedaan. Geen mening. Eisniveaus, in gepubliceerde RFC’s.
| Wat | Waar het nu staat | Bron |
|---|---|---|
| IKEv1 | Afgeschaft; RFC 2407, 2408 en 2409 op Historic gezet | RFC 9395, 202319 |
| DES in ESP | MUST NOT | RFC 82218 |
| 3DES in ESP | SHOULD NOT | RFC 82218 |
| HMAC-MD5-96 | MUST NOT | RFC 82218 |
| ESP samen met AH | NOT RECOMMENDED | RFC 82218 |
| ESP met alleen versleuteling | Onveilig aangetoond, en in 2007 in de praktijk gebroken | Degabriele en Paterson35 |
| IPsec op een IPv6-node | Van MUST naar SHOULD verlaagd | RFC 6434, 201136 |
| PPTP | Nooit een standaard; alleen Informational | RFC 263730 |
De één-na-laatste regel is die welke ik voor zou leggen aan iedereen die mij vertelt dat IPsec prima is en dat het netwerk het probleem is. IPv6 schreef IPsec oorspronkelijk voor — het was het beveiligingsverhaal, vastgelegd in de node requirements. In 2011 bedacht de IETF zich: “Previously, IPv6 mandated implementation of IPsec and recommended the key management approach of IKE. This document updates that recommendation by making support of the IPsec Architecture a SHOULD for all IPv6 nodes.”36
Zelfs de adresfamilie die IPsec alles teruggegeven zou hebben wat NAT wegnam, is vijftien jaar geleden opgehouden het te eisen. Dat is niet het netwerk dat IPsec in de steek laat. Dat zijn de mensen die het netwerk ontworpen hebben en besloten dat het het gebod niet verdiend had.
De complexiteit werd in 1999 gesignaleerd, schriftelijk
Niets hiervan is wijsheid achteraf, en juist dat maakt het het opschrijven waard.
In 1999 kregen Niels Ferguson en Bruce Schneier de opdracht IPsec te beoordelen. Hun rapport is kort, helder en de moeite waard om helemaal te lezen. Het opent met “IPsec was a great disappointment to us. Given the quality of the people that worked on it and the time that was spent on it, we expected a much better result.”37 Het benoemt de oorzaak: “Our main criticism of IPsec is its complexity. IPsec contains too many options and too much flexibility; there are often several ways of doing the same or similar things. This is a typical committee effect.”37
En het deed drie aanbevelingen die nu lezen als een lijst van dingen die toch gebeurd zijn, twintig jaar te laat en op de harde manier:
- Schaf de transportmodus af. “We therefore recommend that transport mode be eliminated.”37 De transportmodus is de modus die L2TP/IPsec gebruikt, en de modus waar NAT het meeste pijn doet.
- Schaf AH af. “We conclude that eliminating transport mode allows the elimination of the AH protocol as well, without loss of functionality.”37 NAT heeft het in plaats daarvan afgeschaft, om een slechtere reden.
- Sta versleuteling zonder authenticatie nooit toe. Ze waarschuwden dat beheerders “will be quite likely to configure ESP for only encryption, believing that it provides security” — ESP zeer waarschijnlijk alleen op versleuteling zouden zetten, in de overtuiging dat dat beveiliging oplevert37.
Acht jaar later hield dat laatste punt op een waarschuwing te zijn. Degabriele en Paterson publiceerden aanvallen die “break any RFC-compliant implementation of IPsec making use of encryption-only ESP” — elke RFC-conforme implementatie breken die ESP met alleen versleuteling gebruikt, uit louter de cijfertekst, en waarvoor niet meer nodig is dan verkeer meelezen en pakketten injecteren35. De voorspelling stond acht jaar in het publieke dossier en de standaard stond de configuratie nog steeds toe.
Het oordeel uit dat rapport van 1999 is de zin waar ik telkens op terugkom: “We have found serious security weaknesses in all major components of IPsec. As always in security, there is no prize for getting 90% right; you have to get everything right.”37
Nog twee gegevens, en dan laat ik het erbij.
Logjam, 2015. Het team erachter scande een steekproef van 1 % van IPv4 op IKE en vond dat 86,1 % van de IKEv1- en 91,0 % van de IKEv2-servers de 1024-bits Oakley-groep 2 ondersteunde, en dat 66,1 % van de geprofileerde IKEv1-servers die prefereerde. Hun conclusie: voorberekening tegen een tweede 1024-bits groep “would allow decryption of traffic to 66% of IPsec VPNs”, en de gepubliceerde inlichtingendocumenten over VPN-exploitatie zijn “consistent with having achieved such a break”38. Cryptografische wendbaarheid, waar IPsec het meeste van heeft, is de reden dat bijna iedereen vijftien jaar op dezelfde zwakke groep bleef zitten.
CVE-2016-1287. Een bufferoverloop in de IKEv1- en IKEv2-code op Cisco ASA, bereikbaar door geprepareerde UDP-pakketten te sturen, met code-uitvoering op afstand vóór authenticatie39. Denk aan waar die doos staat. Het is het apparaat dat je bewust aan het hele internet hebt blootgesteld, waarop het meest optierijke protocol van het hele park draait, met een fragmentassembler voor de parser, en dat de sleutels tot alles daarachter houdt. De complexiteit waar Ferguson en Schneier voor waarschuwden is geen abstractie. Het is aanvalsoppervlak, op de ene machine die je nergens achter kunt zetten.
Het diagnosticeren zolang je het nog draait
Je kunt dit niet vanmiddag allemaal uitzetten, dus hier is hoe je eraan werkt. Dit is de methode, in de volgorde die het minste kost, met wat elk resultaat werkelijk betekent.
Kijk eerst naar de lijn, niet naar de console
Beide consoles vertellen je wat ze geloven. De lijn vertelt je wat er gebeurd is. Eén opname aan de grens, dertig seconden, beantwoordt de eerste drie vragen tegelijk:
tcpdump -ni eth0 'udp port 500 or udp port 4500 or ip proto 50 or ip6 proto 50'
- Helemaal niets uitgaand — het probleem zit vóór IPsec: routering, beleid, of een hostfirewall. Stop met zoeken bij de cryptografie.
- Alleen uitgaand, niets terug — je pakketten gaan weg en hun antwoorden komen niet aan. Filtering onderweg, een dode peer, of de andere kant wijst stil af.
- UDP 500 beide kanten op maar 4500 verschijnt nooit — NAT-traversal is niet onderhandeld. Of een kant heeft het uit staan, of de detectie is mislukt.
- Protocol 50 op de lijn terwijl één kant achter NAT zit — de onderhandeling besloot dat er geen vertaler was terwijl die er wel is. Dat komt nooit meer goed.
De fout bij de sleuteluitwisseling lezen
IKEv2 vertelt je waarom het geweigerd heeft, en de notify-namen zijn specifiek genoeg om er alleen al op te diagnosticeren. Het helpt om eerst de vorm van de hele uitwisseling voor je te hebben, want elke notify hieronder hoort bij een bepaalde sport daarvan.
| Notify | Wat het werkelijk betekent | Waar je kijkt |
|---|---|---|
NO_PROPOSAL_CHOSEN | Geen van de aangeboden combinaties van cijfer/integriteit/DH/PRF is de andere kant acceptabel | Beide proposal-lijsten; verwacht aan één kant een afgeschaft algoritme |
INVALID_KE_PAYLOAD | Diffie-Hellman-groep komt niet overeen — jij bood één groep aan, hij wil een andere | De DH-groep, het eerste in het proposal |
AUTHENTICATION_FAILED | Sleutel, certificaat of identiteit fout — een afwijkende pre-shared key, een verlopen certificaat, of een ID dat de peer niet verwacht | De identiteit, niet alleen het geheim |
TS_UNACCEPTABLE | De traffic selectors overlappen niet — je vroeg subnetten te beschermen die de peer niet beschermt | De selectorconfiguratie aan beide kanten |
INVALID_SPI | Er kwam een pakket aan voor een association die niet meer bestaat, meestal na een eenzijdige herstart | Of één kant hersleuteld is of herstart |
Junipers handleiding voor fase 2 zegt over de meest voorkomende hetzelfde: “no proposal chosen” betekent dat het apparaat “did not accept any of the IKE Phase 2 proposals that the peer sent”, en de oplossing is een wederzijds acceptabel proposal en geen herhaalde herstart40.
Op strongSwan de toestand van alles in één commando:
swanctl --list-sas # what is established, and what it negotiated
swanctl --log # the negotiation as it happens
Op Cisco show crypto ikev2 sa en show crypto ipsec sa, met debug crypto ikev2 als het niet omhoog komt41. Op Junos show security ike security-associations en show security ipsec security-associations, met de onderhandeling in show log kmd-logs42.
Is NAT-traversal eigenlijk wel onderhandeld?
Dit is de controle die mensen overslaan, en hij verklaart een groot deel van “vanaf kantoor werkt het en van thuis niet”.
Elke kant stuurt hashes van de adressen en poorten waarvan hij denkt dat ze in het spel zijn. Komt de hash die de andere kant uit het ontvangen pakket berekent niet overeen met die jij stuurde, dan zit er een vertaler tussen, en gaan beide kanten over op UDP 4500. Faalt de detectie — één kant heeft traversal uit staan, of iets in het midden verminkt de uitwisseling — dan gaan beide kanten verder met kaal ESP, dat de vertaler niet overleeft.
Dus: zie poort 4500 in de opname, uit beide richtingen, of er vindt geen traversal plaats. Neem het woord van de console er niet voor aan.
Controleer daarna of de keepalive echt loopt en of het interval korter is dan waarop je carrier mappings laat verouderen. De standaard is twintig seconden6; de ondergrens van de standaard voor NAT-beheerders is twee minuten9; wat jouw specifieke carrier doet, zie je niet. Sterft de tunnel na inactiviteit en leeft hij op bij verkeer, dan is dit het elke keer.
De kerneltellers die bijna niemand leest
Onder Linux houdt de transformatielaag een volledige uitsplitsing van fouten bij, en dat is de snelste manier om van “het werkt niet” een concrete oorzaak te maken. De tellers zijn door de kernel zelf gedocumenteerd43.
cat /proc/net/xfrm_stat # error counters, by cause
ip -s xfrm state # per-SA packet and byte counters
ip xfrm policy # what should be protected, and in which direction
Het leest beter als pad dan als lijst. Het pakket gaat door vijf stadia, en elk daarvan heeft zijn eigen teller:
Kijk welke beweegt terwijl de storing optreedt:
| Teller | Beschrijving van de kernel | Wat het op de dag zelf betekent |
|---|---|---|
XfrmInNoStates | “No state is found i.e. Either inbound SPI, address, or IPsec protocol at SA is wrong” | Hun pakketten komen aan voor een association die jij niet hebt — meestal een eenzijdig hersleutelen of een herstart |
XfrmInStateSeqError | “Sequence error i.e. Sequence number is out of window” | Herschikking of gedoe met het replayvenster; zie het QoS-samenspel hierboven |
XfrmInStateProtoError | “Transformation protocol specific error e.g. SA key is wrong” | De sleutels lopen uiteen — de association overleefde een hersleuteling aan slechts één kant |
XfrmInTmplMismatch | “No matching template for states e.g. Inbound SAs are correct but SP rule is wrong” | De association klopt en het beleid niet |
XfrmInNoPols | “No policy is found for states e.g. Inbound SAs are correct but no SP is found” | Er komt beschermd verkeer aan waarvan niemand om bescherming vroeg |
XfrmOutPolBlock | “Policy discards” | Je gooit het zelf weg, met opzet, in het beleid |
XfrmOutNoStates | “No state is found” | Verkeer trof beleid zonder association om het te dragen — de tunnel kwam nooit op |
XfrmInTmplMismatch en XfrmInNoPols zijn de twee die je op het zicht moet kennen, want beide betekenen dat de cryptografie klopt en het beleid niet, en dat is het tegenovergestelde van waar iedereen het eerst kijkt.
Het zegt “up” en er beweegt niets
Beide kanten opgezet, geen verkeer. Lees de tellers per association in beide richtingen:
ip -s xfrm state
- Uitgaande bytes stijgen, inkomende vlak — je versleutelt en verstuurt, en er komt niets terug. Of jouw ESP bereikt hen niet, of dat van hen bereikt jou niet. Vraag de andere kant om hun uitgaande teller; stijgt die ook, dan sterven de pakketten onderweg en is de volgende vraag waar, en dat is een TTL-vraag en geen cryptovraag.
- Beide vlak — er wordt niets aan de tunnel aangeboden. Routering of beleid, geen IPsec. Bij route-based: controleer of de route echt naar de tunnelinterface wijst; bij policy-based: controleer de selectors.
- Beide stijgen, applicaties nog steeds stuk — het is de tunnel niet. Ga kijken wat er aan de overkant staat.
Junipers advies voor dit geval volgt hetzelfde instinct in hun taal: stijgt alleen de uitgaande pakketteller van de sessie, bevestig dan bij de peer of het verkeer überhaupt ontvangen wordt44.
Kleine dingen werken, grote blijven hangen
MTU. Het is altijd MTU. De test duurt tien seconden:
ping -M do -s 1400 10.0.0.1 # inside the tunnel, do-not-fragment set
ping -M do -s 1300 10.0.0.1 # step down until it succeeds
Waar het begint te lukken vertelt je de werkelijk bruikbare grootte. Laat TCP het daarna zelf uitzoeken door de aangekondigde segmentgrootte op het pad te klemmen in plaats van te hopen dat elke ICMP-fout de reis overleeft:
nft add rule inet filter forward tcp flags syn tcp option maxseg size set rt mtu
En los ook de onderliggende oorzaak op, en dat is bijna altijd een te brede ICMP-regel aan een grens ergens. Gooi echo weg als je wilt. Ik heb elders betoogd dat het dat verdient. Maar hou Fragmentation Needed en Packet Too Big. Die zijn het mechanisme, geen vriendelijkheid.
Het valt op de klok uit
Klok de storingen. Het interval benoemt de oorzaak vanzelf.
- Een vaste periode die overeenkomt met een ingestelde lifetime — hersleutelen. De association verloopt en de vervangende onderhandeling faalt of loopt in een race. Controleer de lifetimes aan beide kanten; afwijkende waarden zijn normaal en prima, maar een harde lifetime aan de ene kant die korter is dan de zachte van de andere levert precies dit op.
- Na een periode zonder verkeer, terug bij het eerste gebruik — een NAT-mapping is verlopen. Keepalive-interval, of het ontbreken ervan.
- Dead peer detection breekt hem af terwijl de verbinding in orde is — de sondes gaan verloren in plaats van dat de peer dood is, vaak omdat de sondes het enige verkeer zijn en de mapping allang weg is.
De tweede gebruiker gooit de eerste eruit
Twee peers bereiken de concentrator vanaf één adres en authenticeren zich als dezelfde identiteit. De gateway heeft de keuze tussen de oude association behouden en vervangen, en een gangbare standaard is vervangen. De tweede verbinding wint dus en de eerste sterft in stilte.
Geef elke peer een werkelijk unieke identiteit in plaats van een adres of een gedeelde naam, en stel de gateway zo in dat hij meerdere associations vanaf één adres behoudt in plaats van er één per peer aan te nemen. Test het dan op de enige manier die telt: twee clients, één adres, tegelijk. Heeft je acceptatietest nooit twee gebruikers achter één NAT gehad, dan heb je juist het geval niet getest waar de meeste van je gebruikers in zitten.
Dezelfde storingen, op het Fisher-Price OS (Windows)
Elke controle hierboven draait vanaf een Unix-machine, en als je er een in dat netwerk hebt, gebruik hem dan, want hij vertelt je sneller de waarheid en het kan hem niets schelen wat er aan de andere kant draait. Maar een hoop lezers hebben een client die niet verbindt, een besturingssysteem dat de machine bewust voor hen verbergt, en verder niets om naar te kijken. Dus hier dezelfde methode nog eens, in dezelfde volgorde, met het gereedschap dat dat systeem werkelijk meelevert.
Kijk naar de lijn. Er is geen tcpdump, maar er is een capture. Start hem verhoogd, reproduceer de storing, stop hem:
netsh wfp capture start cab=on file=ipsec
netsh wfp capture stop
Dat schrijft een .cab. Daarin zit het spoor van wat het filterplatform en de sleuteluitwisseling werkelijk deden terwijl het misging, en dat is meer dan een van beide consoles wil toegeven. Voor live meekijken in plaats van een archief schrijft dezelfde commandofamilie met file=- naar de console: netsh wfp show state “Displays the current state of WFP and IPsec”, en netsh wfp show ikeevents “Displays recent Internet Key Exchange (IKE) epoch events matching the specified parameters”, gefilterd op één peer45.
netsh wfp show state file=-
netsh wfp show ikeevents remoteaddr=203.0.113.5 file=-
show ikeevents is hier het dichtst bij het uitwisselingslogboek dat elke andere stack ongevraagd schrijft. Goed om te weten dat het er is. Anders geeft de interface je een getal van drie cijfers en verder niets, en zit je een sleuteluitwisseling te diagnosticeren op gevoel.
Lees de associaties, en lees ze allebei. De tegenhangers van ip -s xfrm state en swanctl --list-sas zijn twee cmdlets, en de scheiding daartussen is de hele diagnose:
Get-NetIPsecMainModeSA
Get-NetIPsecQuickModeSA
Main mode is de sleuteluitwisseling. Quick mode draagt de pakketten. Microsoft zegt het verband gewoon hardop: “There is only one main mode SA between a pair of computers, but there can be many quick mode SAs”46. Main mode aanwezig met quick mode leeg is dus dezelfde storing als een staande IKE_SA zonder CHILD_SA eronder, en het betekent hetzelfde: de twee kanten werden het eens over hoe ze praten en vervolgens niet over wat er beschermd wordt. Kijk naar de traffic selectors, niet naar de algoritmen.
Lees de logboeken, op de twee plekken waar ze zich verstoppen. Storingen op verbindingsniveau landen in het Toepassingenlogboek onder de bron RasClient, en Microsofts eigen opmerking over het lezen ervan is het nuttige deel: “All error messages return the error code at the end of the message”47. Dat getal is de diagnose, en de volgende sectie zegt wat de getallen betekenen. Beleids- en filterbeslissingen landen ergens heel anders, onder Logboeken van toepassingen en services, in de kanalen van Windows Firewall met geavanceerde beveiliging. Twee logboeken, twee teams, één storing.
Verzamel het netjes als je moet escaleren. Het ondersteunde pakket is TSS — TSS.ps1 -Scenario NET_VPN op de client, TSS.ps1 -Scenario NET_RAS op de server, gestart voordat je de storing reproduceert en daarna gestopt48. Leer het voordat iemand erom vraagt.
Als hij op Verbinden blijft staan en dan afloopt
Dit is de storing die de tickets vult, en het woord in de fout is een leugen. Begin met het benoemen van de code. De code is precies, ook als het bericht nergens op slaat.
| Code | Naam in raserror.h | Wat er werkelijk gebeurde |
|---|---|---|
| 809 | ERROR_VPN_TIMEOUT | Er kwam helemaal niets terug. De door Microsoft genoemde oorzaak: “the UDP 500 or 4500 ports on the VPN server or firewall are blocked”47 — maar blocked dekt drie verschillende dingen en maar één daarvan is een verbodsregel. Meestal is 4500 nooit verstuurd, omdat NAT-traversal nooit onderhandeld is, of staat de helper die het vroeger droeg uit. Lees verder voordat je om een firewallwijziging vraagt |
| 789 | ERROR_OAKLEY_GENERAL_PROCESSING | “The L2TP connection attempt failed because the security layer encountered a processing error during initial negotiations” — de inloggegevens of de certificaten, niet het netwerk |
| 718 | ERROR_PPP_TIMEOUT | Het IPsec-deel werkte. PPP in de L2TP-tunnel kreeg geen antwoord |
| 828 | ERROR_IDLE_TIMEOUT | “The connection was terminated because of idle timeout” — een instelling aan de serverkant, met opzet |
| 930 | ERROR_AUTH_SERVER_TIMEOUT | RADIUS antwoordde niet op tijd. Heeft niets met IPsec te maken |
| 638 | ERROR_REQUEST_TIMEOUT | De algemene. Behandel hem als geen informatie en ga naar de lijn |
Elk daarvan komt uit Microsofts eigen foutenlijst49. Lees 809 nu nog eens. Hij heet ERROR_VPN_TIMEOUT, en de gedocumenteerde oorzaak is een geblokkeerde poort. De client loopt niet af omdat de overkant traag is. Hij loopt af omdat de overkant stil is, en stilte is de enige storingsvorm die een protocol zonder poorten en zonder zichtbare handshake kan melden.
Wees wel voorzichtig met het woord blocked, want het draagt meer dan het aankan. Drie verschillende dingen dragen het, en maar één daarvan is een verbodsregel.
Er heeft nooit iemand 4500 gestuurd. NAT-traversal is niet onderhandeld, dus de client bleef ESP spreken, en ESP geeft een vertaler niets om te herschrijven. De standaardinstelling van dat platform is op zichzelf al genoeg reden: zonder de registerwaarde vormt het helemaal geen NAT-T-associatie met een server achter een vertaler31. 4500 is dus niet geblokkeerd. Het is nooit geprobeerd.
De helper die dat vroeger wegpoetste, staat uit. Firewalls en thuisrouters dragen helpers per protocol — IPsec passthrough op consumentenapparatuur, en de hele familie application-layer gateways erachter — die een protocol lezen dat NAT niet aankan en het pad terug ervoor openzetten. Op Linux is de automatische vorm daarvan vanaf kernel 4.7 standaard uitgezet “for security reasons”, met sindsdien het advies om een helper bewust met een regel aan te hangen of helemaal niet; onder de gedekte helpers zit die voor PPTP50.
En ze uitzetten was de juiste keuze. Een helper is een stuk van je firewall dat een payload leest en daarna op grond van wat het las een gat slaat. NAT Slipstreaming is de rekening daarvoor: een browser die een pagina bezoekt, verkeer zo gevormd dat de SIP- of H.323-helper van de router het als een gesprek leest, en een gat door de NAT — in de versie van 2021 naar elk intern adres, niet alleen naar de machine die de pagina laadde51. Helpers uitzetten sluit dat. Het legt ook je IPsec stil. Allebei waar tegelijk, en het tweede is geen argument om het eerste terug te draaien.
Wat opnieuw deze post in het klein is. Het protocol werkte alleen omdat kastjes in het midden verkeer lazen dat hen niet aanging en namens dat protocol gaten openzetten, en de branche heeft het afgelopen decennium volkomen terecht besloten daarmee te stoppen.
Werk de oorzaken dus in deze volgorde af, het goedkoopste eerst.
Eén: er komt niets terug. Capture aan de clientkant, of vraag het de gateway. Gaat UDP 500 eruit en komt er niets terug, dan is het filtering of bereikbaarheid, en geen enkele timer lost dat op. Gaat 500 beide kanten op en verschijnt 4500 nooit, dan is NAT-traversal niet onderhandeld. En zit een van beide kanten achter een vertaler, dan ben je terug bij de registerwaarde van eerder in deze post: AssumeUDPEncapsulationContextOnSendRule, 1 of 2, op beide machines, daarna opnieuw opstarten31. Zonder die waarde weigert de client bij ontwerp, en meldt dat als een time-out.
Twee: het antwoord is te groot om aan te komen. Deze kost hele middagen. Certificaatauthenticatie maakt de tweede uitwisseling groot, want die draagt een keten, en een grote uitwisseling fragmenteert. De fragmenten worden weggegooid door dezelfde tussenkastjes als al het andere in deze post, de client verstuurt opnieuw in hetzelfde gat, en dan geeft hij het op en zegt time-out. Het teken is op zichzelf al de diagnose: een vooraf gedeelde sleutel verbindt wel en een certificaat niet. Dat is geen certificaatstoring. Dat is een groottestoring, want de uitwisseling met een vooraf gedeelde sleutel is klein genoeg om te passen. Gestandaardiseerde IKEv2-fragmentatie bestaat precies hiervoor23, en strongSwan legt vast wanneer dit platform het kreeg: “IKEv2 fragmentation is supported since the v1803 release of Windows 10 and Windows Server”33. Iets ouders, of een gateway met fragmentatie uit, en je vertrouwt op een pad dat een gefragmenteerd UDP-datagram draagt. Een hoop paden doen dat niet.
Drie: hij verbindt en valt dan op de klok uit. Klok het. Sterft hij na een vaste periode zonder verkeer, dan is dat 828 en is het configuratie, geen storing — -IdleDisconnectSeconds op de server, met -SALifeTimeSeconds, -MMSALifeTimeSeconds en -SADataSizeForRenegotiationKilobytes als de drie andere klokken die een sessie kunnen beëindigen52. Die laatste beëindigt hem op volume in plaats van op tijd, en daarom kan een sessie betrouwbaar sterven tijdens een grote bestandskopie en nooit tijdens een dag e-mail. En sterft hij bij het hersleutelen met de client achter NAT, dan is dat de gedocumenteerde interop-storing van eerder: de client weigert een door de server gestart hersleutelen met Microsoft-fout 13863, en het antwoord aan de gatewaykant is ermee ophouden en de client het laten doen33.
Vier: het is de tunnel helemaal niet. 930 is RADIUS. 812 is een authenticatiemethode die de server niet accepteerde47. 13801 en 13806 zijn certificaten — verkeerd uitgebreid sleutelgebruik, verlopen, ontbrekende root, of een servernaam die niet bij het onderwerp van het certificaat past47. De tunnelonderhandeling was in alle vier de gevallen in orde, en als je de middag aan algoritmen besteedt vind je er geen enkele van.
Dit is wat je uit die tabel mee moet nemen. Zes foutcodes, vijf ervan met het woord timeout in de naam, en geen enkele is werkelijk een time-out. Het zijn een geblokkeerde poort, een verloren fragment, een beleidsbeslissing en een RADIUS-server, allemaal met hetzelfde woord om, want de laag die de storing meldt ziet te weinig van wat er gebeurde om iets nuttigers te zeggen. De timer verlengen lost er geen een op, en de timer verlengen is precies waar de interface je toe uitnodigt.
Wat je in plaats daarvan moet draaien
Ik ga niet doen alsof de vervanger exotisch is. Hij zit in de kernel en dat al jaren.
WireGuard is één UDP-poort, één sleutel per peer, geen onderhandeling over cijfers en helemaal geen protocolwendbaarheid. Het standpunt van de auteur daarover is bewust en uitgesproken: “It intentionally lacks cipher and protocol agility. If holes are found in the underlying primitives, all endpoints will be required to update. As shown by the continuing torrent of SSL/TLS vulnerabilities, cipher agility increases complexity monumentally.”53 Die ene beslissing schrapt NO_PROPOSAL_CHOSEN, INVALID_KE_PAYLOAD, downgrade-aanvallen en de bevinding van Logjam in één keer, want er valt niets te onderhandelen en niets te verlagen.
Het is ook eerlijk over de prijs, en ik ook: geen wendbaarheid betekent dat je op de dag dat een primitief valt de hele vloot bijwerkt in plaats van één configuratieregel om te zetten. Dat zijn echte beheerkosten en het zijn de juiste om te betalen.
De rest sluit bijna punt voor punt aan op de lijst hierboven. Een UDP-poort hebben betekent dat NAT en CGNAT het als elke andere stroom behandelen, en dat ECMP en link aggregation het als elke andere stroom hashen. Roaming is ingebouwd in plaats van erop geschroefd — een geauthenticeerd pakket van een nieuw adres verplaatst het eindpunt van de peer, dus een telefoon die van wifi naar mobiel gaat onderhandelt niets opnieuw. Op een niet-geauthenticeerd pakket antwoordt het niets, dus een scanner vindt een gesloten poort waar IPsec hem een concentrator zou bieden om mee te praten. En het past in minder dan 4.000 regels code53, tegenover een stapel die een heel document nodig heeft om zijn zestien onverenigbaarheden met één tussendoos op te sommen.
Qua prestaties mat het simpelweg sneller dan beide IPsec-configuraties waartegen het getest werd: 1.011 Mbit/s tegen 881 en 825, met lagere latentie53. Ik zou een protocol niet uitfaseren op grond van een benchmark. Ik noem het omdat het laatste argument dat voor IPsec overblijft meestal prestaties is, en dat klopt ook niet.
Om een persoon bij een applicatie te krijgen — in plaats van een netwerk bij een netwerk — is het antwoord helemaal geen tunnel. Identiteit aan de voordeur, de applicatie daardoorheen gepubliceerd, niets gerouteerd. Dat heb ik met Proxmox en Cloudflare Access uitgebouwd in Zero-Trust-VDI zonder de cloudrekening, en het relevante punt hier is dat wie drie interne applicaties nodig heeft geen route naar je hele park nodig heeft.
En zeg het stille deel hardop over hardware. Ja, er zijn netwerkkaarten en ASIC’s met ESP-offload, en dat is een echt argument voor IPsec op specifieke apparatuur bij specifieke snelheden. Het is een argument over silicium dat iemand je al verkocht heeft, niet over de juistheid van het protocol. Als zodanig veroudert het, en snel. PPTP heeft precies zo overleefd, precies zolang als het vinkje bestond.
Het netjes uitfaseren
Uitfaseren is een plan met datums, geen gevoel. Dit is het plan waar ik mijn naam aan zou verbinden.
Stop nu met nieuwe IPsec-uitrollen. Niet “alternatieven verkiezen”. Stoppen. Elke nieuwe tunnel is een tunnel die iemand later moet migreren, en die vandaag gebouwd worden draaien in 2035 nog steeds als niemand deze week nee zegt.
Doe toegang op afstand eerst, want daar komt elke storing uit deze post het hardst aan: het CGNAT, het gedeelde adres, de keepalives, de tweede gebruiker in hetzelfde huis, het MTU-gat op een willekeurig hotelnetwerk. Het is ook het makkelijkst te verplaatsen, want de eindpunten worden beheerd en de wijziging is een client.
Daarna site-to-site over het publieke internet, dezelfde problemen met minder eindpunten en een onderhoudsvenster.
Bewaar voor het laatst de tunnels waarvan je niet beide kanten bezit: een partner, een toezichthouder, de managed service van een carrier. Die bewegen als het contract beweegt, en hoe je ze in beweging krijgt staat in het volgende punt.
Koop geen apparatuur meer waarvan de enige tunnel IPsec is. Zet het in de aanbesteding. Een regel die om een moderne, poortgebaseerde, roamingvaste tunnel vraagt, is een regel die een leverancier beantwoordt of niet, en zo verliest het argument van de geïnstalleerde basis uiteindelijk. Dat argument is het enige dat dit alles in leven houdt, en het wordt alleen door inkoop verslagen.
Schrijf op welke tunnels er over zijn en waarom, en zet op elk een datum. Een protocol waar tien jaar niemand van was, is hoe PPTP tot 2026 gekomen is. Een inventarisatie met datums is het verschil tussen iets uitfaseren en het alleen maar niet leuk vinden.
Als je het nog steeds uitrolt, mag je jezelf dan IT-professional noemen?
Dat is een echte vraag, en ik ga hem eerlijk beantwoorden, want het is de vraag waar de rest van deze post naartoe loopt.
Het hangt af van of je het weet. En weten overkomt je niet. Zorgen dat je het weet, is het werk.
Als je dit jaar een nieuwe IPsec-toegang op afstand neerzet en je kunt niet uit je hoofd zeggen waarom ESP geen poorten heeft, wat een woonlijn achter carrier-grade NAT ermee doet, waarom een NAT64-netwerk het helemaal niet draagt, of waar dat ene byte per twintig seconden eigenlijk voor is — dan nee. Hierin niet, nog niet. Je kiest geen protocol. Je herhaalt een vorm, want de vorige zag er zo uit en niemand in de kamer vroeg waarom — jij ook niet. Het falen is niet het gat. Iedereen heeft gaten. Het falen is bouwen over een gat dat je nooit bent gaan dichten. Als zodanig krijgt degene die het in 2035 erft een decennium aan tickets die allemaal te vermijden waren op de dag dat jij het tekende.
En ik geef het de juiste naam, want de beleefde versie gaat al twintig jaar rond en heeft niets veranderd. Wie een protocol uitrolt dat hij niet kan uitleggen, is geen engineer. Die is een volger. Die leest kaartjes voor — de referentiearchitectuur van de leverancier, het laatste wijzigingsverzoek, een tekening die iemand in 2014 maakte en die sindsdien niemand heeft geopend — en leest ze voor met echte overtuiging, en achter het optreden zit geen begrip. Van buiten ziet dat er precies uit als vakmanschap. Het blijft er ook precies uitzien als vakmanschap, tot de eerste storing die de kaartjes niet dekken, en vanaf dat moment is het het enige in de kamer dat ertoe doet.
De kaartjes zijn ook de reden dat dit protocol er nog is. Niemand stond in 2026 bij een whiteboard IPsec inhoudelijk te verdedigen. Het werd opnieuw uitgerold omdat het op het kaartje stond, en het kaartje is geschreven door een leverancier wiens belang is dat je de doos blijft kopen die het termineert. Zo overleeft iets zijn eigen overlijdensbericht met twintig jaar — niet door verdedigd te worden, maar door zich nooit één keer te hoeven verantwoorden in een kamer waar iemand het verschil zou merken.
En dit wordt hardop gezegd. In de kamer, op het moment zelf — niet achteraf op de gang gemompeld. Wie het woord professional naast zijn naam zet, krijgt met dat woord de uitnodiging om bevraagd te worden, en vragen is niet onbeleefd. Bevraagd worden en een antwoord hebben is het hele verschil tussen het woord en een visitekaartje.
Het telt het zwaarst als je ervoor betaalt. Een adviesbureau, een MSP, de professional-services-tak van een leverancier, de integrator op het raamcontract — wat je koopt is oordeelsvermogen, en oordeelsvermogen is het enige dat je bij levering niet kunt keuren. Keur het dus vooraf. Vraag waarom dit protocol en niet een ander. Vraag wat ermee gebeurt op een lijn achter carrier-grade NAT, op een IPv6-only mobiel netwerk, op een pad dat stilletjes fragmenten weggooit. Vraag welke daarvan ze zelf hebben meegemaakt en wat ze toen deden. Je weet binnen twee minuten of je iets verteld krijgt of wordt voorgelezen, en twee minuten is een flink goedkopere test dan vier jaar tickets. En als het antwoord uit kaartjes bestaat en je tekent toch, dan is dat ook een besluit — het is alleen net van hen naar jou verhuisd.
Kun je dat allemaal wél zeggen en rol je het toch uit omdat een toezichthouder het bij naam voorschrijft, omdat de apparatuur van de partner niets anders termineert, of omdat de vervanger in het budget van volgend jaar staat en dit in maart moet werken — dan ja, uiteraard, en dan doe je je werk goed. Randvoorwaarden zijn echt, en ik heb om ergere heen gebouwd. Wat de twee scheidt is niet het protocol op de tekening. Het is of je hebt opgeschreven waarom, en of er een datum naast staat.
De onverdedigbare positie is de middelste. Genoeg weten om er ongemakkelijk van te worden, en het toch bouwen omdat niemand je dwong het te verantwoorden. Geen engineering. Gewoonte, met een wijzigingsnummer erop — en precies zo belandde L2TP op een datasheet die dit jaar gedrukt is.
Stel jezelf die vraag dus vóór de aanbesteding sluit, niet erna. Professional is geen woord over welke protocollen je kent. Het is een woord over of je het gekozen protocol hardop kunt verdedigen, tegenover iemand die de storingsvormen kent. Kun je dat, rol dan uit wat de randvoorwaarden eisen en slaap prima. Kun je dat niet, dan heb je net gevonden wat je vanavond gaat lezen, en dat is geen belediging. Iedereen was ooit een volger, zonder uitzondering, ik ook. Wat niet te verdedigen is, is ervoor kiezen er een te blijven en dat een loopbaan noemen.
Een goed idee mag ook voorbij zijn
Ik wil recht doen aan IPsec, want dat verdient het.
Het was het juiste instinct. Beveiliging hoort laag in de stapel, waar alles het erft en geen enkele applicatie vertrouwd hoeft te worden om het goed te doen. De association aan het adres binden was in 1995 geen fout — het adres was de machine, en daarop bouwen was juist. De mensen die het schreven waren serieuze mensen met een echt probleem, en uitgerekend het WireGuard-artikel zegt het het best: de gelaagdheid van IPsec is deugdelijk, alles zit op de juiste plek, tot academische perfectie toe53.
En toen bewoog de grond. Niet omdat IPsec iets fout deed, maar omdat deze branche besloot dat adressen een te beheren kostenpost waren in plaats van iets dat elke machine krijgt, en vijfentwintig jaar vertaling bouwde om het alternatief te ontlopen. IPsec werd stilletjes het fundament ontnomen, en in plaats van dat toe te geven hebben we ondersteund. UDP-encapsulatie. Toen keepalives. Toen TCP-encapsulatie voor de netwerken die UDP blokkeren. Toen nog een UDP-header zodat een router iets vindt om op te hashen. Elke oplossing op zich redelijk; de stapel ervan is een protocol dat overeind wordt gehouden door mensen die betaald worden om het overeind te houden.
Dat is het deel dat woede verdient, en het gaat eigenlijk helemaal niet over IPsec. Onze branche is heel goed in dingen onderhouden en heel slecht in ze beëindigen. Onderhoud is factureerbaar, begroot, bemenst en veilig. Uitfaseren is een beslissing die iemand moet tekenen, met zijn naam eronder, en zonder directe beloning. Dus leefde PPTP veertien jaar voort na het bewijs van zijn waardeloosheid, wordt L2TP nog steeds geleverd op dozen die dit jaar verkocht worden, en bleef IKEv1 nog een decennium na zijn Historic-status tunnels onderhandelen. Niet omdat iemand ze verdedigde. Maar omdat niemand ooit verplicht was ze te beëindigen.
Er is geen prijs voor 90 % goed. Ferguson en Schneier schreven dat in 1999 over IPsec, en wat er sindsdien gebeurd is, zijn dertig jaar waarin de branche de laatste 10 % elke keer op een nieuwe manier fout deed en de pleister een oplossing noemde.
Een goed idee mag ook voorbij zijn. Weten wanneer je moet ophouden iets te onderhouden is een vaardigheid, en het is die waarin dit vak het slechtst is. Iemand moet degene zijn die zegt dat een protocol zijn leven gehad heeft, de datum opschrijft en de gevolgen draagt van degene te zijn geweest die het zei. Anders sturen we in 2040 nog elke twintig seconden een pakket van één byte, om een tabel warm te houden in een doos die niet van ons is, op een netwerk dat ons onze adressen afnam en ons ervoor liet betalen.
RFC 4301 — Security Architecture for the Internet Protocol, december 2005. Definieert de security association en het drietal waarop hij wordt opgezocht: bestemmingsadres, beveiligingsprotocol en SPI. ↩︎ ↩︎
RFC 4302 — IP Authentication Header, december 2005. De integriteitscontrole van AH dekt de onveranderlijke velden van de IP-header, bron- en bestemmingsadres inbegrepen. ↩︎ ↩︎
RFC 9329 — TCP Encapsulation of Internet Key Exchange Protocol (IKE) and IPsec Packets, november 2022, vervangt RFC 8229. Bestaat omdat tussendozen op publieke netwerken UDP blokkeren. ↩︎ ↩︎ ↩︎
RFC 3715 — IPsec-Network Address Translation (NAT) Compatibility Requirements, maart 2004. Zestien opgesomde onverenigbaarheden, waaronder: “Since the AH header incorporates the IP source and destination addresses in the keyed message integrity check, NAT or reverse NAT devices making changes to address fields will invalidate the message integrity check.” en “Where IP addresses are used as identifiers in Internet Key Exchange Protocol (IKE) Phase 1 or Phase 2, modification of the IP source or destination addresses by NATs or reverse NATs will result in a mismatch between the identifiers and the addresses in the IP header.” ↩︎ ↩︎ ↩︎
Cisco — Configuring IPsec NAT-Traversal, Security Configuration Guide, Cisco IOS XE 17.15.x (Catalyst 9300 Switches). “If PAT found a legislative IP address and port, it would drop the Encapsulating Security Payload (ESP) packet”; de UDP-header en een acht byte lange niet-IKE-markering worden tussen de buitenste IP-header en de ESP-header gezet; de beperkingenlijst noemt statische regels voor poort 500 en 4500, geen ondersteuning voor dynamisch NAT-beleid, geen IPv6, en dat IPsec en NAT niet allebei op hetzelfde apparaat kunnen werken. ↩︎ ↩︎ ↩︎ ↩︎
RFC 3948 — UDP Encapsulation of IPsec ESP Packets, januari 2005, met de onderhandeling in RFC 3947. Definieert de keepalive als “a one-octet-long payload with the value 0xFF”, verstuurd “if no other packet to the peer has been sent in M seconds. M is a locally configurable parameter with a default value of 20 seconds.”, en eist dat de UDP-checksum op nul gaat: “If the protocol header after the ESP header is a UDP header, set the checksum field to zero in the UDP header.” Microsoft, Cisco, F-Secure, Nortel en SafeNet staan allemaal op de auteurslijsten van RFC 3947 en RFC 3948. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Juniper — Route-Based and Policy-Based VPNs with NAT-T, Junos OS IPsec VPN User Guide. “NAT-T encapsulates both IKE and ESP traffic within UDP with port 4500 used as both the source and destination port”; “Because NAT devices age out stale UDP translations, keepalive messages are required between the peers”; en op SRX5400, SRX5600 en SRX5800: “the total number of tunnels from a given public translated IP cannot exceed 1000 tunnels.” ↩︎ ↩︎ ↩︎
RFC 8221 — Cryptographic Algorithm Implementation Requirements and Usage Guidance for ESP and AH, oktober 2017. ENCR_DES MUST NOT, ENCR_3DES SHOULD NOT, AUTH_HMAC_MD5_96 MUST NOT; ESP samen met AH is NOT RECOMMENDED. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
RFC 4787 — Network Address Translation (NAT) Behavioral Requirements for Unicast UDP, januari 2007. REQ-5: “A NAT UDP mapping timer MUST NOT expire in less than two minutes”, met “a default value of five minutes or more for the NAT UDP mapping timer is RECOMMENDED”. ↩︎ ↩︎
RFC 6146 — Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers, april 2011. “The current specification only defines how stateful NAT64 translates unicast packets carrying TCP, UDP, and ICMP traffic. Multicast packets and other protocols, including the Stream Control Transmission Protocol (SCTP), the Datagram Congestion Control Protocol (DCCP), and IPsec, are out of the scope of this specification.” Pakketten met iets anders “SHOULD be discarded”. ↩︎ ↩︎
RFC 6877 — 464XLAT: Combination of Stateful and Stateless Translation, april 2013. Geeft een IPv6-only-apparaat een lokale IPv4-stack zodat verkeer werkt dat NAT64 niet kan dragen. ↩︎
IETF — draft-xu-ipsecme-esp-in-udp-lb, Encapsulating IPsec ESP in UDP for Load-balancing. “Although the ESP SPI field within the IPsec packets can be used as the load-balancing key, but it cannot be used by legacy switches and routers”; “Many cloud service providers allow customers to establish multiple IPsec VPN tunnels in parallel to enable ECMP and increase aggregate bandwidth. However, this approach is not ideal, as each tunnel typically requires its own public IP address, leading to higher public IP consumption and increased operational overhead.” ↩︎ ↩︎
Cisco — Resolve IPv4 Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPsec. De al lang onderhouden referentie over tunneloverhead, path MTU discovery en wat er stukgaat als de ICMP-fouten niet terugkomen. ↩︎
Cisco — Troubleshoot IPsec Anti-Replay Check Failures. “Certain QoS features, such as Low Latency Queueing (LLQ), could cause IPsec packet delivery to become out-of-order and dropped by the receiving endpoint due to a replay check failure.” Standaardvenster 64 pakketten; 1024 op nieuwere platformen; het andere middel zijn meerdere volgnummerruimtes per association. ↩︎ ↩︎ ↩︎
RFC 2661 — Layer Two Tunneling Protocol “L2TP”, augustus 1999. Een tunnelprotocol voor PPP zonder eigen vertrouwelijkheid op pakketniveau; de beveiligingsparagraaf verwijst naar IPsec. ↩︎
Moxie Marlinspike en David Hulton — Divide and Conquer: Cracking MS-CHAPv2 with a 100% Success Rate, 2012; gereedschap op github.com/moxie0/chapcrack. De beveiliging van MS-CHAPv2 brengt zich ongeacht de wachtwoordlengte terug tot één DES-bewerking; verslag uit die tijd in The Register. Hun conclusie was PPTP-verkeer als onversleuteld te beschouwen. ↩︎ ↩︎
Apple — If you see a “VPN Using PPTP May Not Be Secure” alert. PPTP is in 2016 uit de ingebouwde client van macOS Sierra en iOS 10 gehaald. ↩︎
RFC 4303 — IP Encapsulating Security Payload (ESP), december 2005. IP-protocol 50; de ESP-header draagt de SPI en het volgnummer en heeft geen poortveld. ↩︎
RFC 9395 — Deprecation of the Internet Key Exchange Version 1 (IKEv1) Protocol and Obsolete Cryptographic Algorithms, april 2023. “Internet Key Exchange Version 1 (IKEv1) has been deprecated, and RFCs 2407, 2408, and 2409 have been moved to Historic status.” ↩︎ ↩︎
RFC 7296 — Internet Key Exchange Protocol Version 2 (IKEv2), oktober 2014. De huidige sleuteluitwisseling, en de bron van de notify-namen in de diagnosetabel. ↩︎ ↩︎
RFC 3173 — IP Payload Compression Protocol (IPComp), september 2001. Een eigen IP-protocolnummer en eigen associations, naast ESP onderhandeld. ↩︎
RFC 2367 — PF_KEY Key Management API, Version 2, juli 1998. De kernelinterface waarmee een sleuteldaemon associations installeert. ↩︎
RFC 7383 — IKEv2 Message Fragmentation, november 2014. “This document describes a way to avoid IP fragmentation of large Internet Key Exchange Protocol version 2 (IKEv2) messages.” ↩︎ ↩︎
RFC 4555 — IKEv2 Mobility and Multihoming Protocol (MOBIKE), juni 2006. Laat een opgezette tunnel een adreswisseling overleven. ↩︎
RFC 3706 — A Traffic-Based Method of Detecting Dead Internet Key Exchange (IKE) Peers, februari 2004. ↩︎
draft-beaulieu-ike-xauth — Extended Authentication within IKE (XAUTH). Laatste revisie 02, oktober 2001, status Expired, “Expired & archived”, nooit als RFC gepubliceerd. Het concept legt vast dat het als Informational werd aangeboden omdat “the IPSRA working group will not accept any protocol which extends ISAKMP or IKE, and the IPsec working group refuses to accept any protocols that deal with remote access.” Mode-Config onderging hetzelfde lot. ↩︎ ↩︎ ↩︎ ↩︎
RFC 3193 — Securing L2TP using IPsec, november 2001. Mede geschreven bij Microsoft. ↩︎
RFC 2332 — NBMA Next Hop Resolution Protocol (NHRP), april 1998. Het stuk waarmee DMVPN-spokes elkaar vinden. ↩︎
RFC 6407 — The Group Domain of Interpretation, oktober 2011. Groepssleutels, zoals GETVPN ze gebruikt. ↩︎
RFC 2637 — Point-to-Point Tunneling Protocol (PPTP), juli 1999. Categorie: Informational. Een opgeschreven leveranciersprotocol, nooit een standaard. ↩︎ ↩︎ ↩︎
Microsoft — Configure L2TP/IPsec server behind NAT-T device, KB 926179, voor het laatst herzien op 12 februari 2026. “By default, Windows Vista and Windows Server 2008 don’t support Internet Protocol security (IPsec) network address translation (NAT) Traversal (NAT-T) security associations to servers that are located behind a NAT device”; de DWORD-waarde
AssumeUDPEncapsulationContextOnSendRuleonderHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgentneemt 0 (standaard, kan niet), 1 (server achter NAT) of 2 (beide kanten achter NAT), en de machine moet herstarten. Ook: “If you must use IPsec for communication, use public IP addresses for all servers that you can connect to from the Internet.” ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎strongSwan — Windows Certificate Requirements. Het gatewaycertificaat heeft de EKU serverAuth nodig, OID 1.3.6.1.5.5.7.3.1, en de EKU IP Security IKE Intermediate, OID 1.3.6.1.5.5.8.2.2. ↩︎
strongSwan — Windows Clients. Documenteert het toevoegen van de DWORD
NegotiateDH2048_AES256onderRasman\Parametersvoor AES-256-CBC en MODP-2048; de hersleutel-noodoplossing voor clients achter NAT (rekey_time = 0op de gateway, de client begint); en dat de Windows-client “does not currently support IKE redirection (RFC 5685) and multiple authentication rounds (RFC 4739)”. Daarnaast: “IKEv2 fragmentation is supported since the v1803 release of Windows 10 and Windows Server”, en clients achter NAT weigeren een door de server gestarte CHILD_SA-hersleuteling met Microsoft-fout 13863. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎Microsoft — DirectAccess en Remote Access Always On VPN migration overview. DirectAccess is afgeschaft en wordt in een toekomstige versie van Windows Server verwijderd; klanten worden naar Always On VPN verwezen. ↩︎
Jean Paul Degabriele en Kenneth G. Paterson — Attacking the IPsec Standards in Encryption-only Configurations, IEEE Symposium on Security and Privacy, 2007. Aanvallen die “break any RFC-compliant implementation of IPsec making use of encryption-only ESP”, uit louter de cijfertekst, en die niet meer vergen dan verkeer meelezen en pakketten injecteren. ↩︎ ↩︎
RFC 6434 — IPv6 Node Requirements, december 2011. “Previously, IPv6 mandated implementation of IPsec and recommended the key management approach of IKE. This document updates that recommendation by making support of the IPsec Architecture [RFC4301] a SHOULD for all IPv6 nodes.” ↩︎ ↩︎
Niels Ferguson en Bruce Schneier — A Cryptographic Evaluation of IPsec, Counterpane Internet Security, 1999. “IPsec was a great disappointment to us”; “Our main criticism of IPsec is its complexity”; “We therefore recommend that transport mode be eliminated”; “We conclude that eliminating transport mode allows the elimination of the AH protocol as well, without loss of functionality”; en “We have found serious security weaknesses in all major components of IPsec. As always in security, there is no prize for getting 90% right; you have to get everything right.” ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
David Adrian e.a. — Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice, ACM CCS 2015. Voorberekening voor een tweede 1024-bits groep “would allow decryption of traffic to 66% of IPsec VPNs”; 86,1 % van de gescande IKEv1- en 91,0 % van de IKEv2-servers ondersteunde Oakley-groep 2, en 66,1 % van de geprofileerde IKEv1-servers prefereerde die. ↩︎
CVE-2016-1287 en Cisco’s advisory, Cisco ASA Software IKEv1 and IKEv2 Buffer Overflow Vulnerability. Code-uitvoering op afstand vóór authenticatie, bereikt met geprepareerde UDP-pakketten naar de IKE-dienst. ↩︎
Juniper — How to Analyze IKE Phase 2 VPN Status Messages. “No proposal chosen” betekent dat het apparaat “did not accept any of the IKE Phase 2 proposals that the peer sent”. ↩︎
Cisco — Understand and Use Debug Commands to Troubleshoot IPsec en Troubleshoot Common L2L and Remote Access IPsec VPN Issues. ↩︎
Juniper — Troubleshoot a VPN Tunnel That is Down. ↩︎
Linux-kernel — XFRM proc counters. De beschrijvingen in de tabel komen uit de kerneldocumentatie zelf. ↩︎
Juniper — Troubleshoot a VPN That Is Up But Not Passing Traffic. “If only the
pktscounter in the out direction of the session is incrementing, then validate with the VPN peer that the traffic is being received.” ↩︎Microsoft —
netsh wfp, Windows Commands.netsh wfp capture start“Starts a capture session for network events processed by WFP” en schrijft standaardwfpdiag.cab;netsh wfp show state“Displays the current state of WFP and IPsec”;netsh wfp show ikeevents“Displays recent Internet Key Exchange (IKE) epoch events matching the specified parameters” en accepteert een filterremoteaddr=. Metfile=-schrijft elkeshownaar de console in plaats van XML. ↩︎Microsoft —
Get-NetIPsecQuickModeSA, module NetSecurity. “There is only one main mode SA between a pair of computers, but there can be many quick mode SAs”, en het monitoren ervan “can provide information about which peers are currently connected to this computer, and which protection suite is protecting the data exchanged between them”. ↩︎Microsoft — Troubleshoot Always On VPN, laatst herzien op 12 februari 2026. Over het lezen van de clientlogboeken: “look for events labeled RasClient. All error messages return the error code at the end of the message.” Oorzaak van fout 809: “You can encounter this issue when the UDP 500 or 4500 ports on the VPN server or firewall are blocked.” Fout 812 is een verschil in authenticatiemethode tussen het beleid van de server en het profiel van de client. De vier genoemde oorzaken van 13801 zijn een machinecertificaat zonder Server Authentication in het uitgebreide sleutelgebruik, een verlopen RAS-machinecertificaat, een client zonder het rootcertificaat, en een client waarvan de “VPN server name doesn’t match the subjectName value on the server certificate”; 13806 is “IKE can’t find a valid machine certificate”. ↩︎ ↩︎ ↩︎ ↩︎
Microsoft — Guidance for troubleshooting Remote Access (VPN and AOVPN). De ondersteunde verzameling is TSS, verhoogd uitgevoerd:
TSS.ps1 -Scenario NET_VPNop de client enTSS.ps1 -Scenario NET_RASop de server, met de storing gereproduceerd tussen start en stop en de sporen geschreven naarC:\MS_DATA. ↩︎Microsoft — Routing and Remote Access Error Codes, de codes gedefinieerd in
raserror.h. 638ERROR_REQUEST_TIMEOUT; 718ERROR_PPP_TIMEOUT; 789ERROR_OAKLEY_GENERAL_PROCESSING, “The L2TP connection attempt failed because the security layer encountered a processing error during initial negotiations with the remote computer”; 809ERROR_VPN_TIMEOUT, “The network connection between your computer and the VPN server could not be established because the remote server is not responding”; 828ERROR_IDLE_TIMEOUT, “The connection was terminated because of idle timeout”; 930ERROR_AUTH_SERVER_TIMEOUT, “The authentication server did not respond to authentication requests in a timely fashion”. ↩︎firewalld — Automatic Helper Assignment. “With kernel 4.7 and up the automatic helper assignment in kernel has been turned off by default”, gestuurd door de sysctl onder
/proc/sys/net/netfilter/nf_conntrack_helper, en “for the secure use of iptables and connection tracking helpers it is recommended to turn AutomaticHelpers off”. De kernelmelding over de wijziging noemt de reden en de vervanging: de automatische toewijzing “has been turned off for security reasons”, gebruik in plaats daarvan hetCT-target. De gedekte helpers zijn onder meerftp,irc,sip,h323,tftp,snmpenpptp. ↩︎Samy Kamkar — NAT Slipstreaming, v1 van 31 oktober 2020, v2 van 26 januari 2021 met Ben Seri en Gregory Vishnipolsky van Armis. De aanval misbruikt “the Application Level Gateway (ALG) connection tracking mechanism built into NATs, routers, and firewalls” om “bypass victim NAT and connect directly back to any port on any machine on the network, exposing previously protected/hidden services and systems”. v1 gebruikte de SIP-gateway op poort 5060, v2 H.323 op 1720, waarmee het gat op elke interne host gericht kon worden in plaats van alleen op de machine die de pagina laadde. ↩︎
Microsoft —
Set-VpnServerConfiguration, module RemoteAccess.-IdleDisconnectSeconds“Specifies the time, in seconds, after which an idle connection is terminated”;-SALifeTimeSecondsen-MMSALifeTimeSecondszetten de levensduur van quick mode en main mode;-SADataSizeForRenegotiationKilobytes“Specifies the number of kilobytes that are allowed to transfer using a security association (SA), after which the SA will be renegotiated”. ↩︎Jason A. Donenfeld — WireGuard: Next Generation Kernel Network Tunnel, NDSS 2017. “It intentionally lacks cipher and protocol agility. If holes are found in the underlying primitives, all endpoints will be required to update. As shown by the continuing torrent of SSL/TLS vulnerabilities, cipher agility increases complexity monumentally”; “implemented for Linux in less than 4,000 lines of code”; “it is important to stress, however, that the layering of IPsec is correct and sound; everything is in the right place with IPsec, to academic perfection”. Metingen: 1.011 Mbit/s tegen 881 en 825 voor twee IPsec-cijfersuites, en 0,403 ms ping tegen 0,501 en 0,508. ↩︎ ↩︎ ↩︎ ↩︎