Timalemba chitetezo ku DDoS pa XDP. Mbali ya nyukiliya

Tekinoloje ya eXpress Data Path (XDP) imalola kuti magalimoto aziyenda mosagwirizana ndi Linux mapaketi asanalowe mu kernel network stack. Kugwiritsa ntchito XDP - chitetezo ku DDoS kuukira (CloudFlare), zosefera zovuta, kusonkhanitsa ziwerengero (Netflix). Mapulogalamu a XDP amachitidwa ndi makina enieni a eBPF, motero amakhala ndi zoletsa pama code awo onse ndi ntchito zomwe zilipo, kutengera mtundu wa fyuluta.

Nkhaniyi idapangidwa kuti ikwaniritse zofooka zazinthu zambiri pa XDP. Choyamba, amapereka ma code okonzeka omwe amadumpha nthawi yomweyo mawonekedwe a XDP: okonzekera kutsimikiziridwa kapena osavuta kuyambitsa mavuto. Mukayesa kulemba khodi yanuyanu kuyambira pachiyambi, palibe kumvetsetsa zoyenera kuchita ndi zolakwika zomwe zimachitika. Kachiwiri, sichikuphimba njira zoyesera XDP kwanuko popanda VM ndi hardware, ngakhale ali ndi misampha yawo. Mawuwa amapangidwira opanga mapulogalamu odziwa ma network ndi Linux omwe ali ndi chidwi ndi XDP ndi eBPF.

Mugawoli, timvetsetsa mwatsatanetsatane momwe fyuluta ya XDP imasonkhanitsidwa komanso momwe tingayesere, ndiye kuti tilemba mtundu wosavuta wa makina odziwika bwino a SYN cookie pamlingo wokonza paketi. Mpaka tipange "white list"
makasitomala otsimikiziridwa, sungani zowerengera ndikuwongolera zosefera - zipika zokwanira.

Tidzalemba mu C - izi sizowoneka bwino, koma zothandiza. Ma code onse amapezeka pa GitHub pa ulalo kumapeto ndipo agawidwa muzochita molingana ndi zomwe zafotokozedwa m'nkhaniyi.

Zotsutsa. M'kati mwa nkhaniyi, njira yothetsera vuto la DDoS idzapangidwa, chifukwa iyi ndi ntchito yeniyeni ya XDP ndi dera langa. Komabe, cholinga chachikulu ndikumvetsetsa ukadaulo, izi sizowongolera kupanga chitetezo chokonzekera. Khodi yamaphunziroyo simakometsedwa ndipo imasiya ma nuances ena.

Chidule Chachidule cha XDP

Nditchula mfundo zazikulu zokha kuti ndisabwereze zolemba ndi zolemba zomwe zilipo kale.

Chifukwa chake, code yosefera imayikidwa mu kernel. Zosefera zimadutsa mapaketi obwera. Zotsatira zake, fyulutayo iyenera kupanga chisankho: kupatsira paketi ku kernel (XDP_PASS), tsitsani paketi (XDP_DROP) kapena tumizani (XDP_TX). Zosefera zitha kusintha phukusi, izi ndizowona makamaka kwa XDP_TX. Mukhozanso kusokoneza pulogalamu (XDP_ABORTED) ndikugwetsa phukusi, koma izi ndizofanana assert(0) - kwa debugging.

EBPF (yowonjezera Berkley Packet Filter) makina owoneka bwino amapangidwa mwadala kuti kernel iwonetsetse kuti codeyo siyimazungulira komanso siyiwononga kukumbukira kwa anthu ena. Zoletsa ndi macheke:

  • Lupu (kudumpha kumbuyo) ndizoletsedwa.
  • Pali mulu wa data, koma palibe ntchito (zonse za C ziyenera kukhala ndi mzere).
  • Kulowa m'makumbukidwe kunja kwa stack ndi paketi ya buffer ndikoletsedwa.
  • Kukula kwa code ndikochepa, koma pochita izi sizofunika kwambiri.
  • Ntchito zapadera za kernel (othandizira eBPF) ndizololedwa.

