Trasiga paket: IP-fragmentering är bristfällig

I motsats till det allmänna telefonnätet är Internet paketförmedlat. Men hur stora kan dessa paket vara?

CC BY 2.0 image by ajmexico, inspired by

Detta är en gammal fråga och IPv4 RFC:erna svarar ganska tydligt på den. Tanken var att dela upp problemet i två separata frågor:

  • Vad är den maximala paketstorlek som kan hanteras av operativsystemen i båda ändar?

  • Vad är den högsta tillåtna datagramstorleken som säkert kan skjutas genom de fysiska förbindelserna mellan värdarna?

När ett paket är för stort för en fysisk länk kan en mellanliggande router dela upp det i flera mindre datagram för att få plats. Denna process kallas IP-fragmentering ”framåt” och de mindre datagrammen kallas IP-fragment.

Bild av Geoff Huston, återgiven med tillstånd

I IPv4-specifikationen definieras minimikraven. Från RFC791:

Every internet destination must be able to receive a datagramof 576 octets either in one piece or in fragments tobe reassembled. Every internet module must be able to forward a datagram of 68octets without further fragmentation. 

Det första värdet – tillåten återmonterad paketstorlek – är vanligtvis inte problematiskt. IPv4 definierar det minsta värdet till 576 bytes, men populära operativsystem kan hantera mycket stora paket, vanligtvis upp till 65 KiB.

Det andra värdet är mer problematiskt. Alla fysiska anslutningar har inneboende datagramstorleksgränser, beroende på det specifika medium de använder. Frame Relay kan till exempel skicka datagram mellan 46 och 4 470 bytes. ATM använder fasta 53 bytes, klassisk Ethernet kan göra mellan 64 och 1 500 bytes.

Specifikationen definierar minimikravet – varje fysisk länk måste kunna sända datagram på minst 68 bytes. För IPv6 har detta minimivärde höjts till 1280 bytes (se RFC2460).

Å andra sidan är den maximala datagramstorleken som kan sändas utan fragmentering inte definierad i någon specifikation och varierar beroende på länktyp. Detta värde kallas MTU (Maximum Transmission Unit).

MTU definierar en maximal datagramstorlek på en lokal fysisk länk. Internet skapas av icke-homogena nätverk, och på vägen mellan två värdar kan det finnas länkar med kortare MTU-värden. Den maximala paketstorlek som kan överföras utan fragmentering mellan två fjärrvärdar kallas Path MTU och kan potentiellt vara olika för varje anslutning.

Undervik fragmentering

Det kan tyckas att det går bra att bygga program som överför mycket stora paket och förlita sig på att routrar utför IP-fragmenteringen. Detta är ingen bra idé. Problemen med detta tillvägagångssätt diskuterades först av Kent och Mogul 1987. Här är några av höjdpunkterna:

  • För att lyckas sätta ihop ett paket på nytt måste alla fragment levereras. Inget fragment kan bli skadat eller gå förlorat under flygningen. Det finns helt enkelt inget sätt att meddela den andra parten om saknade fragment!

  • Det sista fragmentet kommer nästan aldrig att ha den optimala storleken. För stora överföringar innebär detta att en betydande del av trafiken kommer att bestå av suboptimala korta datagram – ett slöseri med värdefulla routerresurser.

  • För återmontering måste en värd hålla partiella, fragmenterade datagram i minnet. Detta öppnar en möjlighet för minnesutnyttjandeattacker.

  • Följande fragment saknar huvudet i det högre lagret. TCP- eller UDP-huvudet finns endast i det första fragmentet. Detta gör det omöjligt för brandväggar att filtrera fragmentdatagram baserat på kriterier som käll- eller målportar.

En mer utförlig beskrivning av IP-fragmenteringsproblem finns i dessa artiklar av Geoff Huston:

  • Evaluating IPv4 and IPv6 packet fragmentation
  • Fragmentering av IPv6

Don’t fragment – ICMP Packet too big


Bild av Geoff Huston, återgiven med tillstånd

En lösning på dessa problem fanns med i IPv4-protokollet. En avsändare kan sätta DF-flaggan (Don’t Fragment) i IP-huvudet och be mellanliggande routrar att aldrig fragmentera ett paket. Istället kommer en router med en länk som har en mindre MTU att skicka ett ICMP-meddelande ”bakåt” och informera avsändaren om att minska MTU för denna anslutning.

