Peb tab tom sau kev tiv thaiv DDoS tawm tsam ntawm XDP. Nuclear ib feem

eXpress Data Path (XDP) thev naus laus zis tso cai rau kev ua lag luam random ua rau ntawm Linux interfaces ua ntej cov pob ntawv nkag mus rau hauv cov ntsiav tshuaj network. Daim ntawv thov XDP - tiv thaiv DDoS tawm tsam (CloudFlare), cov ntxaij lim dej nyuaj, kev sau txheeb cais (Netflix). XDP cov kev pab cuam raug tua los ntawm eBPF lub tshuab virtual, yog li lawv muaj kev txwv rau ob qho tib si lawv cov cai thiab cov khoom siv muaj nyob ntawm seb hom lim.

Tsab ntawv no yog npaj los ua kom tiav qhov tsis txaus ntawm ntau cov ntaub ntawv ntawm XDP. Ua ntej, lawv muab cov cai npaj ua ntej uas tam sim ntawd hla cov yam ntxwv ntawm XDP: nws tau npaj rau kev txheeb xyuas lossis yooj yim dhau los ua teeb meem. Thaum koj sim sau koj cov cai los ntawm kos, koj tsis muaj lub tswv yim yuav ua li cas nrog qhov tsis raug. Qhov thib ob, txoj hauv kev los sim XDP hauv zos yam tsis muaj VM thiab kho vajtse tsis raug them, txawm tias lawv muaj lawv tus kheej qhov teeb meem. Cov ntawv nyeem yog npaj rau cov programmers paub txog kev sib tham thiab Linux uas txaus siab rau XDP thiab eBPF.

Hauv seem no, peb yuav nkag siab meej tias XDP lim tau sib sau ua ke li cas thiab kuaj nws li cas, tom qab ntawd peb yuav sau cov qauv yooj yim ntawm cov txheej txheem SYN cov ncuav qab zib uas paub zoo ntawm cov txheej txheem ntim khoom. Peb yuav tsis tsim "dawb daim ntawv teev npe" tseem
cov neeg tau txais kev pom zoo, khaws cov txee thiab tswj xyuas cov lim dej - cov ntaub ntawv txaus.

Peb yuav sau hauv C - nws tsis yog fashionable, tab sis nws yog tswv yim. Tag nrho cov cai muaj nyob rau ntawm GitHub ntawm qhov txuas ntawm qhov kawg thiab muab faib ua kev cog lus raws li cov theem tau piav qhia hauv tsab xov xwm.

Kev tsis lees paub. Nyob rau hauv cov ntaub ntawv no, kuv yuav tsim ib tug mini-kev daws teeb meem los tiv thaiv DDoS tawm tsam, vim hais tias qhov no yog ib tug tiag tiag txoj hauj lwm rau XDP thiab kuv cheeb tsam ntawm kev txawj ntse. Txawm li cas los xij, lub hom phiaj tseem ceeb yog kom nkag siab txog thev naus laus zis; qhov no tsis yog phau ntawv qhia los tsim kev tiv thaiv npaj txhij. Cov lus qhia code tsis zoo thiab tshem tawm qee qhov nuances.

XDP Cov ntsiab lus luv luv

Kuv yuav piav qhia tsuas yog cov ntsiab lus tseem ceeb xwb thiaj li tsis txhob muab cov ntaub ntawv thiab cov ntawv uas twb muaj lawm.

Yog li, lim code yog loaded rau hauv lub ntsiav. Cov pob khoom tuaj raug xa mus rau lub lim. Yog li ntawd, lub lim yuav tsum txiav txim siab: hla lub pob ntawv rau hauv cov ntsiav (XDP_PASS), poob pob ntawv (XDP_DROP) lossis xa rov qab (XDP_TX). Cov lim tuaj yeem hloov lub pob, qhov no yog qhov tseeb tshwj xeeb rau XDP_TX. Koj tseem tuaj yeem rho tawm qhov program (XDP_ABORTED) thiab pib dua lub pob, tab sis qhov no yog qhov sib piv assert(0) - rau kev debugging.