Kupanga ndi kukhazikitsa fyuluta kumawoneka motere:

  1. gwero kodi (mwachitsanzo. kernel.c) amaphatikiza kutsutsa (kernel.o) pakupanga makina a eBPF. Pofika Okutobala 2019, kulembetsa ku eBPF kumathandizidwa ndi Clang ndipo adalonjeza mu GCC 10.1.
  2. Ngati mu code ya chinthu ichi pali mafoni kumagulu a kernel (mwachitsanzo, ku matebulo ndi ma counters), m'malo mwa ma ID awo pali ziro, ndiye kuti, codeyo singathe kuchitidwa. Musanalowe mu kernel, zero izi ziyenera kusinthidwa ndi ma ID azinthu zomwe zidapangidwa kudzera pama foni a kernel (kulumikiza nambalayo). Mutha kuchita izi ndi zida zakunja, kapena mutha kulemba pulogalamu yomwe ingalumikizane ndikuyika fyuluta inayake.
  3. Kernel imatsimikizira kuti pulogalamuyo yakwezedwa. Imayang'ana kusakhalapo kwa kuzungulira komanso kusatuluka kwa phukusi ndi malire a stack. Ngati wotsimikizira sangathe kutsimikizira kuti codeyo ndi yolondola, pulogalamuyo imakanidwa - munthu ayenera kumukondweretsa.
  4. Pambuyo potsimikizira bwino, kernel imaphatikiza kachidindo kamangidwe ka eBPF kukhala makina omangira makina (munthawi yake).
  5. Pulogalamuyi imamangiriridwa ku mawonekedwe ndikuyamba kukonza mapaketi.

Popeza XDP imayenda mu kernel, kukonza zolakwika kumatengera zolemba, ndipo, pamapaketi omwe pulogalamuyo imasefa kapena kupanga. Komabe, eBPF imasunga manambala otsitsidwa kukhala otetezeka pamakina, kotero mutha kuyesa XDP pomwe pa Linux yanu.

Kukonzekera Chilengedwe

Msonkhano

Clang sangathe kupereka mwachindunji kachidindo kamangidwe ka eBPF, chifukwa chake njirayi ili ndi masitepe awiri:

  1. Lembani C code ku LLVM bytecode (clang -emit-llvm).
  2. Sinthani bytecode kukhala eBPF object code (llc -march=bpf -filetype=obj).

Mukalemba fyuluta, mafayilo angapo okhala ndi ntchito zothandizira ndi ma macros adzakhala othandiza kuchokera ku mayeso a kernel. Ndikofunika kuti zigwirizane ndi mtundu wa kernel (KVER). Koperani iwo kuti 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 kwa 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 ili ndi njira yopita kumutu wa kernel, ARCH - kamangidwe kadongosolo. Njira ndi zida zitha kusiyanasiyana pang'ono pakati pa magawo.

Chitsanzo chosiyana cha 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 Phatikizani chikwatu chokhala ndi mitu yothandiza ndi maulalo angapo okhala ndi mitu ya kernel. Chizindikiro __KERNEL__ zikutanthauza kuti mitu ya UAPI (userspace API) imatanthauzidwa ngati kernel code, popeza fyulutayo imachitidwa mu kernel.

Chitetezo cha stack chikhoza kuzimitsidwa (-fno-stack-protector) chifukwa chotsimikizira khodi ya eBPF chimayang'ana ngati palibe malire a stack. Muyenera kuyambitsa kukhathamiritsa nthawi yomweyo, chifukwa kukula kwa eBPF bytecode ndikochepa.

Tiyeni tiyambe ndi zosefera zomwe zimadutsa mapaketi onse osachita chilichonse:

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

timu make amatenga xdp_filter.o. Kodi mungayesere kuti tsopano?

benchi yoyesera

Choyimiriracho chiyenera kukhala ndi mawonekedwe awiri: pomwe padzakhala fyuluta ndi zomwe mapaketi adzatumizidwa. Izi ziyenera kukhala zida zonse za Linux zokhala ndi ma IP awoawo kuti muwone momwe mapulogalamu amagwirira ntchito ndi fyuluta yathu.