TCP-protokollet sätter alltid DF-flaggan. Nätverksstacken tittar noga efter inkommande ICMP-meddelanden om ”Packet too big” och håller reda på egenskapen ”path MTU” för varje anslutning. Den här tekniken kallas ”path MTU discovery” och används oftast för TCP, även om den också kan tillämpas på andra IP-baserade protokoll. Att kunna leverera ICMP-meddelandena ”Packet too big” är avgörande för att TCP-stacken ska fungera optimalt.

Hur internet faktiskt fungerar

I en perfekt värld skulle internetanslutna enheter samarbeta och hantera fragmenterade datagram och tillhörande ICMP-paket på rätt sätt. I verkligheten filtreras dock IP-fragment och ICMP-paket mycket ofta bort.

Detta beror på att det moderna internet är mycket mer komplext än vad som förutsågs för 36 år sedan. I dag är det i princip ingen som är direkt ansluten till det offentliga internet.

Kundernas enheter ansluts via hemmets routrar som gör NAT (Network Address Translation) och vanligtvis tillämpar brandväggsregler. Allt oftare finns det mer än en NAT-installation på paketvägen (t.ex. carrier-grade NAT). Därefter når paketen ISP:s infrastruktur där det finns ISP:s ”middle boxes”. De gör alla möjliga konstiga saker med trafiken: de tillämpar tak för abonnemang, stryper anslutningar, loggar, kapar DNS-förfrågningar, tillämpar förbud mot webbplatser på uppdrag av regeringen, tvingar fram transparent cachelagring eller ”optimerar” trafiken på något annat magiskt sätt. Mellanlådorna används särskilt av mobila telekombolag.

På samma sätt finns det ofta flera lager mellan en server och det offentliga Internet. Tjänsteleverantörer använder ibland Anycast BGP-routing. Det vill säga: de hanterar samma IP-områden från flera fysiska platser runt om i världen. Inom ett datacenter är det å andra sidan alltmer populärt att använda ECMP Equal Cost Multi Path för lastbalansering.

Var och en av dessa lager mellan en klient och en server kan orsaka ett Path MTU-problem. Låt mig illustrera detta med fyra scenarier.

1. Klient -> Server DF+ / ICMP

I det första scenariot laddar en klient upp data till servern med hjälp av TCP så DF-flaggan sätts på alla paket. Om klienten misslyckas med att förutsäga en lämplig MTU kommer en mellanliggande router att släppa de stora paketen och skicka ett ICMP-meddelande ”Packet too big” tillbaka till klienten. Dessa ICMP-paket kan tappas bort av felkonfigurerade NAT-enheter hos kunden eller ISP:s mellanlådor.

Enligt Maikel de Boers och Jeffrey Bosmas artikel från 2012 blockerar cirka 5 % av IPv4- och 1 % av IPv6-värdarna inkommande ICMP-paket.

Min erfarenhet bekräftar detta. ICMP-meddelanden tappas faktiskt ofta bort på grund av upplevda säkerhetsfördelar, men detta är relativt enkelt att åtgärda. Ett större problem är vissa mobila internetleverantörer med konstiga mellanlådor. Dessa ignorerar ofta ICMP helt och hållet och utför mycket aggressiva omskrivningar av anslutningar. Orange Polska ignorerar till exempel inte bara inkommande ICMP-meddelanden med ”Packet too big”, utan skriver också om anslutningsstatusen och begränsar MSS till icke förhandlingsbara 1344 bytes.

2. Klient -> Server DF- / fragmentering

I nästa scenario laddar en klient upp data med ett annat protokoll än TCP, där DF-flaggan är rensad. Det kan till exempel vara en användare som spelar ett spel med UDP eller har ett röstsamtal. De stora utgående paketen kan fragmenteras vid någon punkt i vägen.

Vi kan emulera detta genom att starta ping med en stor nyttolaststorlek:

$ ping -s 2048 facebook.com

Denna ping kommer att misslyckas med nyttolaster som är större än 1472 bytes. Alla större storlekar kommer att fragmenteras och levereras inte korrekt. Det finns flera anledningar till att servrar kan hantera fragment felaktigt, men ett av de vanligaste problemen är användningen av ECMP-lastutjämning. På grund av ECMP-hashningen är det troligt att det första datagrammet som innehåller ett protokollhuvud kommer att lastbalanseras till en annan server än resten av fragmenten, vilket förhindrar återmontering.

För en mer detaljerad diskussion av detta problem, se:

  • Vår tidigare artikel om ECMP.
  • Hur Google försöker lösa ECMP-fragmenteringsproblem med Maglev L4 Load Balancer.

Den felaktiga konfigurationen av servrar och routrar är dessutom ett stort problem. Enligt RFC7852 släpper mellan 30 och 55 % av servrarna IPv6-datagram som innehåller fragmenteringshuvudet.