Lub eBPF (extended Berkley Packet Filter) lub tshuab virtual yog txhob txwm ua kom yooj yim kom cov ntsiav tuaj yeem tshawb xyuas tias cov cai tsis voj thiab tsis ua rau lwm tus neeg lub cim xeeb. Kev txwv ntau thiab kev kuaj xyuas:

  • Loops (rov qab) raug txwv.
  • Muaj ib pawg rau cov ntaub ntawv, tab sis tsis muaj kev ua haujlwm (tag nrho cov haujlwm C yuav tsum nyob hauv kab).
  • Nco nkag mus rau sab nraud ntawm pawg thiab pob ntawv tsis raug txwv.
  • Cov lej loj yog txwv, tab sis hauv kev xyaum qhov no tsis yog qhov tseem ceeb heev.
  • Tsuas yog hu rau cov haujlwm tshwj xeeb kernel (eBPF pab) tau tso cai.

Tsim thiab txhim kho lub lim zoo li no:

  1. Source code (eg kernel.c) muab tso ua ke rau hauv cov khoom (kernel.o) rau eBPF virtual tshuab architecture. Raws li lub Kaum Hlis 2019, muab tso ua ke rau eBPF tau txais kev txhawb nqa los ntawm Clang thiab tau cog lus hauv GCC 10.1.
  2. Yog hais tias cov khoom code no muaj hu mus rau cov qauv kernel (piv txwv li, cov ntxhuav thiab cov txee), lawv cov ID yog hloov los ntawm xoom, uas txhais tau hais tias cov cai no tsis tuaj yeem ua tiav. Ua ntej thauj khoom rau hauv cov ntsiav, koj yuav tsum hloov cov lej no nrog cov IDs ntawm cov khoom tshwj xeeb tsim los ntawm cov xov tooj hu (txuas cov cai). Koj tuaj yeem ua qhov no nrog cov khoom siv hluav taws xob sab nraud, lossis koj tuaj yeem sau qhov program uas yuav txuas thiab thauj cov lim tshwj xeeb.
  3. Lub kernel txheeb xyuas qhov kev pab cuam loaded. Qhov tsis muaj lub voj voog thiab tsis ua kom dhau ntawm pob ntawv thiab pawg ciam teb raug kuaj xyuas. Yog tias tus neeg kuaj xyuas tsis tuaj yeem ua pov thawj tias cov cai yog qhov tseeb, qhov kev zov me nyuam raug tsis lees paub - koj yuav tsum muaj peev xwm txaus siab rau nws.
  4. Tom qab ua tiav kev pov thawj, lub kernel compiles eBPF architecture khoom code rau hauv tshuab code rau lub system architecture (tsuas yog-hauv-lub sijhawm).
  5. Qhov kev pab cuam txuas mus rau lub interface thiab pib ua cov pob ntawv.

Txij li thaum XDP khiav hauv lub kernel, debugging yog nqa tawm siv cov ntaub ntawv taug qab thiab, qhov tseeb, pob ntawv uas qhov kev pab cuam lim lossis tsim. Txawm li cas los xij, eBPF ua kom ntseeg tau tias cov lej rub tawm muaj kev nyab xeeb rau lub kaw lus, yog li koj tuaj yeem sim nrog XDP ncaj qha ntawm koj lub zos Linux.

Npaj ib puag ncig

Sib dhos

Clang tsis tuaj yeem tsim cov cai ncaj qha rau eBPF architecture, yog li cov txheej txheem muaj ob kauj ruam:

  1. Compile C code rau LLVM bytecode (clang -emit-llvm).
  2. Hloov bytecode rau eBPF khoom code (llc -march=bpf -filetype=obj).

Thaum sau cov lim, ob peb cov ntaub ntawv nrog cov haujlwm pabcuam thiab macros yuav pab tau los ntawm cov kev xeem kernel. Nws yog ib qho tseem ceeb uas lawv phim lub kernel version (KVER). Download tau lawv rau 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 rau 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 muaj txoj hauv kev mus rau kernel headers, ARCH - system architecture. Txoj kev thiab cov cuab yeej yuav txawv me ntsis ntawm kev faib khoom.