Zipangizo monga veth (virtual Efaneti) ndizoyenera kwa ife: ndi ma netiweki awiri olumikizirana "olumikizidwa" mwachindunji wina ndi mnzake. Mutha kuwapanga motere (m'gawo lino, malamulo onse ip anachita kuchokera root):

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

ndi xdp-remote и xdp-local - mayina zida. Yambani xdp-local (192.0.2.1/24) fyuluta idzalumikizidwa, ndi xdp-remote (192.0.2.2/24) magalimoto obwera adzatumizidwa. Komabe, pali vuto: zolumikizira zili pamakina omwewo, ndipo Linux sidzatumiza magalimoto kwa amodzi mwa iwo kudzera mwa imzake. Mutha kuzithetsa ndi malamulo ovuta iptables, koma adzayenera kusintha maphukusi, zomwe zimakhala zovuta mukakonza. Ndikwabwino kugwiritsa ntchito ma netiweki namespaces (ma network namespaces, ma network ena).

Malo ochezera a pa intaneti ali ndi ma interfaces, ma routing tables, ndi malamulo a NetFilter omwe ali olekanitsidwa ndi zinthu zofanana mu maukonde ena. Njira iliyonse imayenda m'malo ena a mayina, ndipo zinthu zokha za maukondewa ndi omwe amapezeka kwa iwo. Mwachikhazikitso, dongosololi liri ndi malo amodzi a netiweki azinthu zonse, kotero mutha kugwira ntchito pa Linux osadziwa za maukonde.

Tiyeni tipange malo atsopano xdp-test ndi kusamukira kumeneko xdp-remote.

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

Ndiye ndondomeko ikuyenda mkati xdp-test, sindidzawona " xdp-local (idzakhalabe muukonde mwachisawawa) ndipo potumiza paketi ku 192.0.2.1 idzadutsa xdp-remote, chifukwa ndiwo mawonekedwe okhawo pa 192.0.2.0/24 omwe akupezeka pa ndondomekoyi. Izi zimagwiranso ntchito mosiyana.

Mukasuntha pakati pa ma neti, mawonekedwewo amatsika ndikutaya adilesi. Kukhazikitsa mawonekedwe mu netns, muyenera kuthamanga ip ... m'malo awa amalamulo 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

Monga mukuwonera, izi sizosiyana ndi kukhazikitsa xdp-local m'malo okhazikika:

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

Ngati kuthamanga tcpdump -tnevi xdp-local, mutha kuwona mapaketi omwe amatumizidwa kuchokera xdp-test, amaperekedwa ku mawonekedwe awa:

ip netns exec xdp-test   ping 192.0.2.1

Ndikwabwino kuyendetsa chipolopolo mkati xdp-test. Chosungiracho chili ndi zolemba zomwe zimangogwira ntchito ndi choyimilira, mwachitsanzo, mutha kuyika choyimira ndi lamulo. sudo ./stand up ndi kuchotsa sudo ./stand down.

kutsatira

Zosefera zimalumikizidwa ku chipangizochi motere:

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

Mphindi -force zofunika kulumikiza pulogalamu yatsopano ngati ina yalumikizidwa kale. "Palibe nkhani yomwe ili yabwino" sizikunena za lamuloli, zomwe zimatuluka ndizochuluka. sonyeza verbose mwachisawawa, koma ndi izo lipoti la ntchito ya code verifier ndi assembler mindandanda ikuwoneka:

Verifier analysis:

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

Chotsani pulogalamuyi kuchokera ku mawonekedwe:

ip link set dev xdp-local xdp off

Mu script, awa ndi malamulo sudo ./stand attach и sudo ./stand detach.

Pomanga fyuluta, mutha kutsimikiza kuti ping ikugwirabe ntchito, koma kodi pulogalamuyi imagwira ntchito? Tiyeni tiwonjezere ma logo. Ntchito bpf_trace_printk() ofanana ndi printf(), koma zimangochirikiza mpaka ziganizo zitatu kupatula pateni, ndi mndandanda wochepera wa ofotokozera. Macro bpf_printk() imathandizira kuyimba.

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

Zomwe zimatuluka zimapita ku kernel trace channel, yomwe imayenera kuyatsidwa:

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

Onani kutuluka kwa uthenga:

cat /sys/kernel/debug/tracing/trace_pipe

Magulu onsewa amayimba foni sudo ./stand log.

Ping iyenera kutulutsa mauthenga ngati awa mmenemo:

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

Ngati muyang'anitsitsa zomwe zimachokera ku verifier, mukhoza kuona kuwerengera kwachilendo:

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

Chowonadi ndi chakuti mapulogalamu a eBPF alibe gawo la data, chifukwa chake njira yokhayo yolumikizira chingwe chamtundu ndi mikangano yaposachedwa ya malamulo a VM:

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

Pachifukwa ichi, kutulutsa zolakwika kumalepheretsa kwambiri code yomwe ikubwera.

Kutumiza mapaketi a XDP

Tiyeni tisinthe fyuluta: ilole kuti itumizenso mapaketi onse omwe akubwera. Izi sizolakwika kuchokera pamawonedwe a intaneti, chifukwa zingakhale zofunikira kusintha maadiresi pamutu, koma tsopano ntchitoyo ndi yofunika kwambiri.

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

Yambitsani tcpdump pa xdp-remote. Iyenera kuwonetsa zomwe zikutuluka komanso zomwe zikubwera ICMP Echo Pempho ndikusiya kuwonetsa ICMP Echo Reply. Koma sizikuwoneka. Zimagwira ntchito XDP_TX mu pulogalamu ya xdp-local ndikofunikirakugwirizanitsa mawonekedwe xdp-remote pulogalamu inaperekedwanso, ngakhale itakhala yopanda kanthu, ndipo idakwezedwa.

Ndinadziwa bwanji?

Kutsata njira ya phukusi mu kernel makina a perf amalola, mwa njira, kugwiritsa ntchito makina omwewo, ndiye kuti, eBPF imagwiritsidwa ntchito posokoneza ndi eBPF.

Muyenera kupanga zabwino mwa zoyipa, chifukwa palibe china choti muchite.

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

Kodi 6 ndi chiyani?

$ errno 6
ENXIO 6 No such device or address

ntchito veth_xdp_flush_bq() amalandira khodi yolakwika kuchokera veth_xdp_xmit(), kumene kufufuza ndi ENXIO ndi kupeza ndemanga.

Bwezeretsani zosefera zochepa (XDP_PASS) mu fayilo xdp_dummy.c, onjezani ku Makefile, sungani xdp-remote:

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

Tsopano tcpdump zikuwonetsa zomwe zikuyembekezeredwa:

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

Ngati ARP ikuwonetsedwa m'malo mwake, muyenera kuchotsa zosefera (izi zimapangitsa sudo ./stand detach), ife ping, kenako ikani zosefera ndikuyesanso. Vuto ndiloti fyulutayo XDP_TX imakhudzanso ARP, komanso ngati stack
malo a mayina xdp-test adakwanitsa "kuyiwala" adilesi ya MAC 192.0.2.1, sangathe kuthetsa IP iyi.

Kupanga kwa vuto

Tiyeni tipitirire ku ntchito yomwe yanenedwa: kulemba makina a SYN cookie pa XDP.

Mpaka pano, kusefukira kwa SYN kumakhalabe kutchuka kwa DDoS, zomwe zili motere. Pamene kugwirizana kukhazikitsidwa (TCP kugwirana chanza), seva imalandira SYN, imagawa zothandizira kuti igwirizane ndi mtsogolo, imayankha ndi paketi ya SYNACK, ndikudikirira ACK. Wowukirayo amangotumiza mapaketi a SYN kuchokera ku ma adilesi abodza mu kuchuluka kwa masauzande pamphindikati kuchokera kwa wolandira aliyense mu botnet ya masauzande ambiri. Seva imakakamizika kugawa zothandizira mwamsanga pakafika paketi, koma imatulutsa pambuyo pa nthawi yayitali, chifukwa chake, kukumbukira kapena malire atha, kugwirizana kwatsopano sikuvomerezedwa, ntchitoyo sikupezeka.

Ngati simukugawa zothandizira pa paketi ya SYN, koma mungoyankha ndi paketi ya SYNACK, ndiye seva ingamvetse bwanji kuti paketi ya ACK yomwe inabwera pambuyo pake ndi ya paketi ya SYN yomwe sinasungidwe? Kupatula apo, wowukira amathanso kupanga ma ACK abodza. Chofunikira pa cookie ya SYN ndikulowetsamo seqnum magawo olumikizirana ngati ma adilesi, madoko ndikusintha mchere. Ngati ACK inatha kufika mchere usanasinthe, mukhoza kuwerengera hashi kachiwiri ndikuyerekeza ndi acknum. zabodza acknum wowukirayo sangathe, popeza mchere umaphatikizapo chinsinsi, ndipo sadzakhala ndi nthawi yoti athetse chifukwa cha njira yochepa.

Ma SYN makeke akhazikitsidwa mu Linux kernel kwa nthawi yayitali ndipo amatha kuthandizidwa ngati ma SYN afika mwachangu komanso mochulukira.

Pulogalamu yamaphunziro pa TCP kugwirana chanza

TCP imapereka kusamutsa kwa data ngati mtsinje wa ma byte, mwachitsanzo, zopempha za HTTP zimatumizidwa pa TCP. Mtsinjewo umafalikira pang'onopang'ono m'mapaketi. Mapaketi onse a TCP ali ndi mbendera zomveka ndi manambala otsatizana a 32-bit:

  • Kuphatikiza kwa mbendera kumatanthawuza udindo wa phukusi linalake. Mbendera ya SYN imatanthawuza kuti iyi ndiye paketi yoyamba ya wotumiza pamalumikizidwe. Mbendera ya ACK imatanthawuza kuti wotumizayo walandira deta yonse yolumikizana mpaka pa byte. acknum. Phukusi likhoza kukhala ndi mbendera zingapo ndipo limatchedwa kuphatikizika kwawo, mwachitsanzo, paketi ya SYNACK.

  • Nambala yotsatizana (seqnum) imatanthawuza kuchotsera kwa data pa baiti yoyamba yomwe imatumizidwa mu paketi iyi. Mwachitsanzo, ngati mu paketi yoyamba yokhala ndi ma X a data nambalayi inali N, mu paketi yotsatira yokhala ndi deta yatsopano idzakhala N + X. Kumayambiriro kwa kugwirizana, phwando lirilonse limasankha nambala iyi mwachisawawa.

  • Nambala yovomerezeka (acknum) - yofanana ndi seqnum, koma sichidziwa chiwerengero cha byte yopatsirana, koma chiwerengero cha byte yoyamba kuchokera kwa wolandira, yomwe wotumizayo sanawone.

Kumayambiriro kwa kugwirizana, maphwando ayenera kuvomereza seqnum и acknum. Makasitomala amatumiza paketi ya SYN ndi yake seqnum = X. Seva imayankha ndi paketi ya SYNACK, pomwe imalemba yake seqnum = Y ndi kuwulula acknum = X + 1. Wothandizira amayankha SYNACK ndi paketi ya ACK, komwe seqnum = X + 1, acknum = Y + 1. Pambuyo pake, kusamutsidwa kwenikweni kwa data kumayamba.

Ngati interlocutor savomereza kulandira paketi, TCP imatumizanso panthawi yopuma.

Chifukwa chiyani ma cookie a SYN sagwiritsidwa ntchito nthawi zonse?

Choyamba, ngati SYNACK kapena ACK itatayika, muyenera kuyembekezera kutumizanso - kukhazikitsidwa kwa kugwirizana kumachepetsa. Kachiwiri, mu paketi ya SYN - komanso momwemo! - zosankha zingapo zimaperekedwa zomwe zimakhudza kupitilira kwa kulumikizana. Osakumbukira mapaketi a SYN omwe akubwera, seva imanyalanyaza zosankhazi, m'mapaketi otsatirawa kasitomala sangawatumizenso. TCP ikhoza kugwira ntchito pankhaniyi, koma pagawo loyambirira, mtundu wa kulumikizana udzachepa.

Pankhani ya phukusi, pulogalamu ya XDP iyenera kuchita izi:

  • yankhani SYN ndi SYNACK ndi cookie;
  • yankhani ACK ndi RST (kuswa kulumikizana);
  • kusiya mapaketi ena.

Pseudocode ya algorithm pamodzi ndi paketi parsing:

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

Mmodzi (*) mfundo zomwe muyenera kuyang'anira dongosolo la dongosolo zimayikidwa - pa gawo loyamba, mutha kuchita popanda iwo mwa kungogwiritsa ntchito TCP kugwirana chanza ndikupanga cookie ya SYN ngati seqnum.

Komweko (**), pamene tilibe tebulo, tidzadumpha paketi.

Kugwirana chanza kwa TCP

Kuyika phukusi ndi kutsimikizira ma code

Timafunikira zida zamutu wamaneti: Ethernet (uapi/linux/if_ether.hIPv4 ()uapi/linux/ip.hndi TCP (uapi/linux/tcp.h). Yomaliza sindinathe kuyilumikiza chifukwa cha zolakwika zokhudzana nayo atomic64_t, ndinayenera kukopera matanthauzo ofunikira mu code.

Ntchito zonse zomwe zimasiyanitsidwa ndi C kuti ziwerengeke ziyenera kulumikizidwa pamalo oimbira foni, chifukwa chotsimikizira eBPF mu kernel chimaletsa kulumpha kumbuyo, ndiye kuti, malupu ndi kuyimbira foni.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() imalepheretsa kusindikiza mumapangidwe omasulidwa.

Pulogalamuyi ndi gawo la ntchito. Aliyense amalandira paketi momwe mutu wa mulingo wofananira umawonetsedwa, mwachitsanzo, process_ether() kuyembekezera kudzazidwa ether. Kutengera zotsatira za kusanthula kwamunda, ntchitoyi imatha kusamutsa paketi kupita kumtunda wapamwamba. Chotsatira cha ntchitoyi ndikuchita kwa XDP. Pomwe oyang'anira SYN ndi ACK amalola mapaketi onse kudutsa.

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

Ndimayang'anitsitsa macheke omwe ali ndi A ndi B. Ngati mupereka ndemanga pa A, pulogalamuyo idzamanga, koma padzakhala cholakwika chotsimikizira pamene mukutsegula:

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!

Chingwe chofunikira invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): pali njira zochitira pomwe baiti yakhumi ndi itatu kuyambira koyambira kwa buffer ili kunja kwa paketi. Ndizovuta kudziwa kuchokera pamndandanda womwe tikukamba, koma pali nambala ya malangizo (12) ndi chophatikizira chomwe chikuwonetsa mizere ya magwero:

llvm-objdump -S xdp_filter.o | less

Pankhaniyi, ikuloza ku mzere

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

zomwe zikusonyeza kuti vuto ndi ether. Zikanakhala choncho nthawi zonse.

Yankhani SYN

Cholinga pakadali pano ndikupanga paketi yolondola ya SYNACK yokhala ndi chokhazikika seqnum, yomwe idzalowe m'malo ndi SYN cookie mtsogolomu. Zosintha zonse zimachitika mkati process_tcp_syn() ndi malo ozungulira.

Kuyang'ana phukusi

Chodabwitsa, nawu mzere wodabwitsa kwambiri, kapena m'malo mwake, ndemanga kwa iwo:

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

Polemba mtundu woyamba wa code, 5.1 kernel idagwiritsidwa ntchito, chifukwa chotsimikizira chomwe panali kusiyana pakati pawo. data_end и (const void*)ctx->data_end. Panthawi yolemba, 5.3.1 kernel inalibe vuto ili. Mwinamwake wolembayo anali kupeza kusintha komweko mosiyana ndi gawo. Makhalidwe - pa chisa chachikulu, kuphweka malamulo kungathandize.

Kufufuzanso chizolowezi cha kutalika kwa ulemerero wa wotsimikizira; O MAX_CSUM_BYTES pansipa.

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

Phukusi kufalikira

Timadzaza seqnum и acknum, ikani ACK (SYN yakhazikitsidwa kale):

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

Sinthani madoko a TCP, IP ndi ma adilesi a MAC. Laibulale wamba sapezeka ku pulogalamu ya XDP, kotero memcpy() - zazikulu zomwe zimabisa Clang intrinsik.

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

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

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

Checksum recalculation

IPv4 ndi TCP checksums zimafuna kuwonjezera mawu onse a 16-bit pamutu, ndipo kukula kwa mitu kumalembedwa mmenemo, ndiko kuti, panthawi yosonkhanitsa sikudziwika. Ili ndi vuto chifukwa chotsimikizira sichidumpha kuzungulira kwanthawi zonse mpaka malirewo asinthe. Koma kukula kwa mitu ndi kochepa: mpaka 64 byte iliyonse. Mutha kupanga lupu ndi nambala yokhazikika yobwerezabwereza, yomwe imatha kutha msanga.

Ndikuwona kuti alipo RFC 1624 za momwe mungawerengerenso cheke pang'ono ngati mawu okhazikika apaketi asinthidwa. Komabe, njirayo si yapadziko lonse lapansi, ndipo kukhazikitsa kumakhala kovuta kwambiri kusunga.

Ntchito yowerengera 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;
}

