A n kọ aabo lodi si awọn ikọlu DDoS lori XDP. Apakan iparun

Imọ-ẹrọ eXpress Data Path (XDP) ngbanilaaye sisẹ ijabọ laileto lati ṣee ṣe lori awọn atọkun Linux ṣaaju ki awọn apo-iwe to tẹ akopọ nẹtiwọọki ekuro. Ohun elo XDP - aabo lodi si awọn ikọlu DDoS (CloudFlare), awọn asẹ eka, ikojọpọ awọn iṣiro (Netflix). Awọn eto XDP jẹ ṣiṣe nipasẹ ẹrọ foju eBPF, nitorinaa wọn ni awọn ihamọ lori mejeeji koodu wọn ati awọn iṣẹ ekuro ti o wa da lori iru àlẹmọ.

Nkan naa jẹ ipinnu lati kun awọn ailagbara ti awọn ohun elo lọpọlọpọ lori XDP. Ni akọkọ, wọn pese koodu ti a ti ṣetan ti o kọja awọn ẹya XDP lẹsẹkẹsẹ: o ti pese sile fun ijẹrisi tabi rọrun pupọ lati fa awọn iṣoro. Nigbati o ba gbiyanju lati kọ koodu rẹ lati ibere, iwọ ko ni imọran kini lati ṣe pẹlu awọn aṣiṣe aṣoju. Ni ẹẹkeji, awọn ọna lati ṣe idanwo XDP ni agbegbe laisi VM ati ohun elo ko ni aabo, botilẹjẹpe wọn ni awọn ọfin tiwọn. Ọrọ naa jẹ ipinnu fun awọn olupilẹṣẹ ti o faramọ pẹlu Nẹtiwọọki ati Lainos ti o nifẹ si XDP ati eBPF.

Ni apakan yii, a yoo loye ni apejuwe bi a ṣe pejọ àlẹmọ XDP ati bii o ṣe le ṣe idanwo rẹ, lẹhinna a yoo kọ ẹya ti o rọrun ti ẹrọ kuki SYN ti a mọ daradara ni ipele processing apo. A kii yoo ṣẹda “akojọ funfun” sibẹsibẹ
wadi ibara, pa awọn ounka ati ki o ṣakoso awọn àlẹmọ - to àkọọlẹ.

A yoo kọ ni C - kii ṣe asiko, ṣugbọn o wulo. Gbogbo koodu wa lori GitHub nipasẹ ọna asopọ ni ipari ati pe o pin si awọn iṣe ni ibamu si awọn ipele ti a ṣalaye ninu nkan naa.

AlAIgBA. Ni akoko ti nkan yii, Emi yoo ṣe agbekalẹ ojutu kekere kan lati yago fun awọn ikọlu DDoS, nitori eyi jẹ iṣẹ-ṣiṣe ti o daju fun XDP ati agbegbe ti oye mi. Sibẹsibẹ, ibi-afẹde akọkọ ni lati ni oye imọ-ẹrọ; Koodu ikẹkọ ko ṣe iṣapeye ati fi awọn nuances diẹ silẹ.

XDP Brief Akopọ

Emi yoo ṣe ilana awọn aaye bọtini nikan ki o ma ṣe ṣe ẹda iwe-iwe ati awọn nkan ti o wa tẹlẹ.

Nitorinaa, koodu àlẹmọ ti kojọpọ sinu ekuro. Awọn apo-iwe ti nwọle ti kọja si àlẹmọ. Bi abajade, àlẹmọ gbọdọ ṣe ipinnu: fi apo-iwe naa sinu ekuro (XDP_PASS), soso silẹ (XDP_DROP) tabi firanṣẹ pada (XDP_TX). Ajọ le yi package pada, eyi jẹ otitọ paapaa fun XDP_TX. O tun le fagilee eto naa (XDP_ABORTED) ati tunto package, ṣugbọn eyi jẹ afọwọṣe assert(0) - fun n ṣatunṣe aṣiṣe.