Piv txwv ntawm qhov sib txawv rau 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 txuas ib daim ntawv teev npe nrog pab pawg headers thiab ob peb phau ntawv nrog cov kernel headers. Cim __KERNEL__ txhais tau hais tias UAPI (userspace API) headers yog txhais rau kernel code, txij li thaum lub lim raug tua nyob rau hauv lub kernel.

Kev tiv thaiv pawg tuaj yeem raug kaw (-fno-stack-protector), vim tias eBPF code verifier tseem kuaj xyuas cov kev ua txhaum cai ntawm pawg. Nws tsim nyog tig rau kev ua kom zoo tam sim ntawd, vim tias qhov loj ntawm eBPF bytecode raug txwv.

Cia peb pib nrog lub lim uas hla tag nrho cov pob ntawv thiab tsis muaj dab tsi:

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

pab neeg make sau xdp_filter.o. Tam sim no sim qhov twg?

Test sawv

Lub chaw muag khoom yuav tsum muaj ob lub interfaces: ntawm qhov uas yuav muaj lub lim dej thiab los ntawm cov pob ntawv twg yuav raug xa mus. Cov no yuav tsum yog tag nrho cov khoom siv Linux nrog lawv tus kheej IPs txhawm rau txheeb xyuas seb cov ntawv thov ua haujlwm li cas nrog peb cov lim dej.

Devices ntawm veth (virtual Ethernet) hom yog haum rau peb: cov no yog ib khub ntawm virtual network interfaces "txuas" ncaj qha rau ib leeg. Koj tuaj yeem tsim lawv zoo li no (hauv ntu no tag nrho cov lus txib ip yog ua los ntawm root):

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

nws yog xdp-remote и xdp-local - cov npe khoom siv. Ntawm xdp-local (192.0.2.1/24) lub lim yuav txuas nrog, nrog xdp-remote (192.0.2.2/24) cov tsheb thauj mus los yuav raug xa mus. Txawm li cas los xij, muaj ib qho teeb meem: cov interfaces nyob rau tib lub tshuab, thiab Linux yuav tsis xa tsheb mus rau ib qho ntawm lawv mus rau lwm qhov. Koj tuaj yeem daws qhov no nrog cov cai tsis yooj yim iptables, tab sis lawv yuav tau hloov cov pob khoom, uas tsis yooj yim rau kev debugging. Nws yog qhov zoo dua los siv network namespaces (tom qab no netns).

Lub network namespace muaj cov txheej txheem kev sib txuas, cov rooj sib tham, thiab NetFilter cov cai uas raug cais tawm ntawm cov khoom zoo sib xws hauv lwm cov netns. Txhua tus txheej txheem khiav hauv lub npe chaw thiab tsuas yog nkag mus rau cov khoom ntawm cov netns ntawd. Los ntawm lub neej ntawd, lub kaw lus muaj ib lub network namespace rau txhua yam khoom, yog li koj tuaj yeem ua haujlwm hauv Linux thiab tsis paub txog netns.

Cia peb tsim lub npe tshiab xdp-test thiab txav mus rau ntawd xdp-remote.

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

Ces tus txheej txheem khiav hauv xdp-test, yuav tsis "pom" xdp-local (nws yuav nyob twj ywm hauv netns los ntawm lub neej ntawd) thiab thaum xa ib pob ntawv rau 192.0.2.1 nws yuav dhau los ntawm xdp-remotevim nws yog tib lub interface ntawm 192.0.2.0/24 nkag mus rau cov txheej txheem no. Qhov no kuj ua hauj lwm nyob rau hauv qhov opposite direction.

Thaum tsiv ntawm netns, lub interface poob thiab poob nws qhov chaw nyob. Txhawm rau teeb tsa lub interface hauv netns, koj yuav tsum khiav ip ... hauv no command 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

Raws li koj tuaj yeem pom, qhov no tsis txawv ntawm qhov chaw xdp-local nyob rau hauv lub default namespace:

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

Yog koj khiav tcpdump -tnevi xdp-local, koj tuaj yeem pom tias pob ntawv xa los ntawm xdp-test, yog xa mus rau qhov interface no:

ip netns exec xdp-test   ping 192.0.2.1

