MÄs rakstÄm aizsardzÄ«bu pret DDoS uzbrukumiem XDP. KodolenerÄ£ijas daļa
eXpress Data Path (XDP) tehnoloÄ£ija ļauj veikt nejauÅ”u trafika apstrÄdi Linux saskarnÄs, pirms paketes nonÄk kodola tÄ«kla kaudzÄ. XDP pielietojums - aizsardzÄ«ba pret DDoS uzbrukumiem (CloudFlare), sarežģīti filtri, statistikas apkopoÅ”ana (Netflix). XDP programmas izpilda eBPF virtuÄlÄ maŔīna, tÄpÄc tÄm ir ierobežojumi gan kodam, gan pieejamajÄm kodola funkcijÄm atkarÄ«bÄ no filtra veida.
Raksts ir paredzÄts, lai aizpildÄ«tu daudzu XDP materiÄlu trÅ«kumus. PirmkÄrt, tie nodroÅ”ina gatavu kodu, kas nekavÄjoties apiet XDP funkcijas: tas ir sagatavots pÄrbaudei vai ir pÄrÄk vienkÄrÅ”s, lai radÄ«tu problÄmas. MÄÄ£inot rakstÄ«t kodu no jauna, jums nav ne jausmas, ko darÄ«t ar tipiskÄm kļūdÄm. OtrkÄrt, nav ietverti veidi, kÄ lokÄli pÄrbaudÄ«t XDP bez virtuÄlÄs maŔīnas un aparatÅ«ras, neskatoties uz to, ka tiem ir savas nepilnÄ«bas. Teksts ir paredzÄts programmÄtÄjiem, kuri pÄrzina tÄ«klu un Linux, kurus interesÄ XDP un eBPF.
Å ajÄ daÄ¼Ä mÄs detalizÄti sapratÄ«sim, kÄ tiek salikts XDP filtrs un kÄ to pÄrbaudÄ«t, pÄc tam uzrakstÄ«sim vienkÄrÅ”u versiju par labi zinÄmo SYN sÄ«kfailu mehÄnismu pakeÅ”u apstrÄdes lÄ«menÄ«. MÄs vÄl neveidosim ābalto sarakstuā.
verificÄti klienti, uzturÄt skaitÄ«tÄjus un pÄrvaldÄ«t filtru - pietiekami daudz žurnÄlu.
MÄs rakstÄ«sim C ā tas nav modÄ, bet tas ir praktiski. Viss kods ir pieejams GitHub, izmantojot saiti beigÄs, un ir sadalÄ«ts saistÄ«bÄs saskaÅÄ ar rakstÄ aprakstÄ«tajiem posmiem.
Atruna Å Ä« raksta laikÄ es izstrÄdÄÅ”u mini risinÄjumu, lai novÄrstu DDoS uzbrukumus, jo tas ir reÄls XDP un manas kompetences jomas uzdevums. TomÄr galvenais mÄrÄ·is ir izprast tehnoloÄ£iju; tas nav ceļvedis gatavas aizsardzÄ«bas izveidoÅ”anai. ApmÄcÄ«bas kods nav optimizÄts un izlaiž dažas nianses.
XDP Ä«ss pÄrskats
Es izklÄstÄ«Å”u tikai galvenos punktus, lai nedublÄtos dokumentÄcija un esoÅ”ie raksti.
TÄtad filtra kods tiek ielÄdÄts kodolÄ. IenÄkoÅ”Äs paketes tiek nodotas filtram. RezultÄtÄ filtram ir jÄpieÅem lÄmums: nodot paketi kodolÄ (XDP_PASS), nomest paciÅu (XDP_DROP) vai nosÅ«tÄ«t atpakaļ (XDP_TX). Filtrs var mainÄ«t iepakojumu, jo Ä«paÅ”i tas attiecas uz XDP_TX. Varat arÄ« pÄrtraukt programmu (XDP_ABORTED) un atiestatiet pakotni, taÄu tas ir lÄ«dzÄ«gi assert(0) - atkļūdoÅ”anai.
eBPF (paplaÅ”inÄtais Berkley pakeÅ”u filtrs) virtuÄlÄ maŔīna ir apzinÄti vienkÄrÅ”a, lai kodols varÄtu pÄrbaudÄ«t, vai kods neveidojas cilpa un nebojÄ citu cilvÄku atmiÅu. KumulatÄ«vie ierobežojumi un pÄrbaudes:
Cilpas (atpakaļ) ir aizliegtas.
Ir datu steks, bet nav funkciju (visÄm C funkcijÄm jÄbÅ«t iekļautÄm).
Piekļuve atmiÅai Ärpus steka un pakeÅ”u bufera ir aizliegta.
Koda lielums ir ierobežots, taÄu praksÄ tas nav Ä«paÅ”i nozÄ«mÄ«gi.
Ir atļauti tikai izsaukumi uz Ä«paÅ”Äm kodola funkcijÄm (eBPF palÄ«giem).
Filtra projektÄÅ”ana un uzstÄdÄ«Å”ana izskatÄs Å”Ädi:
Avota kods (piem kernel.c) ir apkopots objektÄ (kernel.o) eBPF virtuÄlÄs maŔīnas arhitektÅ«rai. No 2019. gada oktobra kompilÄciju eBPF atbalsta Clang un sola GCC 10.1.
Ja Å”is objekta kods satur izsaukumus uz kodola struktÅ«rÄm (piemÄram, tabulÄm un skaitÄ«tÄjiem), to ID tiek aizstÄti ar nullÄm, kas nozÄ«mÄ, ka Å”Ädu kodu nevar izpildÄ«t. Pirms ielÄdÄÅ”anas kodolÄ Å”Ä«s nulles jÄaizstÄj ar konkrÄtu objektu ID, kas izveidoti, izmantojot kodola izsaukumus (saistiet kodu). To var izdarÄ«t, izmantojot ÄrÄjÄs utilÄ«tas, vai arÄ« varat uzrakstÄ«t programmu, kas saistÄ«s un ielÄdÄs noteiktu filtru.
Kodols pÄrbauda ielÄdÄto programmu. Tiek pÄrbaudÄ«ts ciklu neesamÄ«ba un nespÄja pÄrsniegt pakeÅ”u un steku robežas. Ja pÄrbaudÄ«tÄjs nevar pierÄdÄ«t, ka kods ir pareizs, programma tiek noraidÄ«ta - jums ir jÄspÄj viÅu iepriecinÄt.
Programma pievienojas saskarnei un sÄk apstrÄdÄt pakeÅ”us.
TÄ kÄ XDP darbojas kodolÄ, atkļūdoÅ”ana tiek veikta, izmantojot izsekoÅ”anas žurnÄlus un faktiski paketes, kuras programma filtrÄ vai Ä£enerÄ. TomÄr eBPF nodroÅ”ina, ka lejupielÄdÄtais kods ir droÅ”s sistÄmai, lai jÅ«s varÄtu eksperimentÄt ar XDP tieÅ”i savÄ vietÄjÄ Linux.
Vides sagatavoŔana
MontÄža
Clang nevar tieÅ”i radÄ«t objekta kodu eBPF arhitektÅ«rai, tÄpÄc process sastÄv no diviem posmiem:
KompilÄjiet C kodu LLVM baitkodÄ (clang -emit-llvm).
KonvertÄt baitkodu par eBPF objekta kodu (llc -march=bpf -filetype=obj).
Rakstot filtru, noderÄs pÄris faili ar palÄ«gfunkcijÄm un makro no kodola testiem. Ir svarÄ«gi, lai tie atbilstu kodola versijai (KVER). LejupielÄdÄjiet tos uz helpers/:
CFLAGS savienojiet direktoriju ar papildu galvenÄm un vairÄkus direktorijus ar kodola galvenÄm. Simbols __KERNEL__ nozÄ«mÄ, ka UAPI (lietotÄja telpas API) galvenes ir definÄtas kodola kodam, jo āāfiltrs tiek izpildÄ«ts kodolÄ.
Stacka aizsardzÄ«bu var atspÄjot (-fno-stack-protector), jo eBPF koda verificÄtÄjs joprojÄm pÄrbauda, āāvai nav pÄrkÄptas steka Ärpus robežÄm. OptimizÄciju ir vÄrts ieslÄgt uzreiz, jo eBPF baitkoda lielums ir ierobežots.
SÄksim ar filtru, kas iztur visas paketes un neko nedara:
Komanda make savÄc xdp_filter.o. Kur to tagad izmÄÄ£inÄt?
Testa stends
StendÄ jÄiekļauj divas saskarnes: uz kuras bÅ«s filtrs un no kuras tiks sÅ«tÄ«tas paketes. TÄm ir jÄbÅ«t pilnvÄrtÄ«gÄm Linux ierÄ«cÄm ar saviem IP, lai pÄrbaudÄ«tu, kÄ parastÄs lietojumprogrammas darbojas ar mÅ«su filtru.
Mums ir piemÄrotas veth (virtuÄlÄ Ethernet) tipa ierÄ«ces: tie ir virtuÄlo tÄ«kla interfeisu pÄris, kas āsavienotiā tieÅ”i viens ar otru. JÅ«s varat tos izveidot Å”Ädi (Å”ajÄ sadaÄ¼Ä visas komandas ip tiek veiktas no root):
ip link add xdp-remote type veth peer name xdp-local
Å eit xdp-remote Šø xdp-local ā ierÄ«Äu nosaukumi. IeslÄgts xdp-local (192.0.2.1/24) tiks pievienots filtrs, ar xdp-remote (192.0.2.2/24) tiks nosÅ«tÄ«ta ienÄkoÅ”Ä trafika. TomÄr pastÄv problÄma: saskarnes atrodas tajÄ paÅ”Ä datorÄ, un Linux nenosÅ«tÄ«s trafiku uz vienu no tiem caur otru. To var atrisinÄt ar sarežģītiem noteikumiem iptables, taÄu viÅiem bÅ«s jÄmaina pakotnes, kas ir neÄrti atkļūdoÅ”anai. LabÄk ir izmantot tÄ«kla nosaukumu telpas (turpmÄk netns).
TÄ«kla nosaukumvieta satur saskarÅu, marÅ”rutÄÅ”anas tabulu un NetFilter kÄrtulu kopu, kas ir izolÄtas no lÄ«dzÄ«giem objektiem citos netns. Katrs process darbojas nosaukumvietÄ, un tam ir piekļuve tikai Ŕī netns objektiem. PÄc noklusÄjuma sistÄmai ir viena tÄ«kla nosaukumvieta visiem objektiem, lai jÅ«s varÄtu strÄdÄt operÄtÄjsistÄmÄ Linux un nezinÄt par netns.
Izveidosim jaunu nosaukumvietu xdp-test un pÄrvietojiet to uz turieni xdp-remote.
ip netns add xdp-test
ip link set dev xdp-remote netns xdp-test
PÄc tam process sÄkas xdp-test, "neredzÄs" xdp-local (pÄc noklusÄjuma tas paliks netns) un, nosÅ«tot paketi uz 192.0.2.1, tÄ to nodos cauri xdp-remotejo tÄ ir vienÄ«gÄ saskarne 192.0.2.0/24, kas pieejama Å”im procesam. Tas darbojas arÄ« pretÄjÄ virzienÄ.
PÄrvietojoties starp netns, saskarne pazÅ«d un zaudÄ adresi. Lai konfigurÄtu saskarni netns, jums ir jÄpalaiž ip ... Å”ajÄ komandas nosaukumvietÄ ip netns exec:
ip netns exec xdp-test
ip address add 192.0.2.2/24 dev xdp-remote
ip netns exec xdp-test
ip link set xdp-remote up
KÄ redzat, tas neatŔķiras no iestatÄ«juma xdp-local noklusÄjuma nosaukumvietÄ:
ip address add 192.0.2.1/24 dev xdp-local
ip link set xdp-local up
Ja tu skrien tcpdump -tnevi xdp-local, jÅ«s varat redzÄt, ka paketes nosÅ«tÄ«tas no xdp-test, tiek piegÄdÄti uz Å”o interfeisu:
ip netns exec xdp-test ping 192.0.2.1
Ir Ärti palaist Äaulu xdp-test. RepozitorijÄ ir skripts, kas automatizÄ darbu ar stendu, piemÄram, stendu var konfigurÄt ar komandu sudo ./stand up un izdzÄsiet to sudo ./stand down.
IzsekoŔana
Filtrs ir saistÄ«ts ar ierÄ«ci Å”Ädi:
ip -force link set dev xdp-local xdp object xdp_filter.o verbose
TaustiÅÅ” -force nepiecieÅ”ams, lai saistÄ«tu jaunu programmu, ja cita jau ir saistÄ«ta. āNav ziÅu nav labas ziÅasā nav par Å”o komandu, secinÄjums jebkurÄ gadÄ«jumÄ ir apjomÄ«gs. norÄdÄ«t verbose neobligÄti, bet kopÄ ar to tiek parÄdÄ«ts ziÅojums par koda verificÄtÄja darbu ar montÄžas sarakstu:
Verifier analysis:
0: (b7) r0 = 2
1: (95) exit
Atsaistīt programmu no saskarnes:
ip link set dev xdp-local xdp off
SkriptÄ tÄs ir komandas sudo ./stand attach Šø sudo ./stand detach.
Par to varat pÄrliecinÄties, pievienojot filtru ping turpina darboties, bet vai programma darbojas? Pievienosim žurnÄlus. Funkcija bpf_trace_printk() lÄ«dzÄ«gs printf(), bet atbalsta tikai lÄ«dz trim argumentiem, izÅemot modeli, un ierobežotu specifikÄciju sarakstu. Makro bpf_printk() vienkÄrÅ”o zvanu.
Å Ä« iemesla dÄļ atkļūdoÅ”anas izvade ievÄrojami palielina iegÅ«to kodu.
XDP pakeŔu sūtīŔana
MainÄ«sim filtru: ļaujiet tam sÅ«tÄ«t atpakaļ visas ienÄkoÅ”Äs paketes. Tas ir nepareizi no tÄ«kla viedokļa, jo bÅ«tu jÄmaina adreses galvenÄs, bet tagad darbs principÄ ir svarÄ«gs.
Palaist tcpdump par xdp-remote. Tam ir jÄparÄda identisks izejoÅ”ais un ienÄkoÅ”ais ICMP atbalss pieprasÄ«jums un jÄpÄrtrauc rÄdÄ«t ICMP atbalss atbildi. Bet tas neparÄdÄs. IzrÄdÄs, ka darbam XDP_TX programmÄ ieslÄgts xdp-localir nepiecieÅ”amauz pÄra saskarni xdp-remote tika pieŔķirta arÄ« programma, pat ja tÄ bija tukÅ”a, un viÅÅ” tika audzinÄts.
KÄ es to uzzinÄju?
Izsekojiet pakotnes ceļu kodolÄ Perf notikumu mehÄnisms, starp citu, ļauj izmantot to paÅ”u virtuÄlo maŔīnu, tas ir, eBPF tiek izmantots demontÄžai ar eBPF.
No ļauna ir jÄizdara labs, jo nav nekÄ cita, no kÄ to izdarÄ«t.
Ja tÄ vietÄ tiek rÄdÄ«ti tikai ARP, jums ir jÄnoÅem filtri (tas tiek darÄ«ts sudo ./stand detach), atlaidiet ping, pÄc tam iestatiet filtrus un mÄÄ£iniet vÄlreiz. ProblÄma ir tÄda, ka filtrs XDP_TX derÄ«ga gan ARP, gan ja steka
nosaukumvietas xdp-test izdevÄs āaizmirstā MAC adresi 192.0.2.1, tas nevarÄs atrisinÄt Å”o IP.
ProblÄmas paziÅojums
PÄrejam pie norÄdÄ«tÄ uzdevuma: uzrakstiet SYN sÄ«kfailu mehÄnismu uz XDP.
SYN plÅ«di joprojÄm ir populÄrs DDoS uzbrukums, kura bÅ«tÄ«ba ir Å”Äda. Kad savienojums ir izveidots (TCP rokasspiediens), serveris saÅem SYN, pieŔķir resursus turpmÄkajam savienojumam, atbild ar SYNACK paketi un gaida ACK. UzbrucÄjs vienkÄrÅ”i nosÅ«ta tÅ«kstoÅ”iem SYN pakeÅ”u sekundÄ no viltotÄm adresÄm no katra saimniekdatora vairÄku tÅ«kstoÅ”u robotu tÄ«klÄ. Serveris ir spiests pieŔķirt resursus uzreiz pÄc paketes pienÄkÅ”anas, bet atbrÄ«vo tos pÄc liela taimauta, kÄ rezultÄtÄ tiek iztÄrÄta atmiÅa vai ierobežojumi, jauni savienojumi netiek pieÅemti un pakalpojums nav pieejams.
Ja jÅ«s nepieŔķirat resursus, pamatojoties uz SYN paketi, bet atbildat tikai ar SYNACK paketi, kÄ tad serveris var saprast, ka ACK pakete, kas tika saÅemta vÄlÄk, attiecas uz SYN paketi, kas netika saglabÄta? Galu galÄ uzbrucÄjs var Ä£enerÄt arÄ« viltotus ACK. SYN sÄ«kfaila mÄrÄ·is ir to iekodÄt seqnum savienojuma parametrus kÄ adreÅ”u, portu un mainÄ«go sÄls jauktu. Ja ACK izdevÄs saÅemt pirms sÄls maiÅas, varat vÄlreiz aprÄÄ·inÄt hash un salÄ«dzinÄt to ar acknum. Kalts acknum uzbrucÄjs nevar, jo sÄls ietver noslÄpumu, un ierobežotÄ kanÄla dÄļ viÅam nebÅ«s laika to Ŕķirot.
SYN sÄ«kfails jau sen ir ieviests Linux kodolÄ, un to var pat automÄtiski iespÄjot, ja SYN pienÄk pÄrÄk Ätri un masveidÄ.
Izglītības programma par TCP rokasspiedienu
TCP nodroÅ”ina datu pÄrraidi kÄ baitu straumi, piemÄram, HTTP pieprasÄ«jumi tiek pÄrsÅ«tÄ«ti pa TCP. Straume tiek pÄrraidÄ«ta gabalos pa paketÄm. VisÄm TCP paketÄm ir loÄ£iski karodziÅi un 32 bitu kÄrtas numuri:
Karogu kombinÄcija nosaka konkrÄtas pakotnes lomu. SYN karodziÅÅ” norÄda, ka Ŕī ir sÅ«tÄ«tÄja pirmÄ pakete savienojumÄ. ACK karodziÅÅ” nozÄ«mÄ, ka sÅ«tÄ«tÄjs ir saÅÄmis visus savienojuma datus lÄ«dz baitam acknum. Paketei var bÅ«t vairÄki karodziÅi, un to izsauc pÄc to kombinÄcijas, piemÄram, SYNACK pakete.
SecÄ«bas numurs (seqnum) norÄda nobÄ«di datu straumÄ pirmajam baitam, kas tiek pÄrsÅ«tÄ«ts Å”ajÄ paketÄ. PiemÄram, ja pirmajÄ paketÄ ar X baitiem datu Å”is skaitlis bija N, tad nÄkamajÄ paketÄ ar jauniem datiem tas bÅ«s N+X. Savienojuma sÄkumÄ katra puse izvÄlas Å”o numuru nejauÅ”i.
ApstiprinÄjuma numurs (acnum) - tÄda pati nobÄ«de kÄ seqnum, taÄu tas nenosaka pÄrsÅ«tÄmÄ baita numuru, bet gan pirmÄ baita numuru no adresÄta, kuru sÅ«tÄ«tÄjs neredzÄja.
Savienojuma sÄkumÄ pusÄm ir jÄvienojas seqnum Šø acknum. Klients kopÄ ar to nosÅ«ta SYN paketi seqnum = X. Serveris atbild ar SYNACK paketi, kur tas ieraksta to seqnum = Y un atmasko acknum = X + 1. Klients atbild uz SYNACK ar ACK paketi, kur seqnum = X + 1, acknum = Y + 1. PÄc tam sÄkas faktiskÄ datu pÄrsÅ«tÄ«Å”ana.
Ja partneris neapstiprina paketes saÅemÅ”anu, TCP pÄc taimauta to nosÅ«ta atkÄrtoti.
KÄpÄc ne vienmÄr tiek izmantotas SYN sÄ«kdatnes?
PirmkÄrt, ja SYNACK vai ACK tiek zaudÄts, jums bÅ«s jÄgaida, lÄ«dz tas tiks nosÅ«tÄ«ts vÄlreiz - savienojuma iestatÄ«Å”ana palÄninÄsies. OtrkÄrt, SYN pakotnÄ - un tikai tajÄ! ā tiek pÄrraidÄ«tas vairÄkas opcijas, kas ietekmÄ savienojuma turpmÄko darbÄ«bu. Neatceroties ienÄkoÅ”Äs SYN paketes, serveris ignorÄ Å”Ä«s opcijas; klients tÄs nesÅ«tÄ«s nÄkamajÄs paketÄs. TCP Å”ajÄ gadÄ«jumÄ var darboties, taÄu vismaz sÄkotnÄjÄ posmÄ savienojuma kvalitÄte samazinÄsies.
RunÄjot par pakotnÄm, XDP programmai ir jÄveic Å”Ädas darbÄ«bas:
atbildÄt uz SYN ar SYNACK ar sÄ«kfailu;
atbildÄt uz ACK ar RST (atvienot);
izmetiet atlikuÅ”Äs paketes.
Algoritma pseidokods kopÄ ar pakotnes parsÄÅ”anu:
Viens (*) ir atzÄ«mÄti punkti, kur jums jÄpÄrvalda sistÄmas stÄvoklis - pirmajÄ posmÄ jÅ«s varat iztikt bez tiem, vienkÄrÅ”i ievieÅ”ot TCP rokasspiedienu ar SYN sÄ«kfaila Ä£enerÄÅ”anu kÄ secÄ«bu.
Uz vietas (**), kamÄr mums nav galda, mÄs izlaidÄ«sim paciÅu.
TCP rokasspiediena ievieŔana
Paka parsÄÅ”ana un koda pÄrbaude
Mums bÅ«s nepiecieÅ”amas tÄ«kla galvenes struktÅ«ras: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) un TCP (uapi/linux/tcp.h). Es nevarÄju savienot pÄdÄjo kļūdu dÄļ, kas saistÄ«tas ar atomic64_t, man vajadzÄja iekopÄt kodÄ nepiecieÅ”amÄs definÄ«cijas.
Visas funkcijas, kas ir izceltas C, lai nodroÅ”inÄtu lasÄmÄ«bu, ir jÄiekļauj izsaukuma punktÄ, jo eBPF verificÄtÄjs kodolÄ aizliedz atpakaļsekoÅ”anu, tas ir, cilpas un funkciju izsaukumus.
Programma ir funkciju konveijers. Katrs saÅem paketi, kurÄ ir izcelta atbilstoÅ”Ä lÄ«meÅa galvene, piemÄram, process_ether() sagaida, ka tas tiks aizpildÄ«ts ether. Pamatojoties uz lauka analÄ«zes rezultÄtiem, funkcija var nodot paketi augstÄkam lÄ«menim. Funkcijas rezultÄts ir XDP darbÄ«ba. PagaidÄm SYN un ACK apstrÄdÄtÄji nodod visas paketes.
Es vÄrÅ”u jÅ«su uzmanÄ«bu uz Äekiem, kas atzÄ«mÄti ar A un B. Ja komentÄsit A, programma tiks veidota, taÄu ielÄdes laikÄ tiks parÄdÄ«ta pÄrbaudes kļūda:
AtslÄgu virkne invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): ir izpildes ceļi, kad trÄ«spadsmitais baits no bufera sÄkuma atrodas Ärpus paketes. No saraksta ir grÅ«ti saprast, par kuru rindiÅu mÄs runÄjam, taÄu ir instrukcijas numurs (12) un demontÄtÄjs, kas parÄda avota koda rindas:
kas skaidri parÄda, ka problÄma ir ether. Tas vienmÄr bÅ«tu Å”Ädi.
AtbildÄt uz SYN
Å ajÄ posmÄ mÄrÄ·is ir Ä£enerÄt pareizu SYNACK paketi ar fiksÄtu seqnum, kas nÄkotnÄ tiks aizstÄts ar SYN sÄ«kfailu. Visas izmaiÅas notiek iekÅ”Ä process_tcp_syn() un apkÄrtÄjÄs teritorijas.
Pakas pÄrbaude
SavÄdi, bet Å”eit ir visievÄrojamÄkÄ lÄ«nija vai drÄ«zÄk tÄs komentÄrs:
Rakstot pirmo koda versiju, tika izmantots 5.1 kodols, kura pÄrbaudÄ«tÄjam bija atŔķirÄ«ba starp data_end Šø (const void*)ctx->data_end. RakstÄ«Å”anas laikÄ kodolam 5.3.1 nebija Ŕīs problÄmas. IespÄjams, ka kompilators piekļuva lokÄlajam mainÄ«gajam citÄdi nekÄ laukam. StÄsta morÄle: koda vienkÄrÅ”oÅ”ana var palÄ«dzÄt, ja ir daudz ligzdoÅ”anas.
NÄkamÄs ir kÄrtÄjÄs garuma pÄrbaudes, lai novÄrtÄtu verificÄtÄja godÄ«bu; O MAX_CSUM_BYTES zemÄk.
Apmainiet TCP portus, IP adreses un MAC adreses. Standarta bibliotÄka nav pieejama no XDP programmas, tÄpÄc memcpy() ā makro, kas slÄpj Clang bÅ«tÄ«bas.
IPv4 un TCP kontrolsummÄs galvenÄs ir jÄpievieno visi 16 bitu vÄrdi, un tajos tiek ierakstÄ«ts galveÅu lielums, tas ir, kompilÄÅ”anas laikÄ tas nav zinÄms. TÄ ir problÄma, jo pÄrbaudÄ«tÄjs neizlaidÄ«s parasto cilpu uz robežas mainÄ«go. Bet galveÅu lielums ir ierobežots: katrs lÄ«dz 64 baitiem. Varat izveidot cilpu ar noteiktu atkÄrtojumu skaitu, kas var beigties agri.
Es atzÄ«mÄju, ka ir RFC 1624 par to, kÄ daļÄji pÄrrÄÄ·inÄt kontrolsummu, ja tiek mainÄ«ti tikai pakotÅu fiksÄtie vÄrdi. TomÄr metode nav universÄla, un to bÅ«tu grÅ«tÄk uzturÄt.
Kontrolsummas aprÄÄ·inÄÅ”anas funkcija:
#define MAX_CSUM_WORDS 32
#define MAX_CSUM_BYTES (MAX_CSUM_WORDS * 2)
INTERNAL u32
sum16(const void* data, u32 size, const void* data_end) {
u32 s = 0;
#pragma unroll
for (u32 i = 0; i < MAX_CSUM_WORDS; i++) {
if (2*i >= size) {
return s; /* normal exit */
}
if (data + 2*i + 1 + 1 > data_end) {
return 0; /* should be unreachable */
}
s += ((const u16*)data)[i];
}
return s;
}
Lai gan size verificÄts ar izsaucÄja kodu, ir nepiecieÅ”ams otrais izejas nosacÄ«jums, lai pÄrbaudÄ«tÄjs varÄtu pierÄdÄ«t cilpas pabeigÅ”anu.
32 bitu vÄrdiem ir ieviesta vienkÄrÅ”Äka versija:
INTERNAL u32
sum16_32(u32 v) {
return (v >> 16) + (v & 0xffff);
}
Faktiski pÄrrÄÄ·inot kontrolsummas un nosÅ«tot paketi atpakaļ:
Funkcija carry() saskaÅÄ ar RFC 32 veido kontrolsummu no 16 bitu vÄrdu 791 bitu summas.
TCP rokasspiediena pÄrbaude
Filtrs pareizi izveido savienojumu ar netcat, trÅ«kst galÄ«gÄ ACK, uz kuru Linux atbildÄja ar RST paketi, jo tÄ«kla steks nesaÅÄma SYN - tas tika pÄrveidots par SYNACK un nosÅ«tÄ«ts atpakaļ - un no OS viedokļa atnÄca pakete, kas nebija saistÄ«ta ar atvÄrÅ”anu. savienojumiem.
$ sudo ip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer
Ir svarÄ«gi pÄrbaudÄ«t ar pilnvÄrtÄ«gÄm lietojumprogrammÄm un novÄrot tcpdump par xdp-remote jo, piemÄram, hping3 nereaÄ£Ä uz nepareizÄm kontrolsummÄm.
SYN sīkfails
No XDP viedokļa pati pÄrbaude ir triviÄla. AprÄÄ·inu algoritms ir primitÄ«vs un, iespÄjams, neaizsargÄts pret sarežģītu uzbrucÄju. PiemÄram, Linux kodols izmanto kriptogrÄfisko SipHash, taÄu tÄ ievieÅ”ana XDP nepÄrprotami neietilpst Ŕī raksta darbÄ«bas jomÄ.
Ieviests jauniem TODO, kas saistÄ«ti ar ÄrÄjo komunikÄciju:
XDP programma nevar saglabÄt cookie_seed (sÄls slepenÄ daļa) globÄlajÄ mainÄ«gajÄ, jums ir nepiecieÅ”ama krÄtuve kodolÄ, kuras vÄrtÄ«ba periodiski tiks atjauninÄta no uzticama Ä£eneratora.
Ja SYN sÄ«kfails sakrÄ«t ACK paketÄ, jums nav jÄdrukÄ ziÅojums, bet jÄatceras verificÄtÄ klienta IP, lai turpinÄtu nosÅ«tÄ«t pakeÅ”u no tÄ.
Lai gan nav pÄrbaudÄ«to IP saraksta, nebÅ«s aizsardzÄ«bas pret paÅ”u SYN plÅ«diem, taÄu Å”eit ir reakcija uz ACK plÅ«diem, ko palaida Å”Äda komanda:
sudo ip netns exec xdp-test hping3 --flood -A -s 1111 -p 2222 192.0.2.1
Dažreiz eBPF kopumÄ un jo Ä«paÅ”i XDP tiek pasniegts vairÄk kÄ uzlabots administratora rÄ«ks, nevis kÄ izstrÄdes platforma. PatieÅ”Äm, XDP ir rÄ«ks, kas traucÄ kodola pakeÅ”u apstrÄdi, nevis alternatÄ«va kodola stekam, piemÄram, DPDK un citas kodola apieÅ”anas opcijas. SavukÄrt XDP ļauj ieviest visai sarežģītu loÄ£iku, kuru turklÄt ir viegli atjauninÄt, netraucÄjot trafika apstrÄdÄ. Verifikators lielas problÄmas nerada, personÄ«gi es neatteiktos no lietotÄja telpas koda daļÄm.
OtrajÄ daļÄ, ja tÄma ir interesanta, aizpildÄ«sim verificÄto klientu un atvienojumu tabulu, ieviesÄ«sim skaitÄ«tÄjus un uzrakstÄ«sim userspace utilÄ«tu filtra pÄrvaldÄ«bai.