Stāsts par trÅ«kstoŔām DNS paketēm no Google Cloud tehniskā atbalsta

No Google emuāra redaktora: Vai esat kādreiz domājis, kā Google mākoņa tehnisko risinājumu (TSE) inženieri apstrādā jÅ«su atbalsta pieprasÄ«jumus? TSE tehniskā atbalsta inženieri ir atbildÄ«gi par lietotāju ziņoto problēmu avotu identificÄ“Å”anu un laboÅ”anu. Dažas no Ŕīm problēmām ir diezgan vienkārÅ”as, taču dažreiz jÅ«s saskaraties ar biļeti, kas prasa vairāku inženieru uzmanÄ«bu vienlaikus. Å ajā rakstā viens no TSE darbiniekiem pastāstÄ«s par vienu ļoti sarežģītu problēmu no savas nesenās prakses - trÅ«kstoÅ”o DNS pakeÅ”u gadÄ«jumā. Å ajā stāstā mēs redzēsim, kā inženieriem izdevās atrisināt situāciju un kādas jaunas lietas viņi uzzināja, novērÅ”ot kļūdu. Mēs ceram, ka Å”is stāsts ne tikai izglÄ«tos jÅ«s par dziļi iesakņojuÅ”os kļūdu, bet arÄ« sniegs ieskatu procesos, kas tiek veikti, iesniedzot atbalsta kvÄ«ti pakalpojumā Google Cloud.

Stāsts par trÅ«kstoŔām DNS paketēm no Google Cloud tehniskā atbalsta

Problēmu novērÅ”ana ir gan zinātne, gan māksla. Viss sākas ar hipotēzes izstrādi par sistēmas nestandarta uzvedÄ«bas iemeslu, pēc tam tiek pārbaudÄ«ta tās izturÄ«ba. Tomēr, pirms formulējam hipotēzi, mums ir skaidri jādefinē un precÄ«zi jāformulē problēma. Ja jautājums izklausās pārāk neskaidrs, jums viss bÅ«s rÅ«pÄ«gi jāanalizē; Tā ir problēmu novērÅ”anas ā€œmākslaā€.

Izmantojot Google Cloud, Ŕādi procesi kļūst eksponenciāli sarežģītāki, jo Google Cloud cenÅ”as nodroÅ”ināt savu lietotāju privātumu. Å Ä« iemesla dēļ TSE inženieriem nav piekļuves jÅ«su sistēmu rediģēŔanai, kā arÄ« iespēju skatÄ«t konfigurācijas tikpat plaÅ”i kā lietotājiem. Tāpēc, lai pārbaudÄ«tu kādu no mÅ«su hipotēzēm, mēs (inženieri) nevaram ātri pārveidot sistēmu.

Daži lietotāji uzskata, ka mēs visu salabosim kā mehāniku autoservisā un vienkārÅ”i nosÅ«tÄ«sim mums virtuālās maŔīnas ID, turpretÄ« patiesÄ«bā process notiek sarunvalodas formātā: tiek vākta informācija, veidotas un apstiprinātas (vai atspēkotas) hipotēzes, un galu galā lēmuma pieņemÅ”anas problēmas ir balstÄ«tas uz saziņu ar klientu.

Attiecīgā problēma

Å odien mums ir stāsts ar labām beigām. Viens no ierosinātās lietas veiksmÄ«gas atrisināŔanas iemesliem ir ļoti detalizēts un precÄ«zs problēmas apraksts. Tālāk ir redzama pirmās biļetes kopija (rediģēta, lai paslēptu konfidenciālu informāciju):
Stāsts par trÅ«kstoŔām DNS paketēm no Google Cloud tehniskā atbalsta
Šis ziņojums satur mums daudz noderīgas informācijas:

  • NorādÄ«ta konkrēta VM
  • Tiek norādÄ«ta pati problēma - DNS nedarbojas
  • Ir norādÄ«ts, kur problēma izpaužas - VM un konteiners
  • Ir norādÄ«tas darbÄ«bas, ko lietotājs veica, lai identificētu problēmu.