Nws yog qhov yooj yim los tso lub plhaub rau hauv xdp-test. Lub chaw cia khoom muaj ib tsab ntawv uas automates ua haujlwm nrog lub chaw muag khoom; piv txwv li, koj tuaj yeem teeb tsa qhov muag nrog cov lus txib sudo ./stand up thiab rho tawm nws sudo ./stand down.

Tracing

Lub lim yog txuam nrog cov cuab yeej zoo li no:

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

Ntsiab -force xav tau los txuas ib qhov kev pab cuam tshiab yog tias lwm tus twb tau txuas lawm. "Tsis muaj xov xwm yog xov xwm zoo" tsis yog hais txog cov lus txib no, qhov xaus yog voluminous nyob rau hauv txhua rooj plaub. qhia verbose xaiv tau, tab sis nrog nws ib tsab ntawv ceeb toom tshwm nyob rau hauv kev ua hauj lwm ntawm tus code verifier nrog ib tug sib sau npe teev:

Verifier analysis:

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

Unlink qhov kev pab cuam los ntawm lub interface:

ip link set dev xdp-local xdp off

Hauv tsab ntawv no yog cov lus txib sudo ./stand attach и sudo ./stand detach.

Los ntawm kev txuas lub lim, koj tuaj yeem paub tseeb tias ping txuas ntxiv mus, tab sis qhov kev zov me nyuam puas ua haujlwm? Cia peb ntxiv cov cav. Muaj nuj nqi bpf_trace_printk() zoo ib yam li printf(), tab sis tsuas yog txhawb nqa mus txog peb qhov kev sib cav uas tsis yog tus qauv, thiab cov npe txwv ntawm cov khoom tshwj xeeb. Macro bpf_printk() yooj yim hu.

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

Cov zis tawm mus rau kernel trace channel, uas yuav tsum tau qhib:

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

Saib kab lus:

cat /sys/kernel/debug/tracing/trace_pipe

Ob leeg ntawm cov lus txib no ua hu sudo ./stand log.

Ping yuav tsum tam sim no ua cov lus zoo li no:

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

Yog tias koj saib ze ntawm tus txheeb xyuas cov zis, koj yuav pom cov kev suav txawv txawv:

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

Qhov tseeb yog tias eBPF cov kev pab cuam tsis muaj cov ntaub ntawv seem, yog li tib txoj hauv kev los encode ib txoj hlua hom yog qhov kev sib cav tam sim ntawm VM cov lus txib:

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

Vim li no, debug tso zis heev bloats lub resulting code.

Xa XDP Packets

Cia peb hloov lub lim: cia nws xa rov qab tag nrho cov pob khoom tuaj. Qhov no yog qhov tsis raug los ntawm qhov kev xav hauv lub network, vim nws yuav tsim nyog hloov chaw nyob hauv cov ntsiab lus, tab sis tam sim no txoj haujlwm tseem ceeb.

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

Tua tawm tcpdump rau xdp-remote. Nws yuav tsum pom zoo ib yam tawm thiab tuaj ICMP Echo Thov thiab tso tseg tsis pom ICMP Echo Teb. Tab sis nws tsis qhia. Nws hloov tawm tias ua haujlwm XDP_TX hauv qhov program rau xdp-local yog tsim nyogmus rau tus khub interface xdp-remote ib qho kev pab cuam kuj raug muab, txawm tias nws yog khoob, thiab nws tau tsa.

Kuv paub qhov no li cas?

Taug qab txoj kev ntawm ib pob hauv cov ntsiav Lub perf txheej xwm mechanism tso cai, los ntawm txoj kev, siv tib lub tshuab virtual, uas yog, eBPF yog siv rau disassemblies nrog eBPF.

Koj yuav tsum ua qhov zoo tawm ntawm qhov phem, vim tsis muaj dab tsi ua kom nws tawm.

$ 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 yog dab tsi?

$ errno 6
ENXIO 6 No such device or address

muaj nuj nqi veth_xdp_flush_bq() tau txais qhov yuam kev code los ntawm veth_xdp_xmit(), qhov twg search ENXIO thiab nrhiav cov lus pom.

Cia peb rov qab cov lim yam tsawg kawg nkaus (XDP_PASS) hauv cov ntaub ntawv xdp_dummy.c, ntxiv rau Makefile, khi rau xdp-remote:

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

Tam sim no tcpdump qhia tau hais tias xav tau:

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