Ẹrọ foju eBPF (filter Berkley Packet Filter) jẹ imọọmọ rọrun ki ekuro le ṣayẹwo pe koodu ko lupu ati pe ko ba iranti eniyan miiran jẹ. Awọn ihamọ akopọ ati awọn sọwedowo:

  • Yipo (ehin) ti wa ni idinamọ.
  • Akopọ wa fun data, ṣugbọn ko si awọn iṣẹ (gbogbo awọn iṣẹ C gbọdọ wa ni inline).
  • Awọn iraye si iranti ni ita akopọ ati ifipamọ apo jẹ eewọ.
  • Iwọn koodu naa ni opin, ṣugbọn ni iṣe eyi kii ṣe pataki pupọ.
  • Awọn ipe nikan si awọn iṣẹ ekuro pataki (awọn oluranlọwọ eBPF) ni a gba laaye.

Apẹrẹ ati fifi sori ẹrọ àlẹmọ dabi eyi:

  1. Koodu orisun (fun apẹẹrẹ kernel.c) ti ṣe akojọpọ si nkan (kernel.o) fun eBPF foju ẹrọ faaji. Ni Oṣu Kẹwa Ọdun 2019, ikojọpọ si eBPF jẹ atilẹyin nipasẹ Clang ati ṣe ileri ni GCC 10.1.
  2. Ti koodu nkan yii ba ni awọn ipe si awọn ẹya ekuro (fun apẹẹrẹ, awọn tabili ati awọn iṣiro), awọn ID wọn yoo rọpo nipasẹ awọn odo, eyiti o tumọ si pe iru koodu ko ṣee ṣe. Ṣaaju ikojọpọ sinu ekuro, o nilo lati rọpo awọn odo wọnyi pẹlu awọn ID ti awọn ohun kan pato ti a ṣẹda nipasẹ awọn ipe ekuro (ṣe asopọ koodu naa). O le ṣe eyi pẹlu awọn ohun elo ita, tabi o le kọ eto kan ti yoo sopọ ati fifuye àlẹmọ kan pato.
  3. Ekuro naa jẹrisi eto ti kojọpọ. Aisi awọn iyipo ati ikuna lati kọja apo-iwe ati awọn aala akopọ ti ṣayẹwo. Ti oludaniloju ko ba le fi mule pe koodu naa tọ, a kọ eto naa - o nilo lati ni anfani lati wu u.
  4. Lẹhin ijerisi aṣeyọri, ekuro n ṣajọ koodu ohun elo faaji eBPF sinu koodu ẹrọ fun faaji eto (ni akoko kan).
  5. Awọn eto so si awọn wiwo ati ki o bẹrẹ processing awọn apo-iwe.

Niwọn igba ti XDP n ṣiṣẹ ninu ekuro, n ṣatunṣe aṣiṣe ni a ṣe ni lilo awọn akọọlẹ itọpa ati, ni otitọ, awọn apo-iwe ti eto naa ṣe asẹ tabi ṣe ipilẹṣẹ. Sibẹsibẹ, eBPF ṣe idaniloju pe koodu ti a ṣe igbasilẹ wa ni aabo fun eto naa, nitorinaa o le ṣe idanwo pẹlu XDP taara lori Lainos agbegbe rẹ.

Ngbaradi ayika

Apejọ

Clang ko le ṣe agbekalẹ koodu ohun taara fun faaji eBPF, nitorinaa ilana naa ni awọn igbesẹ meji:

  1. Ṣajọ koodu C si bytecode LLVM (clang -emit-llvm).
  2. Ṣe iyipada bytecode si koodu ohun eBPF (llc -march=bpf -filetype=obj).

Nigbati o ba nkọ àlẹmọ, awọn faili meji kan pẹlu awọn iṣẹ iranlọwọ ati awọn macros yoo wulo lati awọn idanwo kernel. O ṣe pataki ki wọn baamu ẹya ekuro (KVER). Ṣe igbasilẹ wọn si 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 fun 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 ni ọna si awọn akọle kernel, ARCH - eto faaji. Awọn ọna ati awọn irinṣẹ le yatọ diẹ laarin awọn pinpin.

Apẹẹrẹ ti awọn iyatọ fun 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 so itọsọna kan pọ pẹlu awọn akọle oluranlọwọ ati ọpọlọpọ awọn ilana pẹlu awọn akọle kernel. Aami __KERNEL__ tumo si wipe UAPI (userspace API) afori ti wa ni telẹ fun ekuro koodu, niwon awọn àlẹmọ ti wa ni ṣiṣẹ ninu awọn ekuro.

