Re ngola tšireletso khahlanong le litlhaselo tsa DDoS ho XDP. Karolo ea nyutlelie

Theknoloji ea eXpress Data Path (XDP) e lumella ts'ebetso e sa reroang ea sephethephethe ho li-interface tsa Linux pele lipakete li kena ka har'a kernel network stack. Tšebeliso ea XDP - tšireletso khahlanong le litlhaselo tsa DDoS (CloudFlare), li-filters tse rarahaneng, pokello ea lipalo-palo (Netflix). Mananeo a XDP a etsoa ke mochini o sebetsang oa eBPF, ka hona a na le lithibelo ho khoutu ea bona le mesebetsi e fumanehang ea kernel, ho latela mofuta oa sefahla.

Sengoliloeng se reretsoe ho lokisa mefokolo ea lisebelisoa tse ngata ho XDP. Taba ea pele, ba fana ka khoutu e lokiselitsoeng eo hang-hang e fetang likarolo tsa XDP: e lokiselitsoeng ho netefatsoa kapa e bonolo haholo ho baka mathata. Ha u leka ho ngola khoutu ea hau ho tloha qalong hamorao, ha ho na kutloisiso ea hore na u etse eng ka liphoso tse tloaelehileng. Taba ea bobeli, ha e akaretse mekhoa ea ho leka XDP sebakeng sa heno ntle le VM le hardware, leha ba na le maraba a bona. Sengoloa se reretsoe baetsi ba mananeo ba tloaelaneng le marang-rang le Linux ba ratang XDP le eBPF.

Karolong ena, re tla utloisisa ka botlalo hore na filthara ea XDP e bokelloa joang le hore na e ka e leka joang, ebe re ngola mofuta o bonolo oa mochini o tsebahalang oa li-cookies oa SYN boemong ba ts'ebetso ea pakete. Ho fihlela re theha "lethathamo le lesoeu"
bareki ba netefalitsoeng, boloka li-counters le ho laola sefa - li-log tse lekaneng.

Re tla ngola ka C - sena ha se feshene, empa se sebetsa. Khoutu eohle e fumaneha ho GitHub sehokelong qetellong mme e arotsoe ka boitlamo ho latela mehato e hlalositsoeng sengolong.

Taba ea bohlokoa. Nakong ea sengoloa, ho tla ntlafatsoa tharollo e nyane ea ho leleka litlhaselo tsa DDoS, hobane ona ke mosebetsi oa nnete bakeng sa XDP le sebaka sa heso. Leha ho le joalo, sepheo se seholo ke ho utloisisa theknoloji, sena hase tataiso ea ho theha tšireletso e lokiselitsoeng. Khoutu ea thupelo ha ea ntlafatsoa ebile e siea menahano e meng.

Kakaretso e Khutšoanyane ea XDP

Ke tla bolela lintlha tsa bohlokoa feela e le hore ke se ke ka kopitsa litokomane le lingoliloeng tse teng.

Kahoo, khoutu ea filthara e kenngoa ka har'a kernel. Sesefe se fetisoa lipakete tse kenang. Ka lebaka leo, filthara e tlameha ho etsa qeto: ho fetisetsa pakete ho kernel (XDP_PASS), tlohela pakete (XDP_DROP) kapa e khutlisetse (XDP_TX). Sefahla se ka fetola sephutheloana, sena ke 'nete haholo bakeng sa XDP_TX. U ka boela ua senya lenaneo (XDP_ABORTED) ebe o theola sephutheloana, empa sena se tšoana assert(0) - bakeng sa ho lokisa liphoso.

EBPF (e atolositsoeng ea Berkley Packet Filter) mochini o bonolo o entsoe ka boomo e le hore kernel e ka lekola hore na khoutu ha e theohe le hore ha e senye mohopolo oa batho ba bang. Lithibelo tse akaretsang le licheke:

  • Loops (ho qhomela morao) e thibetsoe.
  • Ho na le stack bakeng sa data, empa ha ho na mesebetsi (mesebetsi eohle ea C e tlameha ho kenngoa).
  • Ho fihlella memori ka ntle ho stack le buffer ea pakete ha ho lumelloe.
  • Boholo ba khoutu bo lekanyelitsoe, empa ts'ebetsong sena ha se bohlokoa haholo.
  • Ke feela mesebetsi e khethehileng ea kernel (bathusi ba eBPF) e lumelletsoeng.

