E mafai ai e le tekinolosi o le eXpress Data Path (XDP) ona fa'agasolo fa'afuase'i fefa'ataua'iga i luga o feso'ota'iga Linux до того, как пакеты поступят в сетевой стек ядра. Применение XDP — защита от DDoS-атак (CloudFlare), сложные фильтры, сбор статистики (Netflix). Программы XDP исполняются виртуальной машиной eBPF, поэтому имеют ограничения как на свой код, так и на доступные функции ядра в зависимости от типа фильтра.
Статья призвана восполнить недостатки многочисленных материалов по XDP. Во-первых, в них дается готовый код, который сразу обходит особенности XDP: подготовлен для верификации или слишком прост, чтобы вызвать проблемы. При попытке потом написать свой код с нуля нет понимания, что делать с характерными ошибками. Во-вторых, не освещаются способы локально тестировать XDP без ВМ и «железа», при том, что у них свои «подводные камни». Текст рассчитан на программистов, знакомых с сетями и Linux, которым интересен XDP и eBPF.
I lenei vaega, o le a tatou malamalama auiliili pe faʻafefea ona faʻapipiʻi le XDP faamama ma pe faʻapefea ona faʻataʻitaʻiina, ona matou tusia lea o se faʻamatalaga faigofie o le lauiloa SYN kuki masini i le tulaga o le gaosiga o pusa. Matou te le faia se "lisi paʻepaʻe" i le taimi nei
fa'amaonia tagata fa'atau, tausia fa'atau ma pulea le faamama - lava ogalaau.
O le a matou tusia i le C - e le o se mea masani, ae e aoga. O loʻo maua uma tulafono ile GitHub e ala ile fesoʻotaʻiga ile faʻaiʻuga ma vaevaeina i tuʻufaʻatasiga e tusa ai ma laasaga o loʻo faʻamatalaina ile tusiga.
Faʻasalaga. I le gasologa o lenei tusiga, o le a ou atiina ae se tamaʻi fofo e puipuia ai osofaʻiga DDoS, aua o se galuega moni lenei mo XDP ma laʻu vaega o tomai. Ae ui i lea, o le sini autu o le malamalama i tekinolosi e le o se taʻiala i le fatuina o puipuiga ua saunia. Ole tulafono ole a'oa'oga e le'o fa'asilisiliina ma fa'ate'aina nisi o nuances.
XDP Aotelega Aotelega
O le a ou faʻamatalaina naʻo manatu autu ina ia aua neʻi faʻaluaina faʻamaumauga ma tala o loʻo iai.
O lea la, ua utaina le code faamama i totonu o le fatu. O afifi o loʻo oʻo mai e pasi atu i le faamama. O se taunuuga, e tatau i le faamama ona faia se faaiuga: pasi le afifi i totonu o le fatu (XDP_PASS), tu'u le afifi (XDP_DROP) pe toe lafo atu (XDP_TX). E mafai e le faamama ona suia le afifi, e matua moni lava mo XDP_TX. E mafai fo'i ona e fa'amuta le polokalame (XDP_ABORTED) ma toe setiina le afifi, ae tutusa lea assert(0) - mo le debugging.
O le eBPF (extended Berkley Packet Filter) masini komepiuta e fa'afaigofieina ma le loto i ai ina ia mafai e le fatu ona siaki e le o fa'afefe le code ma e le fa'aleagaina ai mafaufauga o isi tagata. Fa'aopoopo fa'atapula'a ma siaki:
- E fa'asa ni fa'ailoga (i tua).
- O loʻo i ai se faaputuga mo faʻamatalaga, ae leai ni galuega (o galuega uma C e tatau ona faʻapipiʻi).
- E fa'asaina le fa'aogaina o mea e manatua i fafo atu o le fa'aputuga ma fa'aputuga.
- Ole tele ole code e fa'atapula'a, ae i le fa'atinoga e le taua tele.
- E na'o le vala'au i galuega fa'apitoa (eBPF fesoasoani) e fa'atagaina.
O le mamanuina ma le faʻapipiʻiina o se faamama e pei o lenei:
- Fa'ailoga puna (eg
kernel.c) ua tuufaatasia i mea (kernel.o) mo le fausaga masini masini eBPF. E oʻo mai ia Oketopa 2019, o le tuʻufaʻatasia i le eBPF e lagolagoina e Clang ma folafola i le GCC 10.1. - Afai o lenei mea fa'ailoga o lo'o i ai vala'au i fatu fausaga (mo se fa'ata'ita'iga, laulau ma fa'atau), o latou ID e suia i zeros, o lona uiga e le mafai ona fa'atinoina ia code. Aʻo leʻi utaina i totonu o le fatu, e tatau ona e suia nei zeros i ID o mea faʻapitoa na faia e ala i le kernel calls (fesoʻotaʻi le code). E mafai ona e faia lenei mea i mea faʻaoga i fafo, pe mafai foi ona e tusia se polokalama e fesoʻotaʻi ma utaina se faamama patino.
- E fa'amaonia e le fatu le polokalame ua utaina. O le leai o ni ta'amilosaga ma le le mafai ona sili atu i tuaoi o pusa ma faaputuga ua siaki. Afai e le mafai e le faʻamaonia ona faʻamaonia e saʻo le code, ua teena le polokalame - e tatau ona e faʻamalieina o ia.
- A maeʻa le faʻamaoniga manuia, e faʻapipiʻi e le fatu le faʻailoga mea faʻataʻitaʻi eBPF i totonu o le masini faʻailoga mo le faʻaogaina o le faiga (naʻo le taimi).
- O lo'o fa'apipi'i le polokalame i le fa'aoga ma amata ai ona fa'agasolo pepa.
Поскольку XDP работает в ядре, отладка ведется по логам трассировки и, собственно, по пакетам, которые программа фильтрует или генерирует. Тем не менее, eBPF обеспечивает безопасность загруженного кода для системы, поэтому экспериментировать с XDP можно прямо на локальном Linux.
Saunia o le Siosiomaga
Fono Aoao
E le mafai e Clang ona tuʻuina saʻo le faʻailoga mea mo le fausaga o le eBPF, o lona uiga o le faagasologa e lua laasaga:
- Fa'aopoopo le C code ile LLVM bytecode (
clang -emit-llvm). - Suia le bytecode i le eBPF mea faitino (
llc -march=bpf -filetype=obj).
Pe a tusia se faamama, o le a aoga ni faila faila ma galuega fesoasoani ma macros . E taua le fetaui ma le kernel version (KVER). La'u i lalo i 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 BASEMakefile для Arch Linux (ядро 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 ./*.oKDIR o loʻo i ai le ala i ulutala fatu, ARCH - fausaga fausaga. Auala ma meafaigaluega e mafai ona eseese teisi i le va o tufatufaga.
Пример отличий для Debian 10 (ядро 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 fa'afeso'ota'i se lisi fa'atasi ma fa'auluuluga fesoasoani ma nisi fa'atonuga fa'atasi ma fa'auluulu fatu. Faailoga __KERNEL__ o lona uiga o ulutala UAPI (userspace API) ua faʻamatalaina mo le kernel code, talu ai o le faamama o loʻo faʻatinoina i le fatu.
E mafai ona fa'aletonu le puipuiga o fa'aputuga (-fno-stack-protector), ona o le eBPF code verifier o loʻo siaki pea mo le faʻaputuina o soliga i fafo atu o tuaoi. E aoga le faʻaogaina vave o suʻesuʻega, aua o le tele o le eBPF bytecode e faʻatapulaʻaina.
Tatou amata i se faamama e pasi uma pepa ae leai se mea e faia:
#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";au make aoina xdp_filter.o. O fea e taumafai ai nei?
nofoa su'ega
Стенд должен включать два интерфейса: на котором будет фильтр и с которого будут отправляться пакеты. Это должны быть полноценные устройства Linux со своими IP, чтобы проверять, как обычные приложения работают с нашим фильтром.
O masini o le veth (virtual Ethernet) e fetaui lelei mo i tatou: o se paga o fesoʻotaʻiga fesoʻotaʻiga vavalalata "fesoʻotaʻi" tuusaʻo i le tasi ma le isi. E mafai ona e faia i latou e pei o lenei (i lenei vaega o poloaiga uma ip e faia mai root):
ip link add xdp-remote type veth peer name xdp-localo xdp-remote и xdp-local — igoa o masini. luga xdp-local (192.0.2.1/24) o le a faʻapipiʻi se faamama, ma xdp-remote (192.0.2.2/24) будет отправляться входящий трафик. Однако есть проблема: интерфейсы находятся на одной машине, и Linux не будет слать трафик на один из них через другой. Можно решать это хитрыми правилами iptables, ae o le a tatau ona latou suia afifi, lea e le faigofie mo le debugging. E sili atu le fa'aogaina o igoa ole upegatafa'ilagi (e mulimuli ane netns).
Сетевое пространство имен содержит набор интерфейсов, таблиц маршрутизации и правил NetFilter, изолированные от аналогичных объектов в других netns. Каждый процесс работает в каком-то пространстве имен, и ему доступны только объекты этого netns. По умолчанию в системе единственное сетевое пространство имен для всех объектов, поэтому можно работать в Linux и не знать про netns.
Se'i o tatou faia se igoa avanoa fou xdp-test ma ave i ai xdp-remote.
ip netns add xdp-test
ip link set dev xdp-remote netns xdp-testOna alu lea o le faagasologa xdp-test, o le a le "vaai" xdp-local (o le a tumau i netns e ala i le faaletonu) ma pe a lafoina se afifi i le 192.0.2.1 o le a pasi xdp-remoteaua e na'o le pau lea o le fa'aoga ile 192.0.2.0/24 e mafai ona maua i lenei faiga. E galue foi lea i le itu faafeagai.
A feoai i le va o upega, e alu i lalo le fa'aoga ma leiloa lona tuatusi. Ina ia faʻapipiʻi le atinaʻe i netns, e tatau ona e tamoe ip ... i le igoa lea o le poloaiga 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 upE pei ona e vaʻai, e leai se eseesega mai le faʻatulagaga xdp-local i le igoa avanoa:
ip address add 192.0.2.1/24 dev xdp-local
ip link set xdp-local upAfai e te tamoe tcpdump -tnevi xdp-local, e mafai ona e vaʻaia o afifi na lafo mai xdp-test, e tu'uina atu i lenei fa'aoga:
ip netns exec xdp-test ping 192.0.2.1E faigofie ona lafo se atigi i totonu xdp-test. O le fale teu oloa o loʻo i ai se faʻamaumauga e faʻaautomatika ai le galue ma le tulaga, mo se faʻataʻitaʻiga, e mafai ona e faʻatulagaina le tulaga ma le poloaiga sudo ./stand up ma tape ese sudo ./stand down.
Su'e
O le faamama e fesoʻotaʻi ma le masini e pei o lenei:
ip -force link set dev xdp-local xdp object xdp_filter.o verboseKi -force mana'omia e fa'afeso'ota'i se polokalame fou pe afai ua uma ona feso'ota'i se isi. "Leai se tala o se tala lelei" e le o faatatau i lenei poloaiga, o le faaiuga e tele i soo se tulaga. faailoa mai verbose faitalia, ae faʻatasi ai ma se lipoti o loʻo faʻaalia i luga o le galuega a le code verifier ma se lisi faʻapotopotoga:
Verifier analysis:
0: (b7) r0 = 2
1: (95) exitTatala le feso'ota'iga mai le fa'aoga:
ip link set dev xdp-local xdp offI totonu o tusitusiga o poloaiga ia sudo ./stand attach и sudo ./stand detach.
E ala i le faʻapipiʻiina o se faamama, e mafai ona e mautinoa lena mea ping fa'aauau pea ona tamo'e, ae e aoga le polokalame? Tatou faaopoopo i ai ogalaau. Galuega tutusa ma printf(), ae na'o le lagolagoina o finauga e tolu e ese mai i le mamanu, ma se lisi fa'atapula'a o fa'amatalaga. Macro bpf_printk() faafaigofie le valaau.
SEC("prog")
int xdp_main(struct xdp_md* ctx) {
+ bpf_printk("got packet: %pn", ctx);
return XDP_PASS;
}O le gaioiga e alu i le kernel trace channel, lea e manaʻomia ona mafai:
echo -n 1 | sudo tee /sys/kernel/debug/tracing/options/trace_printkVa'ai fe'au fe'au:
cat /sys/kernel/debug/tracing/trace_pipeO nei poloaiga uma e lua e faia se valaau sudo ./stand log.
O le ping ua tatau nei ona fa'aosoina fe'au fa'apenei:
<...>-110930 [004] ..s1 78803.244967: 0: got packet: 00000000ac510377Afai e te vaʻavaʻai totoʻa i le gaioiga a le tagata faʻamaonia, o le ae matauina faʻatusatusaga uiga ese:
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
<...>O le mea moni o polokalame eBPF e leai se vaega o faʻamatalaga, o lea na o le pau lava le auala e faʻapipiʻi ai se manoa faʻasologa o faʻamatalaga vave o poloaiga VM:
$ python -c "import binascii; print(bytes(reversed(binascii.unhexlify('0a7025203a74656b63617020746f67'))))"
b'got packet: %pn'Mo lenei mafua'aga, o le debug output e matua fa'apupulaina ai le code e maua mai ai.
Tuuina atu XDP Paketi
Se'i o tatou sui le faamama: tu'u atu e toe fa'afo'i uma pepa o lo'o o'o mai. E le sa'o lenei mea mai se va'aiga feso'otaiga, talu ai e tatau ona suia tuatusi i ulutala, ae o le taimi nei e taua le galuega i le mataupu faavae.
bpf_printk("got packet: %pn", ctx);
- return XDP_PASS;
+ return XDP_TX;
}Fa'alauiloa tcpdump i xdp-remote. E tatau ona faʻaalia tutusa le alu atu ma le ulufale mai ICMP Echo Request ma taofi le faʻaalia o le ICMP Echo Reply. Ae e le o faaalia. E foliga mai mo galuega XDP_TX i le polokalame i luga xdp-local i le fa'aoga paga xdp-remote sa tofia foi se polokalama, e tusa lava pe gaogao, ma sa ia faatuina.
Na faapefea ona ou iloa lenei mea?
O le faʻaogaina o mea faʻapitoa e mafai ai, i le ala, faʻaaogaina le masini komepiuta tutusa, o lona uiga, o le eBPF e faʻaaogaina mo faʻalavelave faʻatasi ma le eBPF.
E tatau ona e faia le lelei mai le leaga, aua e leai se isi mea e mafai ai.
$ 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])
<...>O le a le code 6?
$ errno 6
ENXIO 6 No such device or addressgaluega tauave veth_xdp_flush_bq() maua se code sese mai veth_xdp_xmit(), o fea e su'e ai ENXIO ma su'e le fa'amatalaga.
Se'i o tatou toe fa'afo'i le faamama aupito maualalo (XDP_PASS) i faila xdp_dummy.c, fa'aopoopo i le Makefile, fusifusia i xdp-remote:
ip netns exec remote
ip link set dev int xdp object dummy.oO lenei tcpdump faʻaalia le mea o loʻo faʻamoemoeina:
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 64Afai e naʻo ARP o loʻo faʻaalia, e tatau ona e aveese le filiga (faʻapea sudo ./stand detach), tu'u ping, ona seti lea o filiga ma toe taumafai. O le faafitauli o le faamama XDP_TX aoga uma i luga o le ARP ma pe afai o le faaputuga
igoa avanoa xdp-test mafai ona "galo" le tuatusi MAC 192.0.2.1, o le a le mafai ona foia lenei IP.
Fausiaina o le faʻafitauli
Se'i o tatou aga'i i le galuega ua ta'ua: tusi se masini kuki SYN ile XDP.
SYN lolo o loʻo tumau pea se osofaʻiga DDoS lauiloa, o lona uiga e faʻapea. Pe a faʻatūina se fesoʻotaʻiga (TCP lulu lima), e maua e le 'auʻaunaga se SYN, tuʻufaʻatasia punaoa mo le fesoʻotaʻiga i le lumanaʻi, tali atu i se pusa SYNACK ma faʻatali mo se ACK. O le tagata osofaʻi e naʻo le auina atu o le faitau afe o SYN packet i le sekone mai tuatusi faʻasese mai tagata taʻitasi i totonu o le tele-afe-malosi botnet. E faʻamalosia le 'auʻaunaga e tuʻuina atu punaoa i le taimi lava e oʻo mai ai le afifi, ae faʻamalolo i latou pe a maeʻa le tele o le taimi e faʻagata ai, o le manatua poʻo le faʻatapulaʻaina ua vaivai, o fesoʻotaʻiga fou e le taliaina, ma ua le maua le auaunaga;
Afai e te le faʻasoaina punaoa e faʻavae i luga o le SYN packet, ae naʻo le tali atu i se SYNACK packet, faʻafefea ona malamalama le server o le ACK packet na taunuu mulimuli ane e faasino i se SYN packet e leʻi faʻasaoina? A uma mea uma, e mafai foi e se tagata osofaʻi ona faʻatupuina ACKs pepelo. O le uiga o le kuki SYN o le fa'ailoga i totonu seqnum feso'ota'iga tapula'a e pei o se hash o tuatusi, ports ma suiga masima. Afai na mafai ona taunuu le ACK aʻo leʻi suia le masima, e mafai ona e toe faʻatusatusa le hash ma faʻatusatusa i ai acknum. Forge acknum e le mafai e le osofaʻi, talu ai o le masima e aofia ai le mealilo, ma o le a le maua se taimi e faʻavasega ai ona o le faʻatapulaʻaina o le auala.
SYN cookie давно реализован в ядре Linux и даже может автоматически включаться, если SYN приходят слишком быстро и массово.
Polokalama a'oa'oga ile TCP lululima
TCP e tuʻuina atu faʻamatalaga faʻamatalaga o se vaitafe o bytes, mo se faʻataʻitaʻiga, o talosaga HTTP o loʻo tuʻuina atu i luga ole TCP. O le alia o lo'o fa'asalalauina i ni fasipepa i totonu o afifi. O pusa TCP uma e iai fu'a talafeagai ma numera fa'asologa 32-bit:
O le tuʻufaʻatasia o fuʻa e fuafua ai le matafaioi a se afifi faapitoa. O le fu'a a le SYN o lo'o ta'u mai ai o le pepa muamua lea a le tagata e lafo i luga o le feso'ota'iga. O le fu'a a le ACK o lona uiga ua maua uma e le tagata na auina atu faʻamatalaga fesoʻotaʻiga e oʻo atu i le byte
acknum. E mafai ona i ai ni fu'a i se afifi ma e ta'ua i le latou tuufaatasiga, mo se fa'ata'ita'iga, o le SYNACK packet.Numera fa'asologa (seqnum) o lo'o fa'amaoti mai ai le fa'asili i le fa'asologa o fa'amaumauga mo le paita muamua o lo'o tu'uina atu i totonu o lenei afifi. Mo se faʻataʻitaʻiga, afai i le pepa muamua ma X bytes o faʻamaumauga o lenei numera o le N, i le isi afifi ma faʻamatalaga fou o le N + X. I le amataga o le fesoʻotaʻiga, e filifilia e itu taʻitasi lenei numera faʻafuaseʻi.
Fa'ailoa numera (acknum) - tutusa tutusa ma seqnum, ae e le iloa ai le numera o le byte o loʻo tuʻuina atu, ae o le numera o le paita muamua mai le tagata na mauaina, lea e leʻi vaʻaia e le tagata na auina atu.
I le amataga o le sootaga, e tatau i itu auai ona malilie seqnum и acknum. E lafo e le kalani se pepa SYN ma lana seqnum = X. E tali mai le 'au'aunaga i se pusa SYNACK, lea e fa'amaumau ai seqnum = Y ma fa'aalia acknum = X + 1. E tali atu le kalani i le SYNACK ma se pusa ACK, o fea seqnum = X + 1, acknum = Y + 1. A maeʻa lenei mea, e amata le faʻaliliuga moni o faʻamatalaga.
Afai e le faailoa mai e le tupulaga le mauaina o le afifi, e toe auina atu e le TCP pe a uma le taimi.
Aisea e le fa'aaogaina ai i taimi uma kuki SYN?
Muamua, afai e leiloa le SYNACK poʻo le ACK, e tatau ona e faʻatali mo le toe lafoina - o le seti fesoʻotaʻiga o le a faʻagesegese. Lona lua, i le SYN package - ma naʻo totonu! - o le tele o filifiliga o loʻo tuʻuina atu e aʻafia ai le faʻaogaina atili o le fesoʻotaʻiga. A aunoa ma le manatuaina o pusa SYN o loʻo oʻo mai, o le a le amanaʻia e le 'auʻaunaga nei filifiliga; TCP e mafai ona galue i lenei tulaga, ae o le mea sili i le tulaga muamua o le a faʻaitiitia le lelei o le fesoʻotaʻiga.
Mai se vaaiga faʻapipiʻi, e tatau i se polokalame XDP ona faia mea nei:
- tali ile SYN ile SYNACK ile kuki;
- tali atu ile ACK ile RST (motu'ese);
- lafoa'i pepa o totoe.
Pseudocode o le algorithm faʻatasi ai ma le faʻavasegaina o pusa:
Если это не Ethernet,
пропустить пакет.
Если это не IPv4,
пропустить пакет.
Если адрес в таблице проверенных, (*)
уменьшить счетчик оставшихся проверок,
пропустить пакет.
Если это не TCP,
сбросить пакет. (**)
Если это SYN,
ответить SYN-ACK с cookie.
Если это ACK,
если в acknum лежит не cookie,
сбросить пакет.
Занести в таблицу адрес с N оставшихся проверок. (*)
Ответить RST. (**)
В остальных случаях сбросить пакет.Tasi (*) o mea e te manaʻomia e pulea ai le tulaga o le faiga o loʻo faʻailogaina - i le laasaga muamua e mafai ona e faia e aunoa ma i latou i le na o le faʻatinoina o le TCP faʻatalofa ma le faʻatupuina o se kuki SYN e fai ma seqnum.
I luga o le nofoaga (**), a'o leai se matou laulau, o le a matou fa'ase'e le taga.
Fa'atinoina o le lululima TCP
Fa'asalalau le afifi ma fa'amaonia le code
Matou te manaʻomia faʻapipiʻi ulutala fesoʻotaʻiga: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) ma le TCP (uapi/linux/tcp.h). Sa le mafai ona ou faʻafesoʻotaʻi le mea mulimuli ona o mea sese e fesoʻotaʻi ma atomic64_t, Sa tatau ona ou kopiina faʻamatalaga talafeagai i totonu o le code.
O galuega uma o loʻo faʻamamafaina i le C mo le mafai ona faitau e tatau ona faʻapipiʻi i le tulaga o le valaau, talu ai o le eBPF verifier i totonu o le fatu e faʻasa ai le toe foʻi i tua, o lona uiga, o le mea moni, matasele ma valaau galuega.
#define INTERNAL static __attribute__((always_inline))Macro LOG() fa'agata le lomitusi i le fa'asa'olotoga.
O le polokalame o se conveyor o galuega tauave. E maua e ta'itasi se taga o lo'o fa'amanino ai le ulutala tulaga tutusa, mo se fa'ata'ita'iga, process_ether() e faamoemoe e faatumuina ether. Faʻavae i luga o faʻaiʻuga o suʻesuʻega fanua, e mafai e le galuega ona pasi atu le pusa i se tulaga maualuga. O le taunuuga o le galuega o le XDP gaioiga. Mo le taimi nei, o le SYN ma le ACK o loʻo faʻaaogaina e pasi uma pepa.
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);
}Ou te tosina atu lou mafaufau i siaki ua faailogaina A ma B. Afai e te faʻaalia A, o le a fausia le polokalama, ae o le ai ai se faʻamaoniga sese pe a faʻapipiʻi:
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!manoa ki invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): O loʻo i ai auala faʻataunuʻu pe a o le sefulutolu byte mai le amataga o le pa puipui o loʻo i fafo atu o le afifi. E faigata ona malamalama mai le lisi o le laina lea o loʻo tatou talanoa ai, ae o loʻo i ai se faʻatonuga numera (12) ma se faʻalavelave faʻaalia e faʻaalia ai laina o le faʻailoga autu:
llvm-objdump -S xdp_filter.o | lessI lenei tulaga e faasino i le laina
LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));lea e manino ai o le faafitauli ether. E fa'apenei i taimi uma.
Tali ia SYN
Ole fa'amoemoe ile la'asaga lea ole fa'atupuina ose SYNACK sa'o ma se fa'amautu seqnum, lea o le a suia i le lumanaʻi e le kuki SYN. O suiga uma e tupu ile process_tcp_syn() ma nofoaga lata ane.
Fa'amaoniga o afifi
O le mea e ese ai, o le laina sili lea ona mataʻina, pe sili atu, o le faʻamatalaga i ai:
/* Required to verify checksum calculation */
const void* data_end = (const void*)ctx->data_end;A o tusia le uluai kopi o le code, sa faʻaaogaina le 5.1 kernel, mo le faʻamaonia o loʻo i ai se eseesega i le va. data_end и (const void*)ctx->data_end. I le taimi o le tusitusi, kernel 5.3.1 e leʻi iai lenei faʻafitauli. E ono mafai e le tagata fa'apipi'i ona fa'aogaina se suiga fa'apitonu'u e ese mai i se fanua. Amioga o le tala: O le faafaigofieina o le code e mafai ona fesoasoani pe a tele le ofaga.
Sosoo ai ma siaki umi masani mo le mamalu o le fa'amaonia; O MAX_CSUM_BYTES lalo.
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 */
}Tatala le afifi
Faatumu i totonu seqnum и acknum, seti ACK (SYN ua uma ona seti):
const u32 cookie = 42;
tcp->ack_seq = bpf_htonl(bpf_ntohl(tcp->seq) + 1);
tcp->seq = bpf_htonl(cookie);
tcp->ack = 1;Fesuia'i ports TCP, tuatusi IP ma tuatusi MAC. O le faletusi masani e le mafai ona maua mai le polokalame XDP, o lea memcpy() - o se macro e natia ai le 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);Toe fuaina o siaki tupe
IPv4 ma TCP siaki siaki e manaʻomia le faʻaopoopoina o upu 16-bit uma i ulutala, ma le tele o ulutala o loʻo tusia i totonu ia i latou, o lona uiga, e le iloa i le taimi faʻapipiʻi. Ose fa'afitauli ona o le a le fa'amisi e le tagata fa'amaonia le matasele masani i le fesuiaiga o tuaoi. Ae o le tele o ulutala e faʻatapulaʻaina: e oʻo atu i le 64 paita taʻitasi. E mafai ona e faia se matasele ma se numera tumau o faʻasalalauga, lea e mafai ona muta vave.
Ou te matauina e i ai pe fa'afefea ona toe fa'atatau le su'ega pe a na'o upu mau o afifi e sui. Ae ui i lea, o le auala e le lautele, ma o le faʻatinoga o le a sili atu ona faigata ona tausia.
Galuega fa'atatauga siaki:
#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;
}E ui lava size fa'amaonia e le code vala'au, e mana'omia le tulaga lona lua e alu ese ai ina ia mafai e le fa'amaonia ona fa'amaonia le mae'a o le matasele.
Mo upu 32-bit, ua faʻatinoina se faʻamatalaga faigofie:
INTERNAL u32
sum16_32(u32 v) {
return (v >> 16) + (v & 0xffff);
}O le mea moni o le toe fa'atatauina o siaki tupe ma toe tu'u atu le afifi:
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;galuega tauave carry() faia se siaki tupe mai se aofaiga 32-bit o upu 16-bit, e tusa ai ma le RFC 791.
TCP fa'amaonia lululima
O le faamama e sa'o ona fa'atuina se feso'ota'iga ma netcat, пропуская финальный ACK, на который Linux отвечал RST-пакетом, так как сетевой стек не получал SYN — он был переделан в SYNACK и отправлен обратно — и с точки зрения ОС прибыл пакет, не относящийся к открытым соединениям.
$ sudo ip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peerE taua le siakiina ma faʻaoga atoatoa ma mataʻituina tcpdump i xdp-remote aua, mo se faataitaiga, hping3 e le tali atu i siaki tupe sese.
kuki SYN
С точки зрения XDP сама проверка тривиальна. Алгоритм расчета примитивный и, вероятно, уязвимый для изощренного злоумышленника. Ядро Linux, например, использует криптографический SipHash, но его реализация для XDP явно выходит за рамки статьи.
Fa'ailoa mo TODO fou e feso'ota'i ma feso'ota'iga i fafo:
XDP polokalame e le mafai ona teuina
cookie_seed(le vaega faalilolilo o le masima) i se fesuiaiga o le lalolagi, e te manaʻomia le teuina i totonu o le fatu, o le tau o le a faʻafouina i lea taimi ma lea taimi mai se generator faatuatuaina.Afai e fetaui le kuki SYN i le pusa ACK, e te le manaʻomia le lolomiina o se feʻau, ae ia manatua le IP o le tagata faʻamaonia faʻamaonia ina ia mafai ai ona faʻaauau le pasi mai ai.
Fa'amaoniga a le tagata o tausia:
$ sudoip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peerO lo'o fa'aalia i ogalaau na pasi le siaki (flags=0x2 - o le SYN lea, flags=0x10 o le 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 20200c0E ui e leai se lisi o IP faʻamaonia, o le a leai se puipuiga mai le lolo SYN lava ia, ae o le tali atu lea i se lolo ACK na faʻalauiloaina e le poloaiga lenei:
sudo ip netns exec xdp-test hping3 --flood -A -s 1111 -p 2222 192.0.2.1Fa'amaumauga o fa'amaumauga:
Ether(proto=0x800)
IP(src=0x15bd11a dst=0x15bd11e proto=6)
TCP(sport=3236 dport=2222 flags=0x10)
cookie mismatchiʻuga
O nisi taimi o le eBPF i le lautele ma le XDP faʻapitoa e tuʻuina atu e avea o se meafaigaluega faʻapitoa a le pule nai lo le avea o se faʻavae atinaʻe. O le mea moni, o le XDP o se meafaigaluega mo le faʻalavelaveina o le faʻaogaina o paʻu e le fatu, ae le o se isi mea i le faʻaputuga fatu, pei o le DPDK ma isi filifiliga e ala i le kernel. I le isi itu, o le XDP e mafai ai ona e faʻatinoina le faʻaogaina o manatu faigata, lea, e le gata i lea, e faigofie ona faʻafouina e aunoa ma le faʻalavelaveina o fefaʻatauaiga. E le faia e le tagata faʻamaonia ni faʻafitauli tetele, ou te le teenaina lenei mea mo vaega o le faʻaoga avanoa.
I le vaega lona lua, afai e manaia le autu, o le a matou faʻamaeʻaina le laulau o tagata faʻamaonia ma motusia, faʻatino faʻatau ma tusi se faʻaoga avanoa e pulea ai le faamama.
Faʻamatalaga:
puna: www.habr.com
