Pachete sparte: Fragmentarea IP este defectuoasă

Spre deosebire de rețeaua de telefonie publică, internetul are un design de tip Packet Switched. Dar cât de mari pot fi aceste pachete?

CC BY 2.0 image by ajmexico, inspired by

Aceasta este o întrebare veche, iar RFC-urile IPv4 răspund la ea destul de clar. Ideea a fost de a împărți problema în două preocupări separate:

  • Care este dimensiunea maximă a pachetelor care poate fi gestionată de sistemele de operare de la ambele capete?

  • Care este dimensiunea maximă permisă a datagramelor care poate fi împinsă în siguranță prin conexiunile fizice dintre gazde?

Când un pachet este prea mare pentru o legătură fizică, un router intermediar îl poate tăia în mai multe datagrame mai mici pentru a-l face să încapă. Acest proces se numește fragmentare IP „înainte”, iar datagramele mai mici se numesc fragmente IP.

Imagine de Geoff Huston, reprodusă cu permisiune

Specificația IPv4 definește cerințele minime. Din 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. 

Prima valoare – dimensiunea permisă a pachetului reasamblat – nu este de obicei problematică. IPv4 definește minimul ca fiind de 576 octeți, dar sistemele de operare populare pot face față unor pachete foarte mari, de obicei de până la 65KiB.

Cea de-a doua valoare este mai problematică. Toate conexiunile fizice au limite inerente de dimensiune a datagramelor, în funcție de mediul specific pe care îl utilizează. De exemplu, Frame Relay poate trimite datagrame între 46 și 4.470 de octeți. ATM folosește fix 53 de octeți, iar Ethernet-ul clasic poate face între 64 și 1.500 de octeți.

Specificația definește cerința minimă – fiecare legătură fizică trebuie să fie capabilă să transmită datagrame de cel puțin 68 de octeți. Pentru IPv6, această valoare minimă a fost urcată la 1.280 de octeți (a se vedea RFC2460).

Pe de altă parte, dimensiunea maximă a datagramelor care pot fi transmise fără fragmentare nu este definită de nicio specificație și variază în funcție de tipul de legătură. Această valoare se numește MTU (Maximum Transmission Unit).

MTU definește dimensiunea maximă a unui datagram pe o legătură fizică locală. Internetul este creat din rețele neomogene, iar pe traseul dintre două gazde pot exista legături cu valori MTU mai mici. Dimensiunea maximă a pachetului care poate fi transmisă fără fragmentare între două gazde la distanță se numește MTU de cale și poate fi potențial diferită pentru fiecare conexiune.

Evitați fragmentarea

Oamenii ar putea crede că este în regulă să construiască aplicații care transmit pachete foarte mari și să se bazeze pe routere pentru a realiza fragmentarea IP. Aceasta nu este o idee bună. Problemele legate de această abordare au fost discutate pentru prima dată de Kent și Mogul în 1987. Iată câteva repere:

  • Pentru a reasambla cu succes un pachet, toate fragmentele trebuie să fie livrate. Niciun fragment nu poate deveni corupt sau să se piardă în zbor. Pur și simplu nu există nicio modalitate de a notifica cealaltă parte despre fragmentele lipsă!

  • Ultimul fragment nu va avea aproape niciodată dimensiunea optimă. Pentru transferuri mari, acest lucru înseamnă că o parte semnificativă a traficului va fi compusă din datagrame scurte suboptime – o risipă de resurse prețioase ale routerului.

  • Înainte de reasamblare, o gazdă trebuie să dețină în memorie datagrame parțiale, fragmentate. Acest lucru deschide o oportunitate pentru atacuri de epuizare a memoriei.

  • Fragmentelor ulterioare le lipsește antetul stratului superior. Antetul TCP sau UDP este prezent doar în primul fragment. Acest lucru face imposibilă filtrarea de către firewall-uri a fragmentelor de datagrame pe baza unor criterii precum porturile sursă sau destinație.

O descriere mai elaborată a problemelor de fragmentare IP poate fi găsită în aceste articole ale lui Geoff Huston:

  • Evaluarea fragmentării pachetelor IPv4 și IPv6
  • Fragmentarea IPv6

Don’t fragment – ICMP Packet too big


Imagine de Geoff Huston, reprodusă cu permisiunea

O soluție la aceste probleme a fost inclusă în protocolul IPv4. Un expeditor poate seta steagul DF (Don’t Fragment) în antetul IP, cerând routerelor intermediare să nu efectueze niciodată fragmentarea unui pachet. În schimb, un router cu o legătură care are un MTU mai mic va trimite un mesaj ICMP „înapoi” și va informa expeditorul să reducă MTU pentru această conexiune.

