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.
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):
Å 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:
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 funkcijasprintk 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.