Isu tinonyora dziviriro kubva kuDDoS kurwiswa paXDP. Nuclear chikamu

eXpress Data Path (XDP) tekinoroji inobvumira kugadzika kugadziridzwa kwetraffic paLinux interfaces mapaketi asati apinda mukernel network stack. Kushandiswa kweXDP - dziviriro kubva kuDDoS kurwiswa (CloudFlare), mafirita akaomarara, muunganidzwa wenhamba (Netflix). Zvirongwa zveXDP zvinoitwa neiyo eBPF chaiyo muchina, uye nekudaro vane zvirambidzo pane ese ari maviri kodhi uye anowanikwa kernel mabasa, zvichienderana nerudzi rwesefa.

Chinyorwa chakagadzirirwa kugadzirisa kukanganisa kwezvinhu zvakawanda paXDP. Chekutanga, ivo vanopa yakagadzirira-yakagadzirwa kodhi iyo inokurumidza kupfuura maficha eXDP: yakagadzirirwa kuongororwa kana yakapusa kukonzeresa matambudziko. Paunoyedza kunyora yako kodhi kubva kutanga gare gare, hapana kunzwisisa kwezvekuita nezvikanganiso zvakajairwa. Kechipiri, haifukidze nzira dzekuyedza XDP munharaunda isina VM uye Hardware, zvisinei nekuti ivo vane mhango dzavo. Iwo mameseji akaitirwa vanogadzira mapurogiramu vanoziva network uye Linux vanofarira XDP uye eBPF.

Muchikamu chino, isu tichanzwisisa zvakadzama kuti XDP sefa yakaunganidzwa sei uye maitiro ekuiyedza, tobva tanyora yakapusa vhezheni yeinozivikanwa SYN makuki michina padanho rekugadzirisa pakiti. Kusvikira tagadzira "white list"
vatengi vakasimbiswa, chengeta zviverengero uye maneja iyo sefa - matanda akakwana.

Tichanyora muC - iyi haisi fashoni, asi inoshanda. Yese kodhi inowanikwa paGitHub pane chinongedzo kumagumo uye yakakamurwa kuita maitirwo zvinoenderana nematanho anotsanangurwa muchinyorwa.

Zvinonzwisisika. Mukufamba kwechinyorwa, mini-mhinduro yekudzinga DDoS kurwiswa ichagadzirwa, nekuti iri ibasa rechokwadi reXDP nenzvimbo yangu. Nekudaro, chinangwa chikuru ndechekunzwisisa tekinoroji, iyi haisi nhungamiro yekugadzira kuchengetedzwa kwakagadzirirwa. Iyo kodhi yedzidziso haina kugadziridzwa uye inosiya mamwe nuances.

Mhedziso pfupi yeXDP

Ini ndichataura chete mapoinzi akakosha kuti ndisaite kopi zvinyorwa uye zvinyorwa zviripo.

Saka, iyo sefa kodhi inoiswa mu kernel. Sefa inopfuudzwa mapeketi anouya. Nekuda kweizvozvo, iyo sefa inofanirwa kuita sarudzo: kupfuudza pakiti kune kernel (XDP_PASS), drop packet (XDP_DROP) kana kutumira zvakare (XDP_TX) Iyo sefa inogona kushandura package, izvi ndezvechokwadi kune XDP_TX. Unogonawo kukanganisa purogiramu (XDP_ABORTED) uye udonhedze pasuru, asi izvi zvakafanana assert(0) - kuti debugging.

Iyo eBPF (yakawedzerwa Berkley Packet Filter) muchina chaiwo wakaitwa nyore nemaune kuitira kuti kernel itarise kuti kodhi haina loop uye haina kukuvadza ndangariro dzevamwe vanhu. Cumulative zvirambidzo uye cheki:

  • Loops (kusvetuka kumashure) inorambidzwa.
  • Iko kune stack yedata, asi hapana mabasa (ese C mabasa anofanirwa kuiswa mukati).
  • Kupinda mundangariro kunze kwestack uye packet buffer kunorambidzwa.
  • Ukuru hwekodhi hushoma, asi mukuita izvi hazvina kunyanya kukosha.
  • Chete yakakosha kernel mabasa (eBPF vabatsiri) inotenderwa.