Protocolul TCP setează întotdeauna steagul DF. Stiva de rețea se uită cu atenție la mesajele ICMP „Packet too big” primite și ține evidența caracteristicii „path MTU” pentru fiecare conexiune. Această tehnică se numește „path MTU discovery” (descoperirea MTU a traseului) și este utilizată în principal pentru TCP, deși poate fi aplicată și altor protocoale bazate pe IP. A fi capabil să livreze mesajele ICMP „Packet too big” este esențial pentru ca stiva TCP să funcționeze în mod optim.

Cum funcționează de fapt internetul

Într-o lume perfectă, dispozitivele conectate la internet ar coopera și ar gestiona corect fragmentele de datagramă și pachetele ICMP asociate. În realitate însă, fragmentele IP și pachetele ICMP sunt foarte des filtrate.

Acest lucru se datorează faptului că internetul modern este mult mai complex decât se anticipa acum 36 de ani. Astăzi, practic nimeni nu este conectat direct la internetul public.

Dispozitivele clienților se conectează prin intermediul routerelor casnice care fac NAT (Network Address Translation) și, de obicei, aplică reguli de firewall. Din ce în ce mai des există mai mult de o instalație NAT pe traseul pachetelor (de exemplu, NAT de tip carrier-grade). Apoi, pachetele ajung la infrastructura ISP, unde există „cutii intermediare” ale ISP. Acestea efectuează tot felul de acțiuni ciudate asupra traficului: aplică plafoane de plan, restricționează conexiunile, efectuează înregistrări, deturnează cererile DNS, implementează interdicții de site-uri web impuse de guvern, forțează memoria cache transparentă sau, probabil, „optimizează” traficul într-un alt mod magic. Cutiile intermediare sunt folosite în special de către operatorii de telefonie mobilă.

În mod similar, există adesea mai multe straturi între un server și internetul public. Furnizorii de servicii folosesc uneori rutarea Anycast BGP. Adică: ei gestionează aceleași intervale IP din mai multe locații fizice din întreaga lume. În cadrul unui centru de date, pe de altă parte, este din ce în ce mai populară utilizarea ECMP Equal Cost Multi Path pentru echilibrarea sarcinii.

Care dintre aceste straturi dintre un client și server poate cauza o problemă de Path MTU. Permiteți-mi să ilustrez acest lucru cu patru scenarii.

1. Client -> Server DF+ / ICMP

În primul scenariu, un client încarcă niște date către server folosind TCP, astfel încât steagul DF este setat pe toate pachetele. Dacă clientul nu reușește să prezică un MTU adecvat, un router intermediar va renunța la pachetele mari și va trimite o notificare ICMP „Packet too big” înapoi la client. Aceste pachete ICMP ar putea fi scăpate de dispozitive NAT ale clienților configurate greșit sau de cutii intermediare ale ISP.

Potrivit lucrării lui Maikel de Boer și Jeffrey Bosma din 2012, aproximativ 5% dintre gazdele IPv4 și 1% dintre gazdele IPv6 blochează pachetele ICMP de intrare.

Experiența mea confirmă acest lucru. Mesajele ICMP sunt într-adevăr adesea abandonate pentru avantaje de securitate percepute, dar acest lucru este relativ ușor de rezolvat. O problemă mai mare este cu anumiți ISP mobili cu cutii de mijloc ciudate. Acestea ignoră adesea complet ICMP și efectuează o rescriere foarte agresivă a conexiunii. De exemplu, Orange Polska nu numai că ignoră mesajele ICMP „Packet too big” primite, dar, de asemenea, rescrie starea conexiunii și fixează MSS la un număr nenegociabil de 1344 de octeți.

2. Client -> Server DF- / fragmentare

În următorul scenariu, un client încarcă niște date cu un alt protocol decât TCP, care are steagul DF eliminat. De exemplu, ar putea fi vorba de un utilizator care joacă un joc folosind UDP sau care are un apel vocal. Pachetele mari de ieșire ar putea fi fragmentate la un moment dat pe traseu.

Potem emula acest lucru lansând ping cu o dimensiune mare a încărcăturii utile:

$ ping -s 2048 facebook.com

Acest ping special va eșua cu încărcături utile mai mari de 1472 octeți. Orice dimensiune mai mare va fi fragmentată și nu va fi livrată corespunzător. Există mai multe motive pentru care serverele ar putea gestiona greșit fragmentele, dar una dintre problemele populare este utilizarea echilibrării sarcinii ECMP. Datorită hașurării ECMP, este probabil ca prima datagramă care conține un antet de protocol să fie echilibrată în funcție de sarcină către un server diferit de restul fragmentelor, împiedicând reasamblarea.

