Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu

Google'i ajaveebi redaktorist: Kas olete kunagi mõelnud, kuidas Google'i pilve tehniliste lahenduste (TSE) insenerid teie tugitaotlusi käsitlevad? TSE tehnilise toe insenerid vastutavad kasutajate teatatud probleemide allikate tuvastamise ja parandamise eest. Mõned neist probleemidest on üsna lihtsad, kuid mõnikord tuleb ette pilet, mis nõuab korraga mitme inseneri tähelepanu. Selles artiklis räägib üks TSE töötajatest meile ühest väga keerulisest probleemist, mis on tema hiljutisest praktikast pärit - puuduvate DNS-pakettide korral. Selles loos näeme, kuidas inseneridel õnnestus olukord lahendada ja mida uut nad vea parandamisel teada said. Loodame, et see lugu ei teavita teid mitte ainult sügavalt juurdunud veast, vaid annab teile ka ülevaate protsessidest, mis kuluvad Google Cloudi tugipileti esitamiseks.

Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu

Veaotsing on nii teadus kui ka kunst. Kõik algab süsteemi ebastandardse käitumise põhjuse kohta hüpoteesi püstitamisest, misjärel testitakse selle tugevust. Enne hüpoteesi sõnastamist peame aga probleemi selgelt määratlema ja täpselt sõnastama. Kui küsimus tundub liiga ebamäärane, peate kõike hoolikalt analüüsima; See on tõrkeotsingu "kunst".

Google Cloudi all muutuvad sellised protsessid eksponentsiaalselt keerukamaks, kuna Google Cloud annab endast parima, et tagada oma kasutajate privaatsus. Seetõttu pole TSE inseneridel juurdepääsu teie süsteemide redigeerimiseks ega ka võimalust vaadata konfiguratsioone nii laialt kui kasutajatel. Seetõttu ei saa me (insenerid) oma hüpoteesi testimiseks süsteemi kiiresti muuta.

Mõned kasutajad usuvad, et teeme kõik asjad korda nagu mehaanika autoteeninduses ja saadame meile lihtsalt virtuaalmasina ID, samas kui tegelikult toimub protsess vestlusvormingus: info kogumine, hüpoteeside moodustamine ja kinnitamine (või ümberlükkamine), ja lõpuks põhinevad otsustusprobleemid kliendiga suhtlemisel.

Probleem kõne all

Täna on meil hea lõpuga lugu. Kavandatava juhtumi eduka lahendamise üheks põhjuseks on probleemi väga detailne ja täpne kirjeldus. Allpool näete esimese pileti koopiat (konfidentsiaalse teabe peitmiseks muudetud):
Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu
See sõnum sisaldab meile palju kasulikku teavet:

  • Määratud konkreetne VM
  • Probleem ise on näidatud - DNS ei tööta
  • Näidatakse, kus probleem avaldub - VM ja konteiner
  • Näidatud on toimingud, mida kasutaja probleemi tuvastamiseks astus.

Taotlus registreeriti kui “P1: Critical Impact – Service Unusable in production”, mis tähendab pidevat 24/7 olukorra jälgimist skeemi “Follow the Sun” järgi (saate lugeda lähemalt kasutajapäringute prioriteedid) koos selle üleminekuga ühelt tehnilise toe meeskonnalt teisele iga ajavööndivahetusega. Tegelikult oli probleem meie meeskonnani Zürichis jõudnud juba ümber maakera. Selleks ajaks oli kasutaja võtnud leevendusmeetmeid, kuid kartis tootmises olukorra kordumist, kuna algpõhjust polnud veel avastatud.

Kui pilet Zürichisse jõudis, oli meil juba käes järgmine info:

  • Sisu /etc/hosts
  • Sisu /etc/resolv.conf
  • Väljund iptables-save
  • Meeskonna poolt kokku pandud ngrep pcap fail

Nende andmetega olime valmis alustama "juurdluse" ja tõrkeotsingu etappi.

Meie esimesed sammud