Idaabobo akopọ le jẹ alaabo (-fno-stack-protector), nitori pe koodu eBPF ṣi n ṣayẹwo fun awọn irufin akopọ-ti-aala. O tọ lati tan awọn iṣapeye lẹsẹkẹsẹ, nitori iwọn ti eBPF bytecode ti ni opin.

Jẹ ki a bẹrẹ pẹlu àlẹmọ ti o kọja gbogbo awọn apo-iwe ti ko ṣe nkankan:

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

Egbe make gba xdp_filter.o. Nibo ni lati gbiyanju bayi?

igbeyewo imurasilẹ

Iduro gbọdọ ni awọn atọkun meji: lori eyiti àlẹmọ yoo wa ati lati awọn apo-iwe wo ni yoo firanṣẹ. Iwọnyi gbọdọ jẹ awọn ẹrọ Linux ti o ni kikun pẹlu awọn IP tiwọn lati le ṣayẹwo bii awọn ohun elo deede ṣe n ṣiṣẹ pẹlu àlẹmọ wa.

Awọn ẹrọ ti iru veth (Ethernet foju) dara fun wa: iwọnyi jẹ bata ti awọn atọkun nẹtiwọọki foju “ti sopọ” taara si ara wọn. O le ṣẹda wọn bi eleyi (ni apakan yii gbogbo awọn aṣẹ ip ti wa ni ti gbe jade lati root):

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

o ti wa ni xdp-remote и xdp-local - ẹrọ awọn orukọ. Lori xdp-local (192.0.2.1/24) a àlẹmọ yoo wa ni so, pẹlu xdp-remote (192.0.2.2/24) ti nwọle ijabọ yoo wa ni rán. Sibẹsibẹ, iṣoro kan wa: awọn atọkun wa lori ẹrọ kanna, ati Lainos kii yoo firanṣẹ ijabọ si ọkan ninu wọn nipasẹ ekeji. O le yanju yi pẹlu ẹtan awọn ofin iptables, ṣugbọn wọn yoo ni lati yi awọn idii pada, eyiti ko ṣe aibalẹ fun n ṣatunṣe aṣiṣe. O dara lati lo awọn aaye orukọ netiwọki (netn lẹyin eyi).

Aaye orukọ nẹtiwọọki kan ni akojọpọ awọn atọkun, awọn tabili ipa-ọna, ati awọn ofin NetFilter ti o ya sọtọ si awọn nkan ti o jọra ni awọn netisi miiran. Ilana kọọkan nṣiṣẹ ni aaye orukọ kan ati pe o ni iraye si awọn nkan ti awọn netisi yẹn. Nipa aiyipada, eto naa ni aaye orukọ nẹtiwọọki kan fun gbogbo awọn nkan, nitorinaa o le ṣiṣẹ ni Linux ati pe ko mọ nipa awọn neti.

Jẹ ki a ṣẹda aaye orukọ tuntun kan xdp-test ki o si gbe e si xdp-remote.

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

Lẹhinna ilana naa n ṣiṣẹ xdp-test, kii yoo "ri" xdp-local (yoo wa ni awọn netisi nipasẹ aiyipada) ati nigbati o ba fi apo-iwe ranṣẹ si 192.0.2.1 yoo kọja nipasẹ xdp-remotenitori ti o jẹ nikan ni wiwo lori 192.0.2.0/24 wiwọle si yi ilana. Eyi tun ṣiṣẹ ni ọna idakeji.

Nigbati o ba nlọ laarin awọn neti, wiwo naa lọ si isalẹ ki o padanu adirẹsi rẹ. Lati tunto ni wiwo ni netns, o nilo lati ṣiṣe ip ... ni aaye orukọ aṣẹ yii 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

Bi o ti le rii, eyi ko yatọ si eto naa xdp-local ninu aaye orukọ aiyipada:

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

Ti o ba sare tcpdump -tnevi xdp-local, o le rii pe awọn apo-iwe ti a firanṣẹ lati xdp-test, ti wa ni jišẹ si wiwo yi:

ip netns exec xdp-test   ping 192.0.2.1

O rọrun lati ṣe ifilọlẹ ikarahun kan sinu xdp-test. Ibi ipamọ naa ni iwe afọwọkọ ti o ṣe adaṣe ṣiṣẹ pẹlu iduro fun apẹẹrẹ, o le tunto iduro pẹlu aṣẹ naa sudo ./stand up ki o si pa a sudo ./stand down.

Itọpa

Ajọ naa ni nkan ṣe pẹlu ẹrọ bii eyi:

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

Bọtini -force nilo lati sopọ mọ eto tuntun ti omiiran ba ti sopọ mọ tẹlẹ. "Ko si iroyin ti o jẹ iroyin ti o dara" kii ṣe nipa aṣẹ yii, ipari jẹ iwọn didun ni eyikeyi ọran. tọkasi verbose iyan, ṣugbọn pẹlu rẹ ijabọ kan han lori iṣẹ ti oluṣeto koodu pẹlu atokọ apejọ kan:

Verifier analysis:

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

Yọọ eto naa kuro ni wiwo:

ip link set dev xdp-local xdp off

Ninu iwe afọwọkọ wọnyi ni awọn aṣẹ sudo ./stand attach и sudo ./stand detach.

Nipa sisopọ àlẹmọ, o le rii daju pe ping tẹsiwaju lati ṣiṣẹ, ṣugbọn eto naa n ṣiṣẹ bi? Jẹ ki a fi awọn akọọlẹ kun. Išẹ bpf_trace_printk() iru si printf(), ṣugbọn ṣe atilẹyin nikan to awọn ariyanjiyan mẹta miiran ju apẹrẹ, ati atokọ lopin ti awọn asọye. Makiro bpf_printk() simplifies ipe.

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

Ijade naa lọ si ikanni itọpa ekuro, eyiti o nilo lati mu ṣiṣẹ:

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

Wo okun ifiranṣẹ:

cat /sys/kernel/debug/tracing/trace_pipe

Mejeji ti awọn aṣẹ wọnyi ṣe ipe kan sudo ./stand log.

Ping yẹ ki o fa awọn ifiranṣẹ bii eyi:

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

Ti o ba wo ni pẹkipẹki ni iṣelọpọ ti oludarisi, iwọ yoo ṣe akiyesi awọn iṣiro ajeji:

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

Otitọ ni pe awọn eto eBPF ko ni apakan data kan, nitorinaa ọna kan ṣoṣo lati ṣe koodu okun ọna kika ni awọn ariyanjiyan lẹsẹkẹsẹ ti awọn aṣẹ VM:

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

Fun idi eyi, yokokoro o wu gidigidi bloats awọn Abajade koodu.

Fifiranṣẹ awọn apo-iwe XDP

Jẹ ki a yi àlẹmọ pada: jẹ ki o firanṣẹ gbogbo awọn apo-iwe ti nwọle pada. Eyi jẹ aṣiṣe lati oju wiwo nẹtiwọki, niwon o yoo jẹ dandan lati yi awọn adirẹsi pada ni awọn akọle, ṣugbọn nisisiyi iṣẹ ni opo jẹ pataki.

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

Ifilọlẹ tcpdump on xdp-remote. O yẹ ki o ṣafihan ijade kanna ati ti nwọle ICMP Echo Ibeere ati da duro fifi ICMP Echo Idahun han. Sugbon ko han. O wa ni pe fun iṣẹ XDP_TX ninu eto lori xdp-local jẹ patakito bata ni wiwo xdp-remote ìtòlẹ́sẹẹsẹ kan náà ni wọ́n yàn, kódà bí ó bá ṣófo, a sì gbé e dìde.

Bawo ni MO ṣe mọ eyi?

Tọpasẹ ọna ti package kan ninu ekuro Ilana awọn iṣẹlẹ perf ngbanilaaye, nipasẹ ọna, lilo ẹrọ foju kanna, iyẹn ni, eBPF ni a lo fun disassemblies pẹlu eBPF.

O gbọdọ ṣe rere lati inu ibi, nitori ko si ohun miiran lati ṣe e jade ninu rẹ.

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