PieprasÄ«jums tika reÄ£istrēts kā ā€œP1: Critical Impact - Service Unusable in productionā€, kas nozÄ«mē pastāvÄ«gu situācijas uzraudzÄ«bu 24/7 saskaņā ar shēmu ā€œSeko sauleiā€ (var lasÄ«t vairāk par lietotāju pieprasÄ«jumu prioritātes), ar tās pāreju no vienas tehniskā atbalsta komandas uz citu ar katru laika joslu maiņu. Faktiski brÄ«dÄ«, kad problēma sasniedza mÅ«su komandu CÄ«rihē, tā jau bija apbraukusi visu pasauli. LÄ«dz tam laikam lietotājs bija veicis mazināŔanas pasākumus, taču baidÄ«jās no situācijas atkārtoÅ”anās ražoÅ”anā, jo galvenais iemesls vēl nebija atklāts.

Kad biļete sasniedza Cīrihi, mums jau bija Ŕāda informācija:

  • Saturs /etc/hosts
  • Saturs /etc/resolv.conf
  • secinājums iptables-save
  • Komandas komplektēta ngrep pcap fails

Ar Å”iem datiem mēs bijām gatavi sākt ā€œizmeklÄ“Å”anasā€ un problēmu novērÅ”anas posmu.

Mūsu pirmie soļi

Pirmkārt, mēs pārbaudÄ«jām metadatu servera žurnālus un statusu un pārliecinājāmies, ka tas darbojas pareizi. Metadatu serveris reaģē uz IP adresi 169.254.169.254 un, cita starpā, ir atbildÄ«gs par domēna nosaukumu kontroli. Mēs arÄ« vēlreiz pārbaudÄ«jām, vai ugunsmÅ«ris darbojas pareizi ar virtuālo maŔīnu un nebloķē paketes.

Tā bija sava veida dÄ«vaina problēma: nmap pārbaude atspēkoja mÅ«su galveno hipotēzi par UDP pakeÅ”u zudumu, tāpēc mēs domājām izdomājām vēl vairākas iespējas un veidus, kā tās pārbaudÄ«t:

  • Vai paketes tiek nomestas selektÄ«vi? => Pārbaudiet iptables noteikumus
  • ŠŠµ сŠ»ŠøшŠŗŠ¾Š¼ Š»Šø Š¼Š°Š» MTU? => Pārbaudiet izvadi ip a show
  • Vai problēma skar arÄ« tikai UDP paketes vai TCP? => Brauc prom dig +tcp
  • Vai rakÅ”anas Ä£enerētās paketes tiek atgrieztas? => Brauc prom tcpdump
  • Vai libdns darbojas pareizi? => Brauc prom strace lai pārbaudÄ«tu pakeÅ”u pārraidi abos virzienos

Å eit mēs nolemjam piezvanÄ«t lietotājam, lai tieÅ”raidē novērstu problēmas.

Sarunas laikā mēs varam pārbaudīt vairākas lietas:

  • Pēc vairākām pārbaudēm mēs izslēdzam iptables noteikumus no iemeslu saraksta
  • Mēs pārbaudām tÄ«kla saskarnes un marÅ”rutÄ“Å”anas tabulas un vēlreiz pārbaudām, vai MTU ir pareiza
  • Mēs to atklājam dig +tcp google.com (TCP) darbojas kā nākas, bet dig google.com (UDP) nedarbojas
  • Aizbraucis tcpdump tas joprojām darbojas dig, mēs atklājam, ka tiek atgrieztas UDP paketes
  • Braucam prom strace dig google.com un mēs redzam, kā rakt pareizi aicina sendmsg() Šø recvms(), tomēr otro pārtrauc taimauts

Diemžēl pienāk maiņas beigas un esam spiesti problēmu eskalēt uz nākamo laika joslu. Taču pieprasÄ«jums mÅ«su komandā izraisÄ«ja interesi, un kāds kolēģis iesaka izveidot sākotnējo DNS pakotni, izmantojot skrāpējoÅ”o Python moduli.

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

Šis fragments izveido DNS paketi un nosūta pieprasījumu metadatu serverim.