Yog tias tsuas yog ARPs tau pom xwb, koj yuav tsum tshem tawm cov lim dej (qhov no ua sudo ./stand detach), cia mus ping, ces teeb cov lim thiab sim dua. Qhov teeb meem yog qhov lim XDP_TX siv rau ob qho tib si ARP thiab yog tias pawg
cov npe xdp-test tswj kom "tsis nco qab" MAC chaw nyob 192.0.2.1, nws yuav tsis tuaj yeem daws qhov IP no.

Nqe lus ntawm qhov teeb meem

Cia peb mus rau txoj haujlwm tau hais tseg: sau SYN ncuav qab zib mechanism ntawm XDP.

SYN dej nyab tseem yog qhov nrov DDoS nres, cov ntsiab lus ntawm cov hauv qab no. Thaum muaj kev sib txuas (TCP tuav tes), tus neeg rau zaub mov tau txais SYN, faib cov peev txheej rau kev sib txuas yav tom ntej, teb nrog SYNACK pob ntawv thiab tos ACK. Tus neeg tawm tsam tsuas yog xa ntau txhiab SYN pob ntawv ib ob los ntawm qhov chaw nyob spoofed los ntawm txhua tus tswv tsev hauv ntau txhiab-muaj zog botnet. Cov neeg rau zaub mov raug yuam kom faib cov peev txheej tam sim ntawd thaum tuaj txog ntawm pob ntawv, tab sis tso tawm tom qab lub sijhawm loj; vim li ntawd, nco lossis txwv tsis pub dhau, kev sib txuas tshiab tsis tau txais, thiab cov kev pabcuam tsis muaj.

Yog tias koj tsis faib cov peev txheej raws li SYN pob ntawv, tab sis tsuas yog teb nrog pob ntawv SYNACK, yuav ua li cas tus neeg rau zaub mov nkag siab tias ACK pob ntawv uas tuaj txog tom qab yog hais txog SYN pob ntawv uas tsis tau txais kev cawmdim? Tom qab tag nrho, tus neeg tawm tsam tuaj yeem tsim cov ACKs cuav. Lub ntsiab lus ntawm SYN ncuav qab zib yog encode nws seqnum kev twb kev txuas tsis raws li ib tug hash ntawm chaw nyob, ports thiab hloov ntsev. Yog tias ACK tswj tuaj txog ua ntej cov ntsev hloov pauv, koj tuaj yeem suav cov hash dua thiab muab piv nrog acknum. Forge acknum tus neeg tawm tsam tsis tuaj yeem, txij li cov ntsev suav nrog qhov zais cia, thiab yuav tsis muaj sijhawm los txheeb xyuas nws vim qhov txwv channel.

Lub SYN ncuav qab zib tau ntev tau siv nyob rau hauv Linux ntsiav thiab tuaj yeem qhib tau txawm tias SYNs tuaj txog sai heev thiab ntau.

Kev kawm txuj ci ntawm TCP tuav tes

TCP muab cov ntaub ntawv xa mus raws li cov kwj ntawm bytes, piv txwv li, HTTP thov raug xa mus rau TCP. Cov kwj deg yog xa mus rau hauv daim hauv pob ntawv. Tag nrho cov pob ntawv TCP muaj cov cim cim thiab 32-ntsis kab zauv:

  • Kev sib xyaw ntawm cov chij txiav txim siab lub luag haujlwm ntawm ib pob tshwj xeeb. Tus chij SYN qhia tias qhov no yog tus xa khoom thawj pob khoom ntawm kev sib txuas. Tus chij ACK txhais tau hais tias tus neeg xa khoom tau txais tag nrho cov ntaub ntawv txuas mus txog byte acknum. Ib pob ntawv tuaj yeem muaj ntau tus chij thiab raug hu los ntawm lawv qhov sib xyaw ua ke, piv txwv li, pob ntawv SYNACK.

  • Sequence naj npawb (seqnum) qhia txog qhov offset nyob rau hauv cov ntaub ntawv kwj rau thawj byte uas kis tau nyob rau hauv lub pob ntawv no. Piv txwv li, yog tias hauv thawj pob ntawv nrog X bytes ntawm cov ntaub ntawv tus lej no yog N, hauv pob ntawv tom ntej nrog cov ntaub ntawv tshiab nws yuav yog N + X. Thaum pib ntawm kev sib txuas, txhua sab xaiv tus lej no randomly.

  • Kev lees paub tus lej (acknum) - tib yam offset raws li seqnum, tab sis nws tsis txiav txim siab tus lej ntawm byte raug xa mus, tab sis tus naj npawb ntawm thawj byte los ntawm tus neeg tau txais, uas tus xa tsis pom.

Thaum pib ntawm kev sib txuas, ob tog yuav tsum pom zoo seqnum и acknum. Tus neeg siv khoom xa SYN pob ntawv nrog nws seqnum = X. Cov neeg rau zaub mov teb nrog SYNACK pob ntawv, qhov twg nws sau nws seqnum = Y thiab nthuav tawm acknum = X + 1. Tus neeg siv khoom teb rau SYNACK nrog ACK pob ntawv, qhov twg seqnum = X + 1, acknum = Y + 1. Tom qab no, qhov tseeb cov ntaub ntawv hloov chaw pib.

Yog tias tus phooj ywg tsis lees paub qhov tau txais ntawm pob ntawv, TCP rov xa nws tom qab lub sijhawm.

Vim li cas SYN ncuav qab zib tsis siv tas li?

Ua ntej, yog tias SYNACK lossis ACK ploj lawm, koj yuav tsum tau tos kom nws xa rov qab - kev teeb tsa kev sib txuas yuav qeeb. Thib ob, hauv pob SYN - thiab tsuas yog hauv nws! - Ntau qhov kev xaiv raug xa mus uas cuam tshuam rau kev ua haujlwm ntxiv ntawm kev sib txuas. Yog tias tsis nco qab cov pob ntawv SYN tuaj, tus neeg rau zaub mov yog li tsis quav ntsej cov kev xaiv no; tus neeg siv yuav tsis xa lawv mus rau hauv cov pob ntawv tom ntej. TCP tuaj yeem ua haujlwm nyob rau hauv rooj plaub no, tab sis tsawg kawg ntawm thawj theem qhov zoo ntawm kev sib txuas yuav txo qis.

Los ntawm kev pom pob khoom, ib qho kev pab cuam XDP yuav tsum ua cov hauv qab no:

  • teb rau SYN nrog SYNACK nrog lub ncuav qab zib;
  • teb rau ACK nrog RST (disconnect);
  • pov tseg cov pob ntawv ntxiv.

Pseudocode ntawm lub algorithm nrog rau pob parsing:

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

Ib (*) cov ntsiab lus uas koj xav tau los tswj lub xeev ntawm lub kaw lus raug cim - thawj theem koj tuaj yeem ua yam tsis muaj lawv los ntawm kev siv TCP tuav tes nrog lub cim ntawm SYN ncuav qab zib ua seqnum.

Ntawm qhov chaw (**), thaum peb tsis muaj lub rooj, peb yuav hla lub pob ntawv.

Siv TCP tuav tes

Parsing lub pob thiab txheeb xyuas qhov chaws

Peb yuav xav tau network header qauv: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) thiab TCP (uapi/linux/tcp.h). Kuv tsis tuaj yeem txuas qhov tom kawg vim qhov yuam kev cuam tshuam nrog atomic64_t, Kuv yuav tsum luam cov ntsiab lus tsim nyog rau hauv cov cai.

Tag nrho cov haujlwm uas tau hais tseg hauv C rau kev nyeem tau yuav tsum tau sau rau ntawm qhov chaw hu, vim tias eBPF tus neeg txheeb xyuas hauv lub ntsiav txwv tsis pub rov qab los, qhov tseeb, lub voj voog thiab kev ua haujlwm hu.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() disables luam ntawv nyob rau hauv lub tso tawm tsim.

Qhov kev pab cuam yog lub conveyor ntawm functions. Txhua tus tau txais ib pob ntawv nyob rau hauv uas tus coj theem header yog highlighted, piv txwv li, process_ether() cia siab tias nws yuav puv ether. Raws li cov txiaj ntsig ntawm kev tshuaj ntsuam teb, qhov ua haujlwm tuaj yeem dhau lub pob ntawv mus rau qib siab dua. Qhov tshwm sim ntawm kev ua haujlwm yog XDP kev ua. Txog tam sim no, SYN thiab ACK handlers dhau tag nrho cov pob ntawv.

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

Kuv kos koj cov xim rau cov tshev A thiab B. Yog tias koj tawm tswv yim A, qhov kev pab cuam yuav tsim, tab sis yuav muaj kev pov thawj yuam kev thaum thauj khoom:

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!

Txoj hlua tseem ceeb invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Muaj txoj hauv kev ua tiav thaum lub kaum peb byte txij thaum pib ntawm qhov tsis yog sab nraum pob ntawv. Nws yog ib qho nyuaj rau kev nkag siab los ntawm cov npe uas peb tab tom tham txog, tab sis muaj tus lej qhia (12) thiab tus disassembler uas qhia cov kab ntawm qhov chaws:

llvm-objdump -S xdp_filter.o | less

Hauv qhov no nws taw qhia rau kab

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

uas ua kom pom tseeb tias qhov teeb meem yog ether. Nws yeej yuav zoo li no.

Teb rau SYN

Lub hom phiaj ntawm theem no yog tsim kom muaj ib pob ntawv SYNACK kom raug nrog rau qhov ruaj khov seqnum, uas yuav raug hloov yav tom ntej los ntawm SYN ncuav qab zib. Txhua qhov kev hloov pauv tshwm sim hauv process_tcp_syn() thiab thaj chaw ib puag ncig.

Pob ntawv pov thawj

Oddly txaus, ntawm no yog cov kab lus zoo tshaj plaws, lossis theej, cov lus hais rau nws:

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

Thaum sau thawj version ntawm tus lej, 5.1 kernel tau siv, rau kev txheeb xyuas qhov uas muaj qhov sib txawv ntawm data_end и (const void*)ctx->data_end. Thaum lub sijhawm sau ntawv, kernel 5.3.1 tsis muaj qhov teeb meem no. Nws muaj peev xwm hais tias lub compiler tau nkag mus rau qhov sib txawv hauv zos txawv dua li thaj chaw. Kev coj ncaj ncees ntawm zaj dab neeg: Simplifying cov cai yuav pab tau thaum muaj ntau qhov zes.

Tom ntej no yog niaj hnub kuaj xyuas lub yeeb koob ntawm tus neeg txheeb xyuas; O MAX_CSUM_BYTES hauv qab.

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

Unfolding lub pob

Peb sau seqnum и acknum, teeb ACK (SYN twb teem):

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

Hloov TCP chaw nres nkoj, IP chaw nyob thiab MAC chaw nyob. Tus qauv tsev qiv ntawv tsis tuaj yeem nkag tau los ntawm XDP program, yog li memcpy() - ib qho macro uas zais 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);

Recalculation ntawm checksums

IPv4 thiab TCP checksums xav tau qhov sib ntxiv ntawm tag nrho 16-ntsis cov lus nyob rau hauv headers, thiab qhov luaj li cas ntawm headers yog sau rau hauv lawv, uas yog, tsis paub thaum compile lub sij hawm. Qhov no yog ib qho teeb meem vim hais tias tus neeg txheeb xyuas yuav tsis hla lub voj voog ib txwm mus rau qhov sib txawv ntawm ciam teb. Tab sis qhov loj ntawm headers yog txwv: mus txog 64 bytes txhua. Koj tuaj yeem ua ib lub voj nrog ib tus naj npawb ntawm iterations, uas tuaj yeem xaus ntxov.

Kuv nco ntsoov tias muaj RFC 1624 hais txog yuav ua li cas rov xam ib nrab ntawm cov checksum yog tias tsuas yog cov lus ruaj khov ntawm cov pob khoom raug hloov. Txawm li cas los xij, txoj kev tsis yog universal, thiab kev siv yuav nyuaj dua los tswj.

Checksum xam muaj nuj nqi:

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

Txawm tias size txheeb xyuas los ntawm kev hu xov tooj, qhov kev tawm thib ob yog qhov tsim nyog kom tus neeg txheeb xyuas tuaj yeem ua pov thawj qhov ua tiav ntawm lub voj.

Rau 32-ntsis cov lus, ib qho yooj yim version yog siv:

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

Tiag tiag rov xam cov checksums thiab xa cov pob ntawv rov qab:

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;

muaj nuj nqi carry() ua ib qho checksum los ntawm 32-ntsis suav ntawm 16-ntsis cov lus, raws li RFC 791.

TCP tes tuav pov thawj

Lub lim kom raug tsim kom muaj kev sib txuas nrog netcat, ploj lawm qhov kawg ACK, uas Linux tau teb nrog RST pob ntawv, txij li pawg network tsis tau txais SYN - nws tau hloov mus rau SYNACK thiab xa rov qab - thiab los ntawm OS qhov kev xav, pob ntawv tuaj txog uas tsis cuam tshuam rau qhib. kev sib txuas.

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

Nws yog ib qho tseem ceeb uas yuav tau soj ntsuam nrog cov ntawv thov puv thiab saib xyuas tcpdump rau xdp-remote vim, piv txwv li, hping3 tsis teb rau cov checksums tsis raug.

Los ntawm XDP qhov kev xav, qhov kev txheeb xyuas nws tus kheej yog qhov tsis tseem ceeb. Kev suav cov algorithm yog qhov tseem ceeb thiab yuav muaj kev cuam tshuam rau tus neeg tawm tsam sophisticated. Lub Linux ntsiav, piv txwv li, siv cryptographic SipHash, tab sis nws qhov kev siv rau XDP yog kom meej meej dhau ntawm cov kab lus no.

Qhia rau TODOs tshiab ntsig txog kev sib txuas lus sab nraud:

  • XDP program tsis tuaj yeem khaws cia cookie_seed (qhov zais cia ntawm cov ntsev) nyob rau hauv lub ntiaj teb no sib txawv, koj yuav tsum tau cia nyob rau hauv lub ntsiav, tus nqi ntawm uas yuav tsum tau hloov kho raws sij hawm los ntawm ib tug txhim khu kev qha generator.

  • Yog tias SYN ncuav qab zib sib tw hauv pob ntawv ACK, koj tsis tas yuav luam cov lus, tab sis nco ntsoov tus IP ntawm tus neeg siv khoom tau lees paub txhawm rau txhawm rau txuas ntxiv cov pob ntawv los ntawm nws.

Kev lees paub tus neeg siv khoom raug cai:

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

Cov log qhia tias daim tshev dhau (flags=0x2 - qhov no yog SYN, flags=0x10 yog 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

Txawm hais tias tsis muaj npe ntawm IPs uas tau lees paub, yuav tsis muaj kev tiv thaiv los ntawm SYN dej nyab nws tus kheej, tab sis ntawm no yog cov tshuaj tiv thaiv rau ACK dej nyab uas tau tsim los ntawm cov lus txib hauv qab no:

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

Cov ntaub ntawv log:

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

xaus

Qee lub sij hawm eBPF feem ntau thiab XDP tshwj xeeb tau nthuav tawm ntau dua li tus thawj tswj hwm cov cuab yeej tshaj li kev txhim kho platform. Qhov tseeb, XDP yog ib qho cuab yeej rau cuam tshuam nrog kev ua cov pob ntawv los ntawm cov ntsiav, thiab tsis yog lwm txoj hauv kev rau cov pawg pawg, xws li DPDK thiab lwm cov kev xaiv ntawm cov ntsiav bypass. Ntawm qhov tod tes, XDP tso cai rau koj los siv cov logic nyuaj, uas, ntxiv rau, nws yooj yim los hloov kho yam tsis muaj kev cuam tshuam hauv kev ua haujlwm. Tus neeg kuaj xyuas tsis tsim teeb meem loj; tus kheej, kuv yuav tsis kam lees qhov no rau qhov chaw ntawm userspace code.

Hauv ntu thib ob, yog tias lub ncauj lus nthuav dav, peb yuav ua kom tiav cov lus ntawm cov neeg tau txais kev pom zoo thiab kev txiav tawm, siv cov txee thiab sau cov khoom siv hluav taws xob siv los tswj cov lim.

Links:

Tau qhov twg los: www.hab.com

Ntxiv ib saib