Kini koodu 6?

$ errno 6
ENXIO 6 No such device or address

Išẹ veth_xdp_flush_bq() gba koodu aṣiṣe lati veth_xdp_xmit(), ibi ti wa nipasẹ ENXIO ki o si ri ọrọìwòye.

Jẹ ki a mu àlẹmọ ti o kere ju pada (XDP_PASS) ninu faili xdp_dummy.c, fi kun si Makefile, so o si xdp-remote:

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

Bayi tcpdump fihan ohun ti a reti:

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

Ti awọn ARP nikan ba han dipo, o nilo lati yọ awọn asẹ kuro (eyi ṣe sudo ./stand detach), jẹ ki lọ ping, lẹhinna ṣeto awọn asẹ ki o tun gbiyanju lẹẹkansi. Awọn isoro ni wipe awọn àlẹmọ XDP_TX wulo mejeeji lori ARP ati ti o ba ti akopọ
awọn aaye orukọ xdp-test ṣakoso lati "gbagbe" adirẹsi MAC 192.0.2.1, kii yoo ni anfani lati yanju IP yii.

Igbekalẹ iṣoro naa

Jẹ ki a lọ si iṣẹ-ṣiṣe ti a sọ: kọ ẹrọ kuki SYN kan lori XDP.

Ikun omi SYN jẹ ikọlu DDoS olokiki kan, pataki eyiti eyiti o jẹ atẹle. Nigba ti a asopọ ti wa ni idasilẹ (TCP bowo), awọn olupin gba a SYN, allocates oro fun ojo iwaju asopọ, dahun pẹlu kan SYNACK soso ati ki o duro fun ACK. Olukọni naa nfiranṣẹ awọn ẹgbẹẹgbẹrun awọn apo-iwe SYN fun iṣẹju-aaya lati awọn adirẹsi ti o ni ẹgbin lati ọdọ agbalejo kọọkan ni botnet-pupọ-ẹgbẹrun-lagbara. Olupin naa fi agbara mu lati pin awọn orisun lẹsẹkẹsẹ nigbati o ba de idii, ṣugbọn o tu wọn silẹ lẹhin igbati o tobi;

Ti o ko ba pin awọn orisun ti o da lori apo SYN, ṣugbọn dahun nikan pẹlu apo SYNACK kan, bawo ni olupin le ṣe loye pe apo ACK ti o de nigbamii n tọka si apo-iwe SYN ti ko fipamọ? Lẹhinna, ikọlu tun le ṣe agbekalẹ awọn ACK iro. Ojuami ti kuki SYN ni lati fi koodu sii sinu seqnum awọn paramita asopọ bi elile ti awọn adirẹsi, awọn ebute oko oju omi ati iyọ iyipada. Ti ACK ba ṣakoso lati de ṣaaju iyipada iyọ, o le ṣe iṣiro hash lẹẹkansi ki o ṣe afiwe pẹlu acknum. Forge acknum kolu ko le, niwon awọn iyọ pẹlu awọn ikoko, ati ki o yoo ko ni akoko lati to awọn nipasẹ o nitori kan lopin ikanni.

Kuki SYN ti pẹ ni imuse ninu ekuro Linux ati pe o le muu ṣiṣẹ laifọwọyi ti awọn SYN ba de ni iyara pupọ ati lọpọlọpọ.

Eto ẹkọ lori ọwọ ọwọ TCP