Lietotājs palaiž kodu, tiek atgriezta DNS atbilde, un lietojumprogramma to saņem, apstiprinot, ka tīkla līmenī nav problēmu.

Pēc kārtējā ā€œapceļojuma apkārt pasauleiā€ pieprasÄ«jums atgriežas mÅ«su komandā, un es to pilnÄ«bā nododu sev, domājot, ka lietotājam bÅ«s ērtāk, ja pieprasÄ«jums pārstās riņķot no vienas vietas uz otru.

Tikmēr lietotājs laipni piekrÄ«t nodroÅ”ināt sistēmas attēla momentuzņēmumu. Tā ir ļoti laba ziņa: iespēja paÅ”am pārbaudÄ«t sistēmu padara traucējummeklÄ“Å”anu daudz ātrāku, jo man vairs nav jāprasa lietotājam palaist komandas, sÅ«tÄ«t rezultātus un analizēt tos, visu varu izdarÄ«t pats!

Mani kolēģi sāk nedaudz apskaust. Pusdienu laikā mēs apspriežam konversiju, bet nevienam nav ne jausmas, kas notiek. Par laimi, lietotājs pats jau ir veicis pasākumus, lai mazinātu sekas, un nesteidzas, tāpēc mums ir laiks, lai atrisinātu problēmu. Un, tā kā mums ir attēls, mēs varam veikt jebkurus testus, kas mūs interesē. Lieliski!

Atkāpjoties

Viens no populārākajiem intervijas jautājumiem sistēmu inženiera amatiem ir: ā€œKas notiek, kad ping www.google.com? Jautājums ir lielisks, jo kandidātam ir jāapraksta viss, sākot no čaulas lÄ«dz lietotāja telpai, lÄ«dz sistēmas kodolam un pēc tam lÄ«dz tÄ«klam. Es smaidu: dažreiz intervijas jautājumi dzÄ«vē noder...

Es nolemju Å”o HR jautājumu attiecināt uz aktuālu problēmu. Aptuveni runājot, mēģinot noteikt DNS nosaukumu, notiek Ŕādi:

  1. Lietojumprogramma izsauc sistēmas bibliotēku, piemēram, libdns
  2. libdns pārbauda sistēmas konfigurāciju, ar kuru DNS serveri tam jāsazinās (shēmā tas ir 169.254.169.254, metadatu serveris)
  3. libdns izmanto sistēmas izsaukumus, lai izveidotu UDP ligzdu (SOKET_DGRAM) un nosūtītu UDP paketes ar DNS vaicājumu abos virzienos
  4. Izmantojot sysctl saskarni, varat konfigurēt UDP steku kodola līmenī
  5. Kodols mijiedarbojas ar aparatūru, lai pārsūtītu paketes tīklā, izmantojot tīkla interfeisu
  6. Hipervizors uztver un pārsūta paketi metadatu serverim, saskaroties ar to
  7. Metadatu serveris ar savu burvību nosaka DNS nosaukumu un atgriež atbildi, izmantojot to paŔu metodi

Stāsts par trÅ«kstoŔām DNS paketēm no Google Cloud tehniskā atbalsta
Ä»aujiet man atgādināt, kādas hipotēzes mēs jau esam apsvēruÅ”i:

Hipotēze: bojātas bibliotēkas

  • 1. tests: palaidiet strace sistēmā, pārbaudiet, vai dig izsauc pareizos sistēmas zvanus
  • Rezultāts: tiek izsaukti pareizie sistēmas zvani
  • 2. tests: izmantojiet srapy, lai pārbaudÄ«tu, vai mēs varam noteikt nosaukumus, apejot sistēmas bibliotēkas
  • Rezultāts: mēs varam
  • 3. tests: palaidiet rpm ā€“V libdns pakotnē un md5sum bibliotēkas failos
  • Rezultāts: bibliotēkas kods ir pilnÄ«gi identisks kodam darba operētājsistēmā
  • 4. tests: uzstādiet lietotāja saknes sistēmas attēlu virtuālajā datorā bez Ŕīs darbÄ«bas, palaidiet chroot, pārbaudiet, vai DNS darbojas
  • Rezultāts: DNS darbojas pareizi

Secinājums, pamatojoties uz testiem: problēma nav bibliotēkās

Hipotēze: DNS iestatījumos ir kļūda

  • 1. tests: pārbaudiet tcpdump un pārbaudiet, vai DNS paketes tiek nosÅ«tÄ«tas un atgrieztas pareizi pēc dig palaiÅ”anas
  • Rezultāts: paketes tiek pārsÅ«tÄ«tas pareizi
  • 2. tests: vēlreiz pārbaudiet serverÄ« /etc/nsswitch.conf Šø /etc/resolv.conf
  • Rezultāts: viss ir pareizi

Secinājums, pamatojoties uz testiem: problēma nav DNS konfigurācijā

Hipotēze: serde bojāta

  • Tests: instalējiet jaunu kodolu, pārbaudiet parakstu, restartējiet
  • Rezultāts: lÄ«dzÄ«ga uzvedÄ«ba

Secinājums, pamatojoties uz testiem: kodols nav bojāts

Hipotēze: nepareiza lietotāja tīkla (vai hipervizora tīkla interfeisa) uzvedība

  • 1. pārbaude: pārbaudiet ugunsmÅ«ra iestatÄ«jumus
  • Rezultāts: ugunsmÅ«ris nodod DNS paketes gan resursdatorā, gan GCP
  • 2. tests: pārtveriet trafiku un uzraugiet DNS pieprasÄ«jumu pārsÅ«tÄ«Å”anas un atgrieÅ”anas pareizÄ«bu
  • Rezultāts: tcpdump apstiprina, ka resursdators ir saņēmis atgrieÅ”anas paketes

Secinājums, pamatojoties uz testiem: problēma nav tīklā

Hipotēze: metadatu serveris nedarbojas

  • 1. tests: pārbaudiet, vai metadatu servera žurnālos nav anomāliju
  • Rezultāts: žurnālos nav anomāliju
  • 2. tests: apiet metadatu serveri, izmantojot dig @8.8.8.8
  • Rezultāts: izŔķirtspēja ir bojāta, pat neizmantojot metadatu serveri

Secinājums, pamatojoties uz testiem: problēma nav metadatu serverī

ApakŔējā lÄ«nija: mēs pārbaudÄ«jām visas apakÅ”sistēmas, izņemot izpildlaika iestatÄ«jumi!

Iedziļināties kodola izpildlaika iestatījumos

Lai konfigurētu kodola izpildes vidi, varat izmantot komandrindas opcijas (grub) vai sysctl saskarni. Es paskatÄ«jos iekŔā /etc/sysctl.conf un padomājiet, es atklāju vairākus pielāgotus iestatÄ«jumus. SajÅ«ta, ka esmu kaut ko uztvēris, es atmetu visus iestatÄ«jumus, kas nav saistÄ«ti ar tÄ«klu vai TCP, atstājot kalnu iestatÄ«jumus. net.core. Tad es devos uz vietu, kur virtuālajā maŔīnā bija saimniekdatora atļaujas, un sāku lietot iestatÄ«jumus pa vienam, vienu pēc otra ar bojāto VM, lÄ«dz atradu vainÄ«go:

net.core.rmem_default = 2147483647

Šeit tā ir DNS pārkāpuma konfigurācija! Es atradu slepkavības ieroci. Bet kāpēc tas notiek? Man joprojām bija vajadzīgs motīvs.

Pamata DNS pakeÅ”u bufera lielums ir konfigurēts, izmantojot net.core.rmem_default. Tipiskā vērtÄ«ba ir aptuveni 200 KiB, taču, ja jÅ«su serveris saņem daudz DNS pakeÅ”u, iespējams, vēlēsities palielināt bufera lielumu. Ja buferis ir pilns, kad tiek saņemta jauna pakete, piemēram, tāpēc, ka lietojumprogramma to neapstrādā pietiekami ātri, jÅ«s sāksit zaudēt paketes. MÅ«su klients pareizi palielināja bufera lielumu, jo baidÄ«jās no datu zuduma, jo viņŔ izmantoja lietojumprogrammu metriku apkopoÅ”anai, izmantojot DNS paketes. Viņa iestatÄ«tā vērtÄ«ba bija maksimālā iespējamā: 231-1 (ja iestatÄ«ta uz 231, kodols atgriezÄ«s ā€œINVALID ARGUMENTā€).

PēkŔņi es sapratu, kāpēc nmap un scapy darbojās pareizi: viņi izmantoja neapstrādātas ligzdas! Neapstrādātas ligzdas atŔķiras no parastajām ligzdām: tās apiet iptables, un tās netiek buferētas!

Bet kāpēc "buferis pārāk liels" rada problēmas? Tas acīmredzami nedarbojas, kā paredzēts.

Šajā brīdī es varētu reproducēt problēmu vairākos kodolos un vairākos izplatījumos. Problēma jau parādījās 3.x kodolā, un tagad tā parādījās arī 5.x kodolā.

PatieŔām, startējot

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

DNS pārtrauca darbu.

Es sāku meklēt darba vērtÄ«bas, izmantojot vienkārÅ”u bināro meklÄ“Å”anas algoritmu, un atklāju, ka sistēma darbojās ar 2147481343, taču Å”is skaitlis man bija bezjēdzÄ«gs skaitļu kopums. Es ieteicu klientam izmēģināt Å”o numuru, un viņŔ atbildēja, ka sistēma darbojas ar google.com, taču joprojām radÄ«ja kļūdu citos domēnos, tāpēc es turpināju izmeklÄ“Å”anu.

Esmu uzstādÄ«jis piliens, rÄ«ks, kuru vajadzēja izmantot agrāk: tas precÄ«zi parāda, kur kodolā nonāk pakete. VainÄ«gais bija funkcija udp_queue_rcv_skb. Es lejupielādēju kodola avotus un pievienoju dažus funkcijas printk lai izsekotu, kur tieÅ”i pakete nonāk. Es ātri atradu pareizo stāvokli if, un kādu laiku vienkārÅ”i skatÄ«jās uz to, jo tieÅ”i tad viss beidzot sanāca veselā attēlā: 231-1, bezjēdzÄ«gs skaitlis, nestrādājoÅ”s domēns... Tas bija koda fragments __udp_enqueue_schedule_skb:

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

Lūdzu, ņemiet vērā:

  • rmem ir tipa int
  • size ir u16 tipa (neparakstÄ«ts seÅ”padsmit bitu int) un saglabā paketes izmēru
  • sk->sk_rcybuf ir int tipa un saglabā bufera lielumu, kas pēc definÄ«cijas ir vienāds ar vērtÄ«bu in net.core.rmem_default

Kad sk_rcvbuf tuvojas 231, paketes lieluma summÄ“Å”ana var izraisÄ«t veselu skaitļu pārpilde. Un, tā kā tas ir int, tā vērtÄ«ba kļūst negatÄ«va, tāpēc nosacÄ«jums kļūst patiess, kad tam vajadzētu bÅ«t nepatiesam (vairāk par to varat lasÄ«t vietnē saite).

Kļūdu var labot triviālā veidā: ar lieÅ”anu unsigned int. Es piemēroju labojumu un restartēju sistēmu, un DNS atkal darbojās.

Uzvaras garŔa

Es savus atklājumus pārsūtīju klientam un nosūtīju LKML kodola ielāps. Esmu gandarīts: katrs puzles gabals sader kopā, es varu precīzi izskaidrot, kāpēc mēs novērojām to, ko novērojām, un galvenais, ka mēs spējām atrast problēmas risinājumu, pateicoties mūsu komandas darbam!

Ir vērts atzīt, ka gadījums izrādījās rets, un par laimi mēs reti saņemam tik sarežģītus pieprasījumus no lietotājiem.

Stāsts par trÅ«kstoŔām DNS paketēm no Google Cloud tehniskā atbalsta


Avots: www.habr.com

Pievieno komentāru