Pentru o discuție mai detaliată a acestei probleme, consultați:

  • Scrisoarea noastră anterioară despre ECMP.
  • Cum încearcă Google să rezolve problemele de fragmentare ECMP cu Maglev L4 Load balancer.

În plus, configurarea greșită a serverului și a routerului este o problemă semnificativă. Conform RFC7852, între 30% și 55% dintre servere renunță la datagramele IPv6 care conțin antet de fragmentare.

3. Server -> Client DF+ / ICMP

Scenariul următor se referă la un client care descarcă niște date prin TCP. Atunci când serverul nu reușește să prezică MTU-ul corect, acesta ar trebui să primească un mesaj ICMP „Packet too big”. Ușor, nu-i așa?

Din păcate, nu este așa, din nou din cauza rutei ECMP. Cel mai probabil, mesajul ICMP va fi livrat către serverul greșit – hash-ul de 5tuple al pachetului ICMP nu se va potrivi cu hash-ul de 5tuple al conexiunii problematice. Am scris despre acest lucru în trecut și am dezvoltat un demon simplu de spațiu utilizator pentru a-l rezolva. Acesta funcționează prin difuzarea notificării ICMP de intrare „Packet too big” către toate serverele ECMP, în speranța că cel care are conexiunea problematică o va vedea.

În plus, din cauza rutei Anycast, ICMP-ul ar putea fi livrat către un centru de date greșit! Rutarea pe internet este adesea asimetrică, iar cea mai bună cale de la un router intermediar ar putea direcționa pachetele ICMP către un loc greșit.

Pierderea notificărilor ICMP „Packet too big” poate duce la blocarea și întreruperea conexiunilor. Acest lucru se numește adesea o gaură neagră PMTU. Pentru a ajuta acest caz pesimist, Linux implementează o soluție de rezolvare – MTU Probing RFC4821. MTU Probing încearcă să identifice în mod automat pachetele abandonate din cauza unui MTU greșit și folosește euristica pentru a-l regla. Această funcție este controlată prin intermediul unui sysctl:

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

Dar MTU probing nu este lipsit de propriile probleme. În primul rând, tinde să clasifice greșit pierderile de pachete legate de congestie ca fiind probleme de MTU. Conexiunile care rulează mult timp tind să sfârșească cu un MTU redus. În al doilea rând, Linux nu implementează MTU Probing pentru IPv6.

4. Server -> Client DF- / fragmentare

În cele din urmă, există o situație în care serverul trimite pachete mari folosind un protocol non-TCP cu bitul DF liber. În acest scenariu, pachetele mari vor fi fragmentate pe traseul către client. Această situație este cel mai bine ilustrată cu răspunsuri DNS mari. Iată două cereri DNS care vor genera răspunsuri mari și vor fi livrate clientului sub formă de mai multe fragmente IP:

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

Aceste cereri ar putea eșua din cauza deja menționată a routerului de acasă configurat greșit, a NAT-ului defectuos, a instalațiilor defectuoase ale ISP-ului sau a setărilor prea restrictive ale firewall-ului.

Potrivit lui Boer și Bosma, aproximativ 6% din gazdele IPv4 și 10% din gazdele IPv6 blochează datagramele de fragmentare de intrare.

Iată câteva link-uri cu mai multe informații despre problemele specifice de fragmentare care afectează DNS:

  • DNS-OARC Reply Size Test
  • IPv6, Large UDP Packets and the DNS

Și totuși internetul încă funcționează!

Cu toate aceste lucruri care merg prost, cum reușește internetul să funcționeze în continuare?

CC BY-SA 3.0, sursa: Wikipedia

Acest lucru se datorează în principal succesului lui Ethernet. Marea majoritate a legăturilor din internetul public sunt Ethernet (sau derivate din acesta) și suportă MTU de 1500 de octeți.

Dacă vă asumați orbește MTU de 1500, veți fi surprins de câte ori va funcționa foarte bine. Internetul continuă să funcționeze mai ales pentru că toți folosim un MTU de 1500 și rareori avem nevoie să facem fragmentare IP și să trimitem mesaje ICMP.

Acest lucru încetează să mai funcționeze într-o configurație neobișnuită cu legături care au un MTU non-standard. VPN-urile și alte programe de tuneluri de rețea trebuie să fie atente pentru a se asigura că fragmentele și mesajele ICMP funcționează bine.

Acest lucru este vizibil în special în lumea IPv6, unde mulți utilizatori se conectează prin tuneluri. A avea o trecere sănătoasă a ICMP în ambele sensuri este foarte important, mai ales că fragmentarea în IPv6 practic nu funcționează (am citat două surse care susțin că între 10% și 50% dintre gazdele IPv6 blochează antetul IPv6 Fragment).