TCP n pese gbigbe data bi ṣiṣan ti awọn baiti, fun apẹẹrẹ, awọn ibeere HTTP ti wa ni gbigbe lori TCP. Awọn ṣiṣan ti wa ni gbigbe ni ona ni awọn apo-iwe. Gbogbo awọn apo-iwe TCP ni awọn asia ọgbọn ati awọn nọmba ọkọọkan 32-bit:

  • Apapo awọn asia ṣe ipinnu ipa ti package kan pato. Asia SYN tọka si pe eyi ni apo akọkọ ti olufiranṣẹ lori asopọ. Asia ACK tumọ si pe olufiranṣẹ ti gba gbogbo data asopọ titi de baiti naa acknum. Pakẹti le ni awọn asia pupọ ati pe a pe nipasẹ apapọ wọn, fun apẹẹrẹ, apo-iwe SYNACK kan.

  • Nọmba ọkọọkan (seqnum) ṣe alaye aiṣedeede ninu ṣiṣan data fun baiti akọkọ ti o tan kaakiri ninu apo-iwe yii. Fun apẹẹrẹ, ti o ba wa ninu apo akọkọ pẹlu X awọn baiti data nọmba yii jẹ N, ninu apo atẹle pẹlu data tuntun yoo jẹ N+X. Ni ibẹrẹ asopọ, ẹgbẹ kọọkan yan nọmba yii laileto.

  • Nọmba itẹwọgba (acknum) - aiṣedeede kanna bi seqnum, ṣugbọn kii ṣe ipinnu nọmba ti baiti ti a firanṣẹ, ṣugbọn nọmba ti baiti akọkọ lati ọdọ olugba, eyiti olufiranṣẹ ko rii.

Ni ibẹrẹ asopọ, awọn ẹgbẹ gbọdọ gba seqnum и acknum. Onibara firanṣẹ apo-iwe SYN kan pẹlu rẹ seqnum = X. Olupin naa dahun pẹlu apo SYNACK kan, nibiti o ti ṣe igbasilẹ rẹ seqnum = Y ati ṣiṣafihan acknum = X + 1. Onibara dahun si SYNACK pẹlu apo ACK kan, nibo seqnum = X + 1, acknum = Y + 1. Lẹhin eyi, gbigbe data gangan bẹrẹ.

Ti ẹlẹgbẹ ko ba jẹwọ gbigba ti apo-iwe naa, TCP tun firanṣẹ lẹhin igbati akoko kan.

Kini idi ti awọn kuki SYN ko nigbagbogbo lo?

Ni akọkọ, ti SYNACK tabi ACK ba sọnu, iwọ yoo ni lati duro fun fifiranṣẹ lẹẹkansi - iṣeto asopọ yoo fa fifalẹ. Ẹlẹẹkeji, ni SYN package - ati ki o nikan ni o! - nọmba kan ti awọn aṣayan ti wa ni gbigbe ti o ni ipa siwaju sisẹ ti asopọ. Laisi iranti awọn apo-iwe SYN ti nwọle, olupin naa kọju awọn aṣayan wọnyi; TCP le ṣiṣẹ ninu ọran yii, ṣugbọn o kere ju ni ipele ibẹrẹ didara asopọ yoo dinku.

Ni awọn ofin ti awọn idii, eto XDP gbọdọ ṣe atẹle naa:

  • dahun si SYN pẹlu SYNACK pẹlu kuki kan;
  • dahun si ACK pẹlu RST (ge asopọ);
  • da awọn apo-iwe ti o ku silẹ.

Pseudocode ti algoridimu pẹlu ṣiṣe itupalẹ package:

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

Ọkan (*) Awọn aaye nibiti o nilo lati ṣakoso ipo ti eto naa ni samisi - ni ipele akọkọ o le ṣe laisi wọn nipa mimuse imudaniwo TCP kan pẹlu iran ti kuki SYN kan bi seqnum kan.

Loju ese (**), nigba ti a ko ni tabili, a yoo foju awọn soso.

Imuwọ ọwọ TCP ṣiṣẹ

Ṣiṣayẹwo idii ati ijẹrisi koodu naa

