Történet a Google Cloud technikai támogatásának hiányzó DNS-csomagjairól

A Google Blogszerkesztőből: Gondolkozott már azon, hogyan kezelik a Google Cloud Technical Solutions (TSE) mérnökei az Ön támogatási kéréseit? A TSE műszaki támogatási mérnökei felelősek a felhasználók által jelentett problémaforrások azonosításáért és kijavításáért. Néhány ilyen probléma meglehetősen egyszerű, de néha olyan jegyekkel találkozhatunk, amelyek egyszerre több mérnök figyelmét igénylik. Ebben a cikkben a TSE egyik alkalmazottja egy nagyon trükkös problémáról mesél a közelmúltbeli gyakorlatából - hiányzó DNS-csomagok esete. Ebben a történetben azt láthatjuk, hogyan sikerült a mérnököknek megoldani a helyzetet, és milyen újdonságokat tanultak a hiba elhárítása során. Reméljük, hogy ez a történet nem csak egy mélyen gyökerező hibáról ad felvilágosítást, hanem betekintést nyújt a Google Cloud támogatási kérelmének benyújtásához szükséges folyamatokba is.

Történet a Google Cloud technikai támogatásának hiányzó DNS-csomagjairól

A hibaelhárítás egyszerre tudomány és művészet. Minden azzal kezdődik, hogy felállítunk egy hipotézist a rendszer nem szabványos viselkedésének okáról, majd teszteljük annak erejét. Mielőtt azonban hipotézist fogalmaznánk meg, egyértelműen meg kell határoznunk és pontosan meg kell fogalmaznunk a problémát. Ha a kérdés túl homályosan hangzik, akkor mindent alaposan elemeznie kell; Ez a hibaelhárítás „művészete”.

A Google Cloud alatt az ilyen folyamatok exponenciálisan bonyolultabbá válnak, mivel a Google Cloud mindent megtesz, hogy garantálja a felhasználók magánéletét. Emiatt a TSE mérnökei nem férhetnek hozzá a rendszer szerkesztéséhez, és nem tekinthetik meg a konfigurációkat olyan széles körben, mint a felhasználók. Ezért, hogy bármelyik hipotézisünket teszteljük, mi (mérnökök) nem tudjuk gyorsan módosítani a rendszert.

Egyes felhasználók úgy gondolják, hogy mindent megjavítunk, mint a mechanikát az autószervizben, és egyszerűen elküldjük nekünk egy virtuális gép azonosítóját, míg a valóságban a folyamat társalgási formában zajlik: információgyűjtés, hipotézisek kialakítása és megerősítése (vagy megcáfolása), és végül a döntési problémák az ügyféllel való kommunikáción alapulnak.

A kérdéses probléma

Ma van egy történetünk, amelynek jó a vége. A javasolt ügy sikeres megoldásának egyik oka a probléma nagyon részletes és pontos leírása. Alább láthatja az első jegy másolatát (a bizalmas információk elrejtésére szerkesztve):
Történet a Google Cloud technikai támogatásának hiányzó DNS-csomagjairól
Ez az üzenet sok hasznos információt tartalmaz számunkra:

  • Meghatározott virtuális gép
  • Maga a probléma jelzi - a DNS nem működik
  • Jelzi, hogy hol jelenik meg a probléma - virtuális gép és tároló
  • Megjelenik a felhasználó által a probléma azonosítására tett lépések.

A kérést „P1: Critical Impact – Service Unusable in Production” néven regisztráltuk, ami a helyzet folyamatos, 24 órás megfigyelését jelenti a „Kövesd a Napot” séma szerint (további információ a a felhasználói kérések prioritásait). Sőt, mire a probléma elérte a zürichi csapatunkat, már körbejárta a világot. Ekkorra a felhasználó enyhítő intézkedéseket hozott, de attól tartott, hogy a gyártás során megismétlődik a helyzet, mivel a kiváltó okot még nem fedezték fel.

Mire a jegy Zürichbe ért, már a következő információkkal rendelkeztünk:

  • Tartalom /etc/hosts
  • Tartalom /etc/resolv.conf
  • Teljesítmény iptables-save
  • Összeállította a csapat ngrep pcap fájl

Ezekkel az adatokkal készen álltunk a „nyomozási” és hibaelhárítási szakasz megkezdésére.

Első lépéseink