Kugadzira uye kuisa sefa inoita seizvi:

  1. source code (eg. kernel.c) anounganidza kupikisa (kernel.o) yeBPF chaiyo muchina wekuvaka. Kubva muna Gumiguru 2019, kugadzirira kuBPF kunotsigirwa naClang uye yakavimbiswa muGCC 10.1.
  2. Kana mune iyi kodhi yechinhu pane mafoni kune zvimiro zve kernel (semuenzaniso, kumatafura uye zviverengero), pane maID avo pane zero, ndiko kuti, kodhi yakadaro haigone kuitwa. Usati warodha mu kernel, mazero aya anofanirwa kutsiviwa nema ID ezvimwe zvinhu zvakagadzirwa kuburikidza ne kernel mafoni (link iyo kodhi). Iwe unogona kuita izvi nezvishandiso zvekunze, kana iwe unogona kunyora chirongwa chinozobatanidza uye kurodha chaiyo sefa.
  3. Iyo kernel inosimbisa chirongwa chiri kurodha. Inotarisa kusavapo kwema cycles uye kusabuda kwepakeji uye stack miganhu. Kana iyo verifier isingakwanisi kuratidza kuti code yakarurama, purogiramu inorambwa - munhu anofanira kukwanisa kumufadza.
  4. Mushure mekubudirira kwechokwadi, iyo kernel inounganidza iyo eBPF yekuvakisa chinhu kodhi mune system yekuvaka muchina kodhi (inga-in-nguva).
  5. Iyo purogiramu yakanamatira kune interface uye inotanga kugadzirisa mapaketi.

Sezvo XDP ichimhanya mu kernel, debugging yakavakirwa pakutsvaga matanda uye, kutaura zvazviri, pamapakiti ayo chirongwa chinosefa kana kugadzira. Nekudaro, eBPF inochengeta iyo yakatorwa kodhi yakachengeteka kune sisitimu, saka unogona kuedza neXDP ipapo paLinux yako yemuno.

Kugadzirira Zvakatipoteredza

Gungano

Clang haigone kuburitsa zvakananga chinhu kodhi yeiyo eBPF architecture, saka maitiro acho ane matanho maviri:

  1. Gadzira C kodhi kuLLVM bytecode (clang -emit-llvm).
  2. Shandura bytecode kuita eBPF chinhu kodhi (llc -march=bpf -filetype=obj).

Paunenge uchinyora sefa, akati wandei mafaera ane ebetsero mabasa uye macros anouya anobatsira kubva ku kernel bvunzo. Zvakakosha kuti vaenderane nekernel version (KVER) Dhaunirodha ku 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 yeArch 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 ine nzira inoenda kune kernel misoro, ARCH - system architecture. Nzira uye zvishandiso zvinogona kusiyana zvishoma pakati pekugovera.

Musiyano muenzaniso weDebian 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 sanganisira dhairekitori rine anobatsira misoro uye akati wandei madhairekitori ane kernel misoro. Symbol __KERNEL__ zvinoreva kuti UAPI (userspace API) misoro inotsanangurwa kernel kodhi, sezvo sefa ichiitwa mukernel.

Stack dziviriro inogona kuremara (-fno-stack-protector) nekuti iyo eBPF kodhi inoongorora inotarisisa kuti haina kubuda muganho. Iwe unofanirwa kukurumidza kugonesa optimizations, nekuti saizi yeBPF bytecode ishoma.

Ngatitangei nesefa inopfuudza mapaketi ese uye hapana chaanoita:

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

chikwata make inounganidza xdp_filter.o. Ndekupi kwaungaiedza iko zvino?

test bhenji

Iyo inomira inofanirwa kusanganisira maviri mainterfaces: paachava nesefa uye kubva papi mapaketi achatumirwa. Izvi zvinofanirwa kunge zvakazara Linux zvishandiso zvine maIPs avo kuitira kutarisa kuti maapplication anoshanda sei nesefa yedu.