A yoo nilo awọn ẹya akọsori nẹtiwọki: Ethernet (uapi/linux/if_ether.hIPv4 (uapi/linux/ip.hati TCP (uapi/linux/tcp.h). Emi ko le sopọ ni igbehin nitori awọn aṣiṣe ti o jọmọ atomic64_t, Mo ni lati daakọ awọn itumọ pataki sinu koodu naa.

Gbogbo awọn iṣẹ ti o ṣe afihan ni C fun kika gbọdọ wa ni itọka ni aaye ipe, niwọn igbati oludaniloju eBPF ninu ekuro ṣe idiwọ ẹhin, iyẹn ni, ni otitọ, awọn losiwajulosehin ati awọn ipe iṣẹ.

#define INTERNAL static __attribute__((always_inline))

Makiro LOG() disables titẹ sita ni Tu Kọ.

Awọn eto ni a conveyor ti awọn iṣẹ. Ọkọọkan gba apo-iwe kan ninu eyiti akọsori ipele ti o baamu ti ṣe afihan, fun apẹẹrẹ, process_ether() nireti pe yoo kun ether. Da lori awọn abajade ti itupalẹ aaye, iṣẹ naa le kọja apo-iwe naa si ipele ti o ga julọ. Abajade iṣẹ naa jẹ iṣẹ XDP. Ni bayi, awọn SYN ati awọn olutọju ACK kọja gbogbo awọn apo-iwe.

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

Mo fa ifojusi rẹ si awọn sọwedowo ti o samisi A ati B. Ti o ba sọ asọye A, eto naa yoo kọ, ṣugbọn aṣiṣe ijẹrisi yoo wa nigbati o ba nṣe ikojọpọ:

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!

Okun bọtini invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Awọn ọna ipaniyan wa nigbati baiti kẹtala lati ibẹrẹ ti ifipamọ wa ni ita apo. O nira lati ni oye lati atokọ wo laini ti a n sọrọ nipa rẹ, ṣugbọn nọmba itọnisọna wa (12) ati ikopa ti n ṣafihan awọn laini koodu orisun:

llvm-objdump -S xdp_filter.o | less

Ni idi eyi o tọka si ila

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

eyi ti o mu ki o han pe iṣoro naa jẹ ether. Yoo nigbagbogbo jẹ bi eyi.

Fesi si SYN

Ibi-afẹde ni ipele yii ni lati ṣe agbekalẹ apo-iwe SYNACK ti o pe pẹlu ti o wa titi seqnum, eyi ti yoo rọpo ni ojo iwaju nipasẹ kuki SYN. Gbogbo awọn ayipada waye ninu process_tcp_syn() ati awọn agbegbe agbegbe.

Ijerisi idii

Ni iyalẹnu, eyi ni laini iyalẹnu julọ, tabi dipo, asọye si rẹ:

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

Nigbati o ba nkọ ẹya akọkọ ti koodu naa, a lo ekuro 5.1, fun ijẹrisi eyiti iyatọ wa laarin data_end и (const void*)ctx->data_end. Ni akoko kikọ, kernel 5.3.1 ko ni iṣoro yii. O ṣee ṣe pe olupilẹṣẹ n wọle si oniyipada agbegbe yatọ si aaye kan. Iwa ti itan naa: nigbati itẹ-ẹiyẹ ba tobi, irọrun koodu le ṣe iranlọwọ.

Nigbamii ni awọn sọwedowo gigun baraku fun ogo ti oludaniloju; O MAX_CSUM_BYTES ni isalẹ.

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 package

Pon si seqnum и acknum, ṣeto ACK (SYN ti ṣeto tẹlẹ):

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

Yipada awọn ebute oko oju omi TCP, adiresi IP ati awọn adirẹsi MAC. Awọn boṣewa ìkàwé ni ko wiwọle lati XDP eto, rẹ memcpy() - Makiro ti o tọju awọn intrinsics Clang.

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

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

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

Recalculation ti checksums

IPv4 ati TCP checksums nilo afikun gbogbo awọn ọrọ 16-bit ninu awọn akọle, ati iwọn awọn akọle ti kọ sinu wọn, iyẹn ni, aimọ ni akoko akopọ. Eyi jẹ iṣoro nitori oludaniloju kii yoo fo lupu deede si oniyipada ala. Ṣugbọn awọn iwọn ti awọn akọle ti wa ni opin: soke si 64 baiti kọọkan. O le ṣe lupu pẹlu nọmba ti o wa titi ti awọn atunwi, eyiti o le pari ni kutukutu.

Mo ṣe akiyesi pe o wa RFC 1624 nipa bii o ṣe le ṣe atunto checksum apakan ti awọn ọrọ ti o wa titi ti awọn idii nikan ba yipada. Sibẹsibẹ, ọna naa kii ṣe gbogbo agbaye, ati imuse yoo nira sii lati ṣetọju.

Iṣẹ iṣiro 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;
}

Biotilejepe size jẹrisi nipasẹ koodu ipe, ipo ijade keji jẹ pataki ki oludaniloju le jẹri ipari ti lupu naa.

Fun awọn ọrọ 32-bit, ẹya ti o rọrun ti wa ni imuse:

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

Ni otitọ ṣe atunto awọn iwe-iyẹwo ati fifiranṣẹ apo-iwe naa pada:

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;

Išẹ carry() ṣe checksum lati apao 32-bit ti awọn ọrọ 16-bit, ni ibamu si RFC 791.

TCP ìmúdájú

Àlẹmọ tọ fi idi asopọ kan mulẹ pẹlu netcat, ti o padanu ACK ti o kẹhin, eyiti Linux ṣe idahun pẹlu apo-iwe RST kan, niwon akopọ nẹtiwọki ko gba SYN - o ti yipada si SYNACK ati firanṣẹ pada - ati lati oju-ọna OS, apo kan ti de ti ko ni ibatan si ṣiṣi. awọn isopọ.

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

O ṣe pataki lati ṣayẹwo pẹlu awọn ohun elo kikun ati akiyesi tcpdump on xdp-remote nitori, fun apẹẹrẹ, hping3 ko dahun si awọn ayẹwo ayẹwo ti ko tọ.

Lati oju wiwo XDP, ijẹrisi funrararẹ jẹ ohun kekere. Alugoridimu iṣiro jẹ alakoko ati pe o le jẹ ipalara si ikọlu ti o fafa. Ekuro Lainos, fun apẹẹrẹ, nlo SipHash cryptographic, ṣugbọn imuse rẹ fun XDP jẹ kedere kọja ipari ti nkan yii.

Ti ṣe ifilọlẹ fun awọn TODO tuntun ti o ni ibatan si ibaraẹnisọrọ ita:

  • Eto XDP ko le fipamọ cookie_seed (apakan ikoko ti iyọ) ni iyipada agbaye, o nilo ibi ipamọ ninu ekuro, iye ti eyi ti yoo ṣe imudojuiwọn lorekore lati ọdọ olupilẹṣẹ ti o gbẹkẹle.

  • Ti kuki SYN ba baamu ninu apo ACK, iwọ ko nilo lati tẹ ifiranṣẹ kan sita, ṣugbọn ranti IP ti alabara ti o rii daju lati tẹsiwaju lati kọja awọn apo-iwe lati ọdọ rẹ.

Ijẹrisi alabara ti o tọ:

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

Awọn akọọlẹ fihan pe ayẹwo ti kọja (flags=0x2 - Eyi ni SYN, flags=0x10 jẹ 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

Lakoko ti ko si atokọ ti awọn IP ti o jẹrisi, kii yoo ni aabo lati iṣan omi SYN funrararẹ, ṣugbọn eyi ni esi si ikun omi ACK ti a ṣe ifilọlẹ nipasẹ aṣẹ atẹle:

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

Awọn titẹ sii wọle:

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

ipari

Nigba miiran eBPF ni gbogbogbo ati XDP ni pataki ni a gbekalẹ diẹ sii bi ohun elo oluṣakoso ilọsiwaju ju bii pẹpẹ ti idagbasoke. Lootọ, XDP jẹ ohun elo fun kikọlu pẹlu sisẹ awọn apo-iwe nipasẹ ekuro, kii ṣe yiyan si akopọ ekuro, bii DPDK ati awọn aṣayan fori ekuro miiran. Ni apa keji, XDP ngbanilaaye lati ṣe ilana ọgbọn ti o nira pupọ, eyiti, pẹlupẹlu, rọrun lati ṣe imudojuiwọn laisi idilọwọ ni sisẹ ijabọ. Oludaniloju ko ṣẹda awọn iṣoro nla tikalararẹ, Emi kii yoo kọ eyi fun awọn apakan ti koodu olumulo.

Ni apakan keji, ti koko-ọrọ ba jẹ iyanilenu, a yoo pari tabili ti awọn alabara ti o rii daju ati awọn asopọ, ṣe awọn iṣiro ati kọ ohun elo aaye olumulo kan lati ṣakoso àlẹmọ naa.

Awọn ọna asopọ:

orisun: www.habr.com

Fi ọrọìwòye kun