Ho theha le ho kenya filthara ho shebahala tjena:

  1. khoutu ea mohloli (mohlala. kernel.c) bokella ho hanyetsa (kernel.o) bakeng sa meralo ea mochini ea eBPF e sebetsang. Ho tloha ka Mphalane 2019, ho bokella ho eBPF ho tšehetsoa ke Clang mme ho tšepisitsoe ho GCC 10.1.
  2. Haeba ka khoutu ea ntho ena ho na le li-call ho mehaho ea kernel (mohlala, ho litafole le li-counters), ho e-na le li-ID tsa bona ho na le zero, ke hore, khoutu e joalo e ke ke ea etsoa. Pele o kenya kernel, li-zero tsena li tlameha ho nkeloa sebaka ke li-ID tsa lintho tse ikhethileng tse entsoeng ka mehala ea kernel (hokela khoutu). U ka etsa sena ka lits'ebeletso tsa kantle, kapa u ka ngola lenaneo le tla hokahanya le ho kenya filthara e itseng.
  3. Kernel e netefatsa hore lenaneo le laetsoe. E hlahloba ho ba sieo ha lipotoloho le ho se tsoe ha sephutheloana le meeli ea stack. Haeba verifier e ke ke ea paka hore khoutu e nepahetse, lenaneo le haneloa - motho o tlameha ho khona ho mo khahlisa.
  4. Kamora ho netefatsoa ka katleho, kernel e bokella khoutu ea ntho ea meralo ea eBPF ka khoutu ea mochini oa meralo (ka nako feela).
  5. Lenaneo le khomaretse sebopeho mme le qala ho sebetsa lipakete.

Kaha XDP e sebetsa ka har'a kernel, debugging e etsoa ka li-trace logs, 'me, ha e le hantle, ka lipakete tseo lenaneo le li hlahisang kapa le li hlahisang. Leha ho le joalo, eBPF e boloka khoutu e jarollotsoeng e bolokehile bakeng sa sistimi, kahoo o ka leka XDP hantle ho Linux ea hau ea lehae.

Ho Lokisetsa Tikoloho

Kopano

Clang ha e khone ho fana ka khoutu ea ntho ka kotloloho bakeng sa meralo ea eBPF, ka hona ts'ebetso e na le mehato e 'meli:

  1. Kopanya khoutu ea C ho LLVM bytecode (clang -emit-llvm).
  2. Fetolela bytecode ho khoutu ea ntho ea eBPF (llc -march=bpf -filetype=obj).

Ha u ngola filthara, lifaele tse 'maloa tse nang le mesebetsi e thusang le li-macros li tla sebetsa hantle ho tsoa litekong tsa kernel. Ho bohlokoa hore li lumellane le mofuta oa kernel (KVER). Li jarolle ho 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 bakeng sa 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 e na le tsela ea lihlooho tsa kernel, ARCH - meralo ea tsamaiso. Litsela le lisebelisoa li ka fapana hanyane lipakeng tsa lipehelo.

Mohlala oa phapang bakeng sa 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 kenyelletsa bukana e nang le lihlooho tse thusang le li-directory tse 'maloa tse nang le lihlooho tsa kernel. Letšoao __KERNEL__ ho bolela hore lihlooho tsa UAPI (userspace API) li hlalosoa bakeng sa khoutu ea kernel, kaha filthara e etsoa ka har'a kernel.

Tšireletso ea stack e ka koaloa (-fno-stack-protector) hobane sehlahlobi sa khoutu ea eBPF se ntse se hlahloba hore na ha ho na meeli ea stack. O lokela ho nolofalletsa optimizations hang hang, hobane boholo ba eBPF bytecode bo na le moeli.

Ha re qale ka sefe e fetisang lipakete tsohle mme e sa etse letho:

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

sehlopha make bokella xdp_filter.o. U ka e leka hokae hona joale?

teko ea teko

Boemo bo lokela ho kenyelletsa li-interfaces tse peli: moo ho tla ba le filthara le hore na lipakete li tla romelloa ho tsoa hokae. Tsena e tlameha ho ba lisebelisoa tse felletseng tsa Linux tse nang le li-IP tsa tsona ho bona hore na lits'ebetso tse tloaelehileng li sebetsa joang le sefahla sa rona.