Zvishandiso zvakaita seveth (virtual Ethernet) zvakatikodzera isu: iwo mapeji echokwadi network network "yakabatana" zvakananga kune mumwe nemumwe. Unogona kuzvigadzira seizvi (muchikamu chino, mirairo yese ip kuitwa kubva root):

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

zviri xdp-remote и xdp-local - mazita emidziyo. On xdp-local (192.0.2.1/24) sefa ichabatanidzwa, ne xdp-remote (192.0.2.2/24) traffic inouya ichatumirwa. Nekudaro, pane dambudziko: iyo inopindirana iri pamushini mumwe chete, uye Linux haitumire traffic kune imwe yavo kuburikidza neimwe. Iwe unogona kuzvigadzirisa nemitemo inonyengera iptables, asi ivo vanozofanira kushandura mapakeji, izvo zvisingaite kana debugging. Zviri nani kushandisa network namespaces (network namespaces, mamwe mambure).

Iyo network namespace ine seti yenzvimbo, matafura ekufambisa, uye NetFilter mitemo yakaparadzaniswa kubva kune zvakafanana zvinhu mune mamwe mambure. Maitiro ega ega anomhanya mune imwe nzvimbo yezita, uye chete zvinhu zvemambure aya zvinowanikwa kwairi. Nekusagadzikana, iyo sisitimu ine imwechete network namespace yezvinhu zvese, saka unogona kushanda paLinux uye usingazive nezve mambure.

Ngatigadzire nzvimbo itsva yezita xdp-test uye tamira ikoko xdp-remote.

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

Ipapo process inopinda mukati xdp-test, handizo "kuona" xdp-local (icharamba iri mumambure nekukasira) uye kana kutumira pakiti ku192.0.2.1 ichapfuura nayo xdp-remote, nokuti ndiyo chete inoshandiswa pa 192.0.2.0/24 inowanikwa kune iyi nzira. Izvi zvinoshandawo kumashure.

Kana uchifamba pakati pemambure, iyo interface inodzika uye inorasikirwa nekero. Kuti umise interface mumambure, unofanirwa kumhanya ip ... mune ino yekuraira namespace 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

Sezvaunogona kuona, izvi hazvina kusiyana nekugadzirisa xdp-local munzvimbo yezita rekutanga:

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

Kana iwe uchimhanya tcpdump -tnevi xdp-local, unogona kuona kuti mapaketi anotumirwa kubva xdp-test, zvinounzwa kune ino interface:

ip netns exec xdp-test   ping 192.0.2.1

Zviri nyore kumhanyisa shell mukati xdp-test. Iyo repository ine script inoita otomatiki kushanda nechimire, semuenzaniso, unogona kuseta chigadziko nemurairo. sudo ./stand up woibvisa sudo ./stand down.

kutsvaga

Iyo sefa inonamirwa kune mudziyo seizvi:

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

Key -force inodiwa kubatanidza chirongwa chitsva kana imwe yatobatanidzwa. "Hapana nhau inhau dzakanaka" hazvisi zvekuraira uku, zvinobuda zvine simba zvakadaro. ratidza verbose sarudzo, asi nayo mushumo webasa rekodhi verifier ine assembler rondedzero inooneka:

Verifier analysis:

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

Bvisa purogiramu kubva kune interface:

ip link set dev xdp-local xdp off

Mune script, iyi ndiyo mirairo sudo ./stand attach и sudo ./stand detach.

Nekusunga sefa, unogona kuve nechokwadi kuti ping inoramba ichishanda, asi purogiramu inoshanda here? Ngatiwedzerei ma logos. Function bpf_trace_printk() zvakafanana ne printf(), asi zvinongotsigira zvipokana zvinosvika zvitatu kunze kwepatani, uye runyoro rushoma rwevanotsanangura. Macro bpf_printk() inorerutsa kufona.

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

Izvo zvinobuda zvinoenda kune kernel trace chiteshi, inoda kugoneswa:

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

Ona kuyerera kwemeseji:

cat /sys/kernel/debug/tracing/trace_pipe

Zvikwata zviviri izvi zvinofona sudo ./stand log.

Ping inofanirwa kuburitsa mameseji akadai mairi:

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

Kana iwe ukatarisa zvakanyanya pakubuda kweiyo verifier, unogona kuona zvinoshamisa kuverenga:

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
<...>

Icho chokwadi ndechekuti mapurogiramu eBPF haana chikamu chedata, saka nzira chete yekukodha iyo fomati tambo ndiyo nharo dzekukurumidza dzemirairo yeVM:

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

Nechikonzero ichi, debug inobuda inovhara zvakanyanya iyo inoguma kodhi.

Kutumira XDP Packets

Ngatichinje sefa: rega itumire ese anouya mapaketi kumashure. Izvi hazvina kururama kubva pakuona kwetiweki, sezvo zvingave zvakakosha kuchinja kero mumusoro, asi ikozvino basa rinokosha rinokosha.

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

Kutanga tcpdump pamusoro xdp-remote. Inofanira kuratidza yakafanana inobuda uye inouya ICMP Echo Chikumbiro uye kumira kuratidza ICMP Echo Reply. Asi hazviratidzi. Inoshanda XDP_TX muchirongwa che xdp-local zvinodiwakubatanidza interface xdp-remote purogiramu yakagoverwawo, kunyange yakanga isina chinhu, uye yakasimudzwa.

Ndakaziva sei?

Kutsvaga nzira yepakeji mu kernel iyo perf zviitiko meshini inobvumira, nenzira, kushandisa imwechete chaiyo muchina, kureva, eBPF inoshandiswa disassembly neBPF.

Unofanira kuita zvakanaka kubva pane zvakaipa, nekuti hapana chimwe chingaitwa nazvo.

$ 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])
                                     <...>

Chii chinonzi code 6?

$ errno 6
ENXIO 6 No such device or address

shanda veth_xdp_flush_bq() inowana kukanganisa kodhi kubva veth_xdp_xmit(), pakutsvaga ne ENXIO uye tsvaga mhinduro.

Dzosera iyo shoma sefa (XDP_PASS) mufaira xdp_dummy.c, wedzera kune Makefile, sunga ku xdp-remote:

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

Iye zvino tcpdump inoratidza zvinotarisirwa:

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

Kana chete ARP inoratidzwa pachinzvimbo, unofanirwa kubvisa mafirita (izvi zvinogadzira sudo ./stand detach), regai ping, wobva waisa mafirita woedza zvakare. Dambudziko nderekuti sefa XDP_TX inobata ARP zvakare, uye kana iyo stack
mazita enzvimbo xdp-test akakwanisa "kukanganwa" kero yeMAC 192.0.2.1, haazokwanisi kugadzirisa iyi IP.

Kugadzirwa kwedambudziko

Ngatienderei kune iro rataurwa basa: kunyora SYN cookie mechanism paXDP.

Kusvika ikozvino, mafashama eSYN anoramba ari akakurumbira DDoS kurwiswa, iwo musimboti waro ndewekutevera. Kana kubatana kwasimbiswa (TCP handshake), sevha inogamuchira SYN, inopa zviwanikwa zvekubatanidza mune ramangwana, inopindura neSYNACK packet, uye inomirira ACK. Anorwisa anongotumira maSYN mapaketi kubva kukero dzemanyepo muhuwandu hwezviuru pasekondi kubva kune yega yega mugadziri mune akawanda-zviuru botnet. Sevha inomanikidzwa kugovera zviwanikwa pakarepo pakusvika kwepakiti, asi inoisunungura mushure menguva yakareba, semugumisiro, chiyeuchidzo kana miganhu inopera, kushamwaridzana kutsva hakugamuchirwi, sevhisi haisipo.