Először is ellenőriztük a metaadat-szerver naplóit és állapotát, és megbizonyosodtunk arról, hogy megfelelően működik. A metaadat-szerver a 169.254.169.254 IP-címre válaszol, és többek között a tartománynevek vezérléséért is felelős. Kétszer is ellenőriztük, hogy a tűzfal megfelelően működik-e a virtuális géppel, és nem blokkolja-e a csomagokat.

Valami furcsa probléma volt: az nmap ellenőrzés megcáfolta az UDP-csomagok elvesztésével kapcsolatos fő hipotézisünket, így gondolatban még több lehetőséget és módot találtunk ezek ellenőrzésére:

  • Szelektíven dobják el a csomagokat? => Ellenőrizze az iptables szabályokat
  • Nem túl kicsi? MTU? => Ellenőrizze a kimenetet ip a show
  • A probléma csak az UDP-csomagokat vagy a TCP-t is érinti? => Vezess el dig +tcp
  • A dig generált csomagokat visszaküldik? => Vezess el tcpdump
  • A libdns megfelelően működik? => Vezess el strace hogy ellenőrizze a csomagok átvitelét mindkét irányban

Itt úgy döntünk, hogy felhívjuk a felhasználót a problémák élő elhárítása érdekében.

A hívás során több dolgot ellenőrizhetünk:

  • Többszöri ellenőrzés után kizárjuk az iptables szabályokat az okok listájából
  • Ellenőrizzük a hálózati interfészeket és az útválasztási táblákat, és kétszer is ellenőrizzük, hogy az MTU helyes-e
  • Azt fedezzük fel dig +tcp google.com (TCP) úgy működik, ahogy kell, de dig google.com (UDP) nem működik
  • Miután elhajtott tcpdump munka közben dig, azt tapasztaljuk, hogy UDP-csomagokat küldenek vissza
  • Elhajtunk strace dig google.com és látjuk, hogyan dig helyesen hív sendmsg() и recvms(), azonban a másodikat időtúllépés szakítja meg

Sajnos elérkezik a műszak vége, és kénytelenek vagyunk a következő időzónára terelni a problémát. A kérés azonban felkeltette az érdeklődést csapatunkban, és egy kolléga azt javasolja, hogy a kezdeti DNS-csomagot hozzuk létre a scrapy Python modul segítségével.

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())

Ez a töredék létrehoz egy DNS-csomagot, és elküldi a kérést a metaadat-kiszolgálónak.

A felhasználó lefuttatja a kódot, visszaküldi a DNS-választ, és az alkalmazás megkapja azt, megerősítve, hogy hálózati szinten nincs probléma.

Egy újabb „világkörüli utazás” után a kérés visszatér a csapatunkhoz, én pedig teljesen átteszem magamnak, gondolván, hogy a felhasználó számára kényelmesebb lesz, ha a kérés megszűnik egyik helyről a másikra keringeni.

Addig is a felhasználó beleegyezik, hogy pillanatképet készít a rendszerképről. Ez nagyon jó hír: a rendszer saját tesztelésének lehetősége sokkal gyorsabbá teszi a hibaelhárítást, mert már nem kell a felhasználót parancsok futtatására, az eredmények elküldésére és elemzésére kérnem, mindent magam is meg tudok csinálni!

A kollégáim kezdenek kicsit irigyelni. Ebéd közben megbeszéljük az átalakítást, de senkinek fogalma sincs, mi történik. Szerencsére a felhasználó maga is tett már intézkedéseket a következmények enyhítésére, és nem siet, így van időnk a probléma boncolgatására. És mivel van képünk, bármilyen tesztet lefuttathatunk, ami érdekel. Nagy!

Hátrál egy lépést

Az egyik legnépszerűbb interjúkérdés rendszermérnöki pozíciókhoz: „Mi történik, ha pingel? www.google.com? A kérdés nagyszerű, hiszen a jelöltnek mindent le kell írnia a shelltől a felhasználói területig, a rendszermagig, majd a hálózatig. Mosolygok: az interjúkérdések néha a való életben is hasznosnak bizonyulnak...