Lisebelisoa tse kang veth (virtual Ethernet) li re loketse: ke marang-rang a marang-rang a "hokahaneng" ka ho toba ho e mong. U ka li etsa ka tsela ena (karolong ena, litaelo tsohle ip etsoa ho tloha root):

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

ke xdp-remote и xdp-local — mabitso a lisebelisoa. E butsoe xdp-local (192.0.2.1/24) sefa se tla kopanngoa, ka xdp-remote (192.0.2.2/24) sephethephethe se tlang se tla romelloa. Leha ho le joalo, ho na le bothata: li-interfaces li mochine o le mong, 'me Linux e ke ke ea romela sephethephethe ho e' ngoe ea tsona ka e 'ngoe. U ka e rarolla ka melao e qhekellang iptables, empa ba tla tlameha ho fetola liphutheloana, e leng ntho e seng bonolo ha ba lokisa liphoso. Ho molemo ho sebelisa libaka tsa mabitso a marang-rang (libaka tsa mabitso a marang-rang, marang-rang a eketsehileng).

Sebaka sa mabitso sa marang-rang se na le sete ea li-interfaces, litafole tsa routing, le melao ea NetFilter e arohaneng le lintho tse tšoanang ho tse ling tsa marang-rang. Ts'ebetso e 'ngoe le e' ngoe e sebetsa sebakeng se seng sa mabitso, 'me ke feela lintho tsa marang-rang ana tse fumanehang ho eona. Ka ho sa feleng, tsamaiso e na le sebaka se le seng sa mabitso sa marang-rang bakeng sa lintho tsohle, kahoo o ka sebetsa Linux mme o sa tsebe ka marang-rang.

Ha re theheng sebaka se secha sa mabitso xdp-test le ho fallela teng xdp-remote.

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

Joale ts'ebetso e ntse e tsoela pele xdp-test, e ke ke ea "bona" xdp-local (e tla lula e le marang-rang ka ho sa feleng) 'me ha u romela pakete ho 192.0.2.1 e tla e fetisa. xdp-remote, hobane ke eona feela sebopeho sa 192.0.2.0/24 se fumanehang ts'ebetsong ena. Sena se boetse se sebetsa ka morao.

Ha u tsamaea pakeng tsa marang-rang, sebopeho se theoha 'me se lahleheloa ke aterese. Ho theha segokanyimmediamentsi sa sebolokigolo ho netns, o hloka ho matha ip ... sebakeng sena sa mabitso sa taelo 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

Joalokaha u ka bona, sena ha se fapane le ho seta xdp-local sebakeng sa kamehla sa mabitso:

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

Haeba matha tcpdump -tnevi xdp-local, u ka bona hore lipakete rometsoe ho tloha xdp-test, li romelloa ho sebopeho sena:

ip netns exec xdp-test   ping 192.0.2.1

Ho bonolo ho kenya khetla xdp-test. Sebaka sa polokelo se na le sengoloa se iketsetsang mosebetsi ka sethala, mohlala, o ka theha sethala ka taelo. sudo ./stand up le ho e tlosa sudo ./stand down.

ho latela

Sesefa se khomaretsoe ho sesebelisoa ka tsela ena:

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

Senotlolo -force e hlokahalang ho hokahanya lenaneo le lecha haeba le leng le se le hoketsoe. "Ha ho litaba tse monate" ha e bue ka taelo ena, tlhahiso e ntse e le ngata. bontsha verbose boikhethelo, empa ka eona tlaleho e mabapi le mosebetsi oa netefatso ea khoutu e nang le lethathamo la batho ba kopanyang e hlaha:

Verifier analysis:

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

Tlosa lenaneo ho tsoa ho interface:

ip link set dev xdp-local xdp off

Ho script, tsena ke litaelo sudo ./stand attach и sudo ./stand detach.

Ka ho tlama filthara, o ka etsa bonnete ba hore ping e tsoela pele ho sebetsa, empa na lenaneo lea sebetsa? Ha re kenye li-logos. Mosebetsi bpf_trace_printk() tšoana le printf(), empa e ts'ehetsa feela likhang tse tharo ntle le paterone, le lenane le lekanyelitsoeng la litlhaloso. Macro bpf_printk() e nolofatsa pitso.

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

Sephetho se ea ho kernel trace channel, e hlokang ho lumelloa:

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

Sheba ho phalla ha molaetsa:

cat /sys/kernel/debug/tracing/trace_pipe

Lihlopha tsena ka bobeli li etsa mohala sudo ./stand log.