Kana iwe ukasagovera zviwanikwa paSYN packet, asi uchingopindura neSYNACK packet, saka server inganzwisisa sei kuti ACK packet yakauya gare gare ndeye SYN packet isina kuchengetwa? Mushure mezvose, anorwisa anogona zvakare kugadzira fake ACKs. Izvo zvakakosha zveSYN cookie ndeye encode mukati seqnum yekubatanidza paramita sehashi yemakero, zviteshi uye kuchinja munyu. Kana iyo ACK yakakwanisa kusvika munyu usati wachinja, unogona kuverenga hashi zvakare uye kuenzanisa nayo acknum. fake acknum munhu anorwisa haakwanisi, sezvo munyu unosanganisira chakavanzika, uye haazove nenguva yekugadzirisa kuburikidza nayo nekuda kwemugero wakaderera.

SYN makuki akaiswa muLinux kernel kwenguva yakareba uye anogona kutogoneswa otomatiki kana maSYN asvika nekukasira uye akawanda.

Chirongwa chekudzidzisa paTCP kubata maoko

TCP inopa kuendeswa kwedata serukova rwemabheti, semuenzaniso, zvikumbiro zveHTTP zvinoparidzirwa pamusoro peTCP. Rukova rwunofambiswa chidimbu nechidimbu mumapaketi. Ese mapaketi eTCP ane mireza inonzwisisika uye 32-bit kutevedzana manhamba:

  • Iko kusanganiswa kwemureza kunotsanangura basa reimwe package. Mureza weSYN unoreva kuti iyi ipakiti yekutanga yeanotumira pane chinongedzo. Iyo ACK mureza inoreva kuti mutumiri agamuchira data rese rekubatanidza kusvika pabyte. acknum. Pakiti inogona kunge iine mireza yakati wandei uye yakatumidzwa zita remusanganiswa wayo, semuenzaniso, SYNACK packet.

  • Kutevedzana nhamba (seqnum) inotsanangura iyo yekubvisa mudhadha rwizi rwekutanga byte inotumirwa mupaketi ino. Semuenzaniso, kana mupakiti yekutanga ine X bytes yedata iyi nhamba yaive N, mune inotevera packet ine data nyowani ichave N+X. Pakutanga kwekubatana, bato rega rega rinosarudza iyi nhamba zvisina tsarukano.

  • Nhamba yekubvuma (acknum) - iyo yakafanana neyo seqnum, asi haitaridzi nhamba yebhaiti yakatumirwa, asi nhamba yebhaiti yekutanga kubva kune anogamuchira, iyo mutumiri haana kuona.

Pakutanga kwekubatana, mapato anofanira kubvumirana seqnum и acknum. Mutengi anotumira SYN pakiti ine yayo seqnum = X. Sevha inopindura neSYNACK packet, iyo inonyora zvayo seqnum = Y uye anofumura acknum = X + 1. Mutengi anopindura SYNACK ne ACK packet, kupi seqnum = X + 1, acknum = Y + 1. Mushure meizvozvo, iyo chaiyo kuendesa data kunotanga.

Kana iyo interlocutor isingabvume kugamuchira kwepakiti, TCP inoitumira zvakare nenguva.

Sei maSYN makuki asingawanzo kushandiswa?

Chekutanga, kana SYNACK kana ACK yakarasika, iwe uchafanirwa kumirira kutumira - iyo yekubatanidza inodzikira. Chechipiri, muSYN packet - uye chete mairi! - akati wandei sarudzo dzinofambiswa dzinokanganisa kuwedzera kushanda kwekubatanidza. Tisingayeuki anouya SYN mapaketi, sevha nekudaro inofuratira idzi sarudzo, mumapaketi anotevera mutengi haachaatumire. TCP inogona kushanda mune iyi kesi, asi zvishoma padanho rekutanga, hutano hwekubatanidza huchaderera.

Panyaya yemapakeji, chirongwa cheXDP chinofanira kuita zvinotevera:

  • pindura SYN neSYNACK nekiki;
  • pindura ACK neRST (kuputsa kubatana);
  • donhedza mamwe mapaketi.

Pseudocode yegorgorithm pamwe chete nepaketi parsing:

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

Poshi (*) iwo mapoinzi aunoda kutonga mamiriro ehurongwa akamakwa - padanho rekutanga, unogona kuita pasina ivo nekungoshandisa TCP kubata maoko nekugadzira SYN cookie se seqnum.