Din moment ce problemele legate de Path MTU în IPv6 sunt atât de frecvente, multe servere IPv6 restrâng Path MTU la minimul impus de protocol de 1280 de octeți. Această abordare tranzacționează un pic de performanță pentru cea mai bună fiabilitate.

Verificator de găuri negre ICMP online

Pentru a ajuta la explorarea și depanarea acestor probleme, am construit un verificator online. Puteți găsi două versiuni ale testului:

  • Versiunea IPv4: http://icmpcheck.popcount.org
  • Versiunea IPv6: http://icmpcheckv6.popcount.org

Aceste site-uri lansează două teste:

  • Primul test va trimite mesaje ICMP către calculatorul dumneavoastră, cu intenția de a reduce MTU-ul căii la o valoare ridicol de mică.
  • Cel de-al doilea test vă va trimite înapoi datagrame de fragmente.

Recepționarea unui „pass” la aceste două teste ar trebui să vă dea o asigurare rezonabilă că internetul de pe partea dumneavoastră de cablu se comportă bine.

Este, de asemenea, ușor să executați testele din linia de comandă, în cazul în care doriți să le executați pe server:

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

Aceasta ar trebui să reducă MTU-ul căii către serverul nostru la 905 octeți. Puteți să verificați acest lucru uitându-vă în tabelul cache de rutare. Pe Linux faceți acest lucru cu:

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

Este posibil să ștergeți cache-ul de rutare pe Linux:

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

Cel de-al doilea test verifică dacă fragmentele sunt livrate corect către client:

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

Summary

În această postare pe blog am descris problemele legate de detectarea valorilor Path MTU pe internet. ICMP și datagramele de fragmente sunt adesea blocate pe ambele părți ale conexiunilor. Clienții pot întâlni firewall-uri configurate greșit, dispozitive NAT sau pot utiliza furnizori de servicii de internet care interceptează agresiv conexiunile. De asemenea, clienții folosesc adesea VPN-uri sau tuneluri IPv6 care, configurate greșit, pot cauza probleme de path MTU.

Serverele, pe de altă parte, se bazează din ce în ce mai des pe Anycast sau ECMP. Ambele lucruri, precum și configurarea necorespunzătoare a routerului și a firewall-ului sunt adesea o cauză a scăpării datelor ICMP și a fragmentelor.

În cele din urmă, sperăm că testul online este util și vă poate oferi mai multe informații despre funcționarea internă a rețelelor dumneavoastră. Testul are exemple utile de sintaxă tcpdump, utile pentru a obține mai multe informații. Depanare de rețea fericită!

Este interesantă rezolvarea problemelor de fragmentare pentru 10% din internet? Angajăm ingineri de sistem de toate felurile, programatori Golang, C wranglers și stagiari în mai multe locații! Alăturați-vă nouă în San Francisco, Londra, Austin, Champaign și Varșovia.

  1. În IPv6, fragmentarea „forward” funcționează puțin diferit față de IPv4. Ruterelor intermediare le este interzis să fragmenteze pachetele, dar sursa o poate face în continuare. Acest lucru este adesea derutant – unei gazde i se poate cere să fragmenteze un pachet pe care l-a transmis în trecut. Acest lucru are puțin sens pentru protocoale fără stare, cum ar fi DNS. ︎

  2. În altă ordine de idei, există, de asemenea, o „unitate minimă de transmisie”! În framing-ul Ethernet utilizat în mod obișnuit, fiecare datagramă transmisă trebuie să aibă cel puțin 64 de octeți pe nivelul 2. Acest lucru se traduce prin 22 de octeți pe UDP și 10 octeți pe stratul TCP. Mai multe implementări obișnuiau să aibă scurgeri de memorie neinitializată în cazul pachetelor mai scurte! ︎

  3. Strict vorbind, în IPv4, pachetul ICMP se numește „Destination Unreachable, Fragmentation Needed and Don’t Fragment was Set”. Dar mi se pare mult mai clară descrierea erorii ICMP IPv6 „Packet too big”. ︎

  4. Ca un indiciu, stiva TCP include, de asemenea, o valoare maximă permisă „MSS” în pachetele SYN (MSS este, practic, o valoare MTU redusă cu dimensiunea antetelor IP și TCP). Acest lucru permite gazdelor să știe care este MTU pe legăturile lor. Observație: acest lucru nu spune care este MTU pe zecile de legături de internet dintre cele două gazde! ︎

  5. Să greșim pe partea sigură. Un MTU mai bun este 1492, pentru a se adapta la conexiunile DSL și PPPoE. ︎

Lasă un răspuns

Adresa ta de email nu va fi publicată.