Ping joale e lokela ho hlahisa melaetsa e kang ena ho eona:

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

Haeba u sheba ka hloko tlhahiso ea verifier, u ka hlokomela lipalo tse makatsang:

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

Taba ke hore mananeo a eBPF ha a na karolo ea data, kahoo tsela e le 'ngoe feela ea ho kenyelletsa khoele ea sebopeho ke likhang tsa hang-hang tsa litaelo tsa VM:

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

Ka lebaka lena, tlhahiso ea debug e thibela khoutu e hlahisoang haholo.

Ho romella lipakete tsa XDP

Ha re fetoleng sefe: e lumelle hore e khutlisetse lipakete tsohle tse kenang. Sena se fosahetse ho tloha ponong ea marang-rang, kaha ho tla hlokahala ho fetola liaterese lihloohong, empa hona joale mosebetsi ka molao-motheo ke oa bohlokoa.

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

Qala tcpdump mabapi le xdp-remote. E lokela ho bonts'a Kopo ea ICMP Echo e ts'oanang le e tlang mme e khaotse ho bonts'a ICMP Echo Reply. Empa ha e bonahale. E ea sebetsa XDP_TX lenaneong la xdp-local hoa hlokahalaho para interface xdp-remote lenaneo le lona le ile la abeloa, leha le ne le se na letho, ’me le ile la phahamisoa.

Ke tsebile jwang?

Ho latela tsela ea sephutheloana ka har'a kernel Perf events mechanism e lumella, ka tsela, ho sebelisa mochine o tšoanang oa sebele, ke hore, eBPF e sebelisetsoa ho qhaqhoa le eBPF.

U tlameha ho etsa botle ho tsoa bobeng, hobane ha ho letho le leng le ka etsoang ka lona.

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

Code 6 ke eng?

$ errno 6
ENXIO 6 No such device or address

Mosebetsi veth_xdp_flush_bq() e fumana khoutu ea phoso ho tsoa ho veth_xdp_xmit(), moo batla ka ENXIO 'me u fumane tlhaloso.

Khutlisa sefe e fokolang (XDP_PASS) faeleng xdp_dummy.c, eketsa ho Makefile, tlama ho xdp-remote:

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

Hona joale tcpdump e bontša se lebelletsoeng:

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

Haeba ho bonts'itsoe ARP feela, o hloka ho tlosa lits'oants'o (sena se etsa sudo ./stand detach), tlohela ping, ebe o kenya lihloela ebe o leka hape. Bothata ke hore filthara XDP_TX e ama ARP hape, le haeba stack
libaka tsa mabitso xdp-test o khona ho "lebala" aterese ea MAC 192.0.2.1, a ke ke a khona ho rarolla IP ena.

Mokhoa oa bothata

Ha re feteleng pele mosebetsing o boletsoeng: ho ngola mochini oa li-cookie oa SYN ho XDP.

Ho fihlela joale, moroallo oa SYN e ntse e le tlhaselo e tsebahalang ea DDoS, eo moelelo oa eona o latelang. Ha khokahano e thehoa (TCP handshake), seva se amohela SYN, se fana ka lisebelisoa bakeng sa khokahanyo ea nakong e tlang, se arabela ka pakete ea SYNACK, 'me se emetse ACK. Mohlaseli o romella lipakete tsa SYN ho tsoa ho liaterese tsa bohata ka bongata ba likete ka motsotsoana ho tsoa ho moamoheli e mong le e mong ka botnet ea likete tse ngata. Seva e qobelloa ho fana ka lisebelisoa hang-hang ha pakete e fihla, empa e e lokolla ka mor'a nako e telele, ka lebaka leo, mohopolo kapa meeli e felile, likhokahano tse ncha ha li amoheloe, tšebeletso ha e fumanehe.

Haeba u sa fane ka lisebelisoa ka har'a pakete ea SYN, empa u arabela feela ka pakete ea SYNACK, joale seva se ka utloisisa joang hore pakete ea ACK e tlileng hamorao ke ea pakete ea SYN e sa kang ea bolokoa? Ntle le moo, mohlaseli a ka boela a hlahisa li-ACK tsa fake. Moko-taba oa kuku ea SYN ke ho kenya khoutu seqnum li-parameter tsa khokahano joalo ka hash ea liaterese, likou le ho fetola letsoai. Haeba ACK e atlehile ho fihla pele letsoai le fetoha, o ka bala hashe hape mme o bapise le acknum. fake acknum mohlaseli ha a khone, kaha letsoai le kenyelletsa sephiri, 'me a ke ke a ba le nako ea ho e hlophisa ka lebaka la mocha o lekanyelitsoeng.

