VPN über NAT: Funktioniert doch… oder?

TL;DR

In diesem Beitrag geht es um die negativen Auswirkungen von Network Address Translation, insbesondere auf Ebene des Internet Service Providers. Illustriert wird das am Beispiel einer VPN-Verbindung. Das Problem kann aber ebenso bei anderen Anwendungen auftreten. Gut, wenn man davon weiß!

Ich hatte vor einiger Zeit ein sehr interessantes Phänomen zur Entstörung vorliegen gehabt, welches ich euch nicht vorenthalten möchte. Es ging um ein Remote-Access-VPN mit IKEv1. Verwendet wurde der Windows-integrierte VPN-Client im Modus L2TP/IPsec mit Zertifikat. Der Kunde meldete, dass dies bei einem seiner Mitarbeiter gestern noch funktionierte und heute plötzlich nicht mehr. Die anderen Mitarbeiter konnten sich allerdings ganz normal ins VPN einwählen. Also kein zentrales Problem.

Wie immer, wenn irgendetwas kurz vorher funktionierte und plötzlich nicht mehr funktioniert, muss es eine Veränderung gegeben haben. Aber welche? Der Mitarbeiter beteuerte, dass er keine neue Software und keine Updates installiert habe, auch war der Microsoft Patchday schon einige Wochen her. Ebenfalls seien keine Config-Änderungen am Endgerät oder im Heimnetz des Kunden vorgenommen worden. Und natürlich hatte ich geprüft, dass das VPN-Zertifikat noch gültig war. Also schaute ich in die Logs der Firewall (Cisco ASA), filterte nach der IP des Kunden und fand dabei die folgende Meldung:

%ASA-4-402116: IPSEC: Received an ESP packet (SPI= 0x5CE4E6D1, sequence number= 0x2) from 198.51.100.11 (user= tunnelgroup2024) to 192.0.2.217.  The decapsulated inner packet doesn't match the negotiated policy in the SA.  The packet specifies its destination as 192.0.2.217, its source as 203.0.113.62, and its protocol as udp.  The SA specifies its local proxy as 192.0.2.217/255.255.255.255/udp/42246 and its remote_proxy as 198.51.100.11/255.255.255.255/udp/0.

Hier noch Ciscos Erklärung zu dieser Meldung:1

Error Message %ASA-4-402116: IPSEC: Received an protocol packet (SPI=spi , sequence number=seq_num ) from remote_IP (username ) to local_IP . The decapsulated inner packet doesn’t match the negotiated policy in the SA. The packet specifies its destination as pkt_daddr , its source as pkt_saddr , and its protocol as pkt_prot . The SA specifies its local proxy as id_daddr /id_dmask /id_dprot /id_dport and its remote proxy as id_saddr /id_smask /id_sprot /id_sport .

Explanation A decapsulated IPsec packet does not match the negotiated identity. The peer is sending other traffic through this security association, which may be caused by a security association selection error by the peer, or it may be part of an attack.

In unserem Fall gilt:2

  • remote_IP: 198.51.100.11 (= IP address of the remote endpoint of the tunnel)
  • local_IP: 192.0.2.217 (= IP address of the local endpoint of the tunnel)
  • pkt_daddr: 192.0.2.217 (= Destination address from the decapsulated packet)
  • pkt_saddr: 203.0.113.62 (= Source address from the decapsulated packet)
  • id_daddr: 192.0.2.217 (= Local proxy IP address)
  • id_saddr: 198.51.100.11 (= Remote proxy IP address)

Ich habe mal etwas Farbe verwendet. Aus Firewall-Sicht steht blau für die entfernten IP-Adressen des VPN-Users und rot für die lokalen IP-Adressen. Auf den ersten Blick fällt auf, dass die roten Adressen einander gleichen. Die IP des lokalen Tunnel-Endpunktes entspricht der Zieladresse des IP-Pakets und dem lokalen Traffic-Selektor der IPsec SA (= Local Proxy ID). Das klingt erst mal plausibel für ein Remote-Access-VPN. Bei den blauen Adressen gibt es jedoch einen Unterschied: Zwar entspricht die IP des entfernten Tunnel-Endpunktes dem Traffic Selector der IPsec SA (= Remote Proxy ID), aber nicht der Quelladresse des IP-Pakets. Da kann doch nur NAT im Spiel sein! Aber damit weiß IPsec ja eigentlich umzugehen

