---
format: markdown
title: TCP Problem bei asymmetrischem Routing durch kaputte pMTUd wegen ICMP Filterung
toc: yes
categories: Hintergrundinfos HOWTO
...

# Ausgangssituation

FF-DO (AS35675) announced das Netz 193.43.221.0/24 zZ nur in Dortmund (auf dem hypervisor01 durch die VMs snng-dtm01 und ...02) an das upstream AS39138 - aber noch nicht in Düsseldorf (auf dem blech02 durch die VM duesseldorf) an das dortige upstream AS50873. Die VM duesseldorf erhält vom AS50873 full table und benutzt diese auch für ausgehende Pakete.  
Der Zusammenhang des Netzes 193.43.221.0/24 wird durch ein VPN (tinc) zwischen Dortmund (VM koerne) und Düsseldorf (VM duesseldorf) hergestellt.

# Problembeschreibung

Das führt dazu, dass von einem unmittelbar hinter der VM duesseldorf befindlichen Host (mit Adresse in 193.43.221.0/24) ausgehende Datenpakete via duesseldorf -> AS50873 direkt ins Internet rausgehen, also mit MTU 1500 / TCP-MSS 1460 [1]. Die Antwortpakete kommen aber in Dortmund an und müssen dann per VPN (tinc) zur VM duesseldorf transportiert werden, um den dahinter befindlichen Host zu erreichen.

Ein großes TCP-Antwortpaket (Größe 1500/IP, 1460/TCP-MSS) passt wg. des overheads eines VPN aber nicht als ganzes Paket durch das VPN. Es müsste also fragmentiert, d.h. in zwei Portionen transportiert und auf der anderen Seite des VPN wieder zusammengesetzt werden. Bei IPv4 ist das möglich, bei IPv6 wurde (De-)Fragmentieren zwecks Entlastung der Router abgeschafft.

Allerdings haben TCP-Pakete normalerweise das DF flag (don't fragment) gesetzt, um path MTU discovery [2] zu ermöglichen. Deshalb fragmentiert die VM koerne ein solches (zu) großes TCP Paket nicht, sondern schickt eine ICMP Fehlermeldung ("fragmentation needed, but DF set") an den Absender des (zu) großen Paketes zurück. Daraufhin kann dieser die MSS für die TCP-Verbindung heruntersetzen und die (jetzt kleineren) TCP-Pakete können mit maximal möglicher Größe durch das VPN transportiert werden.

Doch leider filtern manche Leute die o.g. ICMP Fehlermeldungen weg,-( worduch sie pMTUd kaputt machen, sodass TCP-Verbindungen über Rückwege mit kleinerer MTU nicht funktionieren (asymmetrisches Routing). Hier aufgefallen ist das durch nicht mehr funktionierende Debian-Updates von deb.debian.org, der sich (leider) im CDN des AS54113 ("fastly") befindet.

# Lösung  

Die richtige Lösung bestünde darin, das Problem an der Wurzel zu packen, d.h. den ICMP Filter des AS54113 ("fastly") so zu korrigieren, dass pMTUd wieder funktioniert.

Unser Workaround besteht darin, die ausgehenden Pakete durch MSS-Clamping so zu verändern, dass TCP-Antwortpakete gleich die (für das VPN) passende Maximalgröße haben, d.h. nicht fragmentiert werden müssen. Zu diesem Zweck werden bereits die ausgehenden Pakete durch das VPN geroutet, sodass die MSS durch tinc für sie (und damit auch für die Antwortpakete) reduziert wird.

Dies kann erreicht werden, indem der BGP-Routerprozess (bird) die vom upstream (AS50873) empfangenen Routen des AS54113 (= fastly) so modifiziert, dass der next hop ein tinc peer ist. In diesem Fall ist das sinnvollerweise die VM koerne, bei der ja auch die Antwortpakete hereinkommen. In der bird.conf auf duesseldorf wird dazu der BGP-Eingangsfilter (f_am_ffdo_in) wie folgt ergänzt:

    root@duesseldorf:/etc/bird # diff bird.conf.ok bird.conf  
    145a146,148  
    > 	# deb.debian.org -> fastly => pMTUd broken:-(  
    > 	if bgp_path.last = 54113  
    > 	then gw = 193.43.220.166;  

Dabei ist 193.43.220.166 die Adresse des inneren VPN-(tinc-)Interfaces der VM koerne.

Alternativ zur Modifikation des Routings zwecks MSS-Clamping könnte man auf der duesseldorf VM per Paketfilter die ausgehenden TCP-Pakete zum AS54113 entsprechend modifizieren. Dabei entsteht aber die Frage, für welche Zieladressen das passieren soll. Die genaue Antwort kennt aber nur der BGP-Router, also bird, also s.o.

# Mögliche andere Lösung

Die iptables kann modifiziert werden:  
iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu  
bzw gleich unsere MTU für 1234 einsetzen:  
iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1234 (natürlich anpassen)  

# Ausblick

Wenn dereinst auch das Netz 193.43.221.0/24 in Düsseldorf an upstream announced werden wird, so wird das Problem nicht (vollständig) verschwinden, da nach wie vor Antwortpakete in Dortmund ankommen (können). Außerdem müsste aus Symmetriegründen dann auch in Dortmund der obige Workaround angewendet werden - was leider so einfach nicht möglich ist, da vom dortigen upstream AS39138 nur die default route, aber nicht full table empfangen wird. (Wie man es auch dann noch hinkriegt, behandeln wir, wenn es soweit ist;)  

Die Lösung die iptables zu verändern, sollte das Problem lösen, wenn neue ASN ohne MTU-Anpassung auftreten. Solange die obige Lösung funktioniert, ist es die Beste.  

[1] <https://de.wikipedia.org/wiki/Maximum_Segment_Size>  
[2] <https://de.wikipedia.org/wiki/Path_MTU_Discovery>