Li-cookie tsa SYN li kentsoe tšebetsong kernel ea Linux nako e telele mme li ka khona ho nolofalloa ka bohona haeba li-SYN li fihla kapele le ka bongata.

Lenaneo la thuto ho TCP ho ts'oarana ka matsoho

TCP e fana ka phetiso ea data e le molatsoana oa li-byte, mohlala, likopo tsa HTTP li fetisoa ka TCP. Molapo o fetisoa ka likotoana ka lipakete. Lipakete tsohle tsa TCP li na le lifolakha tse utloahalang le linomoro tsa tatellano ea 32-bit:

  • Motsoako oa lifolakha o hlalosa karolo ea sephutheloana se itseng. Folakha ea SYN e bolela hore ena ke sephutheloana sa pele sa motho ea rometseng khokahanyong. Letšoao la ACK le bolela hore motho ea rometseng o fumane boitsebiso bohle ba khokahanyo ho fihlela ka nako e itseng. acknum. Pakete e ka 'na ea e-ba le lifolakha tse' maloa 'me e bitsoa ka ho kopanya ha tsona, mohlala, pakete ea SYNACK.

  • Nomoro ea tatellano (seqnum) e bolela ho fokotseha ha data stream bakeng sa byte ea pele e rometsoeng ka paketeng ena. Ka mohlala, haeba ka har'a pakete ea pele e nang le X byte ea data nomoro ena e ne e le N, paketeng e latelang e nang le data e ncha e tla ba N + X. Qalong ea ho hokahanya, mokete ka mong o khetha nomoro ena ka mokhoa o sa reroang.

  • Nomoro ea kamohelo (acknum) - e tšoanang le ea seqnum, empa ha e khetholle palo ea li-byte tse fetisitsoeng, empa palo ea li-byte tsa pele ho tsoa ho moamoheli, eo moromuoa a sa kang a e bona.

Qalong ea ho hokahanya, lihlopha li tlameha ho lumellana seqnum и acknum. Moreki o romella pakete ea SYN le eona seqnum = X. Seva e araba ka pakete ea SYNACK, moo e ngolang ea eona seqnum = Y le ho pepesa acknum = X + 1. Moreki o araba SYNACK ka pakete ea ACK, moo seqnum = X + 1, acknum = Y + 1. Ka mor'a moo, phetiso ea 'nete ea data e qala.

Haeba interlocutor a sa amohele ho fumana pakete, TCP e romela hape ka nako ea nako.

Hobaneng ha li-cookie tsa SYN li sa sebelisoe kamehla?

Taba ea pele, haeba SYNACK kapa ACK e lahlehile, o tla tlameha ho emela ho romelloa hape - khokahano ea khokahano e ea fokotseha. Taba ea bobeli, ka har'a pakete ea SYN - mme ho eona feela! - ho fetisoa likhetho tse 'maloa tse amang ts'ebetso e tsoelang pele ea khokahano. Ha u hopole lipakete tsa SYN tse kenang, seva ka hona se hlokomoloha likhetho tsena, lipaketeng tse latelang moreki ha a sa tla hlola a li romella. TCP e ka sebetsa tabeng ena, empa bonyane boemong ba pele, boleng ba khokahano bo tla fokotseha.

Mabapi le liphutheloana, lenaneo la XDP le lokela ho etsa tse latelang:

  • araba SYN ka SYNACK ka kuku;
  • araba ACK ka RST (senya khokahano);
  • lahla lipakete tse ling.

Pseudocode ea algorithm hammoho le pakete ea pakete:

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

E 'ngoe (*) lintlha tseo u li hlokang ho laola boemo ba tsamaiso li tšoailoe - sethaleng sa pele, u ka li etsa ntle le tsona ka ho kenya ts'ebetsong ho tšoara letsoho ha TCP ka ho hlahisa cookie ea SYN e le seqnum.

Sebakeng seo (**), ha re se na tafole, re tla tlola pakete.

Ts'ebetso ea ho ts'oarana ka letsoho ea TCP

Pakete ea sephutheloana le netefatso ea khoutu

Re hloka meaho ea lihlooho tsa marang-rang: Ethernet (uapi/linux/if_ether.hIPv4 (uapi/linux/ip.h) le TCP (uapi/linux/tcp.h). Ea ho qetela ha ke khone ho e hokahanya ka lebaka la liphoso tse amanang le eona atomic64_t, ke ile ka tlameha ho kopitsa litlhaloso tse hlokahalang khoutu.

Mesebetsi eohle e khetholloang ho C bakeng sa ho baloa e tlameha ho kenngoa sebakeng sa mohala, kaha verifier ea eBPF e kernel e thibela ho qhomela morao, ke hore, li-loops le mehala ea ts'ebetso.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() e thibela ho hatisa moahong oa tokollo.

Lenaneo ke phaephe ea mesebetsi. E mong le e mong o amohela pakete eo ho eona ho totobalitsoeng hlooho ea boemo bo lumellanang, mohlala, process_ether() e emetse ho tlatsoa ether. Ho itšetlehile ka liphello tsa tlhahlobo ea tšimo, mosebetsi o ka fetisetsa pakete ho ea boemong bo phahameng. Sephetho sa ts'ebetso ke ts'ebetso ea XDP. Ha li-SYN le li-ACK li sebetsana le lipakete tsohle.

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

Ke ela hloko licheke tse tšoailoeng A le B. Haeba u fana ka maikutlo ka A, lenaneo le tla haha, empa ho tla ba le phoso ea ho netefatsa ha u laela:

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!

Khoele ea senotlolo invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): ho na le litsela tsa ho phethahatsa ha byte ea leshome le metso e meraro ho tloha qalong ea buffer e le ka ntle ho pakete. Ho thata ho tseba ho tsoa lethathamong hore na re bua ka mola ofe, empa ho na le nomoro ea litaelo (12) le disassembler e bontšang mela ea khoutu ea mohloli:

llvm-objdump -S xdp_filter.o | less

Tabeng ena, e supa mola

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

e hlakisang hore bothata bo ether. Ho ne ho tla dula ho le jwalo.

Araba ho SYN

Sepheo sa sethaleng sena ke ho hlahisa pakete e nepahetseng ea SYNACK e nang le e tsitsitseng seqnum, e tla nkeloa sebaka ke cookie ea SYN nakong e tlang. Liphetoho tsohle li etsahala ka hare process_tcp_syn() le tikoloho.

Ho hlahloba sephutheloana

Ka mokhoa o makatsang, mona ke mola o tsotehang ka ho fetisisa, kapa ho e-na le hoo, maikutlo ho oona:

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

Ha ho ngoloa mofuta oa pele oa khoutu, ho ile ha sebelisoa 5.1 kernel, bakeng sa verifier eo ho neng ho e-na le phapang pakeng tsa eona. data_end и (const void*)ctx->data_end. Nakong ea ho ngola, 5.3.1 kernel e ne e se na bothata bona. Mohlomong moqapi o ne a fumana phetoho ea lehae ka tsela e fapaneng le tšimo. Boitšoaro - ka sehlaha se seholo, ho nolofatsa khoutu ho ka thusa.

Litlhahlobo tse ling tse tloaelehileng tsa bolelele bakeng sa khanya ea mohatisi; O MAX_CSUM_BYTES ka tlase.

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

Phakete ea sephutheloana

Re tlatsa seqnum и acknum, seta ACK (SYN e se e setiloe):

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

Fetola likou tsa TCP, IP le liaterese tsa MAC. Laeborari e tloaelehileng ha e fumanehe ho tsoa lenaneong la XDP, kahoo memcpy() - macro e patang 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

Li-checksums tsa IPv4 le TCP li hloka ho eketsoa ha mantsoe ohle a 16-bit lihloohong, 'me boholo ba lihlooho bo ngotsoe ho tsona, ke hore, nakong ea ho bokella ha e tsejoe. Sena ke bothata hobane se netefatsang se ke ke sa tlola loop e tloaelehileng ho fihlela moeli o fetoha. Empa boholo ba lihlooho bo lekanyelitsoe: ho fihla ho li-byte tse 64 ka 'ngoe. U ka etsa loop ka palo e tsitsitseng ea ho pheta-pheta, e ka qetellang kapele.

Ke hlokomela hore ho na le RFC 1624 mabapi le mokhoa oa ho bala cheke hape ka mokhoa o sa fellang haeba feela mantsoe a tsitsitseng a lipakete a fetotsoe. Leha ho le joalo, mokhoa ona ha o hohle, 'me ts'ebetsong e ka ba thata ho feta ho e boloka.

Mosebetsi oa ho bala 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;
}

Leha ho le joalo size e hlahlojoa ke khoutu ea mohala, boemo ba bobeli ba ho tsoa boa hlokahala e le hore verifier e ka paka qetello ea loop.

Bakeng sa mantsoe a 32-bit, ho sebelisoa mofuta o bonolo haholoanyane:

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

Ha e le hantle ho bala li-checksums hape le ho khutlisetsa pakete morao:

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;

Mosebetsi carry() e etsa cheke ho tsoa ho 32-bit kakaretso ea mantsoe a 16-bit, ho latela RFC 791.

TCP ho ts'oarana ka letsoho ho hlahloba

Sefepi se theha khokahano le netcat, ho tlōla ACK ea ho qetela, eo Linux e ileng ea arabela ka eona ka pakete ea RST, kaha sephutheloana sa marang-rang ha sea ka sa fumana SYN - se ile sa fetoloa ho SYNACK 'me sa khutlisetsoa morao -' me ho tloha ponong ea OS, pakete e ile ea fihla e neng e se. tse amanang le dikgokelo tse bulehileng.

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

Ho bohlokoa ho hlahloba lits'ebetso tse felletseng le ho ela hloko tcpdump mabapi le xdp-remote hobane, mohlala, hping3 ha e arabele licheleteng tse fosahetseng.

Ho latela pono ea XDP, cheke ka boeona ha e nyane. Algorithm ea lipalo ke ea khale 'me mohlomong e kotsing ea ho hlaseloa ke mohlaseli ea tsoetseng pele. Ka mohlala, Linux kernel, e sebelisa SipHash ea cryptographic, empa ts'ebetsong ea eona bakeng sa XDP e hlakile ka ntle ho sebaka sa sehlooho sena.

E hlahile bakeng sa li-TODO tse ncha tse amanang le tšebelisano ea kantle:

  • Lenaneo la XDP ha le khone ho boloka cookie_seed (karolo ea lekunutu ea letsoai) ka ho feto-fetoha ha lefatše, o hloka lebenkele la kernel leo boleng ba lona bo tla ntlafatsoa nako le nako ho tsoa ho jenereithara e tšepahalang.

  • Haeba kuku ea SYN ka har'a pakete ea ACK e ts'oana, ha ho hlokahale hore u hatise molaetsa, empa hopola IP ea moreki ea netefalitsoeng e le hore u tsoelepele ho tlola lipakete ho eona.

Netefatso ke moreki ea molaong:

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

Li-log li tlalehile ho feta ha cheke (flags=0x2 ke SYN, flags=0x10 ke 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

Hafeela ho se na lethathamo la li-IP tse netefalitsoeng, ho ke ke ha e-ba le tšireletso khahlanong le moroallo oa SYN ka boeona, empa mona ke karabelo ho moroallo oa ACK o qalileng ka taelo ena:

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

Likenyo tsa logi:

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

fihlela qeto e

Ka linako tse ling eBPF ka kakaretso le XDP ka ho khetheha li hlahisoa e le sesebelisoa sa batsamaisi ba tsoetseng pele ho feta sethala sa nts'etsopele. Ehlile, XDP ke sesebelisoa sa ho kena-kenana le ts'ebetso ea pakete ea kernel, eseng mokhoa o mong oa kernel stack, joalo ka DPDK le likhetho tse ling tsa kernel bypass. Ka lehlakoreng le leng, XDP e u lumella ho kenya ts'ebetsong logic e rarahaneng, eo, ho feta moo, e leng bonolo ho e ntlafatsa ntle le khefu ea ho sebetsana le sephethephethe. Netefatso ha e hlahise mathata a maholo, ka bonna ke ne nke ke ka hana tse joalo bakeng sa likarolo tsa khoutu ea sebaka sa basebelisi.

Karolong ea bobeli, haeba sehlooho se thahasellisa, re tla tlatsa tafole ea bareki ba netefalitsoeng le ho senya likhokahano, re sebelise li-counters le ho ngola lisebelisoa tsa sebaka sa basebetsi ho laola sefa.

Lipeeletso:

Source: www.habr.com

Eketsa ka tlhaloso