Úgy döntök, hogy ezt a HR-kérdést egy aktuális problémára alkalmazom. Durván szólva, amikor megpróbálja meghatározni a DNS-nevet, a következő történik:

  1. Az alkalmazás rendszerkönyvtárat hív meg, például a libdns-t
  2. A libdns ellenőrzi a rendszerkonfigurációt, hogy melyik DNS-kiszolgálóval kell kapcsolatba lépnie (a diagramon ez a 169.254.169.254, metaadat-kiszolgáló)
  3. A libdns rendszerhívásokat használ egy UDP socket (SOKET_DGRAM) létrehozására és az UDP-csomagok DNS-lekérdezéssel történő elküldésére mindkét irányban
  4. A sysctl felületen keresztül konfigurálhatja az UDP-vermet a kernel szintjén
  5. A kernel kölcsönhatásba lép a hardverrel, hogy csomagokat továbbítson a hálózaton keresztül a hálózati interfészen keresztül
  6. A hypervisor elkapja és továbbítja a csomagot a metaadat-kiszolgálónak, amikor kapcsolatba lép vele
  7. A metaadat-szerver varázsereje révén meghatározza a DNS-nevet, és ugyanazzal a módszerrel ad vissza választ

Történet a Google Cloud technikai támogatásának hiányzó DNS-csomagjairól
Hadd emlékeztessem Önöket arra, hogy milyen hipotézisekkel foglalkoztunk már:

Hipotézis: Törött könyvtárak

  • 1. teszt: futtassa a strace-t a rendszerben, ellenőrizze, hogy a dig a megfelelő rendszerhívásokat hívja-e meg
  • Eredmény: Megtörténik a megfelelő rendszerhívások hívása
  • 2. teszt: srapy segítségével ellenőrizzük, hogy meg tudjuk-e határozni a rendszerkönyvtárakat megkerülő neveket
  • Eredmény: megtehetjük
  • 3. teszt: futtassa az rpm –V parancsot a libdns csomagon és az md5sum könyvtárfájlokon
  • Eredmény: a könyvtár kódja teljesen megegyezik a működő operációs rendszer kódjával
  • 4. teszt: csatolja fel a felhasználó gyökérrendszerének képét egy virtuális gépre anélkül, hogy ez a viselkedés, futtassa a chrootot, ellenőrizze, működik-e a DNS
  • Eredmény: A DNS megfelelően működik

Következtetés a tesztek alapján: a probléma nem a könyvtárakban van

Hipotézis: Hiba van a DNS-beállításokban

  • 1. teszt: ellenőrizze a tcpdump-ot, és ellenőrizze, hogy a DNS-csomagok elküldése és visszaadása helyes-e a dig futtatása után
  • Eredmény: a csomagok továbbítása megfelelően megtörtént
  • 2. teszt: ellenőrizze kétszer a szervert /etc/nsswitch.conf и /etc/resolv.conf
  • Eredmény: minden rendben van

Következtetés a tesztek alapján: a probléma nem a DNS konfigurációval van

Hipotézis: mag sérült

  • Teszt: új kernel telepítése, aláírás ellenőrzése, újraindítás
  • Eredmény: hasonló viselkedés

Következtetés a tesztek alapján: a kernel nem sérült

Hipotézis: a felhasználói hálózat (vagy a hypervisor hálózati interfész) helytelen viselkedése

  • 1. teszt: Ellenőrizze a tűzfal beállításait
  • Eredmény: a tűzfal DNS-csomagokat ad át mind a gazdagépen, mind a GCP-n
  • 2. teszt: elfogja a forgalmat, és figyelemmel kíséri a DNS-kérések átvitelének és visszaküldésének helyességét
  • Eredmény: A tcpdump megerősíti, hogy a gazdagép megkapta a visszatérő csomagokat

Következtetés a tesztek alapján: a probléma nem a hálózatban van

Hipotézis: a metaadat-szerver nem működik

  • 1. teszt: ellenőrizze a metaadat-kiszolgáló naplóit anomáliák szempontjából
  • Eredmény: nincsenek anomáliák a naplókban
  • 2. teszt: Kerülje meg a metaadat-kiszolgálót ezen keresztül dig @8.8.8.8
  • Eredmény: A felbontás még metaadat-szerver használata nélkül is hibás

Következtetés a tesztek alapján: a probléma nem a metaadat szerverrel van

Az alsó sor: minden alrendszert teszteltünk, kivéve futásidejű beállítások!

Búvárkodás a kernel futásidejű beállításaiban

A kernel végrehajtási környezetének konfigurálásához használhatja a parancssori opciókat (grub) vagy a sysctl felületet. benéztem /etc/sysctl.conf és gondolj csak bele, számos egyéni beállítást fedeztem fel. Úgy éreztem, hogy megragadtam valamit, elvetettem minden nem hálózati vagy nem tcp beállítást, és a hegyi beállításoknál maradtam net.core. Aztán odamentem, ahol a gazdajogosultságok voltak a virtuális gépben, és elkezdtem egyenként, egymás után alkalmazni a beállításokat a törött virtuális géppel, amíg meg nem találtam a tettest:

net.core.rmem_default = 2147483647

Íme, egy DNS-törő konfiguráció! Megtaláltam a gyilkos fegyvert. De miért történik ez? Még mindig szükségem volt egy indítékra.

Az alapvető DNS-csomagpuffer mérete a következőn keresztül van konfigurálva net.core.rmem_default. A tipikus érték valahol 200KiB körül van, de ha a szervere sok DNS-csomagot kap, érdemes lehet növelni a puffer méretét. Ha a puffer megtelt, amikor új csomag érkezik, például azért, mert az alkalmazás nem dolgozza fel elég gyorsan, akkor a csomagok elvesznek. Ügyfelünk helyesen növelte a puffer méretét, mert félt az adatvesztéstől, mivel DNS-csomagokon keresztül mérőszámokat gyűjtött. Az általa beállított érték a lehető legnagyobb volt: 231-1 (ha 231-re van állítva, a kernel „INVALID ARGUMENT”-et ad vissza).

Hirtelen rájöttem, hogy az nmap és a scapy miért működik megfelelően: nyers socketeket használnak! A nyers socketek eltérnek a hagyományos socketektől: megkerülik az iptable-t, és nincsenek pufferelve!

De miért okoz problémát a "túl nagy puffer"? Nyilvánvalóan nem úgy működik, ahogy tervezték.

Ezen a ponton több kernelen és több disztribúción is reprodukálhattam a problémát. A probléma már megjelent a 3.x-es kernelen, és most az 5.x-es kernelen is.

Valóban, indításkor

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

A DNS leállt.

Elkezdtem keresni a működő értékeket egy egyszerű bináris keresőalgoritmus segítségével, és megállapítottam, hogy a rendszer a 2147481343-mal működik, de ez a szám számomra értelmetlen számkészlet volt. Javasoltam az ügyfélnek, hogy próbálja ki ezt a számot, és ő azt válaszolta, hogy a rendszer működik a google.com webhelyen, de továbbra is hibát adott más domaineknél, ezért folytattam a vizsgálatot.

telepítettem cseppóra, egy olyan eszköz, amelyet korábban kellett volna használni: pontosan megmutatja, hogy a kernelben hova kerül egy csomag. A bűnös a funkció volt udp_queue_rcv_skb. Letöltöttem a kernelforrásokat, és hozzáadtam néhányat függvény printk nyomon követni, hogy a csomag pontosan hol végződik. Gyorsan megtaláltam a megfelelő állapotot if, és egy ideig egyszerűen csak bámulta, mert ekkor állt végre minden egy teljes képbe: 231-1, értelmetlen szám, nem működő domain... Ez egy kódrészlet volt a __udp_enqueue_schedule_skb:

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

Kérjük, vegye figyelembe:

  • rmem int típusú
  • size u16 típusú (előjel nélküli tizenhat bites int), és tárolja a csomagméretet
  • sk->sk_rcybuf int típusú, és a pufferméretet tárolja, amely definíció szerint megegyezik az in értékkel net.core.rmem_default

Mikor sk_rcvbuf megközelíti a 231-et, a csomagméret összegzése azt eredményezheti, hogy integer túlcsordulás. És mivel ez egy int, az értéke negatív lesz, így a feltétel akkor válik igazzá, amikor hamisnak kellene lennie (erről bővebben itt olvashat link).

A hiba triviális módon javítható: öntéssel unsigned int. Alkalmaztam a javítást és újraindítottam a rendszert, és a DNS ismét működött.

A győzelem íze

A leleteimet továbbítottam az ügyfélnek és elküldtem LKML kernel javítás. Örülök: a puzzle minden darabja passzol egymáshoz, pontosan el tudom magyarázni, hogy miért figyeltük meg azt, amit megfigyeltünk, és ami a legfontosabb, csapatmunkánknak köszönhetően tudtunk megoldást találni a problémára!

Érdemes tudni, hogy az eset ritkanak bizonyult, és szerencsére ritkán kapunk ilyen összetett kéréseket a felhasználóktól.

Történet a Google Cloud technikai támogatásának hiányzó DNS-csomagjairól


Forrás: will.com

Hozzászólás