3. Server -> Klient DF+ / ICMP

Nästa scenario handlar om en klient som laddar ner data via TCP. När servern misslyckas med att förutsäga rätt MTU bör den få ett ICMP-meddelande ”Packet too big”. Enkelt, eller hur?

Det är det tyvärr inte, återigen på grund av ECMP-routing. ICMP-meddelandet kommer med största sannolikhet att levereras till fel server – ICMP-paketets 5-tupel-hash kommer inte att matcha 5-tupel-hash för den problematiska anslutningen. Vi skrev om detta tidigare och utvecklade en enkel daemon i användarutrymmet för att lösa det. Den fungerar genom att sända ut ICMP-meddelandet ”Packet too big” till alla ECMP-servrar, i hopp om att den som har den problematiska anslutningen kommer att se det.

Också på grund av Anycast-routing kan ICMP-meddelandet levereras till fel datacenter helt och hållet! Internets routning är ofta asymmetrisk och den bästa vägen från en mellanliggande router kan leda ICMP-paketen till fel ställe.

Missade ICMP-meddelanden om att paketet är för stort kan leda till att anslutningar stannar och stannar upp. Detta kallas ofta för ett PMTU-svart hål. För att hjälpa detta pessimistiska fall implementerar Linux en lösning – MTU Probing RFC4821. MTU Probing försöker automatiskt identifiera paket som tappas på grund av fel MTU och använder heuristik för att ställa in det. Denna funktion styrs via en sysctl:

$ echo 1 > /proc/sys/net/ipv4/tcp_mtu_probing

Men MTU probing är inte utan problem. För det första tenderar den att misskategorisera överbelastningsrelaterad paketförlust som MTU-problem. Långvariga anslutningar tenderar att sluta med en reducerad MTU. För det andra implementerar Linux inte MTU Probing för IPv6.

4. Server -> Klient DF- / fragmentering

Slutligt finns det en situation där servern skickar stora paket med hjälp av ett icke-TCP-protokoll med DF-biten klar. I detta scenario kommer de stora paketen att fragmenteras på vägen till klienten. Denna situation illustreras bäst med stora DNS-svar. Här är två DNS-förfrågningar som kommer att generera stora svar och levereras till klienten som flera IP-fragment:

$ dig +notcp +dnssec DNSKEY org @199.19.56.1$ dig +notcp +dnssec DNSKEY org @2001:500:f::1

Dessa förfrågningar kan misslyckas på grund av redan nämnda felkonfigurerad hemrouter, trasig NAT, trasiga ISP-installationer eller alltför restriktiva brandväggsinställningar.

Enligt Boer och Bosma blockerar cirka 6 % av IPv4- och 10 % av IPv6-värdarna inkommande fragmentdatagram.

Här finns några länkar med mer information om de specifika fragmenteringsproblem som påverkar DNS:

  • DNS-OARC Reply Size Test
  • IPv6, stora UDP-paket och DNS

Men internet fungerar fortfarande!

Med alla dessa saker som går fel, hur lyckas internet fortfarande fungera?

CC BY-SA 3.0, källa: Wikipedia

Detta beror främst på Ethernet. Den stora majoriteten av länkarna på det offentliga internet är Ethernet (eller härstammar från det) och stöder MTU på 1500 bytes.

Om du blint utgår från MTU på 1500 kommer du att bli förvånad över hur ofta det kommer att fungera alldeles utmärkt. Internet fortsätter att fungera främst på grund av att vi alla använder en MTU på 1500 och sällan behöver göra IP-fragmentering och skicka ICMP-meddelanden.

Detta slutar att fungera i en ovanlig konfiguration med länkar som har en icke-standardiserad MTU. VPN-tjänster och annan programvara för nätverkstunnlar måste vara noga med att se till att fragmenteringarna och ICMP-meddelandena fungerar bra.

Detta är särskilt synligt i IPv6-världen, där många användare ansluter via tunnlar. Det är mycket viktigt att ha en sund passage av ICMP i båda riktningarna, särskilt eftersom fragmentering i IPv6 i princip inte fungerar (vi citerade två källor som hävdar att mellan 10 % och 50 % av IPv6-värdarna blockerar IPv6 Fragment header).

Med tanke på att Path MTU-problemen i IPv6 är så vanliga, begränsar många IPv6-servrar Path MTU till det protokollföreskrivna minimumet på 1280 byte. Detta tillvägagångssätt innebär att man byter lite prestanda mot bästa tillförlitlighet.

