Sunt sunat de catre un client pentru a fi informat ca nu ii functioneaza unele site-uri si conferintele video prin orice tip de aplicatie. Unul din aceste site-uri era Wikipedia. Respectivul detinea un Mikrotik hAP Lite. Problema era doar cand se conecta prin Mikrotik, dar daca conecta direct cablul de la provider putea sa acceseze.

Dupa 2 ore de cautari in care am verificat firewall-ul, rutarea, NAT-ul sau Mangle, fara sa gasesc vreo problema, am observat ca interfata pppoe avea mtu (Maximum Transmision Unit) 512 si mru (Maximum Receive Unit) setat cu valoarea 512, ceea ce insemna ca la trimitere si primire pachetele ip nu au voie sa aiba mai mult de 512 bytes. Daca scadem header-ul tcp si ip (total 40 bytes) ajungem la un payload de 472 bytes (MSS).
Neobservand initial ca mru era de 512, am schimbat doar mtu-ul facandu-l de 1480, specific pentru pppoe. Sesiunile video au inceput sa functioneze, dar unele site-uri tot nu puteau fi accesate.

Recunosc ca pana acum nu m-a interesat mru-ul, deoarece in toate discutiile de networking mtu-ul este in varful lor, iar mru-ul ramane undeva in umbra, dar la acest client fusese modificat. By default, el trebuie sa fie la fel ca mtu-ul, pentru ca, logic vorbind, traficul trebuie sa aiba parametri identici atat pe intrare cat si pe iesire. De aceea este numit bidirectional. In acest caz, daca pachetele primite sunt mai mari decat mru-ul setat atunci sunt dropate.

Clientul avea activ pe Mikrotik Path MTU Discovery, cu rolul de a negocia activ dimensiunea mtu, dar aceasta tehnologie nu rezolva toate problemele. Multe dispozitive de securitate in retea blocheaza mesajele ICMP, inclusiv mesajele cu privire la erori, necesare operatiunii PMTUD. Acest lucru poate cauza retinerea datelor pe traseu, cu toate ca avem negocierea TCP (3-way handshake) realizata cu succes. Aceasta situatie este denumita ”black hole connection”. De aceea, trebuie permise mesajele ICMP de tip 3 (Unreachable) pentru ca tcp sa opereze in mod eficient.

In cazul unui mtu mai mic decat default-ul 1500, multi operatori telecom au gasit solutia in modificarea MSS (Max Segment Size), deoarece atunci cand se negociaza mtu si mss nu vor exista probleme de nepotrivire, in sensul ca mss-ul nu va fi mai mare decat poate mtu-ul sa cuprinda.

In cazul clientului nostru puteam sa rezolvam cu modificarea MSS-ului. ICMP era deja permis catre Wikipedia si alte destinatii, insa problema era mai profunda si nu ar fi mers in toate situatiile doar cu modificarea MSS-ului. Este adevarat ca folosind Path MTU Discovery ceilalti erau informati de dimensiunea MTU, avand posibilitatea sa trimita un mesaj pentru fragmentare, iar prin alterarea mss-ului la negocierea tcp nu era acceptat un mss prea mare pentru mtu-ul configurat, insa problema aparea din cazua MRU si in special la traficul SSL.

Wireshark a fost extrem de util in identificarea problemei. Recomand utilizarea acestei aplicatii, deoarece putem observa in detaliu, prin capturarea pachetelor, negocierea tcp si ssl. A trebuit doar ss filtrez ip-ul site-ului Wikipedia si am sesizat punctul in care incep sa apara problemele:

3-Way Handshake s-a realizat cu succes, numai ca din cauza unui MRU mai mic serverul va trimite pachetele cu 512 Window Size, nu cu 1480. Din cate observati primele 2 pachete sunt de fapt unul singur fragmentat in 2 pentru a deservi limitarea (2×256):

Din cate observam primele 4 pachete sunt cu gri, deoarece prin PMTUD serverul web Wikipedia afla care este marimea pachetului potrivita pentru transmitere catre client (512) si seteaza urmatoarele valori specifice acestei sesiuni: MSS=472 și WS=512. Se intelege de la inceput care vor fi valorile, dupa care urmeaza ACK-ul si negocierea SSL:

Clientul trimite ACK si Hello duplicat, din cauza ca nu primeste confirmarea din partea serverului, iar serverul anunta ca secventa numerica a frame-ului nu este cea la care se astepta prin eroarea ”tcp previous segment not captured continuation data”. Practic pachetele s-au pierdut in tranzit tocmai din cauza unui black hole PMTUD. Clientul mai vede din partea serverului un ack duplicat, deoarece primise pentru frame-ul dinainte, dar nu in fereastra de timp in care se astepta. Posibil sa fi avut loc si o fragmentare a ack-ului, deoarece nu toate au avut df bit setat.
Totul incepe cu pachetele acestea:

Am punctat cu rosu marimea pachetelor de 571. In urma negocierii tcp, serverul credea ca este necesar sa trimita cu mss=472 și mtu=512, dar deoarece mtu era 1480, iar mru 512, clientul trimitea cu 571. Serverul web dadea drop fara sa fragmenteze, deoarece pachetul Hello pentru negocierea SSL avea DF bit setat (do not fragment) si trimitea mesaj ca segmentul nu a fost capturat:

Cum am spus, problema era doar pentru unele site-uri https, iar cauza principala a fost bit-ul DF pornit in combinatie cu un MRU de 512, pachetele de hello in negocierea ssl fiind mai mari. Din aceasta cauza ele erau dropate cauzand erori tcp de ack duplicat in negociere. Dupa ce expira exchange-ul mentinut prin keepalive-uri acesta este finalizat printr-un RST:

Steagul DF instruieste routerul sa dropeze pachetele prea mari pentru MTU-ul setat pe link si sa informeze prin mesaj icmp -fragmentation needed- ca acest pachet trebuie trimis cu o dimensiune mai mica. Acesta, in mod normal, ar fragmenta pachetele respective, evident cu riscul de a cauza probleme pentru aplicatiile sensibile din cauza pachetelor care ajung in afara ordinii, de exemplu in cazul nostru cu ACK-urile duplicat, pachetele TCP reasamblate si segmentele necapturate. Cel mai bine este sa lasam dimensiunile default pentru mtu si mru, PMTUD activ si mesajele icmp permise pentru o buna functionare.

Dupa configurarea dimensiunii default pentru MRU (1480, identic cu MTU) site-ul Wikipedia si altele au putut fi accesate. Lectia principala este aceea ca fragmentarea nu este buna pentru aplicatiile sensibile si din aceasta cauza trebuie evitata pe cat posibil. Ce putem face este sa setam MTU-ul standard (da, si MRU-ul), maxim sa alteram MSS-ul in cazul telefoniei IP sau a unor aplicatii sensibile la overhead-ul cauzat de incapsulari aditionale (despre asta intr-un alt articol).

Recapitulam cauzele problemei:

  1. Setarea bitului de interzicere a fragmentarii a cauzat droparea pachetelor mai mari din negocierea SSL si sesiunea efectiva in cazul in care ”Application DATA” incepea sa curga.
  2. Fragmentarea pachetelor SSL datorita mesajului ICMP – fragmentation needed – a cauzat ack-ul duplicat si reasamblarea segmentelor tcp, ducand la ratarea segmentelor de catre server.
  3. MRU-ul prea mic a dus la o fragmentare excesiva si datorita pierderii unor pachete a dus si la deformarea datelor facand imposibila stabilirea sesiunii SSL.

Articol scris de Bogdan Curduban – Network Engineer