Rikkinäiset paketit:
Julkisesta puhelinverkosta poiketen internet on suunniteltu pakettikytkentäiseksi. Mutta kuinka suuria nämä paketit voivat olla?
CC BY 2.0 image by ajmexico, inspired by
Tämä on vanha kysymys, ja IPv4 RFC:t vastaavat siihen melko selvästi. Ajatuksena oli jakaa ongelma kahdeksi erilliseksi huolenaiheeksi:
-
Mikä on suurin pakettikoko, jota käyttöjärjestelmät voivat käsitellä molemmissa päissä?
-
Mikä on suurin sallittu datagrammin koko, joka voidaan turvallisesti työntää isäntien välisten fyysisten yhteyksien läpi?
Kun paketti on liian suuri fyysiselle yhteydelle, välissä oleva reititin saattaa pilkkoa sen useisiin pienempiin datagrammeihin saadakseen sen mahtumaan. Tätä prosessia kutsutaan IP:n pirstaloitumiseksi ”eteenpäin”, ja pienempiä datagrammeja kutsutaan IP-fragmenteiksi.
Kuva Geoff Huston, jäljennetty luvalla
IPv4-spesifikaatiossa määritellään minimivaatimukset. 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.
Ensimmäinen arvo – sallittu uudelleen koottu pakettikoko – ei yleensä ole ongelmallinen. IPv4 määrittelee minimiarvoksi 576 tavua, mutta suositut käyttöjärjestelmät pärjäävät hyvin suurilla paketeilla, tyypillisesti jopa 65 kilotavulla.
Toinen arvo on hankalampi. Kaikilla fyysisillä yhteyksillä on luontaiset datagrammin kokorajoitukset, jotka riippuvat niiden käyttämästä tietovälineestä. Esimerkiksi Frame Relay voi lähettää datagrammeja 46-470 tavun välillä. ATM käyttää kiinteää 53 tavua, klassinen Ethernet voi tehdä 64 ja 1 500 tavun välillä.
Spesifikaatio määrittelee minimivaatimuksen – jokaisen fyysisen linkin on pystyttävä lähettämään vähintään 68 tavun datagrammeja. IPv6:n osalta tuo minimiarvo on nostettu 1280 tavuun (ks. RFC2460).
Toisaalta suurinta datagrammin kokoa, joka voidaan lähettää ilman pirstoutumista, ei ole määritelty missään spesifikaatiossa ja se vaihtelee linkkityypeittäin. Tätä arvoa kutsutaan MTU:ksi (Maximum Transmission Unit).
MTU määrittelee datagrammin enimmäiskoon paikallisella fyysisellä linkillä. Internet on luotu epähomogeenisista verkoista, ja kahden isäntäkoneen välisellä reitillä voi olla linkkejä, joiden MTU-arvo on lyhyempi. Suurinta pakettikokoa, joka voidaan välittää ilman pirstoutumista kahden etä-isännän välillä, kutsutaan polun MTU:ksi, ja se voi mahdollisesti olla erilainen jokaisella yhteydellä.
Välttää pirstoutumista
Voidaan ajatella, että on hienoa rakentaa sovelluksia, jotka lähettävät hyvin isoja paketteja, ja luottaa siihen, että reitittimet suorittavat IP-pirstoutumisen. Tämä ei kuitenkaan ole hyvä ajatus. Tämän lähestymistavan ongelmista keskustelivat ensimmäisen kerran Kent ja Mogul vuonna 1987. Seuraavassa on muutama kohokohta:
-
Paketin onnistunut uudelleenkokoaminen edellyttää, että kaikki fragmentit toimitetaan. Mikään fragmentti ei saa vioittua tai kadota lennon aikana. Ei yksinkertaisesti ole mitään keinoa ilmoittaa toiselle osapuolelle puuttuvista fragmenteista!
-
Viimeinen fragmentti ei lähes koskaan ole optimaalisen kokoinen. Suurissa siirroissa tämä tarkoittaa, että merkittävä osa liikenteestä koostuu epäoptimaalisista lyhyistä datagrammeista – arvokkaiden reititinresurssien tuhlausta.
-
Ennen uudelleenkokoamista isännän on pidettävä muistissa osittaisia, pirstaleisia datagrammeja. Tämä avaa mahdollisuuden muistin uupumishyökkäyksille.
-
Seuraavista fragmenteista puuttuu ylemmän kerroksen otsikko. TCP- tai UDP-otsikko on vain ensimmäisessä fragmentissa. Tämän vuoksi palomuurit eivät voi suodattaa pirstaloituja datagrammeja esimerkiksi lähde- tai kohdeporttien kaltaisten kriteerien perusteella.
Tarkempi kuvaus IP:n pirstaloitumisongelmista löytyy näistä Geoff Hustonin artikkeleista:
- Evaluating IPv4 and IPv6 packet fragmentation
- Fragmenting IPv6
Don’t fragment – ICMP Packet too big
Kuvan on ottanut Geoff Huston, jäljennetty luvalla
Ratkaisu näihin ongelmiin sisällytettiin IPv4-protokollaan. Lähettäjä voi asettaa IP-otsikkoon DF (Don’t Fragment) -lippulauseen, joka pyytää välireitittimiä olemaan koskaan suorittamatta paketin pirstomista. Sen sijaan reititin, jolla on linkki, jolla on pienempi MTU, lähettää ICMP-viestin ”taaksepäin” ja ilmoittaa lähettäjälle, että tämän yhteyden MTU:ta on pienennettävä.
TCP-protokolla asettaa aina DF-lipun. Verkkopino etsii huolellisesti saapuvia ”Packet too big” ICMP-viestejä ja seuraa ”path MTU” -ominaisuutta jokaisen yhteyden osalta. Tätä tekniikkaa kutsutaan ”polun MTU:n löytämiseksi”, ja sitä käytetään useimmiten TCP:ssä, vaikka sitä voidaan soveltaa myös muihin IP-pohjaisiin protokolliin. Kyky toimittaa ICMP ”Packet too big” -viestejä on ratkaisevan tärkeää TCP-pinon optimaalisen toiminnan kannalta.
Miten internet todellisuudessa toimii
Täydellisessä maailmassa internetiin kytketyt laitteet toimisivat yhteistyössä ja käsittelisivät sirpaloituneita datagrammeja ja niihin liittyviä ICMP-paketteja oikein. Todellisuudessa IP-pätkät ja ICMP-paketit suodatetaan kuitenkin hyvin usein pois.
Tämä johtuu siitä, että nykyaikainen internet on paljon monimutkaisempi kuin 36 vuotta sitten ennakoitiin. Nykyään periaatteessa kukaan ei ole kytketty suoraan julkiseen internetiin.
Asiakkaiden laitteet kytkeytyvät kotireitittimien kautta, jotka tekevät NAT:n (Network Address Translation) ja yleensä noudattavat palomuurisääntöjä. Yhä useammin pakettipolulla on useampi kuin yksi NAT-asennus (esim. operaattoritason NAT). Tämän jälkeen paketit saapuvat Internet-palveluntarjoajan infrastruktuuriin, jossa on Internet-palveluntarjoajan ”välikoteloita”. Ne tekevät liikenteelle kaikenlaisia outoja asioita: valvovat suunnitelmien ylärajoja, kuristavat yhteyksiä, kirjaavat lokitietoja, kaappaavat DNS-pyyntöjä, panevat täytäntöön hallituksen määräämiä verkkosivukieltoja, pakottavat läpinäkyvään välimuistitallennukseen tai ”optimoivat” liikennettä jollakin muulla maagisella tavalla. Keskimmäisiä laatikoita käyttävät erityisesti matkapuhelinyhtiöt.
Vastaavasti palvelimen ja julkisen internetin välillä on usein useita kerroksia. Palveluntarjoajat käyttävät joskus Anycast BGP -reititystä. Eli: ne käsittelevät samoja IP-alueita useista fyysisistä paikoista ympäri maailmaa. Tietokeskuksen sisällä taas on yhä suositumpaa käyttää ECMP Equal Cost Multi Path -reititystä kuormanjakoon.
Jokainen näistä kerroksista asiakkaan ja palvelimen välillä voi aiheuttaa Path MTU -ongelman. Sallikaa minun havainnollistaa tätä neljällä skenaariolla.
1. Asiakas -> Palvelin DF+ / ICMP
Ensimmäisessä skenaariossa asiakas lataa palvelimelle jonkin verran dataa TCP:n avulla, joten DF-lippu on asetettu kaikkiin paketteihin. Jos asiakas ei pysty ennustamaan sopivaa MTU:ta, välireititin hylkää suuret paketit ja lähettää ICMP-ilmoituksen ”Packet too big” takaisin asiakkaalle. Nämä ICMP-paketit saattavat pudota asiakkaan väärin konfiguroidut NAT-laitteet tai Internet-palveluntarjoajan välilaatikot.
Maikel de Boerin ja Jeffrey Bosman vuonna 2012 julkaistun artikkelin mukaan noin 5 % IPv4-isännistä ja 1 % IPv6-isännistä estää saapuvat ICMP-paketit.
Kokemukseni vahvistavat tämän. ICMP-viestejä tosiaan usein hylätään havaittujen turvallisuusetujen vuoksi, mutta tämä on suhteellisen helppo korjata. Suurempi ongelma on tiettyjen mobiilipalveluntarjoajien kanssa, joilla on outoja välikäsiä. Nämä jättävät usein ICMP:n kokonaan huomiotta ja suorittavat hyvin aggressiivista yhteyden uudelleenkirjoittamista. Esimerkiksi Orange Polska ei ainoastaan jätä huomiotta saapuvia ”Packet too big” -ICMP-viestejä, vaan myös kirjoittaa yhteyden tilan uudelleen ja rajoittaa MSS:n ei-neuvottelukelpoiseen 1344 tavuun.
2. Asiakas -> Palvelin DF- / fragmentaatio
Seuraavassa skenaariossa asiakas lataa dataa muulla protokollalla kuin TCP:llä, jonka DF-merkki on poistettu. Kyseessä voi olla esimerkiksi käyttäjä, joka pelaa peliä UDP:tä käyttäen, tai jolla on äänipuhelu. Suuret lähtevät paketit saattavat pirstaloitua jossain vaiheessa polkua.
Voimme emuloida tätä käynnistämällä ping
suurella hyötykuorman koolla:
$ ping -s 2048 facebook.com
Tämä kyseinen ping
epäonnistuu, jos hyötykuorma on suurempi kuin 1472 tavua. Suurempi koko pirstaloituu eikä sitä saada toimitettua kunnolla. On useita syitä, miksi palvelimet saattavat käsitellä fragmentteja väärin, mutta yksi suosituimmista ongelmista on ECMP-kuormantasauksen käyttö. ECMP-hajautuksen vuoksi ensimmäinen protokollaotsikon sisältävä datagrammi todennäköisesti kuormitetaan eri palvelimelle kuin loput fragmentit, mikä estää uudelleenkokoamisen.
Tämän ongelman yksityiskohtaisempaa käsittelyä varten katso:
- Edellinen kirjoituksemme ECMP:stä.
- Miten Google yrittää ratkaista ECMP:n pirstaloitumisongelmat Maglev L4 -kuormantasaajalla.
Myös palvelimen ja reitittimen virheellinen konfigurointi on merkittävä ongelma. RFC7852:n mukaan 30-55 % palvelimista pudottaa pirstoutumisotsikon sisältäviä IPv6-datagrammeja.
3. Palvelin -> Asiakas DF+ / ICMP
Seuraavassa skenaariossa on kyse TCP:n kautta dataa lataavasta asiakkaasta. Kun palvelin ei pysty ennustamaan oikeaa MTU:ta, sen pitäisi saada ICMP-viesti ”Packet too big”. Helppoa, eikö?
Se ei valitettavasti ole, jälleen ECMP-reitityksen takia. ICMP-viesti toimitetaan todennäköisesti väärälle palvelimelle – ICMP-paketin 5-tuplan hash ei vastaa ongelmallisen yhteyden 5-tuplan hashia. Kirjoitimme tästä aiemmin ja kehitimme yksinkertaisen userspace-demonin ratkaisemaan ongelman. Se toimii lähettämällä saapuvan ICMP-ilmoituksen ”Packet too big” (paketti liian suuri) kaikille ECMP-palvelimille, toivoen, että ongelmallisen yhteyden omaava palvelin näkee sen.
Lisäksi Anycast-reitityksen vuoksi ICMP-ilmoitus saatetaan toimittaa väärään datakeskukseen! Internet-reititys on usein epäsymmetrinen, ja paras reitti välireitittimeltä saattaa ohjata ICMP-paketit väärään paikkaan.
Puuttuvat ICMP ”Packet too big” -ilmoitukset voivat johtaa yhteyksien pysähtymiseen ja aikakatkaisuun. Tätä kutsutaan usein PMTU-mustaksi aukoksi. Tämän pessimistisen tapauksen avuksi Linux toteuttaa kiertotavan – MTU Probing RFC4821. MTU Probing pyrkii automaattisesti tunnistamaan väärän MTU:n takia pudotetut paketit ja käyttää heuristiikkaa sen virittämiseen. Tätä ominaisuutta ohjataan sysctl:n avulla:
$ echo 1 > /proc/sys/net/ipv4/tcp_mtu_probing
Mutta MTU probing ei ole täysin ongelmaton. Ensinnäkin sillä on taipumus luokitella ruuhkautumiseen liittyvät pakettihäviöt väärin MTU-ongelmiksi. Pitkään käynnissä olevilla yhteyksillä on taipumus päätyä pienempään MTU:hun. Toiseksi Linux ei toteuta MTU Probingia IPv6:lle.
4. Palvelin -> Asiakas DF- / pirstaloituminen
Loppujen lopuksi on tilanne, jossa palvelin lähettää isoja paketteja käyttäen muuta kuin TCP-protokollaa DF-bitin ollessa tyhjä. Tässä skenaariossa isot paketit pirstoutuvat matkalla asiakkaalle. Tilannetta havainnollistetaan parhaiten suurilla DNS-vastauksilla. Seuraavassa on kaksi DNS-pyyntöä, jotka tuottavat suuria vastauksia ja toimitetaan asiakkaalle useina IP-fragmentteina:
$ dig +notcp +dnssec DNSKEY org @199.19.56.1$ dig +notcp +dnssec DNSKEY org @2001:500:f::1
Nämä pyynnöt saattavat epäonnistua jo mainitun väärin konfiguroidun kotireitittimen, rikkinäisen NAT:n, rikkinäisten Internet-palveluntarjoajan asennusten tai liian tiukkojen palomuuriasetusten vuoksi.
Boerin ja Bosman mukaan noin 6 % IPv4- ja 10 % IPv6-isännistä estävät saapuvat fragmentoidut datagrammeja.
Tässä on joitain linkkejä, joissa on lisätietoa DNS:ään vaikuttavista erityisistä pirstaloitumisongelmista:
- DNS-OARC Reply Size Test
- IPv6, suuret UDP-paketit ja DNS
Siltikin internet toimii!
Kun kaikki nämä asiat menevät pieleen, miten internet onnistuu silti toimimaan?
CC BY-SA 3.0, lähde: Wikipedia
Tämä johtuu pääasiassa Ethernetin menestyksestä. Valtaosa julkisen internetin linkeistä on Ethernetiä (tai siitä johdettuja), ja ne tukevat MTU:ta 1500 tavua.
Jos oletat sokeasti MTU:n olevan 1500, yllätyt, kuinka usein se toimii aivan hyvin. Internet toimii enimmäkseen siksi, että me kaikki käytämme MTU:ta 1500 ja tarvitsemme harvoin IP:n pirstalointia ja ICMP-viestien lähettämistä.
Tämä lakkaa toimimasta epätavallisessa kokoonpanossa, jossa linkeillä on epätyypillinen MTU. VPN:ien ja muiden verkkotunneliohjelmistojen on oltava tarkkoja varmistaakseen, että fragmentointi ja ICMP-viestit toimivat moitteettomasti.
Tämä näkyy erityisesti IPv6-maailmassa, jossa monet käyttäjät ovat yhteydessä tunneleiden kautta. ICMP:n terve kulku molempiin suuntiin on erittäin tärkeää, varsinkin kun pirstaloituminen IPv6:ssa ei periaatteessa toimi (siteerasimme kahta lähdettä, joiden mukaan 10-50 % IPv6-isännistä estää IPv6:n pirstaloituneen otsikon).
Koska Path MTU -ongelmat IPv6:ssa ovat niin yleisiä, monet IPv6-palvelimet rajoittavat Path MTU:n protokollan määräämään minimiin 1280 tavuun. Tällä lähestymistavalla vaihdetaan hieman suorituskykyä parhaan luotettavuuden hyväksi.
Online ICMP blackhole checker
Voidaksemme auttaa näiden ongelmien tutkimisessa ja vianmäärityksessä rakensimme online-tarkistusohjelman. Testistä löytyy kaksi versiota:
- IPv4-versio: http://icmpcheck.popcount.org
- IPv6-versio: http://icmpcheckv6.popcount.org
Nämä sivustot käynnistävät kaksi testiä:
- Ensimmäinen testi lähettää ICMP-viestejä tietokoneellesi tarkoituksenaan pienentää polun MTU-arvo naurettavan pieneksi.
- Toinen testi lähettää pirstaleisia datagrammeja takaisin sinulle.
Kummassakin näistä testeistä ”läpäisyn” saamisen pitäisi antaa sinulle kohtuullinen varmuus siitä, että internet sinun puolellasi kaapelia käyttäytyy hyvin.
Testit on myös helppo ajaa komentoriviltä, jos haluat ajaa ne palvelimella:
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
Tämän pitäisi pienentää polun MTU:ta (Path MTU) palvelimellemme 905 tavuun. Voit tarkistaa tämän katsomalla reitityksen välimuistitaulukkoa. Linuxissa tämä tehdään:
ip route get `dig +short icmpcheck.popcount.org`
Linuxissa reititysvälimuisti on mahdollista tyhjentää:
ip route flush cache to `dig +short icmpcheck.popcount.org`
Toisen testin avulla tarkistetaan, että fragmentit toimitetaan asiakkaalle oikein:
curl -v -s http://icmpcheck.popcount.org/frag -o /dev/nullcurl -v -s http://icmpcheckv6.popcount.org/frag -o /dev/null
Yhteenveto
Tässä blogikirjoituksessa kuvailimme ongelmia polun MTU-arvojen havaitsemisessa internetissä. ICMP- ja fragmentti-datagrammeja estetään usein yhteyksien molemmin puolin. Asiakkaat voivat törmätä väärin konfiguroituihin palomuureihin, NAT-laitteisiin tai käyttää Internet-palveluntarjoajia, jotka sieppaavat yhteyksiä aggressiivisesti. Asiakkaat käyttävät usein myös VPN:iä tai IPv6-tunneleita, jotka väärin konfiguroituna voivat aiheuttaa polun MTU-ongelmia.
Palvelimet taas luottavat yhä useammin Anycastiin tai ECMP:hen. Molemmat näistä asioista sekä reitittimen ja palomuurin vääränlainen konfigurointi ovat usein syynä ICMP- ja fragmenttitietosignaalien hylkäämiseen.
Loppujen lopuksi toivomme, että verkkotestistä on hyötyä ja että se voi antaa sinulle lisää tietoa verkkojesi sisäisestä toiminnasta. Testissä on hyödyllisiä esimerkkejä tcpdump-syntaksista, joista on hyötyä lisäymmärryksen saamiseksi. Hyvää verkon virheenkorjausta!
Onko pirstaloitumisongelmien korjaaminen jännittävää 10 prosentille internetistä? Palkkaamme kaikenlaisia järjestelmäinsinöörejä, Golang-ohjelmoijia, C-ohjelmoijia ja harjoittelijoita useisiin paikkoihin! Tule mukaan San Franciscoon, Lontooseen, Austiniin, Champaigniin ja Varsovaan.
-
Ipv6:ssa pirstaloituminen ”eteenpäin” toimii hieman eri tavalla kuin IPv4:ssä. Välireitittimiä kielletään pirstomasta paketteja, mutta lähde voi silti tehdä sen. Tämä on usein hämmentävää – isäntäkanavaa saatetaan pyytää pirstomaan paketti, jonka se on lähettänyt aiemmin. Tässä ei ole juurikaan järkeä DNS:n kaltaisten tilattomien protokollien kannalta. ︎
-
Sivuhuomautuksena mainittakoon, että on olemassa myös ”minimilähetysyksikkö”! Yleisesti käytetyssä Ethernet-kehystyksessä jokaisen lähetettävän datagrammin on oltava vähintään 64 tavua Layer 2:lla. Tämä tarkoittaa 22 tavua UDP-kerroksessa ja 10 tavua TCP-kerroksessa. Useat toteutukset vuotavat alustamatonta muistia lyhyemmissä paketeissa! ︎
-
Suoraan ottaen IPv4:ssä ICMP-paketin nimi on ”Destination Unreachable, Fragmentation Needed and Don’t Fragment was Set”. IPv6:n ICMP-virhekuvaus ”Packet too big” on mielestäni kuitenkin paljon selkeämpi. ︎
-
Vihjeeksi TCP-pino sisältää myös suurimman sallitun ”MSS”-arvon SYN-paketeissa (MSS on periaatteessa MTU-arvo, josta on vähennetty IP- ja TCP-otsakkeiden koko). Näin isännät tietävät, mikä on niiden linkkien MTU-arvo. Huomaa: tämä ei kerro, mikä on kahden isännän välisten kymmenien Internet-linkkien MTU-arvo! ︎
-
Varaudutaan varman päälle. Parempi MTU on 1492, jotta DSL- ja PPPoE-yhteydet mahtuisivat mukaan. ︎