Online ICMP blackhole checker

För att hjälpa till att utforska och felsöka dessa problem har vi byggt en online-kontroll. Du kan hitta två versioner av testet:

  • IPv4-version: http://icmpcheck.popcount.org
  • IPv6-version: http://icmpcheckv6.popcount.org

Dessa webbplatser startar två tester:

  • Det första testet kommer att leverera ICMP-meddelanden till din dator, i syfte att minska Path MTU till ett skrattretande litet värde.
  • Det andra testet kommer att skicka fragmenterade datagram tillbaka till dig.

Om du får ett ”pass” i båda dessa tester bör du få en rimlig försäkran om att internet på din sida av kabeln beter sig väl.

Det är också lätt att köra testerna från kommandoraden, ifall du vill köra det på servern:

perl -e "print 'packettoolongyaithuji6reeNab4XahChaeRah1diej4' x 180" > payload.bincurl -v -s http://icmpcheck.popcount.org/icmp --data @payload.bincurl -v -s http://icmpcheckv6.popcount.org/icmp --data @payload.bin

Detta bör reducera Path MTU till vår server till 905 bytes. Du kan verifiera detta genom att titta i routing cache-tabellen. På Linux gör du detta med:

ip route get `dig +short icmpcheck.popcount.org`

Det är möjligt att rensa routing cache på Linux:

ip route flush cache to `dig +short icmpcheck.popcount.org`

Det andra testet verifierar om fragmenten levereras korrekt till klienten:

curl -v -s http://icmpcheck.popcount.org/frag -o /dev/nullcurl -v -s http://icmpcheckv6.popcount.org/frag -o /dev/null

Sammanfattning

I det här blogginlägget beskrev vi problemen med att upptäcka Path MTU-värden på internet. ICMP- och fragmentdatagram blockeras ofta på båda sidor av anslutningarna. Klienter kan stöta på felkonfigurerade brandväggar, NAT-enheter eller använda internetleverantörer som aggressivt avlyssnar anslutningar. Klienter använder också ofta VPN eller IPv6-tunnlar som, om de är felkonfigurerade, kan orsaka problem med Path MTU.

Servrar å andra sidan förlitar sig allt oftare på Anycast eller ECMP. Båda dessa saker, liksom felkonfigurering av routrar och brandväggar, är ofta en orsak till att ICMP- och fragmentdatagram tappas bort.

Slutligt hoppas vi att onlinetestet är användbart och att det kan ge dig en bättre inblick i det inre arbetet i dina nätverk. Testet har användbara exempel på tcpdump-syntax, användbara för att få mer insikt. Lycka till med nätverksdebuggning!

Är det spännande att åtgärda fragmenteringsproblem för 10 % av internet? Vi anställer systemingenjörer av alla slag, Golang-programmerare, C-wranglers och praktikanter på flera platser! Följ med oss till San Francisco, London, Austin, Champaign och Warszawa.

  1. I IPv6 fungerar ”forward”-fragmenteringen något annorlunda än i IPv4. Mellanliggande routrar är förbjudna att fragmentera paketen, men källan kan fortfarande göra det. Detta är ofta förvirrande – en värd kan bli ombedd att fragmentera ett paket som den skickat tidigare. Detta är föga meningsfullt för statslösa protokoll som DNS. ︎

  2. Om en sidoanmärkning, det finns också en ”minsta sändningsenhet”! I den allmänt använda Ethernet-ramningen måste varje överfört datagram ha minst 64 bytes på Layer 2. Detta motsvarar 22 byte på UDP och 10 byte på TCP-lagret. Flera implementationer brukade läcka oinitialiserat minne vid kortare paket! ︎

  3. Strikt sett heter ICMP-paketet i IPv4 ”Destination Unreachable, Fragmentation Needed and Don’t Fragment was Set”. Men jag tycker att IPv6 ICMP-felbeskrivningen ”Packet too big” är mycket tydligare. ︎

  4. Som ett tips inkluderar TCP-stacken också ett maximalt tillåtet ”MSS”-värde i SYN-paket (MSS är i princip ett MTU-värde reducerat med storleken på IP- och TCP-huvuden). Detta gör det möjligt för värdarna att veta vad som är MTU på deras länkar. Observera: detta säger inte vad MTU:n är på dussintals internetlänkar mellan de två värdarna! ︎

  5. Låt oss gå på den säkra sidan. En bättre MTU är 1492, för att ta hänsyn till DSL- och PPPoE-anslutningar. ︎

Lämna ett svar

Din e-postadress kommer inte publiceras.