Ngakhale size kufufuzidwa ndi nambala yoyimbira, njira yotuluka yachiwiri ndiyofunikira kuti wotsimikizira athe kutsimikizira kutha kwa kuzungulira.

Pamawu a 32-bit, mtundu wosavuta umakhazikitsidwa:

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

Kuwerengeranso macheke ndikutumizanso paketi:

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;

ntchito carry() imapanga cheke kuchokera ku 32-bit kuchuluka kwa mawu 16-bit, malinga ndi RFC 791.

TCP cheke chanza

Zosefera zimakhazikitsa kulumikizana ndi netcat, kudumpha ACK yomaliza, yomwe Linux adayankha ndi paketi ya RST, popeza stack network sinalandire SYN - inatembenuzidwa ku SYNACK ndikubwezeretsanso - ndipo kuchokera kumbali ya OS, paketi inafika yomwe sinali. zokhudzana ndi maulumikizidwe otseguka.

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

Ndikofunikira kuyang'ana ndi mapulogalamu athunthu ndikuwona tcpdump pa xdp-remote chifukwa, mwachitsanzo, hping3 sichimayankha macheke olakwika.

Pakuwona kwa XDP, chekeyo ndiyochepa. Mawerengedwe a algorithm ndi akale ndipo mwina akhoza kukhala pachiwopsezo chaoukira mwaukadaulo. Linux kernel, mwachitsanzo, imagwiritsa ntchito cryptographic SipHash, koma kukhazikitsidwa kwake kwa XDP momveka bwino sikungafotokozedwe ndi nkhaniyi.