Kõigepealt kontrollisime metaandmete serveri logisid ja olekut ning veendusime, et see töötab õigesti. Metaandmete server vastab IP-aadressile 169.254.169.254 ja muuhulgas vastutab domeeninimede kontrollimise eest. Samuti kontrollisime üle, kas tulemüür töötab VM-iga õigesti ega blokeeri pakette.

See oli mingi kummaline probleem: nmap-kontroll lükkas ümber meie peamise hüpoteesi UDP-pakettide kadumise kohta, nii et mõtlesime välja veel mitu võimalust ja viisi nende kontrollimiseks:

  • Kas paketid kukutatakse valikuliselt? => Kontrollige iptablesi reegleid
  • Kas pole liiga väike? MTU? => Kontrolli väljundit ip a show
  • Kas probleem puudutab ka ainult UDP-pakette või TCP-d? => Sõida minema dig +tcp
  • Kas dig genereeritud paketid tagastatakse? => Sõida minema tcpdump
  • Kas libdns töötab õigesti? => Sõida minema strace et kontrollida pakettide edastamist mõlemas suunas

Siin otsustame helistada kasutajale probleemide tõrkeotsinguks.

Kõne ajal saame kontrollida mitmeid asju:

  • Pärast mitut kontrolli jätame põhjuste loendist välja iptablesi reeglid
  • Kontrollime võrguliideseid ja marsruutimistabeleid ning veelkord, et MTU oleks õige
  • Me avastame selle dig +tcp google.com (TCP) töötab nii nagu peab, kuid dig google.com (UDP) ei tööta
  • Olles ära sõitnud tcpdump see ikka töötab dig, leiame, et UDP-pakette tagastatakse
  • Sõidame minema strace dig google.com ja näeme, kuidas dig õigesti kutsub sendmsg() и recvms(), kuid teine ​​katkestatakse ajalõpuga

Kahjuks saabub vahetuse lõpp ja oleme sunnitud probleemi järgmisse ajavööndisse eskaleerima. Taotlus aga äratas meie meeskonnas huvi ning kolleeg soovitab luua algse DNS-i paketi, kasutades kraapivat Pythoni moodulit.

from scapy.all import *

answer = sr1(IP(dst="169.254.169.254")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="google.com")),verbose=0)
print ("169.254.169.254", answer[DNS].summary())

See fragment loob DNS-paketi ja saadab päringu metaandmete serverisse.

Kasutaja käivitab koodi, DNS-i vastus tagastatakse ja rakendus võtab selle vastu, kinnitades, et võrgu tasemel pole probleemi.

Pärast järjekordset “ümbermaailmareisi” naaseb taotlus meie meeskonnale ja ma kannan selle täielikult enda peale, arvates, et kasutajale on mugavam, kui päring lakkab ühest kohast tiirlemas.

Seni on kasutaja lahkelt nõus andma süsteemipildist hetktõmmise. See on väga hea uudis: võimalus süsteemi ise testida muudab tõrkeotsingu palju kiiremaks, sest ma ei pea enam paluma kasutajal käske käivitada, tulemusi mulle saata ja analüüsida, saan kõike ise teha!

Kolleegid hakkavad mind veidi kadestama. Lõuna ajal arutame pöördumist, kuid kellelgi pole aimugi, mis toimub. Õnneks on kasutaja ise tagajärgede leevendamiseks juba meetmeid võtnud ega kiirusta, seega on meil aega probleemi lahkamiseks. Ja kuna meil on pilt, saame läbi viia mis tahes teste, mis meid huvitavad. Suurepärane!

Astudes sammu tagasi

Üks populaarsemaid intervjuuküsimusi süsteemiinseneride ametikohtadel on: „Mis juhtub, kui pingida www.google.com? Küsimus on suurepärane, kuna kandidaat peab kirjeldama kõike alates kestast kuni kasutajaruumi, süsteemituuma ja seejärel võrguni. Naeratan: mõnikord osutuvad intervjuuküsimused ka päriselus kasulikuks...