Panzvimbo (**), nepo isu tisina tafura, isu tichasvetuka pakiti.

TCP kubata maoko kuita

Package parsing uye kodhi yekuongorora

Tinoda network header zvimiro: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) uye TCP (uapi/linux/tcp.h) Yekupedzisira handina kukwanisa kuibatanidza nekuda kwezvikanganiso zvine chekuita nayo atomic64_t, ndaifanira kukopa tsanangudzo dzinodiwa mukodhi.

Masevhisi ese anosiyaniswa muC kuti averengeke anofanirwa kuverengerwa panzvimbo yekufona, sezvo eBPF verifier mukernel inorambidza kusvetuka kumashure, kureva kuti, zvishwe uye mafoni ekuita.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() inodzima kudhinda mune yekuburitsa kuvaka.

Iyo purogiramu ndiyo pombi yemabasa. Imwe neimwe inogamuchira pakiti umo musoro weiyo nhanho inofananidzwa inosimbiswa, semuenzaniso, process_ether() kumirira kugutswa ether. Kubva pamigumisiro yekuongorora kwemunda, basa rinogona kuendesa pakiti kune imwe yepamusoro. Mhedzisiro yebasa ndeye XDP chiito. Nepo iyo SYN uye ACK vanobata vanorega ese mapaketi apfuure.

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

Ini ndinoteerera kune macheki akaiswa A uye B. Kana iwe ukataura kunze kweA, chirongwa chinovaka, asi pachave nekukanganisa kwekusimbisa paunenge uchirodha:

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!

Key tambo invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): kune nzira dzekuuraya kana bhaiti yegumi nenhatu kubva pakutanga kwebhafa iri kunze kwepaketi. Zvakaoma kutaura kubva pane rondedzero kuti ndeupi mutsara watiri kutaura nezvawo, asi pane nhamba yekuraira (12) uye disassembler inoratidza mitsara yekodhi kodhi:

llvm-objdump -S xdp_filter.o | less

Muchiitiko ichi, inonongedza kumutsara

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

izvo zvinoburitsa pachena kuti dambudziko riripo ether. Zvaizogara zvakadaro.

Pindura kuSYN

Chinangwa panguva ino ndechekugadzira chaiyo SYNACK pakiti ine yakagadziriswa seqnum, iyo ichatsiviwa neSYN cookie mune ramangwana. Shanduko dzese dzinoitika mukati process_tcp_syn() uye nharaunda.

Kutarisa pasuru

Zvinoshamisa kuti, heino mutsara unoshamisa, kana kuti, chirevo kwairi:

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

Pakunyora vhezheni yekutanga yekodhi, iyo 5.1 kernel yakashandiswa, kune verifier yaive nemusiyano pakati. data_end и (const void*)ctx->data_end. Panguva yekunyora, 5.3.1 kernel yakanga isina dambudziko iri. Zvichida muunganidzi aiwana shanduko yemunharaunda zvakasiyana pane munda. Tsika - padendere rakakura, kurerutsa kodhi kunogona kubatsira.

Kuenderera mberi kwekutarisa kwehurefu kune kubwinya kweverifier; O MAX_CSUM_BYTES pasi.

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 */
}

Package yakapararira

Tinozadza seqnum и acknum, seta ACK (SYN yatogadzirwa):

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

Chinjana TCP ports, IP uye MAC kero. Raibhurari yakajairika haiwanikwe kubva kuchirongwa cheXDP, saka memcpy() - macro inovanza iyo Clang intrinsik.

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

Checksum recalculation

IPv4 uye TCP checksums inoda kuwedzerwa kwemashoko ose e-16-bit mumisoro, uye ukuru hwemisoro yakanyorwa mairi, ndiko kuti, panguva yekubatanidza haizivikanwi. Iri idambudziko nekuti mutsigiri haasvetuke loop yakajairika kusvika muganhu wachinja. Asi saizi yemusoro inogumira: kusvika ku64 bytes imwe neimwe. Iwe unogona kugadzira loop nenhamba yakatarwa yekudzokorora, iyo inogona kupera kare.