Zawonekera kwa ma TODO atsopano okhudzana ndi kuyanjana kwakunja:

  • Pulogalamu ya XDP siyingasungidwe cookie_seed (gawo lobisika la mchere) muzosintha zapadziko lonse lapansi, muyenera sitolo ya kernel yomwe mtengo wake udzasinthidwa nthawi ndi nthawi kuchokera ku jenereta yodalirika.

  • Ngati cookie ya SYN mu paketi ya ACK ikugwirizana, simuyenera kusindikiza uthenga, koma kumbukirani IP ya kasitomala wotsimikizika kuti mulumphenso mapaketi kuchokera pamenepo.

Kutsimikiziridwa ndi kasitomala wovomerezeka:

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

Zipika zinalemba ndime ya cheke (flags=0x2 ndi SYN, flags=0x10 ndi 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

Malingana ngati palibe mndandanda wa ma IP otsimikiziridwa, sipadzakhala chitetezo ku kusefukira kwa SYN palokha, koma apa pali zomwe zimachitika ku ACK kusefukira komwe kunayambitsidwa ndi lamulo ili:

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

Log zolowa:

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

Pomaliza

Nthawi zina eBPF yonse ndi XDP makamaka imawonetsedwa ngati chida chowongolera chapamwamba kuposa nsanja yachitukuko. Zowonadi, XDP ndi chida chosokoneza pakukonza paketi ya kernel, osati m'malo mwa kernel stack, monga DPDK ndi zosankha zina za kernel bypass. Kumbali ina, XDP imakulolani kuti mugwiritse ntchito malingaliro ovuta, omwe, kuwonjezera apo, ndi osavuta kusintha popanda kuyimitsa kaye pakukonza magalimoto. Chotsimikizira sichimayambitsa mavuto akulu, ine sindikanakana izi pazigawo za codespace.

Mu gawo lachiwiri, ngati mutuwo uli wosangalatsa, tidzamaliza tebulo lamakasitomala otsimikizika ndikuphwanya maulumikizidwe, kukhazikitsa zowerengera ndikulemba ntchito yogwiritsa ntchito kuti isamalire zosefera.

Zolemba:

Source: www.habr.com

Kuwonjezera ndemanga