Otsustan rakendada seda HR-küsimust praegusele probleemile. Jämedalt öeldes, kui proovite DNS-nime määrata, juhtub järgmine:

  1. Rakendus kutsub välja süsteemiteegi, näiteks libdns
  2. libdns kontrollib süsteemi konfiguratsiooni, millise DNS-serveriga ta peaks ühendust võtma (diagrammil on see 169.254.169.254, metaandmete server)
  3. libdns kasutab süsteemikutseid, et luua UDP-pesa (SOKET_DGRAM) ja saata UDP-pakette koos DNS-päringuga mõlemas suunas
  4. Sysctl liidese kaudu saate konfigureerida UDP pinu kerneli tasemel
  5. Kernel suhtleb riistvaraga, et edastada pakette võrgu kaudu võrguliidese kaudu
  6. Hüpervisor püüab kinni ja edastab paketi metaandmeserverisse, kui sellega kokku puutub
  7. Metaandmete server määrab oma võluväel DNS-i nime ja tagastab vastuse sama meetodit kasutades

Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu
Lubage mul teile meelde tuletada, milliseid hüpoteese oleme juba kaalunud:

Hüpotees: Katkised raamatukogud

  • Test 1: käivitage süsteemis strace, kontrollige, kas dig kutsub õigeid süsteemikutseid
  • Tulemus: helistatakse õigetele süsteemikõnedele
  • Test 2: srapy abil kontrollige, kas suudame nimesid määrata süsteemiteeke mööda minnes
  • Tulemus: saame
  • Test 3: käivitage paketis libdns ja md5sum teegifailides rpm –V
  • Tulemus: teegi kood on täiesti identne töötava operatsioonisüsteemi koodiga
  • Test 4: paigaldage kasutaja juursüsteemi kujutis virtuaalsesse masinasse ilma selle käitumiseta, käivitage chroot ja vaadake, kas DNS töötab
  • Tulemus: DNS töötab õigesti

Testide põhjal tehtud järeldus: probleem ei ole raamatukogudes

Hüpotees: DNS-i sätetes on viga

  • Test 1: kontrollige tcpdump ja vaadake, kas DNS-paketid saadetakse ja tagastatakse pärast digi käivitamist õigesti
  • Tulemus: paketid edastatakse õigesti
  • Test 2: kontrollige serverit uuesti /etc/nsswitch.conf и /etc/resolv.conf
  • Tulemus: kõik on õige

Testide põhjal tehtud järeldus: probleem ei ole DNS-i konfiguratsioonis

Hüpotees: südamik kahjustatud

  • Test: installige uus kernel, kontrollige allkirja, taaskäivitage
  • Tulemus: sarnane käitumine

Testide põhjal tehtud järeldus: tuum ei ole kahjustatud

Hüpotees: kasutajavõrgu (või hüperviisori võrguliidese) vale käitumine

  • Test 1: kontrollige tulemüüri sätteid
  • Tulemus: tulemüür edastab DNS-paketid nii hostis kui ka GCP-s
  • Test 2: peatage liiklus ja jälgige DNS-i päringute edastamise ja tagastamise õigsust
  • Tulemus: tcpdump kinnitab, et host on vastu võtnud tagastuspaketid

Testide põhjal tehtud järeldus: probleem pole võrgus

Hüpotees: metaandmete server ei tööta

  • Test 1: kontrollige metaandmeserveri logisid kõrvalekallete suhtes
  • Tulemus: logides pole anomaaliaid
  • Test 2: mööduge metaandmete serverist selle kaudu dig @8.8.8.8
  • Tulemus: eraldusvõime on katki isegi ilma metaandmete serverita

Testide põhjal tehtud järeldus: probleem ei ole metaandmete serveris

Tulemus: testisime kõiki alamsüsteeme v.a käitusaja seaded!

Kerneli käitusaja sätetesse sukeldumine

Kerneli täitmiskeskkonna konfigureerimiseks võite kasutada käsurea suvandeid (grub) või sysctl liidest. Vaatasin sisse /etc/sysctl.conf ja mõelge vaid, avastasin mitu kohandatud seadet. Tundes, nagu oleksin millestki kinni haaranud, loobusin kõik võrguvälised või mitte-tcp-sätted, jäädes mäeseadetele net.core. Seejärel läksin sinna, kus VM-is olid hostiõigused ja hakkasin katkise VM-iga ükshaaval sätteid rakendama, kuni leidsin süüdlase:

net.core.rmem_default = 2147483647

Siin see on, DNS-i murdev konfiguratsioon! Leidsin mõrvarelva. Aga miks see juhtub? Mul oli ikka vaja motiivi.

Põhiline DNS-paketi puhvri suurus on konfigureeritud kaudu net.core.rmem_default. Tüüpiline väärtus on kuskil 200KiB, kuid kui teie server saab palju DNS-pakette, võiksite puhvri suurust suurendada. Kui puhver on uue paketi saabudes täis, näiteks seetõttu, et rakendus ei töötle seda piisavalt kiiresti, siis hakkate pakette kaotama. Meie klient suurendas puhvri suurust õigesti, kuna kartis andmete kadumist, kuna kasutas DNS-pakettide kaudu mõõdikute kogumise rakendust. Tema seatud väärtus oli maksimaalne võimalik: 231-1 (kui see on seatud väärtusele 231, tagastab kernel "INVALID ARGUMENT").

Järsku mõistsin, miks nmap ja scapy õigesti töötasid: nad kasutasid töötlemata pistikupesasid! Toorpesad erinevad tavalistest pesadest: need mööduvad iptable-test ja neid ei puhverdata!

Aga miks "puhver liiga suur" probleeme tekitab? Ilmselgelt see ei tööta nii, nagu ette nähtud.

Siinkohal võin probleemi korrata mitmes tuumas ja mitmes distributsioonis. Probleem ilmnes juba 3.x tuumal ja nüüd ilmnes ka 5.x tuumal.

Tõepoolest, käivitamisel

sysctl -w net.core.rmem_default=$((2**31-1))

DNS lakkas töötamast.

Hakkasin lihtsa binaarotsingu algoritmi abil tööväärtusi otsima ja leidsin, et süsteem töötas numbriga 2147481343, kuid see number oli minu jaoks mõttetu arvude komplekt. Soovitasin kliendil seda numbrit proovida ja ta vastas, et süsteem töötas google.com-iga, kuid andis siiski vea teiste domeenide puhul, nii et jätkasin uurimist.

Olen installinud tilkkell, tööriist, mida oleks pidanud varem kasutama: see näitab täpselt, kuhu tuumas pakett jõuab. Süüdlane oli funktsioon udp_queue_rcv_skb. Laadisin alla kerneli allikad ja lisasin mõned funktsioonid printk et jälgida, kuhu pakett täpselt jõuab. Leidsin kiiresti õige seisukorra if, ja lihtsalt jõllitasin seda mõnda aega, sest just siis sai kõik lõpuks tervikpildiks kokku: 231-1, mõttetu number, mittetöötav domeen... See oli koodijupp aastal __udp_enqueue_schedule_skb:

if (rmem > (size + sk->sk_rcvbuf))
		goto uncharge_drop;

Pange tähele:

  • rmem on tüüpi int
  • size on tüüpi u16 (allkirjata kuueteistkümnebitine int) ja salvestab paketi suuruse
  • sk->sk_rcybuf on tüüpi int ja salvestab puhvri suuruse, mis definitsiooni järgi on võrdne väärtusega in net.core.rmem_default

Millal sk_rcvbuf läheneb 231-le, võib tulemuseks olla paketi suuruse summeerimine täisarvu ülevool. Ja kuna see on int, muutub selle väärtus negatiivseks, nii et tingimus muutub tõeseks, kui see peaks olema väär (selle kohta saate rohkem lugeda aadressilt link).

Viga saab parandada triviaalsel viisil: valades unsigned int. Rakendasin paranduse ja taaskäivitasin süsteemi ning DNS töötas uuesti.

Võidu maitse

Edastasin oma leiud kliendile ja saatsin LKML kerneli plaaster. Mul on hea meel: iga pusletükk sobib kokku, oskan täpselt seletada, miks me vaatletut jälgisime ja mis kõige tähtsam, saime tänu meeskonnatööle probleemile lahenduse leida!

Tasub tõdeda, et juhtum osutus harvaks ja õnneks saame kasutajatelt nii keerulisi taotlusi harva.

Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu


Allikas: www.habr.com

Lisa kommentaar