Ndinocherechedza kuti iripo RFC 1624 nezve maitiro ekuverengazve cheki muchidimbu kana chete mazwi akagadziriswa emapaketi akachinjwa. Zvisinei, iyo nzira haisi yepasi rose, uye kushandiswa kwaizova kwakaoma kuchengetedza.

Checksum kuverenga basa:

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

Nyangwe size yakatariswa nekodhi yekufona, iyo yechipiri yekubuda mamiriro inodiwa kuitira kuti verifier iratidze kupera kwechiuno.

Kune 32-bit mazwi, shanduro iri nyore inoshandiswa:

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

Chaizvoizvo kuverengerazve macheki uye kutumira iyo pakiti kumashure:

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;

shanda carry() inoita cheki kubva pamakumi matatu-bit ehuwandu hwemashoko gumi nematanhatu, maererano neRFC 32.

TCP handshake cheki

Sefa inonyatso gadzira chinongedzo ne netcat, kusvetuka yekupedzisira ACK, iyo Linux yakapindura neRST packet, sezvo network stack haina kugamuchira SYN - yakashandurwa kuva SYNACK uye yakadzoserwa kumashure - uye kubva pakuona kweOS, pakiti yakasvika yakanga isiri. zvine chekuita nekubatanidza kwakavhurika.

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

Izvo zvakakosha kuti utarise nemaapplication akazara uye tarisa tcpdump pamusoro xdp-remote nokuti, semuenzaniso, hping3 haipindure kune zvisizvo checksums.

Kubva pakuona kweXDP, cheki pachayo idiki. Iyo yekuverenga algorithm ndeyechinyakare uye ingangove iri panjodzi yeanorwisa anorwisa. Iyo Linux kernel, semuenzaniso, inoshandisa iyo cryptographic SipHash, asi kuita kwayo kweXDP kuri pachena kupfuura chiyero chechinyorwa ichi.

Yakaonekwa kune itsva TODOs ine chekuita nekudyidzana kwekunze:

  • XDP chirongwa hachigone kuchengeta cookie_seed (chikamu chakavanzika chemunyu) mune shanduko yepasi rose, iwe unoda kernel chitoro icho kukosha kwacho kuchagadziriswa nguva nenguva kubva kune yakavimbika jenareta.

  • Kana iyo SYN cookie iri muACK packet inoenderana, haufanire kudhinda meseji, asi yeuka IP yemutengi akasimbiswa kuti uwedzere kusvetuka mapaketi kubva mairi.

Kusimbiswa nemutengi ari pamutemo:

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

Matanda akarekodha ndima yecheki (flags=0x2 iri SYN, flags=0x10 ari 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

Chero bedzi pasina rondedzero yeIPs dzakasimbiswa, hapazovi nedziviriro paSYN mafashamo pachayo, asi heino maitiro kune ACK mafashama kwakatangwa nemurairo uyu:

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

Log zvinyorwa:

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

mhedziso

Dzimwe nguva eBPF zvakazara uye XDP kunyanya inounzwa sechishandiso chepamusoro chemutungamiriri pane chikuva chekusimudzira. Chokwadi, XDP chishandiso chekuvhiringidza kernel packet processing, uye kwete imwe nzira kune kernel stack, seDPDK uye dzimwe kernel bypass sarudzo. Kune rimwe divi, XDP inokutendera kuti ushandise pfungwa dzakaoma kunzwisisa, izvo, zvakare, zviri nyore kugadzirisa pasina kumbomira mukugadzirisa traffic. Iyo verifier haigadziri matambudziko makuru, ini pachangu handingarambe zvakadaro kune zvikamu zveuserspace kodhi.

Muchikamu chechipiri, kana musoro wacho uchinakidza, isu tinopedzisa tafura yevatengi vakavimbiswa uye kutyora zvinongedzo, kushandisa zviverengero uye kunyora mushandisi wenzvimbo yekushandisa kubata sefa.

Mareferensi:

Source: www.habr.com

Voeg