Anyị na-ede nchebe megide mwakpo DDoS na XDP. Akụkụ nuklia

Teknụzụ eXpress Data Path (XDP) na-enye ohere ka a na-eme nhazi okporo ụzọ na-enweghị usoro na ntanetị Linux tupu ngwugwu abanye na nchịkọta netwọkụ kernel. Ngwa nke XDP - nchebe megide ọgụ DDoS (CloudFlare), nzacha mgbagwoju anya, nchịkọta ọnụ ọgụgụ (Netflix). EBPF mebere igwe na-egbu mmemme XDP, yabụ na ha nwere mgbochi na koodu ha yana ọrụ kernel dị dabere na ụdị nzacha.

Ezubere isiokwu a iji mejupụta adịghị ike nke ọtụtụ ihe na XDP. Nke mbụ, ha na-enye koodu edoziziri nke na-agafe atụmatụ XDP ozugbo: a na-akwado ya maka nkwenye ma ọ bụ dị mfe iji kpata nsogbu. Mgbe ị na-agbalị ịde koodu gị site na ọkọ, ị maghị ihe ị ga-eme na-ahụkarị njehie. Nke abuo, a naghị ekpuchi ụzọ iji nwalee XDP na mpaghara na-enweghị VM na ngwaike, n'agbanyeghị na ha nwere ọnyà nke ha. Ezubere ederede a maka ndị mmemme maara nke ọma ịkparịta ụka n'Ịntanet na Linux ndị nwere mmasị na XDP na eBPF.

N'akụkụ a, anyị ga-aghọta n'ụzọ zuru ezu ka esi ejikọta XDP nzacha na otu esi anwale ya, mgbe ahụ, anyị ga-ede ụdị dị mfe nke usoro kuki SYN a ma ama na ọkwa nhazi ngwugwu. Anyị agaghị emepụta "ndepụta ọcha" ma
ndị ahịa akwadoro, debe ọnụ ọgụgụ ma jikwaa nzacha - ndekọ zuru oke.

Anyị ga-ede na C - ọ bụghị ejiji, mana ọ bara uru. Koodu niile dị na GitHub site na njikọ dị na njedebe wee kewaa ya n'ime mmebe dịka usoro akọwara n'isiokwu ahụ.

Nbudata. N'ime edemede a, m ga-emepụta obere ngwọta iji gbochie mwakpo DDoS, n'ihi na nke a bụ ọrụ ziri ezi maka XDP na mpaghara m. Otú ọ dị, isi ihe mgbaru ọsọ bụ ịghọta nkà na ụzụ; Edozighị koodu nkuzi ma hapụ ụfọdụ nuances.

Nkọwa nkenke XDP

Aga m akọwapụta naanị isi ihe ka m wee ghara imepụtaghachi akwụkwọ na akụkọ dị adị.

Ya mere, a na-etinye koodu nzacha n'ime kernel. A na-ebufe ngwugwu na-abata na nzacha. N'ihi ya, nzacha ga-eme mkpebi: nyefee ngwugwu ahụ n'ime kernel (XDP_PASS), ngwugwu dobe (XDP_DROP) ma ọ bụ zighachi ya (XDP_TX). Nzacha nwere ike ịgbanwe ngwugwu, nke a bụ eziokwu karịsịa maka XDP_TX. Ị nwekwara ike ịkwụsị mmemme (XDP_ABORTED) ma tọgharịa ngwugwu ahụ, mana nke a bụ ihe atụ assert(0) - maka debugging.

A na-ama ụma mee igwe eBPF (Extended Berkley Packet Filter) ka ọ dị mfe ka kernel wee lelee na koodu ahụ anaghị agbagharị ma ghara imebi ebe nchekwa ndị ọzọ. Mkpokọta mmachi na nlele:

  • Amachibidoro loops (azụ).
  • Enwere nchịkọta maka data, mana enweghị ọrụ (ọrụ C niile ga-enwerịrị akara).
  • Amachibidoro ịnweta ebe nchekwa na mpụga ngwugwu na ihe nchekwa ngwugwu.
  • Ogo koodu ahụ nwere oke, mana na omume nke a adịchaghị mkpa.
  • Naanị oku maka ọrụ kernel pụrụ iche (ndị enyemaka eBPF) ka anabatara.

Ịmepụta na ịwụnye nzacha dị ka nke a:

  1. Koodu isi mmalite (dịka kernel.c) achịkọtara n'ime ihe (kernel.o) maka eBPF mebere igwe architecture. Dịka Ọktoba 2019, Clang na-akwado mkpokọta eBPF ma kwe nkwa na GCC 10.1.
  2. Ọ bụrụ na koodu ihe a nwere oku na-aga na nhazi kernel (dịka ọmụmaatụ, tebụl na ọnụ ọgụgụ), a na-eji efu dochie ID ha, nke pụtara na enweghị ike ịme ụdị koodu ahụ. Tupu itinye n'ime kernel, ịkwesịrị iji ID nke ihe ụfọdụ emepụtara site na oku kernel dochie zeros ndị a (njikọ koodu). Ị nwere ike ime nke a site na iji ihe ndị dị na mpụga, ma ọ bụ ị nwere ike dee mmemme nke ga-ejikọta ma buru otu nzacha.
  3. The kernel na-enyocha mmemme eburu ibu. A na-enyocha enweghị cycles na ọdịda gafere ngwugwu na oke oke. Ọ bụrụ na onye nyocha enweghị ike igosi na koodu ahụ ziri ezi, a jụrụ mmemme ahụ - ịkwesịrị inwe ike ime ya obi ụtọ.
  4. Mgbe nyochachara nke ọma, kernel na-achịkọta koodu ihe nrụnye eBPF n'ime koodu igwe maka nhazi sistemu (nke dị n'oge).
  5. Ihe omume ahụ na-ejikọta na interface wee malite nhazi ngwugwu.

Ebe XDP na-agba ọsọ na kernel, a na-eme nbipu site na iji ndekọ ndekọ na, n'ezie, ngwugwu nke mmemme ahụ na-enyocha ma ọ bụ mepụta. Agbanyeghị, eBPF na-achọpụta na koodu ebudatara echekwara maka sistemụ ahụ, yabụ ị nwere ike ịnwale XDP ozugbo na Linux mpaghara gị.

Ịkwadebe gburugburu

Mgbakọ

Clang enweghị ike iwepụta koodu ihe ozugbo maka ihe owuwu eBPF, yabụ usoro a nwere usoro abụọ:

  1. Gwakọta koodu C na bytecode LLVM (clang -emit-llvm).
  2. Tụgharịa bytecode ka ọ bụrụ koodu ihe eBPF (llc -march=bpf -filetype=obj).

Mgbe ị na-ede nzacha, faịlụ ole na ole nwere ọrụ inyeaka na macros ga-aba uru site na ule kernel. Ọ dị mkpa na ha dabara na ụdị kernel (KVER). Budata ha ka 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 maka 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 nwere ụzọ gaa na nkụnye eji isi mee kernel, ARCH - nhazi usoro. Ụzọ na ngwaọrụ nwere ike ịdịgasị iche n'etiti nkesa.

Ọmụmaatụ nke ndịiche maka 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 jikọọ ndekọ na nkụnye eji isi mee enyemaka yana ọtụtụ akwụkwọ ndekọ aha nwere nkụnye eji isi mee kernel. Akara __KERNEL__ pụtara na UAPI (userspace API) akọwara nkụnye eji isi mee maka koodu kernel, ebe ọ bụ na a na-egbu nzacha na kernel.

Enwere ike gbanyụọ nchedo mkpoko (-fno-stack-protector), n'ihi na koodu eBPF ka na-enyocha mmebi iwu enweghị oke. Ọ bara uru ịgbanwuo nkwalite ozugbo, n'ihi na oke nke eBPF bytecode nwere oke.

Ka anyị malite na nzacha na-agafe ngwugwu niile na-emeghị ihe ọ bụla:

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

otu make na -anakọta xdp_filter.o. Ebee ka ịnwale ya ugbu a?

Nwale oche

Ihe nkwụnye ahụ ga-agụnye oghere abụọ: nke a ga-enwe nzacha na nke a ga-ezigara ngwugwu. Ndị a ga-abụrịrị ngwaọrụ Linux zuru oke yana IP nke ha iji lelee ka ngwa ngwa na-arụ ọrụ na nzacha anyị.

Ngwaọrụ nke veth (virtual Ethernet) ụdị dabara anyị: ndị a bụ ụzọ mebere netwọk interfaces "jikọrọ" ozugbo na ibe. Ị nwere ike ịmepụta ha dị ka nke a (na mpaghara a iwu niile ip na-rụrụ si root):

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

ọ bụ xdp-remote и xdp-local - aha ngwaọrụ. Gbanye xdp-local (192.0.2.1/24) a ga-agbakwunye nzacha, ya na xdp-remote (192.0.2.2/24) a ga-eziga okporo ụzọ na-abata. Otú ọ dị, enwere nsogbu: interfaces dị n'otu igwe, Linux agaghị ezipụ okporo ụzọ gaa n'otu n'ime ha site na nke ọzọ. Ị nwere ike iji iwu aghụghọ dozie nke a iptables, ma ha ga-agbanwe ngwugwu, nke na-adịghị mma maka nbipu. Ọ ka mma iji oghere aha netwọkụ (netns ga-esote).

Oghere aha netwọkụ nwere nhazi ihu, tebụl ntụgharị, yana iwu NetFilter dịpụrụ adịpụ na ihe ndị yiri ya na netn ndị ọzọ. Usoro ọ bụla na-aga n'ime oghere aha ma na-enwe ohere ịnweta ihe nke netn ahụ. Site na ndabara, sistemụ ahụ nwere otu oghere aha netwọkụ maka ihe niile, yabụ ị nwere ike ịrụ ọrụ na Linux ma amaghị maka netns.

Ka anyị mepụta oghere aha ọhụrụ xdp-test ma bugharịa ya ebe ahụ xdp-remote.

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

Mgbe ahụ usoro na-aga n'ihu xdp-test, agaghị "hụ" xdp-local (ọ ga-anọgide na netns na ndabara) na mgbe ị na-eziga ngwugwu na 192.0.2.1 ọ ga-agafe ya. xdp-remoten'ihi na ọ bụ naanị interface na 192.0.2.0/24 ịnweta usoro a. Nke a na-arụkwa ọrụ n'akụkụ nke ọzọ.

Mgbe ị na-agagharị n'etiti netn, interface ahụ na-agbada ma tufuo adreesị ya. Iji hazie interface na netns, ịkwesịrị ịgba ọsọ ip ... n'ime iwu aha ebe a 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

Dị ka ị pụrụ ịhụ, nke a adịghị iche na ntọala xdp-local na ebe ndabara aha:

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

Ọ bụrụ na ị na-agba ọsọ tcpdump -tnevi xdp-local, ị pụrụ ịhụ na ngwugwu ezitere xdp-test, na-ebuga na interface a:

ip netns exec xdp-test   ping 192.0.2.1

Ọ dị mma ịmalite shei n'ime xdp-test. Ebe nchekwa ahụ nwere edemede nke na-arụ ọrụ na-arụ ọrụ na nkwụnye dịka ọmụmaatụ, ị nwere ike hazie nkwụnye ahụ na iwu ahụ sudo ./stand up ma hichapụ ya sudo ./stand down.

Ịchọta

Ejikọrọ nzacha na ngwaọrụ dị ka nke a:

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

Igodo -force achọrọ ijikọ mmemme ọhụrụ ma ọ bụrụ na ejikọtara nke ọzọ. "Ọ dịghị ozi ọma bụ ozi ọma" abụghị banyere iwu a, nkwubi okwu bụ oke n'ọnọdụ ọ bụla. gosi verbose nhọrọ, mana na ya a akụkọ na-egosi na ọrụ nke koodu verifier nwere ndepụta mgbakọ:

Verifier analysis:

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

Kwụpụ mmemme na interface:

ip link set dev xdp-local xdp off

N'ime edemede ndị a bụ iwu sudo ./stand attach и sudo ./stand detach.

Site na itinye nzacha, ị nwere ike hụ na nke ahụ ping na-aga n'ihu na-agba ọsọ, mana mmemme ahụ ọ na-arụ ọrụ? Ka anyị tinye ndekọ. Ọrụ bpf_trace_printk() yiri printf(), ma ọ bụ naanị na-akwado ruo arụmụka atọ na-abụghị ụkpụrụ, yana ndepụta nkọwa nkọwa. Macro bpf_printk() na-eme ka oku a dị mfe.

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

Nsonaazụ na-aga na ọwa kernel trace, nke kwesịrị ịgbalite:

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

Lelee eri ozi:

cat /sys/kernel/debug/tracing/trace_pipe

Iwu abụọ a na-akpọ oku sudo ./stand log.

Ping kwesịrị ịkpalite ozi dị ka nke a:

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

Ọ bụrụ na i leruo anya na mpụta nke verifier, ị ga-ahụ mgbako dị iche iche:

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

Nke bụ eziokwu bụ na mmemme eBPF enweghị ngalaba data, yabụ naanị ụzọ ị ga-esi tinye eriri usoro bụ arụmụka ozugbo nke iwu VM:

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

N'ihi nke a, nrụpụta nbipu na-emebi koodu nke arụpụtara nke ukwuu.

Na-eziga ngwugwu XDP

Ka anyị gbanwee nzacha: ka ọ zighachi ngwugwu niile na-abata. Nke a ezighi ezi site na echiche netwọkụ, ebe ọ ga-adị mkpa ịgbanwe adreesị na nkụnye eji isi mee, ma ugbu a, ọrụ na ụkpụrụ dị mkpa.

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

Mwepụta tcpdump on xdp-remote. Ọ kwesịrị igosi arịrịọ ICMP Echo na-apụ apụ na mbata ma kwụsị igosi ICMP Echo Reply. Mana ọ naghị egosi. Ọ na-apụta na maka ọrụ XDP_TX na mmemme na xdp-local dị mkpana interface ụzọ abụọ xdp-remote e kenyekwara usoro ihe omume, ọ bụrụgodị na ọ tọgbọrọ chakoo, a zụlitere ya.

Olee otú m si mara nke a?

Chọpụta ụzọ ngwugwu dị na kernel Usoro ihe omume perf na-enye ohere, n'agbanyeghị, iji otu igwe mebere, ya bụ, eBPF ka ejiri eBPF gbasaa.

Ị ghaghị ime ezi ihe site n'ihe ọjọọ, n'ihi na ọ dịghị ihe ọzọ ị ga-esi na ya pụta.

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

Kedu ihe bụ koodu 6?

$ errno 6
ENXIO 6 No such device or address

ọrụ veth_xdp_flush_bq() na-enweta koodu mperi site na veth_xdp_xmit(), ebe search site ENXIO ma chọta nkọwa.

Ka anyị weghachi ihe nzacha kacha nta (XDP_PASS) na faịlụ xdp_dummy.c, tinye ya na Makefile, kechie ya xdp-remote:

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

Ugbu a tcpdump na-egosi ihe a na-atụ anya ya:

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

Ọ bụrụ na egosiri naanị ARP kama, ị ga-ewepụ ihe nzacha (nke a na-eme sudo ./stand detach), hapụ ping, wee tọọ nzacha wee nwaa ọzọ. Nsogbu bụ na nzacha XDP_TX dị irè ma na ARP ma ọ bụrụ na nchịkọta
oghere aha xdp-test jisiri ike "ichefu" adreesị MAC 192.0.2.1, ọ gaghị enwe ike dozie IP a.

Ulationkpụzi nsogbu a

Ka anyị gaa n'ihu n'ọrụ ekwuru: dee usoro kuki SYN na XDP.

Iju mmiri SYN ka bụ ọgụ DDoS na-ewu ewu, isi ya bụ nke a. Mgbe njikọ guzosiri ike (TCP aka aka), ihe nkesa na-enweta SYN, na-ekenye akụrụngwa maka njikọ n'ọdịnihu, jiri ngwugwu SYNACK zaghachi wee chere ACK. Onye na-awakpo ahụ na-ezipụ puku kwuru puku ngwugwu SYN kwa sekọnd site na adreesị spoofed site na onye ọ bụla ọbịa na botnet ọtụtụ puku ike. A na-amanye ihe nkesa ahụ ka ọ kenye akụrụngwa ozugbo ọ bịarutere ngwugwu ahụ, ma na-ahapụ ya mgbe nnukwu oge gwụchara, ebe nchekwa ma ọ bụ oke agwụla, anabataghị njikọ ọhụrụ, na ọrụ adịghị.

Ọ bụrụ na ị naghị ekenye akụrụngwa dabere na ngwugwu SYN, mana naanị jiri ngwugwu SYNACK zaghachi, kedu ka ihe nkesa ga-esi ghọta na ngwugwu ACK bịarutere mechara na-ezo aka na ngwugwu SYN na-echekwabeghị? E kwuwerị, onye na-awakpo nwekwara ike ịmepụta ACK adịgboroja. Isi ihe dị na kuki SYN bụ itinye koodu na ya seqnum paramita njikọ dị ka hash nke adreesị, ọdụ ụgbọ mmiri na nnu na-agbanwe. Ọ bụrụ na ACK jisiri ike bịarute tupu agbanwee nnu, ị nwere ike gbakọọ hash ọzọ wee jiri ya tụnyere acknum. Forge acknum onye na-awakpo enweghị ike, ebe ọ bụ na nnu na-agụnye ihe nzuzo ahụ, ọ gaghị enwekwa oge iji dozie ya n'ihi ọwa nwere oke.

A na-emejuputa kuki SYN na Linux kernel na enwere ike ịme ya na-akpaghị aka ma ọ bụrụ na SYN rutere ngwa ngwa na n'ozuzu ya.

Mmemme mmụta na aka TCP

TCP na-enye nnyefe data dị ka iyi nke bytes, dịka ọmụmaatụ, a na-ebufe arịrịọ HTTP site na TCP. A na-ebufe iyi ahụ n'ime iberibe na ngwugwu. Ihe ngwugwu TCP niile nwere ọkọlọtọ ezi uche na ọnụọgụ usoro 32-bit:

  • Ngwakọta ọkọlọtọ na-ekpebi ọrụ nke otu ngwugwu. Ọkọlọtọ SYN na-egosi na nke a bụ ngwugwu mbụ onye zitere ya na njikọ ahụ. Ọkọlọtọ ACK pụtara na onye zitere ya anatala data njikọ niile ruo byte acknum. Otu ngwugwu nwere ike inwe ọtụtụ ọkọlọtọ ma a na-akpọ ya site na nchikota ha, dịka ọmụmaatụ, ngwugwu SYNACK.

  • Nọmba usoro (seqnum) na-akọwapụta nkwụghachi n'ime iyi data maka byte nke mbụ ebufere na ngwugwu a. Dịka ọmụmaatụ, ọ bụrụ na ngwugwu mbụ nwere X bytes nke data nọmba a bụ N, na ngwugwu na-esote nwere data ọhụrụ ọ ga-abụ N+X. Na mmalite nke njikọ, akụkụ ọ bụla na-ahọrọ nọmba a na-enweghị usoro.

  • Nọmba nnabata (acknum) - otu nkwụghachi dị ka seqnum, mana ọ naghị ekpebi ọnụọgụ byte na-ebufe, mana ọnụọgụ nke byte mbụ sitere na onye nnata, nke onye na-ezipụ ahụghị.

Ná mmalite nke njikọ, ndị ọzọ ga-ekweta seqnum и acknum. Onye ahịa na-eziga ngwugwu SYN na ya seqnum = X. Ihe nkesa na-aza na ngwugwu SYNACK, ebe ọ na-edekọ ya seqnum = Y na-ekpughe acknum = X + 1. Onye ahịa na-aza SYNACK na ngwugwu ACK, ebe seqnum = X + 1, acknum = Y + 1. Mgbe nke a gasịrị, n'ezie data nyefe amalite.

Ọ bụrụ na ndị ọgbọ anabataghị nnata nke ngwugwu ahụ, TCP na-eziga ya mgbe oge gwụchara.

Kedu ihe kpatara na anaghị eji kuki SYN eme ihe mgbe niile?

Nke mbụ, ọ bụrụ na SYNACK ma ọ bụ ACK efunahụla, ị ga-echere ka ezipu ya ọzọ - nhazi njikọ ga-akwụsịlata. Nke abuo, na ngwugwu SYN - na naanị na ya! - A na-ebufe ọtụtụ nhọrọ nke na-emetụta ọrụ njikọ ọzọ. Na-echetaghị ngwugwu SYN na-abata, ihe nkesa na-eleghara nhọrọ ndị a anya; TCP nwere ike ịrụ ọrụ na nke a, ma ọ dịkarịa ala na mmalite mmalite àgwà njikọ ahụ ga-ebelata.

N'ihe gbasara ngwugwu, mmemme XDP ga-emerịrị ihe ndị a:

  • jiri kuki zaghachi SYN na SYNACK;
  • zaghachi ACK na RST (kwụpụ);
  • tụfuo ngwugwu fọdụrụnụ.

Pseudocode nke algọridim yana nyocha ngwugwu:

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

Otu (*) A na-akara akara ebe ịchọrọ ijikwa steeti sistemụ - na ọkwa mbụ ị nwere ike ime na-enweghị ha site na itinye aka na TCP na ọgbọ kuki SYN dị ka seqnum.

N'ebe ahụ (**), ebe anyị na-enweghị tebụl, anyị ga-awụpụ ngwugwu.

Na-emejuputa aka TCP

Ịtụle ngwugwu ahụ ma nyochaa koodu ahụ

Anyị ga-achọ usoro nkụnye eji isi mee netwọkụ: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.hna TCP (uapi/linux/tcp.h). Enweghị m ike ijikọ nke ikpeazụ n'ihi njehie metụtara atomic64_t, Ekwesịrị m idetuo nkọwa ndị dị mkpa n'ime koodu ahụ.

Ọrụ niile egosipụtara na C maka ịgụ akwụkwọ ga-etinyerịrị n'ahịrị n'ebe a na-akpọ oku, ebe ọ bụ na eBPF verifier na kernel gbochiri azụ azụ, ya bụ, loops na oku ọrụ.

#define INTERNAL static __attribute__((always_inline))

Nnukwu LOG() na-ewepụ mbipụta n'ime nrụpụta ntọhapụ.

Mmemme bụ ihe ebuga ọrụ. Onye ọ bụla na-anata ngwugwu nke etinyere nkụnye eji isi mee ọkwa kwekọrọ, dịka ọmụmaatụ, process_ether() na-atụ anya na ọ ga-ejupụta ether. Dabere na nsonaazụ nyocha nke ubi, ọrụ ahụ nwere ike ịgafe ngwugwu ahụ na ọkwa dị elu. Nsonaazụ nke ọrụ ahụ bụ omume XDP. Maka ugbu a, ndị na-ahụ maka SYN na ACK na-agafe ngwugwu niile.

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

M na-adọta uche gị na akwụkwọ ndenye ego akara A na B. Ọ bụrụ na ị na-ekwu A, mmemme ga-ewuli, ma a ga-enwe nkwenye nkwenye mgbe ị na-ebu:

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!

eriri igodo invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Enwere ụzọ ogbugbu mgbe byte nke iri na atọ site na mmalite nke ihe nchekwa dị n'èzí ngwugwu. O siri ike ịghọta site na ndepụta ahịrị ahịrị anyị na-ekwu maka ya, mana enwere akara ntuziaka (12) yana onye nrụpụta na-egosi ahịrị koodu isi mmalite:

llvm-objdump -S xdp_filter.o | less

N'okwu a, ọ na-atụ aka na akara

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

nke mere ka o doo anya na nsogbu dị ether. Ọ ga-adị ka nke a mgbe niile.

Zaghachi SYN

Ebumnuche n'oge a bụ imepụta ngwugwu SYNACK ziri ezi nwere nke edobere seqnum, nke kuki SYN ga-anọchi anya n'ọdịnihu. Mgbanwe niile na-eme na process_tcp_syn() na mpaghara ndị gbara ya gburugburu.

Nyocha ngwugwu

N'ụzọ dị ịtụnanya, ebe a bụ ahịrị kachasị dị ịrịba ama, ma ọ bụ karịa, nkọwa ya:

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

Mgbe ị na-ede ụdị mbụ nke koodu ahụ, a na-eji kernel 5.1 mee ihe, maka nyocha nke nwere ọdịiche dị n'etiti. data_end и (const void*)ctx->data_end. N'oge ederede, kernel 5.3.1 enweghị nsogbu a. Ọ ga-ekwe omume na onye nchịkọta ahụ na-enweta mgbanwe mpaghara dị iche karịa ubi. Omume nke akụkọ ahụ: mgbe akwụ ụgwọ buru ibu, ime ka koodu dị mfe nwere ike inye aka.

Ihe na-esote bụ nlele ogologo oge na-aga n'ihu maka ebube nke onye nyocha; O MAX_CSUM_BYTES n'okpuru.

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

Na-ekpughe ngwugwu ahụ

Dejupụta seqnum и acknum, tọọ ACK (SYN edobelarị):

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

Gbanwee ọdụ ụgbọ mmiri TCP, adreesị IP na adreesị MAC. Ọbá akwụkwọ ọkọlọtọ adịghị enweta site na mmemme XDP, yabụ memcpy() - nnukwu nnukwu ihe na-ezochi Clang intrinsics.

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

Mweghachi nke checksums

IPV4 na TCP checksum chọrọ mgbakwunye nke okwu 16-bit niile dị na nkụnye eji isi mee, na edere nha nke nkụnye eji isi mee n'ime ha, ya bụ, amaghị na oge achịkọta. Nke a bụ nsogbu n'ihi na ihe nnwapụta agaghị awụpụ akaghị nkịtị gaa na mgbanwe oke. Mana nha nke nkụnye eji isi mee dị oke: ruo 64 bytes ọ bụla. Ị nwere ike ịme loop na ọnụ ọgụgụ a kapịrị ọnụ, nke nwere ike ịkwụsị n'oge.

Amara m na enwere RFC 1624 banyere otu esi atụgharịghachi checksum n'akụkụ ụfọdụ ma ọ bụrụ na a gbanwere naanị okwu ndị edoziri nke ngwugwu ahụ. Otú ọ dị, usoro ahụ abụghị ihe zuru ụwa ọnụ, na mmejuputa ya ga-esikwu ike ịnọgide na-enwe.

Ọrụ mgbako 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;
}

Agbanyeghị size kwadoro site na koodu oku, ọnọdụ ọpụpụ nke abụọ dị mkpa ka onye nyocha wee gosipụta mmecha nke loop.

Maka okwu 32-bit, a na-emejuputa ụdị dị mfe:

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

N'ezie ịgbakọ checksums na izipu ngwugwu ahụ azụ:

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;

ọrụ carry() na-eme nlele nlele site na nchikota 32-bit nke okwu 16-bit, dị ka RFC 791 si kwuo.

TCP nkwenye aka aka

Ihe nzacha na-ewepụta njikọ na netcat, na-efu ACK ikpeazụ, nke Linux zara ya na ngwugwu RST, ebe ọ bụ na nchịkọta netwọk ahụ enwetaghị SYN - a gbanwere ya na SYNACK ma ziga ya azụ - na site na echiche OS, otu ngwugwu rutere na-enweghị njikọ na-emeghe. njikọ.

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

Ọ dị mkpa ịlele na ngwa zuru oke ma hụ tcpdump on xdp-remote n'ihi na ihe atụ, hping3 anaghị azaghachi na checksums ezighi ezi.

Site na echiche XDP, nkwenye n'onwe ya bụ ihe na-adịghị mkpa. Ngụkọta algọridim bụ ihe ochie ma yie ka ọ dị mfe maka onye mwakpo ọkaibe. Linux kernel, dịka ọmụmaatụ, na-eji SipHash cryptographic, mana mmejuputa ya maka XDP doro anya karịa oke isiokwu a.

Ewebata maka TODO ọhụrụ metụtara nzikọrịta ozi mpụga:

  • Mmemme XDP enweghị ike ịchekwa cookie_seed (akụkụ nzuzo nke nnu) na mgbanwe zuru ụwa ọnụ, ịchọrọ nchekwa na kernel, uru nke a ga-emelite kwa oge site na onye na-emepụta ihe a pụrụ ịdabere na ya.

  • Ọ bụrụ na kuki SYN dakọtara na ngwugwu ACK, ịkwesighi ibipụta ozi, mana cheta IP nke onye ahịa enyochagoro ka ị gaa n'ihu na-ebufe ngwugwu na ya.

Nnwale ndị ahịa ziri ezi:

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

Akwụkwọ ndekọ na-egosi na ego ahụ gafere (flags=0x2 - Nke a bụ SYN, flags=0x10 bụ 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

Ọ bụ ezie na enweghị ndepụta nke IP akwadoro, a gaghị enwe nchebe site na iju mmiri SYN n'onwe ya, mana nke a bụ mmeghachi omume na iju mmiri ACK nke iwu na-esonụ:

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

Ndenye ndenye:

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

nkwubi

Mgbe ụfọdụ eBPF n'ozuzu yana XDP karịsịa ka a na-egosi dị ka ngwa ọrụ nchịkwa dị elu karịa dị ka ikpo okwu mmepe. N'ezie, XDP bụ ngwá ọrụ maka itinye aka na nhazi nke ngwugwu site na kernel, ọ bụghịkwa ihe ọzọ na nchịkọta kernel, dị ka DPDK na nhọrọ nkwụsị kernel ndị ọzọ. N'aka nke ọzọ, XDP na-enye gị ohere imejuputa mgbagwoju anya mgbagwoju anya, nke, ọzọ, dị mfe imelite na-enweghị nkwụsịtụ na nhazi okporo ụzọ. Onye nyocha anaghị emepụta nnukwu nsogbu n'onwe m, agaghị m ajụ nke a maka akụkụ nke koodu njirimara.

N'akụkụ nke abụọ, ọ bụrụ na isiokwu ahụ na-adọrọ mmasị, anyị ga-emecha tebụl nke ndị ahịa ekwenyesiri ike na nkwụsịtụ, mejuputa counters ma dee ihe eji eme ihe iji jikwaa nzacha.

Ntughari:

isi: www.habr.com

Tinye a comment