In der Zwischenzeit wurde exakt das gleiche Problem durch einen weiteren Mitarbeiter unseres Kunden gemeldet. Wie sich kurz darauf herausstellte, gab es eine Gemeinsamkeit zwischen den beiden Mitarbeitern: den Internet-Provider. Das brachte mich schnell auf eine Idee. Ein Blick in die RIPE Datenbank bestätigte den Verdacht: Die IP-Adressen beider Kunden enthielten folgende Beschreibung: Carrier Grade NAT Pool.

Carrier Grade NAT (CGN) ist neben „normalem“ NAT eine weitere Maßnahme zum Sparen von öffentlichen IP-Adressen: Der Provider vergibt seinen Internetkunden WAN-seitig Adressen aus dem speziell reservierten Netzblock 100.64.0.0/10, welcher im Internet nicht geroutet wird. Daher muss der Traffic der Internetkunden dann über die NAT-Server des Providers geroutet werden, welche die CGN-Adresse in eine öffentliche IP-Adresse übersetzen. Mein ehemaliger Kollege Lutz hat damit sehr viel Erfahrung. Einen wichtigen Punkt beschreibt er in diesem Post: „Es ist notwendig, dass die Zuordnung zwischen Client und öffentlich sichtbarer IP weitestgehend konstant bleibt, denn nur so sind die folgenden Anforderungen an einen Internet-Zugang realisierbar.“

Genau das scheint in unserem Fall schief zu gehen: Der Traffic der Kunden wird nicht konstant über eine öffentlich sichtbare IP genattet, denn ein CGN-Server kann im Gegensatz zum Internet-Router zu Hause mehrere öffentliche IPs haben. Um einen festen Kunden konstant auf die gleiche öffentliche IP zu natten, fällt Round Robin also schon mal aus. Naheliegend wäre die Implementierung von Regeln, wie beispielsweise: „100.64.123.0/24 auf 203.0.113.123/32 natten“. Möglicherweise ist das aber nicht performant genug, denn offenbar hat sich der Provider für ein Hash-Verfahren entschieden. Wie komme ich zu dieser Annahme?

  • Das IKE-Protokoll wird zur Aushandlung der SAs verwendet und benutzt dafür den UDP Port 500 (Source und Destination).
  • Die eigentlichen Nutzdaten werden dann durch eines der beiden IPsec Sicherheitsprotokolle Authentication Header (AH) oder Encapsulating Security Payload (ESP) geschützt, meist handelt es sich hierbei um ESP. Beide Protokolle werden direkt in IP transportiert. Es gibt also keinen TCP- oder UDP-Header, dessen Quellport im Zuge von NAT/PAT umgeschrieben werden könnte. Und exakt das löst NAT-Traversal durch einfügen eines zusätzlichen UDP-Headers (Source und Destination Port 4500).

Was wäre nun, wenn der Provider nicht nur die IP-Adresse(n), sondern auch die Port-Nummer(n) hasht, um eine öffentliche Quelladresse für das Datenpaket auszuwählen? Dann wäre die Wahrscheinlichkeit wohl relativ hoch, dass die IKE-Pakete mit anderer Quelladresse ins Internet geroutet werden, als die ESP-Pakete. Nun wissen wir also, welche Veränderung es gegeben hat. 🙂

Ich empfahl den betroffenen Mitarbeitern schließlich, sich beim Provider zu melden und die offenbar vorgenommene Umstellung von öffentlicher IP auf Carrier Grade NAT rückgängig machen zu lassen. Das dauerte einen Tag, danach konnten sich die Mitarbeiter wieder einwählen. Hurra!

Übrigens: IP-Adressen aus 100.64.0.0/10 sollte man ebenfalls nicht in seinem Heimnetz benutzen.

Foto von Hyundai Motor Group auf Unsplash

  1. https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs4.html#con_4772678 ↩︎
  2. Die IP-Adressen habe ich anonymisiert. Daher sei an dieser Stelle erwähnt, dass es sich bei allen vorkommenden IP-Adressen um öffentliche Adressen und nicht um private Adressen aus dem LAN des Mitarbeiters handelte. ↩︎
folder
chat 3

3 Antworten zu “VPN über NAT: Funktioniert doch… oder?”

  1. Hey Lukas. Coole Story, danke dir. Diesen Fall mit CGN hatte ich so noch nicht. Es zeigt aber einmal mehr, dass das Ende von IPv4 erreicht ist und ein „wir packen einfach noch mehr NAT drauf“ in die Hose geht. Meine Empfehlung an den Kunden wäre übrigens gewesen: Das VPN-Gateway per IPv6 erreichbar zu machen. 😉 Das würde dann auch längerfristig skalieren.

    (Einen Typo hast du bei dir drin: Der CGN-Bereich ist 100.64.0.0/10, nicht 10.64.0.0/10.)

    Ciao,
    Johannes

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert