Waxaan qornaa ka hortagga weerarrada DDoS ee XDP. Nukliyeerka qayb

Tiknoolajiyada eXpress Data Path (XDP) waxay u ogolaanaysaa habaynta taraafikada random in lagu sameeyo interfaces Linux ka hor inta aanay xidhmooyinku gelin xidhmada shabakada kernel. Codsiga XDP - ilaalinta weerarrada DDoS (CloudFlare), filtarrada adag, ururinta tirakoobka (Netflix). Barnaamijyada XDP waxaa fuliya mishiinka farsamada ee eBPF, marka waxay leeyihiin xaddidaadyo ku saabsan koodkooda iyo shaqooyinka kernel-ka ee jira iyadoo ku xiran nooca shaandhada.

Maqaalka waxaa loogu talagalay in lagu buuxiyo cilladaha alaabooyin badan oo XDP ah. Marka hore, waxay bixiyaan kood diyaarsan oo isla markiiba dhaafa astaamaha XDP: waxaa loo diyaariyey xaqiijinta ama aad bay u fududahay in ay dhibaato keento. Marka aad markaas isku daydo inaad koodka ka qorto meel eber ah, ma haysatid wax fikrad ah oo lagu sameeyo khaladaadka caadiga ah. Marka labaad, siyaabaha gudaha loogu tijaabiyo XDP iyada oo aan lahayn VM iyo qalab lama daboolo, in kasta oo xaqiiqda ah in ay leeyihiin godad iyaga u gaar ah. Qoraalka waxaa loogu talagalay barnaamijyada yaqaan shabakadaha iyo Linux kuwaas oo xiiseynaya XDP iyo eBPF.

Qaybtan, waxaan si faahfaahsan u fahmi doonaa sida shaandhada XDP loo ururiyo iyo sida loo tijaabiyo, ka dib waxaan qori doonaa nooc fudud oo ah habka loo yaqaan 'cookies SYN' ee heerka baakidhka. Weli ma abuuri doono "liiska cad"
macaamiisha la xaqiijiyay, xaji xisaabaadka oo maamul filtarka - diiwaanno ku filan.

Waxaan ku qori doonaa C - ma aha moodada, laakiin waa wax la taaban karo. Dhammaan koodka waxaa laga heli karaa GitHub iyada oo loo marayo isku xirka dhamaadka waxaana loo qaybiyaa go'aano iyadoo loo eegayo heerarka lagu qeexay maqaalka.

Diidmada. Inta lagu gudajiro maqaalkan, waxaan horumarin doonaa xal-yar si looga hortago weerarrada DDoS, sababtoo ah tani waa hawl dhab ah oo XDP ah iyo aaggayga khibradda leh. Si kastaba ha noqotee, hadafka ugu weyn waa in la fahmo tignoolajiyada; tani maaha hage lagu abuurayo ilaalin diyaarsan. Koodhka casharka lama hagaajin oo waxa uu meesha ka saarayaa nuucyada qaarkood.

Dulmar Kooban XDP

Waxaan dulmarayaa kaliya qodobada muhiimka ah si aan loo nuqulin dukumentiyada iyo maqaallada jira.

Markaa, koodka shaandhada ayaa lagu shubaa kernel-ka. Xirmooyinka soo socda ayaa loo gudbiyaa shaandhada. Natiijo ahaan, filterku waa inuu sameeyaa go'aan: u gudbi baakadda kernelka (XDP_PASS), baakidh tuur (XDP_DROP) ama soo celi (XDP_TX). Shaandheeyaha ayaa bedeli kara xirmada, tani waxay si gaar ah run u tahay XDP_TX. Waxaad sidoo kale iska dhicin kartaa barnaamijka (XDP_ABORTED) oo dib u deji xirmada, laakiin tani waa isku mid assert(0) - si loo saxo.

Mashiinka farsamada eBPF (kordhinta Berkley Packet Filter) ayaa si ula kac ah loo sameeyay si fudud si kernel-ku u hubiyo in koodka uusan duubin oo uusan waxyeello u geysan xusuusta dadka kale. Xayiraadaha iyo hubinta isugeynta:

  • Loops (dib-u-socodka) waa mamnuuc.
  • Waxaa jira kayd xog ah, laakiin ma jiraan hawlo (dhammaan hawlaha C waa in la dhex geliyaa).
  • Gelida xusuusta ee ka baxsan xirmada iyo baakadaha waa mamnuuc.
  • Cabbirka koodhka ayaa xaddidan, laakiin ficil ahaan tani maaha mid aad muhiim u ah.
  • Keliya wicitaanada shaqooyinka kernel-ka gaarka ah (caawiyayaasha eBPF) waa la ogolyahay.

Naqshadeynta iyo rakibida filtarku waxay u egtahay sidan:

  1. Koodhka isha (tusaale kernel.c) waxaa loo soo ururiyey shay (kernel.o) ee eBPF qaab dhismeedka mashiinka farsamada. Laga bilaabo Oktoobar 2019, isu-ururinta eBPF waxaa taageeray Clang waxaana lagu ballan qaaday GCC 10.1.
  2. Haddii koodka shayga uu ka kooban yahay wicitaannada qaab-dhismeedka kernel-ka (tusaale, miisaska iyo miisaska), aqoonsigooda waxaa lagu beddelay eber, taas oo macnaheedu yahay in koodkaas aan la fulin karin. Kahor intaadan gelin kernel-ka, waxaad u baahan tahay inaad eber kuwan ku bedesho aqoonsiga shay gaar ah oo lagu sameeyay wicitaanada kernel-ka (ku xidh koodka). Tan waxaad ku samayn kartaa adeegyada dibadda, ama waxaad qori kartaa barnaamij isku xidhi doona oo ku shubi doona shaandhooyin gaar ah.
  3. Kernelku wuxuu xaqiijiyaa barnaamijka la raray. Maqnaanshaha wareegyada iyo guuldarada in la dhaafo baakidhka iyo xuduudaha waa la hubiyaa. Haddii xaqiijiyaha aanu caddayn karin in koodku sax yahay, barnaamijka waa la diiday - waxaad u baahan tahay inaad ka farxiso isaga.
  4. Xaqiijinta si guul leh ka dib, kernelku wuxuu ururiyaa koodhka shayga eBPF koodka mashiinka ee qaab dhismeedka nidaamka (waqti-yar).
  5. Barnaamijku wuxuu ku xiran yahay interface-ka wuxuuna bilaabayaa socodsiinta xirmooyinka.

Mar haddii XDP ay ku dhex shaqeyso kernel-ka, khaladaadka waxaa lagu fuliyaa iyadoo la adeegsanayo diiwaannada raadraaca iyo, dhab ahaantii, baakado uu barnaamijku shaandheeyo ama soo saaro. Si kastaba ha ahaatee, eBPF waxay hubisaa in koodka la soo dejiyey uu ammaan u yahay nidaamka, si aad si toos ah ugu tijaabin karto XDP Linux gudahaaga.

Diyaarinta Deegaanka

Golaha

Clang si toos ah uma soo saari karo koodka shayga ee qaab dhismeedka eBPF, marka nidaamku wuxuu ka kooban yahay laba tillaabo:

  1. U samee koodhka C ilaa LLVM bytecode (clang -emit-llvm).
  2. U beddel bytecode eBPF koodka shayga (llc -march=bpf -filetype=obj).

Markaad qorayso shaandhada, laba faylal oo leh hawlo caawiye iyo macros ayaa faa'iido yeelan doona laga bilaabo tijaabooyinka kernel-ka. Waa muhiim in ay iswaafaqaan nooca kernel-ka (KVER). U soo deji helpers/:

export KVER=v5.3.7
export BASE=https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/tools/testing/selftests/bpf
wget -P helpers --content-disposition "${BASE}/bpf_helpers.h?h=${KVER}" "${BASE}/bpf_endian.h?h=${KVER}"
unset KVER BASE

Makefile ee Arch Linux (kernel 5.3.7):

CLANG ?= clang
LLC ?= llc

KDIR ?= /lib/modules/$(shell uname -r)/build
ARCH ?= $(subst x86_64,x86,$(shell uname -m))

CFLAGS = 
    -Ihelpers 
    
    -I$(KDIR)/include 
    -I$(KDIR)/include/uapi 
    -I$(KDIR)/include/generated/uapi 
    -I$(KDIR)/arch/$(ARCH)/include 
    -I$(KDIR)/arch/$(ARCH)/include/generated 
    -I$(KDIR)/arch/$(ARCH)/include/uapi 
    -I$(KDIR)/arch/$(ARCH)/include/generated/uapi 
    -D__KERNEL__ 
    
    -fno-stack-protector -O2 -g

xdp_%.o: xdp_%.c Makefile
    $(CLANG) -c -emit-llvm $(CFLAGS) $< -o - | 
    $(LLC) -march=bpf -filetype=obj -o $@

.PHONY: all clean

all: xdp_filter.o

clean:
    rm -f ./*.o

KDIR waxay ka kooban tahay dariiqa loo maro madaxyada kernel, ARCH - qaab dhismeedka nidaamka. Wadooyinka iyo agabyadu waxyar bay ku kala duwanaan karaan qaybinta.

Tusaalaha kala duwanaanshaha Debian 10 (kernel 4.19.67)

# другая команда
CLANG ?= clang
LLC ?= llc-7

# другой каталог
KDIR ?= /usr/src/linux-headers-$(shell uname -r)
ARCH ?= $(subst x86_64,x86,$(shell uname -m))

# два дополнительных каталога -I
CFLAGS = 
    -Ihelpers 
    
    -I/usr/src/linux-headers-4.19.0-6-common/include 
    -I/usr/src/linux-headers-4.19.0-6-common/arch/$(ARCH)/include 
    # далее без изменений

CFLAGS ku xidh buug hage leh madax caawiye ah iyo dhawr hageyaal oo leh madax kernel. Astaanta __KERNEL__ macneheedu waxa weeye in UAPI (userspace API) madaxyada lagu qeexay koodka kernelka, maadaama shaandhada lagu dhex fuliyo kernel-ka.

Ilaalinta xirmada waa la joojin karaa (-fno-stack-protector), sababtoo ah xaqiijiyaha koodka eBPF ayaa wali hubinaya xadgudubyada ka baxsan xadka. Way mudan tahay in isla markaaba daarto hagaajinta, sababtoo ah cabbirka eBPF bytecode waa xaddidan yahay.

Aan ku bilowno filtar ka gudubta dhammaan baakadaha oo aan waxba qaban:

#include <uapi/linux/bpf.h>

#include <bpf_helpers.h>

SEC("prog")
int xdp_main(struct xdp_md* ctx) {
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

kooxda make ururiya xdp_filter.o. Halkee laga tijaabiyaa hadda?

Tijaabi istaag

Istaaggu waa inuu ku jiraa laba isdhexgal: kaas oo ay jiri doonto shaandhayn iyo baakadaha laga soo diri doono. Kuwani waa inay ahaadaan qalab Linux buuxa oo leh IP-yadooda si loo hubiyo sida codsiyada caadiga ah ay ula shaqeeyaan shaandhadayada.

Qalabka veth (virtual Ethernet) nooca waa nagu habboon yihiin: kuwani waa lammaane iskuxiran oo shabakadeed "ku xiran" si toos ah midba midka kale. Waxaad u abuuri kartaa sidan oo kale (qaybtan dhammaan amarrada ip waxaa laga fuliyaa root):

ip link add xdp-remote type veth peer name xdp-local

waa xdp-remote и xdp-local - magacyada qalabka. Daar xdp-local (192.0.2.1/24) filtar ayaa lagu dhejin doonaa, oo leh xdp-remote (192.0.2.2/24) gaadiidka soo galaya ayaa la diri doonaa. Si kastaba ha ahaatee, waxaa jira dhibaato: interfaces waxay ku yaalaan mashiin isku mid ah, Linux-na uma diri doono taraafikada mid ka mid ah kan kale. Tan waxaad ku xallin kartaa xeerar qallafsan iptables, laakiin waa inay beddelaan baakadaha, taas oo aan ku habboonayn cilladaha. Way fiicantahay in la isticmaalo shabakadaha magacyada (netn-ka dambe).

Meesha magaca shabakadu waxay ka kooban tahay is-dhexgalyo, miisas-wareejin, iyo xeerarka NetFilter kuwaas oo ka go'doonsan walxaha la midka ah ee shabakadaha kale. Nidaam kastaa wuxuu ku socdaa meel magaceed oo keliya wuxuu marin u leeyahay shayada shabakadahaas. Sida caadiga ah, nidaamku wuxuu leeyahay hal magac oo shabakad ah oo loogu talagalay dhammaan walxaha, si aad uga shaqeyso Linux oo aadan ka warqabin shabakadaha.

Aan abuurno magac cusub xdp-test oo halkaas u raro xdp-remote.

ip netns add xdp-test
ip link set dev xdp-remote netns xdp-test

Kadibna hawshu way socotaa xdp-test, "ma arki doono" xdp-local (waxay ku sii jiri doontaa netns by default) iyo marka baakidhka loo diro 192.0.2.1 way gudbi doontaa xdp-remotesababtoo ah waa interface kaliya ee 192.0.2.0/24 la heli karo habkan. Tani waxay sidoo kale ka shaqeysaa jihada ka soo horjeeda.

Markaad u guurto inta u dhaxaysa netns, interface-ku wuu hoos u dhacayaa oo luminayaa ciwaankiisa. Si aad u habayso interneedka netns, waxaad u baahan tahay inaad socodsiiso ip ... amarkan magaca 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

Sida aad arki karto, tani kama duwana goobta xdp-local ku dhex jira booska magaca caadiga ah:

    ip address add 192.0.2.1/24 dev xdp-local
    ip link set xdp-local up

Haddaad cararto tcpdump -tnevi xdp-local, waxaad arki kartaa baakadaha laga soo diray xdp-test, waxaa la geeyaa interface-kan:

ip netns exec xdp-test   ping 192.0.2.1

Way ku habboon tahay in qolof la soo galiyo xdp-test. Kaydka ayaa leh qoraal si otomaatig ah ula shaqeeya istaagga; tusaale ahaan, waxaad ku habayn kartaa istaagga amarka sudo ./stand up oo tirtir sudo ./stand down.

Baafinta

Filterku waxa uu ku xidhan yahay qalabka sidan oo kale ah:

ip -force link set dev xdp-local xdp object xdp_filter.o verbose

Furaha -force loo baahan yahay in lagu xidho barnaamij cusub haddii mid kale hore loogu xidhay. "Ma jiro war wanaagsan" kuma saabsana amarkan, gebogebada waa mid aad u weyn xaalad kasta. tilmaami verbose Ikhtiyaar ah, laakiin iyada oo ay la socoto warbixin ayaa ka soo muuqanaysa shaqada koodka xaqiijiyaha oo leh liiska golaha:

Verifier analysis:

0: (b7) r0 = 2
1: (95) exit

Ka saar barnaamijka interface-ka:

ip link set dev xdp-local xdp off

Qoraalka waxaa ku jira amarro sudo ./stand attach и sudo ./stand detach.

Adigoo ku xiraya shaandhada, waxaad xaqiijin kartaa taas ping wuu sii socdaa, laakiin barnaamijku ma shaqeeyaa? Aan ku darno geedaha. Shaqada bpf_trace_printk() la mid ah printf(), laakiin kaliya waxay taageertaa ilaa saddex dood oo aan ahayn qaabka, iyo liis xaddidan oo tilmaameyaal ah. Macro bpf_printk() fududeeya wacitaanka.

   SEC("prog")
   int xdp_main(struct xdp_md* ctx) {
+      bpf_printk("got packet: %pn", ctx);
       return XDP_PASS;
   }

Wax soo saarku waxa uu aadayaa kanaalka raadraaca kernel, kaas oo u baahan in la dhaqaajiyo:

echo -n 1 | sudo tee /sys/kernel/debug/tracing/options/trace_printk

Fiiri taxanaha fariinta:

cat /sys/kernel/debug/tracing/trace_pipe

Labadan amarba way wacayaan sudo ./stand log.

Ping hadda waa inuu kiciyaa fariimaha sidan oo kale ah:

<...>-110930 [004] ..s1 78803.244967: 0: got packet: 00000000ac510377

Haddii aad si dhow u eegto soo-saarka xaqiijiyaha, waxaad dareemi doontaa xisaabaadyo qariib ah:

0: (bf) r3 = r1
1: (18) r1 = 0xa7025203a7465
3: (7b) *(u64 *)(r10 -8) = r1
4: (18) r1 = 0x6b63617020746f67
6: (7b) *(u64 *)(r10 -16) = r1
7: (bf) r1 = r10
8: (07) r1 += -16
9: (b7) r2 = 16
10: (85) call bpf_trace_printk#6
<...>

Xaqiiqdu waxay tahay in barnaamijyada eBPF aysan lahayn qayb xog ah, marka sida kaliya ee lagu codeeyo xargaha qaabku waa doodaha degdega ah ee amarrada VM:

$ python -c "import binascii; print(bytes(reversed(binascii.unhexlify('0a7025203a74656b63617020746f67'))))"
b'got packet: %pn'

Sababtan awgeed, wax-soo-saarka debug-ka ayaa si weyn u burburiya koodka soo baxay.

Diraya Xirmooyinka XDP

Aan bedelno filtarka: ha soo celiyo dhammaan baakadaha soo socda. Tani waa khalad marka loo eego aragtida shabakada, maadaama ay lagama maarmaan noqon doonto in la beddelo cinwaannada madaxyada, laakiin hadda shaqada mabda'a waa muhiim.

       bpf_printk("got packet: %pn", ctx);
-      return XDP_PASS;
+      return XDP_TX;
   }

Daahfurka tcpdump on xdp-remote. Waa inay muujisaa bixitaan isku mid ah oo soo galaya Codsiga Echo ICMP oo ay joojiso muujinta ICMP Echo Reply. Laakiin ma muuqato. Waxaa soo baxday in shaqada XDP_TX barnaamijka ku saabsan xdp-local waa lagama maarmaansi ay labada interface xdp-remote sidoo kale barnaamij baa loo qoondeeyay, xataa hadduu madhan yahay, isna waa la koray.

Sideen ku ogaaday tan?

Raad raac dariiqa xirmada kernel-ka Farsamaynta dhacdooyinka perf waxay ogolaataa, jidka, iyadoo la adeegsanayo mashiin la mid ah, taas oo ah, eBPF waxaa loo isticmaalaa kala dirisyada eBPF.

Waa inaad sharka wanaag ka samaysaa, waayo, wax kale oo aad ka samaysaan ma jiraan.

$ sudo perf trace --call-graph dwarf -e 'xdp:*'
   0.000 ping/123455 xdp:xdp_bulk_tx:ifindex=19 action=TX sent=0 drops=1 err=-6
                                     veth_xdp_flush_bq ([veth])
                                     veth_xdp_flush_bq ([veth])
                                     veth_poll ([veth])
                                     <...>

Waa maxay koodka 6?

$ errno 6
ENXIO 6 No such device or address

function veth_xdp_flush_bq() ka helo kood qalad veth_xdp_xmit(), meesha laga raadiyo ENXIO oo hel faallada.

Aynu soo celino shaandhada ugu yar (XDP_PASS) faylka ku jira xdp_dummy.c, ku dar Makefile, ku xidh xdp-remote:

ip netns exec remote 
    ip link set dev int xdp object dummy.o

Hadda tcpdump waxay tusinaysaa waxa laga filayo:

62:57:8e:70:44:64 > 26:0e:25:37:8f:96, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 13762, offset 0, flags [DF], proto ICMP (1), length 84)
    192.0.2.2 > 192.0.2.1: ICMP echo request, id 46966, seq 1, length 64
62:57:8e:70:44:64 > 26:0e:25:37:8f:96, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 13762, offset 0, flags [DF], proto ICMP (1), length 84)
    192.0.2.2 > 192.0.2.1: ICMP echo request, id 46966, seq 1, length 64

Haddii kaliya ARP-yada la muujiyo, waxaad u baahan tahay inaad ka saarto filtarrada (tani waxay sameyneysaa sudo ./stand detach), daa ping, dabadeed deji filtarrada oo isku day mar kale. Dhibaatadu waxay tahay shaandhada XDP_TX ansax ah labadaba ARP iyo haddi ay xidhmo
meelaha magacyada xdp-test u suurtagashay in ay "hilmaamaan" cinwaanka MAC 192.0.2.1, ma awoodi doonaan in ay xaliyaan IP this.

Abuurista dhibaatada

Aan u gudubno hawsha la sheegay: ku qor habka SYN cookies ee XDP.

Daadka SYN ayaa weli ah weerarka caanka ah ee DDoS, kaas oo nuxurkiisu yahay sidan soo socota. Marka xiriir la sameeyo (gacanta TCP), adeeguhu wuxuu helayaa SYN, wuxuu u qoondeynayaa kheyraadka xiriirka mustaqbalka, wuxuu ku jawaabaa xirmo SYNACK wuxuuna sugayaa ACK. Weeraryahanku wuxuu si fudud u soo diraa kumanaan baakidh SYN ah ilbiriqsi kasta ciwaannada xaaqsan ee martigeliyaha kasta oo ku jira botnet badan oo kun-xoog ah. Server-ku waxa uu ku qasban yahay in uu isla markiiba u qoondeeyo agabka marka uu xidhmo soo galo,laakin waxa uu sii daayaa wakhti badan ka dib;sidaa awgeed,xusuusta ama xadku waa daalan yihiin,xidhiidhyada cusub lama aqbalin, adeegana lama heli karo.

Haddii aadan u qoondeyn kheyraadka ku saleysan xirmada SYN, laakiin aad kaga jawaabto kaliya xirmada SYNACK, sidee markaas server-ku u fahmi karaa in baakadka ACK ee mar dambe yimid uu tixraacayo xirmo SYN ah oo aan la keydin? Ka dib oo dhan, weeraryahanku wuxuu kaloo dhalin karaa ACK-yo been abuur ah. Ujeedada buskudka SYN waa in lagu koodka geliyaa seqnum xuduudaha isku xirka sida xashiishka ciwaanada, dekedaha iyo milixda beddela. Haddii ACK ay u suurtagashay in ay timaado ka hor inta aan milixda la beddelin, waxaad xisaabin kartaa xashiishka mar kale oo aad barbardhigi kartaa acknum. Been abuurasho acknum Weeraryahanku ma awoodo, maadaama milixdu ay ku jirto sirta, mana heli doono wakhti ay ku kala soocaan kanaalka xaddidan awgeed.

Buskudka SYN ayaa muddo dheer laga hirgaliyay Linux kernel oo xitaa si toos ah ayaa loo awoodsiin karaa haddii SYNs ay si degdeg ah u yimaadaan oo guud ahaan.

Barnaamij waxbarasho oo ku saabsan gacan qaadka TCP

TCP waxay bixisaa gudbinta xogta sida qulqulka bytes, tusaale ahaan, codsiyada HTTP waxaa lagu kala qaadaa TCP. Durdurku waxa lagu kala qaadaa qaybo baakidhyo ah. Dhammaan xirmooyinka TCP waxay leeyihiin calammo macquul ah iyo nambarada isku xigxiga ee 32-bit:

  • Isku dhafka calanku wuxuu go'aamiyaa doorka xirmo gaar ah. Calanka SYN waxa uu tilmaamayaa in kani yahay xidhidhiyaha ugu horreeya ee soo diraha. Calanka ACK wuxuu ka dhigan yahay in soo-diraha uu helay dhammaan xogta xiriirka ilaa byte-ka acknum. Baakidhku wuxuu yeelan karaa dhowr calan waxaana loogu yeeraa isku-darkooda, tusaale ahaan, baakidh SYNACK ah.

  • Nambarka isku xigxiga (seqnum) wuxuu qeexayaa ka-goynta qulqulka xogta ee byte-ka ugu horreeya ee lagu gudbiyo xirmadan. Tusaale ahaan, haddii baakidhkii ugu horreeyay ee xogta X bytes ee lambarkani uu ahaa N, baqshadda soo socota ee xog cusub wadata waxay noqonaysaa N+X. Bilawga xidhiidhka, dhinac kastaa wuxuu dooranayaa lambarkan si aan kala sooc lahayn.

  • Nambarka qirashada (acknum) - oo la mid ah kan seqnum, laakiin ma go'aamiyo tirada byte ee la kala qaado, laakiin tirada byte ugu horreeya ee qaataha, kaas oo soo diray ma arkin.

Bilawga xidhiidhka, dhinacyadu waa inay ku heshiiyaan seqnum и acknum. Macmiilku waxa uu soo dirayaa baakidh SYN ah oo wata seqnum = X. Seerfarku waxa uu kaga jawaabayaa baakidh SYNACK ah, halkaas oo uu ku duubo seqnum = Y oo daaha ka qaada acknum = X + 1. Macmiilku wuxuu kaga jawaabaa SYNACK baakidh ACK ah, halkaas oo seqnum = X + 1, acknum = Y + 1. Taas ka dib, wareejinta xogta dhabta ah waxay bilaabmaysaa.

Haddii asaagii aanu qiran helitaanka baakadda, TCP waxay dib u soo celisaa wakhti ka dib.

Waa maxay sababta cookies-ka SYN aan had iyo jeer loo isticmaalin?

Marka hore, haddii SYNACK ama ACK lumo, waa inaad sugtaa inta laguu soo dirayo mar labaad - habaynta isku xidhka ayaa hoos u dhici doonta. Marka labaad, xirmada SYN - oo kaliya ayaa ku jira! - dhowr ikhtiyaar ayaa la kala qaadaa kuwaas oo saameeya hawlgalka dheeraadka ah ee isku xirka. Adigoo aan xasuusan xirmooyinka SYN ee soo galaya, server-ku sidaas ayuu iska indha tiraa xulashooyinkan; macmiilku kuma diri doono xirmooyinka soo socda. TCP waxay ku shaqeyn kartaa kiiskan, laakiin ugu yaraan marxaladda bilowga ah tayada isku xirka ayaa hoos u dhigi doonta.

Marka laga eego dhanka xirmooyinka, barnaamijka XDP waa inuu sameeyaa waxyaabaha soo socda:

  • uga jawaab SYN SYNACK buskud;
  • uga jawaab ACK oo leh RST (kala goy);
  • iska tuur baakadaha soo hadhay.

Pseudocode ee algorithmamka oo ay weheliso falanqaynta xirmada:

Если это не Ethernet,
    пропустить пакет.
Если это не IPv4,
    пропустить пакет.
Если адрес в таблице проверенных,               (*)
        уменьшить счетчик оставшихся проверок,
        пропустить пакет.
Если это не TCP,
    сбросить пакет.     (**)
Если это SYN,
    ответить SYN-ACK с cookie.
Если это ACK,
    если в acknum лежит не cookie,
        сбросить пакет.
    Занести в таблицу адрес с N оставшихся проверок.    (*)
    Ответить RST.   (**)
В остальных случаях сбросить пакет.

Mid (*) Qodobbada aad u baahan tahay inaad ku maareyso xaaladda nidaamka ayaa lagu calaamadeeyay - marxaladda ugu horreysa waxaad samayn kartaa iyaga la'aanteed adigoo si fudud u hirgelinaya is-gacan-qaad TCP oo leh jiilka cookie-ka SYN sida seqnum.

Goobta (**), inta aanaan haysan miis, waxaan ka boodi doonaa xirmada.

Hirgelinta gacan-qaadka TCP

Baarista xirmada iyo xaqiijinta koodka

Waxaan u baahan doonaa qaab-dhismeedka madaxa shabakadda: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.hiyo TCP (uapi/linux/tcp.h). Ma aan awoodin in aan ku xidho tan dambe khaladaad la xidhiidha atomic64_t, Waxaan ku khasbanaaday in aan koobiyeeyo qeexitaannada lagama maarmaanka ah koodka.

Dhammaan hawlaha lagu muujiyey C si loo akhriyi karo waa in lagu dhejiyaa barta wicitaanka, maadaama xaqiijiyaha eBPF ee kernelku uu mamnuucayo dib u noqoshada, taas oo ah, xaqiiqda, wareegyada iyo wicitaannada shaqada.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() wuxuu baabi'iyaa daabacaadda dhismaha siideynta.

Barnaamijku waa gudbiyaha hawlaha. Mid kastaa wuxuu helayaa baakidh kaas oo madaxa heerka u dhigma lagu iftiimiyay, tusaale ahaan, process_ether() filaysa in la buuxiyo ether. Iyada oo ku saleysan natiijooyinka falanqaynta goobta, shaqadu waxay u gudbi kartaa xirmada heer sare. Natiijada shaqadu waa ficilka XDP. Hadda, SYN iyo ACK maamulayaasha waxay dhaafaan dhammaan xirmooyinka.

struct Packet {
    struct xdp_md* ctx;

    struct ethhdr* ether;
    struct iphdr* ip;
    struct tcphdr* tcp;
};

INTERNAL int process_tcp_syn(struct Packet* packet) { return XDP_PASS; }
INTERNAL int process_tcp_ack(struct Packet* packet) { return XDP_PASS; }
INTERNAL int process_tcp(struct Packet* packet) { ... }
INTERNAL int process_ip(struct Packet* packet) { ... }

INTERNAL int
process_ether(struct Packet* packet) {
    struct ethhdr* ether = packet->ether;

    LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));

    if (ether->h_proto != bpf_ntohs(ETH_P_IP)) {
        return XDP_PASS;
    }

    // B
    struct iphdr* ip = (struct iphdr*)(ether + 1);
    if ((void*)(ip + 1) > (void*)packet->ctx->data_end) {
        return XDP_DROP; /* malformed packet */
    }

    packet->ip = ip;
    return process_ip(packet);
}

SEC("prog")
int xdp_main(struct xdp_md* ctx) {
    struct Packet packet;
    packet.ctx = ctx;

    // A
    struct ethhdr* ether = (struct ethhdr*)(void*)ctx->data;
    if ((void*)(ether + 1) > (void*)ctx->data_end) {
        return XDP_PASS;
    }

    packet.ether = ether;
    return process_ether(&packet);
}

Waxaan ku soo jeedinayaa dareenkaaga jeegaga calaamadeysan A iyo B. Haddii aad faallo ka bixiso A, barnaamijku wuu dhisi doonaa, laakiin waxaa jiri doona cilad xaqiijin ah marka la soo shubayo:

Verifier analysis:

<...>
11: (7b) *(u64 *)(r10 -48) = r1
12: (71) r3 = *(u8 *)(r7 +13)
invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0)
R7 offset is outside of the packet
processed 11 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

Error fetching program/map!

Xadhiga muhiimka ah invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Waxaa jira wadooyin fulineed marka byte-ka saddex iyo tobnaad ee bilawga kaydinta uu ka baxsan yahay xirmada. Way adag tahay in liiska laga fahmo xariiqa aanu ka hadlayno, laakiin waxa jira nambar tilmaameed (12) iyo qalab kala-fure oo muujinaya xadhkaha koodhka isha:

llvm-objdump -S xdp_filter.o | less

Xaaladdan oo kale waxay tilmaamaysaa xariiqda

LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));

taas oo caddaynaysa in dhibaatadu tahay ether. Had iyo jeer sidan ayay ahaan lahayd.

U jawaab SYN

Hadafka marxaladan waa in la soo saaro baakidh SYNACK sax ah oo go'an seqnum, kaas oo mustaqbalka lagu bedeli doono buskudka SYN. Dhammaan isbeddeladu waxay ku dhacaan gudaha process_tcp_syn() iyo deegaanada ku xeeran.

Xaqiijinta xirmada

Si la yaab leh, halkan waa xariiqda ugu cajiibsan, ama halkii, faallooyinkeeda:

/* Required to verify checksum calculation */
const void* data_end = (const void*)ctx->data_end;

Marka la qorayo nooca koowaad ee koodka, 5.1 kernel ayaa loo adeegsaday, xaqiijinta kaas oo uu jiray farqi u dhexeeya data_end и (const void*)ctx->data_end. Waqtiga qorista, kernel 5.3.1 ma aysan qabin dhibaatadan. Waxaa suurtogal ah in isku-dubariduhu uu u galayay doorsoome maxalli ah oo ka duwan goobta. Akhlaaqda sheekada: fududaynta koodka waxay ku caawin kartaa marka buul badan jiro.

Ku xiga waa hubinta dhererka joogtada ah ee sharafta xaqiijiyaha; O MAX_CSUM_BYTES hoose.

const u32 ip_len = ip->ihl * 4;
if ((void*)ip + ip_len > data_end) {
    return XDP_DROP; /* malformed packet */
}
if (ip_len > MAX_CSUM_BYTES) {
    return XDP_ABORTED; /* implementation limitation */
}

const u32 tcp_len = tcp->doff * 4;
if ((void*)tcp + tcp_len > (void*)ctx->data_end) {
    return XDP_DROP; /* malformed packet */
}
if (tcp_len > MAX_CSUM_BYTES) {
    return XDP_ABORTED; /* implementation limitation */
}

Furidda xirmada

Waanu buuxinay seqnum и acknum, deji ACK (SYN waa la dajiyay):

const u32 cookie = 42;
tcp->ack_seq = bpf_htonl(bpf_ntohl(tcp->seq) + 1);
tcp->seq = bpf_htonl(cookie);
tcp->ack = 1;

Beddelka dekedaha TCP, ciwaanka IP-ga iyo ciwaanka MAC Maktabadda caadiga ah lagama heli karo barnaamijka XDP, sidaas darteed memcpy() - Macro qarinaya waxyaalaha Clang.

const u16 temp_port = tcp->source;
tcp->source = tcp->dest;
tcp->dest = temp_port;

const u32 temp_ip = ip->saddr;
ip->saddr = ip->daddr;
ip->daddr = temp_ip;

struct ethhdr temp_ether = *ether;
memcpy(ether->h_dest, temp_ether.h_source, ETH_ALEN);
memcpy(ether->h_source, temp_ether.h_dest, ETH_ALEN);

Dib u xisaabinta jeegaggu

IPV4 iyo TCP checksums waxay u baahan yihiin in lagu daro dhammaan ereyada 16-bit ee madaxyada, cabbirka madaxyada ayaa lagu qoraa iyaga, taas oo ah, aan la garanayn wakhtiga la ururiyay. Tani waa dhibaato sababtoo ah xaqiijiyuhu kama boodi doono wareegga caadiga ah doorsoomiyaha xadka. Laakiin cabbirka madaxyada ayaa xaddidan: ilaa 64 bytes midkiiba. Waxaad samayn kartaa wareeg leh tiro go'an oo ku celcelin ah, kaas oo dhammaan kara goor hore.

Waxaan ogsoonahay inay jirto RFC 1624 ku saabsan sida qayb ahaan dib loogu xisaabiyo xisaabinta jeegga haddii kaliya erayada go'an ee xirmooyinka la beddelo. Si kastaba ha ahaatee, habkani maaha mid caalami ah, hirgelintuna way adkaan doontaa in la sii wado.

Shaqada xisaabinta Checksum:

#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;
}

Inkastoo size lagu xaqiijiyay lambarka wicitaanka, xaalada ka bixitaanka labaad waa lagama maarmaan si xaqiijiyaha u caddeeyo dhamaystirka wareegga.

Erayada 32-bit, nooc ka fudud ayaa la hirgeliyay:

INTERNAL u32
sum16_32(u32 v) {
    return (v >> 16) + (v & 0xffff);
}

Dhab ahaantii dib u xisaabinta jeegaga iyo dib u soo celinta xirmada:

ip->check = 0;
ip->check = carry(sum16(ip, ip_len, data_end));

u32 tcp_csum = 0;
tcp_csum += sum16_32(ip->saddr);
tcp_csum += sum16_32(ip->daddr);
tcp_csum += 0x0600;
tcp_csum += tcp_len << 8;
tcp->check = 0;
tcp_csum += sum16(tcp, tcp_len, data_end);
tcp->check = carry(tcp_csum);

return XDP_TX;

function carry() waxa uu jeegag ka sameeyaa wadarta 32-bit ee ereyada 16-bit, sida uu qabo RFC 791.

Xaqiijinta gacan qaadka TCP

Shaandheeyaha ayaa si sax ah u abuura xidhiidh netcat, oo maqan ACK-ga ugu dambeeya, kaas oo Linux ay kaga jawaabtay xirmo RST ah, maadaama xirmada shabakadu aysan helin SYN - waxaa loo beddelay SYNACK oo dib loo soo celiyay - iyo aragtida OS, baakidh aan la xiriirin furitaanka isku xirka.

$ sudo ip netns exec xdp-test   nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer

Waa muhiim in lagu hubiyo codsiyada buuxa oo aad fiirsato tcpdump on xdp-remote sababtoo ah, tusaale ahaan, hping3 kama jawaabo jeegaga khaldan.

Marka loo eego dhinaca XDP, xaqiijinta lafteedu waa mid aan waxtar lahayn. Algorithm-ka xisaabinta ayaa ah mid hore oo ay u badan tahay inay u nugushahay weeraryahan casri ah. Kernel-ka Linux, tusaale ahaan, waxa uu isticmaalaa cryptographic SipHash, laakiin hirgelintiisa XDP ayaa si cad uga baxsan xadka qodobkan.

Loo soo bandhigay TODOs cusub oo la xiriira isgaarsiinta dibadda:

  • Barnaamijka XDP ma kaydin karo cookie_seed (qaybta qarsoodiga ah ee milixda) ee doorsoome caalami ah, waxaad u baahan tahay kaydinta kernel, kaas oo qiimihiisu si joogto ah looga cusbooneysiin doono koronto-dhaliye la isku halleyn karo.

  • Haddii buskudka SYN uu ku habboon yahay xirmada ACK, uma baahnid inaad farriin daabacdo, laakiin xusuusnow IP-ga macmiilka la xaqiijiyay si aad u sii waddo gudbinta baakadaha.

Xaqiijinta macmiilka ee sharciga ah:

$ sudoip netns exec xdp-test   nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer

Diiwaanku wuxuu muujinayaa in jeeggu gudbay (flags=0x2 - Tani waa SYN, flags=0x10 waa ACK):

Ether(proto=0x800)
  IP(src=0x20e6e11a dst=0x20e6e11e proto=6)
    TCP(sport=50836 dport=6666 flags=0x2)
Ether(proto=0x800)
  IP(src=0xfe2cb11a dst=0xfe2cb11e proto=6)
    TCP(sport=50836 dport=6666 flags=0x10)
      cookie matches for client 20200c0

In kasta oo aysan jirin liis IP-yada la xaqiijiyay, ma jiri doono wax ilaalin ah oo ka imanaya daadka SYN laftiisa, laakiin halkan waa falcelinta daadka ACK ee uu bilaabay amarkan soo socda:

sudo ip netns exec xdp-test   hping3 --flood -A -s 1111 -p 2222 192.0.2.1

Gelida galitaanka:

Ether(proto=0x800)
  IP(src=0x15bd11a dst=0x15bd11e proto=6)
    TCP(sport=3236 dport=2222 flags=0x10)
      cookie mismatch

gunaanad

Mararka qaarkood eBPF guud ahaan iyo gaar ahaan XDP waxa loo soo bandhigaa in ka badan sidii qalab maamule horumarsan marka loo eego madal horumarineed. Runtii, XDP waa aalad lagu farageliyo habaynta baakadaha kernel-ku, ee maaha beddelka kaydka kernel-ka, sida DPDK iyo xulashooyinka kale ee kernel-ka. Dhanka kale, XDP waxay kuu ogolaaneysaa inaad fuliso caqli-gal aad u adag, taas oo, sidoo kale, ay fududahay in la cusbooneysiiyo iyada oo aan la joojin habka taraafigga. Xaqiijiye ma abuuro dhibaatooyin waaweyn; shakhsi ahaan, uma diidi doono tan qaybo ka mid ah koodka goobta isticmaalaha.

Qaybta labaad, haddii mawduucu xiiso leeyahay, waxaanu dhamaystiri doonaa shaxda macaamiisha la xaqiijiyay iyo kala-goynta, waxaanu hirgelin doonaa xisaabiyeyaasha oo aan qori doonaa utility spacespace si loo maareeyo shaandhada.

Tixraacyada:

Source: www.habr.com

Add a comment