Kei te tuhi matou i te whakamarumaru ki nga whakaeke DDoS i runga i te XDP. Te wahanga karihi

Ko te hangarau eXpress Raraunga Raraunga (XDP) ka taea te tukatuka i nga waka i runga i nga atanga Linux i mua i te urunga o nga paakete ki te taapu whatunga kernel. Te tono o te XDP - te tiaki i nga whakaeke DDoS (CloudFlare), nga whiriwhiringa matatini, te kohinga tatauranga (Netflix). Ko nga kaupapa XDP e mahia ana e te miihini mariko eBPF, na reira he here i runga i o raatau waehere me nga mahi kernel e waatea ana, i runga i te momo tātari.

Ko te tikanga o te tuhinga ki te whakatika i nga hapa o nga rauemi maha i runga i te XDP. Tuatahi, ka whakaratohia e ratou he waehere kua oti te hanga ka takahi i nga ahuatanga o te XDP: kua rite mo te manatoko, he ngawari rawa ranei ki te raru. Ka ngana koe ki te tuhi i to ake waehere mai i te wahanga i muri mai, karekau he mohio ki nga mahi me nga hapa angamaheni. Tuarua, kaore e kapi i nga huarahi ki te whakamatautau i te rohe XDP me te kore he VM me nga taputapu, ahakoa te mea kei a raatau ano nga raru. Ko te tuhinga mo te hunga hötaka e mohio ana ki nga whatunga me te Linux e aro nui ana ki te XDP me te eBPF.

I tenei waahanga, ka maarama taatau ki te whakahiato i te tātari XDP me pehea te whakamatautau, katahi ka tuhia e matou he waahanga ngawari o te miihini pihikete SYN rongonui i te taumata tukatuka paatete. Kia hanga ra ano he "rarangi ma"
kiritaki manatoko, pupuri porotiti me te whakahaere i te tātari - kia nui nga raarangi.

Ka tuhia e matou ki te C - ehara tenei i te huatau, engari he mahi. Kei te waatea nga waehere katoa i runga i te GitHub i te hono i te mutunga ka wehea ki nga mahi i runga i nga waahanga kua whakaahuahia i roto i te tuhinga.

Nga whakahehae. I te wa o tenei tuhinga, ka hangaia e ahau he otinga paku hei aukati i nga whakaeke DDoS, na te mea he mahi tino tika tenei mo te XDP me taku waahi tohungatanga. Heoi, ko te whainga matua kia mohio ki te hangarau, ehara tenei i te aratohu ki te hanga whakamarumaru kua rite. Ko te waehere akoranga kaore i te arotauhia me te whakakore i etahi ahuatanga.

He tirohanga poto mo te XDP

Ka whakahuahia e au nga kaupapa matua kia kaua e taarua nga tuhinga me nga tuhinga o naianei.

Na, ka utaina te waehere tātari ki te kernel. Ka tukuna te tātari i nga paanui taumai. Ko te mutunga mai, me whakatau te tātari: me tuku te kete ki te pata (XDP_PASS), takai te putea (XDP_DROP) whakahokia mai ranei (XDP_TX). Ka taea e te tātari te huri i te kete, he tino pono tenei mo XDP_TX. Ka taea hoki e koe te tukituki i te papatono (XDP_ABORTED) ka tuku i te kete, engari he rite tonu tenei assert(0) - mo te patuiro.

Ko te miihini mariko eBPF (berkley Packet Filter roa) he mea hanga ngawari kia taea ai e te kakano te tirotiro kia kore te waehere e kopikopiko me te kore e kino te mahara o etahi atu. Nga here me nga arowhai:

  • Ko nga koropiko (peke whakamuri) e rahuitia ana.
  • He puranga mo nga raraunga, engari karekau he mahi (me whakauru nga mahi C katoa).
  • Ko nga urunga ki te mahara ki waho o te puranga me te paatete paatete ka aukatihia.
  • He iti te rahi o te waehere, engari i roto i nga mahi kaore i te tino nui.
  • Ko nga mahi kernel motuhake anake (he kaiawhina eBPF) ka whakaaetia.

Ko te whakawhanake me te whakauru i te tātari he penei te ahua:

  1. Waehere puna (hei tauira kernel.c) ka whakahiato ki te whakahē (kernel.o) mo te hoahoanga miihini mariko eBPF. No Oketopa 2019, ko te whakahiato ki te eBPF e tautokohia ana e Clang me te oati i te GCC 10.1.
  2. Mena kei roto i tenei waehere ahanoa he waea ki nga hanganga kernel (hei tauira, ki nga ripanga me nga porotiti), hei utu mo o ratou ID he kore, ara, kaore e taea te mahi i taua waehere. I mua i te utaina ki roto i te pata, me whakakapi enei koo ki nga ID o nga mea motuhake i hangaia ma nga waea kernel (honohia te waehere). Ka taea e koe tenei me nga taputapu o waho, ka taea ranei e koe te tuhi i tetahi papatono hei hono me te uta i tetahi tātari motuhake.
  3. Ka whakamanahia e te kernel te kaupapa e utaina ana. Ka tirotirohia mo te kore o nga huringa me te kore putanga o te kete me nga rohe o te puranga. Mena kaore e taea e te kaitirotiro te whakaatu he tika te waehere, ka whakakorehia te papatono - me kaha tetahi ki te pai ki a ia.
  4. Whai muri i te manatokonga angitu, ka whakahiatohia e te pata te waehere ahanoa hoahoanga eBPF ki roto i te waehere miihini hoahoanga punaha (tika-i-wa).
  5. Ka piri te papatono ki te atanga ka timata ki te tukatuka i nga paatete.

I te mea kei te rere a XDP i roto i te pata, ka mahia te patuiro ma te whakamahi i nga raarangi tohu, me te pono, ko nga paatete ka tohua, ka mahia ranei e te papatono. Heoi, ka whakarite eBPF he haumaru te waehere kua tangohia mo te punaha, na reira ka taea e koe te whakamatautau me te XDP tika ki to Linux rohe.

Te Whakarite Taiao

Tuhinga

Kaore e taea e Clang te whakaputa tika i te waehere ahanoa mo te hoahoanga eBPF, no reira e rua nga waahanga o te tukanga:

  1. Whakahiato waehere C ki te LLVM bytecode (clang -emit-llvm).
  2. Hurihia te bytecode ki te waehere ahanoa eBPF (llc -march=bpf -filetype=obj).

I te wa e tuhi ana i te tātari, ka uru mai etahi konae me nga mahi awhina me nga tonotono mai i nga whakamatautau kernel. He mea nui kia rite ki te putanga kernel (KVER). Tikiake ratou ki 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 mo 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 kei roto te ara ki nga pane kernel, ARCH - hoahoanga punaha. He rereke pea nga huarahi me nga taputapu i waenga i nga tohatoha.

He tauira rereke mo 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 whakaurua he whaiaronga me nga pane awhina me etahi raarangi me nga pane kernel. Tohu __KERNEL__ Ko te tikanga ko nga pane UAPI (kaiwhakamahi API) kua tautuhia mo te waehere kernel, na te mea ka mahia te tātari i roto i te pata.

Ka taea te whakakore i te parenga tāpae (-fno-stack-protector) na te mea ka tirohia e te kaitirotiro waehere eBPF mo nga rohe karekau i waho. Me whakahohe tonu koe i nga arotautanga, na te mea he iti te rahi o te eBPF bytecode.

Me timata me te tātari ka tukuna nga paanui katoa kaore he mahi:

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

rōpū make kohikohi xdp_filter.o. Kei hea ka taea e koe te whakamatautau inaianei?

pae whakamatautau

Kia rua nga atanga kei roto i te tuunga: kei reira he tātari ka tukuna mai nga paakete. Ko enei me nga taputapu Linux katoa me o raatau ake IP hei tirotiro me pehea te mahi o nga tono me o taatau tātari.

Ko nga taputapu penei i te veth (Itarangi mariko) e tika ana mo tatou: he rua nga hononga whatunga mariko "hono" tika ki a raatau. Ka taea e koe te hanga penei (i tenei waahanga, nga whakahau katoa ip mahia mai root):

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

ko te reira xdp-remote и xdp-local — ingoa taputapu. Kei runga xdp-local (192.0.2.1/24) ka taapirihia he tātari, me te xdp-remote (192.0.2.2/24) ka tukuna nga waka taumai. Heoi ano, he raru: kei runga i te miihini nga hononga, kaore a Linux e tuku waka ki tetahi o ratou ma tetahi atu. Ka taea e koe te whakaoti me nga ture uaua iptables, engari me huri ratou i nga kete, he mea whakaraerae i te wa e patuiro ana. He pai ake te whakamahi i nga mokowāingoa whatunga (nga ingoa ingoa whatunga, etahi atu kupenga).

Kei roto i te mokowāingoa whatunga he huinga atanga, ripanga ararere, me nga ture NetFilter kua wehea mai i nga mea rite i etahi atu kupenga. Ka haere ia tukanga ki etahi waahi ingoa, a ko nga taonga o enei kupenga e waatea ana ki a ia. Ma te taunoa, he waahi ingoa whatunga kotahi te punaha mo nga mea katoa, na ka taea e koe te mahi i runga i te Linux me te kore e mohio mo nga kupenga.

Me hanga he mokowāingoa hōu xdp-test ka neke ki reira xdp-remote.

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

Na ka rere te tukanga xdp-test, e kore e "kite" xdp-local (ka noho ki roto i nga kupenga ma te taunoa) ka tukuna he kete ki te 192.0.2.1 ka tukuna atu xdp-remote, no te mea koinei anake te atanga i 192.0.2.0/24 e waatea ana ki tenei mahi. Ka mahi whakamuri hoki tenei.

Ka neke i waenga i nga kupenga, ka heke te atanga ka ngaro te wahitau. Hei whakarite i tetahi atanga i roto i nga kupenga, me rere koe ip ... i tenei mokowā ingoa whakahau 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

Ka taea e koe te kite, kaore tenei i te rereke mai i te whakatakotoranga xdp-local i te mokowāingoa taunoa:

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

Ki te rere tcpdump -tnevi xdp-local, ka kite koe i tukuna mai nga paakete mai xdp-test, ka tukuna ki tenei atanga:

ip netns exec xdp-test   ping 192.0.2.1

He pai ki te whakahaere i te anga ki roto xdp-test. He tuhinga kei roto i te whare putunga ka mahi aunoa me te tuunga, hei tauira, ka taea e koe te whakarite i te turanga me te whakahau sudo ./stand up ka tango atu sudo ./stand down.

whaiwhai

Ka piri te tātari ki te taputapu penei:

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

-force e hiahiatia ana ki te hono i tetahi papatono hou mena kua hono kee tetahi atu. "Kaore he korero he korero pai" ehara i te korero mo tenei whakahau, he nui tonu te putanga. tohu verbose ka taea, engari ka puta mai he purongo mo te mahi a te kaitirotiro waehere me te rarangi kaihopu:

Verifier analysis:

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

Wewetehia te papatono mai i te atanga:

ip link set dev xdp-local xdp off

I roto i te tuhinga, koinei nga whakahau sudo ./stand attach и sudo ./stand detach.

Ma te taapiri i te tātari, ka taea e koe te whakarite ping kei te mahi tonu, engari kei te mahi tonu te kaupapa? Kia taapirihia he moko. Mahi bpf_trace_printk() rite ki printf(), engari e tautoko ana kia toru nga tohenga ke atu i te tauira, me te rarangi iti o nga kaitautoko. Tonotono bpf_printk() ka whakangwari i te karanga.

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

Ka haere te putanga ki te hongere tohu kernel, me whakahohe:

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

Tirohia te rerenga karere:

cat /sys/kernel/debug/tracing/trace_pipe

Ka karanga enei kapa e rua sudo ./stand log.

Me whakaputa e Ping nga karere penei i roto:

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

Mena ka ata titiro koe ki te putanga o te kaitirotiro, ka kite koe i nga tatauranga rereke:

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

Ko te meka ko nga kaupapa eBPF kaore he waahanga raraunga, na ko te huarahi anake hei whakawaehere i te aho whakatakotoranga ko nga tohenga tonu o nga whakahau VM:

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

Mo konei, ka nui te pupuhi o te putanga patuiro i te waehere ka puta.

Te tuku Paeke XDP

Me huri tatou i te tātari: me whakahoki mai nga paanui taumai katoa. He he tenei mai i te tirohanga whatunga, na te mea me whakarereke nga wahitau kei roto i nga pane, engari inaianei he mea nui te mahi i roto i te kaupapa.

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

Whakarewatanga tcpdump i runga i xdp-remote. Me whakaatu rite te tono ICMP Echo Tono putaatu me te taumai ka mutu te whakaatu ICMP Echo Reply. Engari kaore e whakaatu. Ka huri ki te mahi XDP_TX i roto i te kaupapa mo xdp-local he mea tikaki te takirua atanga xdp-remote i whakaritea hoki he kaupapa, ahakoa he kau, ka whakaarahia.

I pehea ahau i mohio ai?

Te whai i te ara o te kete i roto i te kernel ka taea e te mahinga takahanga perf, ma te whakamahi i te miihini mariko ano, ara, ka whakamahia te eBPF mo te wetewete me te eBPF.

Me hanga e koe te pai i roto i te kino, no te mea kahore he mea ke atu.

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

He aha te waehere 6?

$ errno 6
ENXIO 6 No such device or address

mahi veth_xdp_flush_bq() whiwhi waehere hapa mai veth_xdp_xmit(), kei hea te rapu ENXIO ka kitea he korero.

Whakahokia te tātari iti rawa (XDP_PASS) kei te konae xdp_dummy.c, tāpirihia ki te Makefile, herea ki xdp-remote:

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

I teie nei tcpdump e whakaatu ana i nga mea e tumanakohia ana:

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

Mena ko te ARP anake ka whakaatuhia, me tango e koe nga whiriwhiringa (ko tenei sudo ./stand detach), tukua ping, ka whakauru i nga whiriwhiringa ka ngana ano. Ko te raruraru ko te tātari XDP_TX ka pa ki te ARP, a, ki te mea ko te puranga
mokowā ingoa xdp-test i kaha ki te "wareware" te wahitau MAC 192.0.2.1, kaore e taea te whakatau i tenei IP.

Kaupapa raru

Me neke atu ki te mahi kua kiia: ki te tuhi i tetahi tikanga pihikete SYN ki XDP.

Tae noa ki tenei wa, kei te noho tonu te waipuke SYN hei whakaeke DDoS rongonui, ko te tino kaupapa e whai ake nei. Ina whakaritea he hononga (TCP ruru ringa), ka whiwhi te tūmau i te SYN, ka tohatoha rauemi mo te hononga a meake nei, ka whakautu me te kete SYNACK, ka tatari mo te ACK. Ka tukuna noa e te kaiwhaiwhai nga paatete SYN mai i nga wahitau rūpahu i roto i te nui o nga mano mo ia hekona mai i ia kaihautu i roto i te mano-mano botnet. Ka akiakihia te tūmau ki te tohatoha rauemi i te taenga mai o te putea, engari ka tukuna i muri i te wa roa, na te mea, kua pau te mahara, nga rohe ranei, kaore e whakaaetia nga hononga hou, kaore i te waatea te ratonga.

Mena karekau koe e tohatoha rauemi ki runga i te paatete SYN, engari ka whakautu me te paatete SYNACK anake, me pehea e mohio ai te tūmau ko te paatete ACK i tae mai i muri mai no te paatete SYN kaore i tiakina? I muri i nga mea katoa, ka taea hoki e te kaitukino te whakaputa i nga ACK rūpahu. Ko te ngako o te pihikete SYN he whakawaehere seqnum tawhā hononga hei hash o nga wahitau, tauranga me te huri tote. Mena i tae mai te ACK i mua i te whakarereketanga o te tote, ka taea e koe te tatau ano i te hash me te whakataurite ki acknum. rūpahu acknum e kore e taea e te kaipahua, no te mea kei roto i te tote te mea ngaro, a ka kore e whai wa ki te wehewehe na te iti o te hongere.

Kua whakatinanahia nga pihikete SYN i roto i te pata Linux mo te wa roa, ka taea te whakahoe aunoa mena ka tere rawa te taenga mai o nga SYN me te nuinga.

He kaupapa ako mo te ruru ringa TCP

Ka tukuna e TCP te whakawhiti raraunga hei awa paita, hei tauira, ka tukuna nga tono HTTP ki runga i te TCP. Ka tukuna te awa ki ia waahanga ki roto i nga paatete. He haki arorau me nga tau raupapa moka-32 katoa o nga paakete TCP:

  • Ko te huinga o nga haki e tohu ana i te mahi o tetahi kete. Ko te tikanga o te haki SYN koinei te kete tuatahi a te kaituku i runga i te hononga. Ko te tohu o te haki ACK kua whiwhi te kaituku i nga raraunga hononga katoa ki te paita. acknum. He maha pea nga haki o te kete, ka whakaingoatia i runga i o raatau huinga, hei tauira, he paatete SYNACK.

  • Ko te tau raupapa (seqnum) e tohu ana i te wehenga i roto i te awa raraunga mo te paita tuatahi ka tukuna i roto i tenei kete. Hei tauira, ki te mea i roto i te paatete tuatahi me nga X paita raraunga ko tenei nama ko N, kei te paatete e whai ake nei me nga raraunga hou ko N+X. I te timatanga o te hononga, ka kowhiria e ia roopu tenei tau matapōkeretia.

  • Tau mihi (acknum) - he rite tonu te wehenga ki te seqnum, engari kaore e whakatauhia te maha o te paita tuku, engari ko te nama o te paita tuatahi mai i te kaiwhiwhi, kaore i kitea e te kaituku.

I te timatanga o te hononga, me whakaae nga taha seqnum и acknum. Ka tukuna e te kiritaki he putea SYN me ona seqnum = X. Ka whakautu te tūmau me te pākete SYNACK, ka tuhia e ia tana ake seqnum = Y me te whakaatu acknum = X + 1. Ka whakautu te kiritaki ki a SYNACK me te putea ACK, kei hea seqnum = X + 1, acknum = Y + 1. I muri i tera, ka timata te whakawhiti raraunga tuuturu.

Ki te kore te kaikorero e whakaae kua riro mai i a ia te kete, ka tukuna ano e TCP kia mutu te wa.

He aha i kore ai e whakamahia nga pihikete SYN i nga wa katoa?

Tuatahi, ki te ngaro tetahi SYNACK, ACK ranei, me tatari koe mo te tuku ano - ka puhoi te hanga hononga. Tuarua, kei roto i te kete SYN - kei roto anake! - he maha nga whiringa ka tukuna e pa ana ki te mahi ano o te hononga. I te kore e mahara ki nga paatete SYN e tau mai ana, ka warewarehia e te tūmau enei whiringa, i roto i nga paatete e whai ake nei ka kore e tukuna e te kaihoko. Ka taea e TCP te mahi i tenei keehi, engari i te waa tuatahi, ka heke te kounga o te hononga.

Mo nga putea, me mahi e te kaupapa XDP nga mea e whai ake nei:

  • whakautu ki a SYN me SYNACK me te pihikete;
  • whakautua te ACK me te RST (whawhati te hononga);
  • whakataka etahi atu kete.

Pseudocode o te hātepe hātepe me te pākete porotiti:

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

Kotahi (*) Ko nga tohu e hiahia ana koe ki te whakahaere i te ahua o te punaha kua tohua - i te waahi tuatahi, ka taea e koe te mahi me te kore o raatau ma te whakamahi noa i te ringaringa TCP me te whakaputa i te pihikete SYN hei raupapa.

I te pae (**), ahakoa karekau he tepu, ka pekehia e matou te kete.

Te whakatinanatanga ruru ringa TCP

Te poroporo me te whakaū waehere

E hiahia ana matou ki nga hanganga pane whatunga: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) me TCP (uapi/linux/tcp.h). Ko te mea whakamutunga kaore i taea e au te hono atu na nga hapa e pa ana ki atomic64_t, Me kape e au nga whakamaramatanga e tika ana ki te waehere.

Ko nga mahi katoa e tohuhia ana i roto i te C mo te panui me tuhi ki te waahi waea, na te mea ka aukati te eBPF i roto i te kernel te peke whakamuri, ara, ko nga koropiko me nga waea mahi.

#define INTERNAL static __attribute__((always_inline))

Tonotono LOG() ka mono i te tā i roto i te hanga tuku.

Ko te kaupapa he paipa o nga mahi. Ka whiwhi ia ki tetahi kete ka tohuhia he pane o te taumata e rite ana, hei tauira, process_ether() e tatari ana kia whakakiia ether. I runga i nga hua o te tātari mara, ka taea e te mahi te whakawhiti i te paatete ki te taumata teitei ake. Ko te hua o te mahi he mahi XDP. Ahakoa ka tukuna e nga kaihautu SYN me ACK nga paanui katoa.

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

Ka aro atu ahau ki nga haki kua tohua A me B. Mena ka korero koe i te A, ka hanga te kaupapa, engari ka puta he hapa manatoko i te wa e utaina ana:

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!

aho matua invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): he ara mahi ina te tekau ma toru nga paita mai i te tiimatanga o te parapare kei waho o te kete. He uaua ki te korero mai i te raarangi ko tehea rarangi e korero ana matou, engari he nama tohutohu (12) me te wetewete e whakaatu ana i nga rarangi o te waehere puna:

llvm-objdump -S xdp_filter.o | less

I tenei take, ka tohu ki te raina

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

e marama ana ko te raruraru ether. Ka pena tonu.

Whakautu ki a SYN

Ko te whainga i tenei wa ko te whakaputa i tetahi paatete SYNACK tika me te pumau seqnum, ka whakakapihia e te pihikete SYN a muri ake nei. Ka puta nga huringa katoa i roto process_tcp_syn() me nga waahi huri noa.

Te tirotiro i te kete

Ko te mea whakamiharo, koinei te rarangi tino whakamiharo, he korero ranei ki a ia:

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

I te wa e tuhi ana i te putanga tuatahi o te waehere, i whakamahia te pata 5.1, mo te manatoko he rereketanga i waenga data_end и (const void*)ctx->data_end. I te wa e tuhi ana, kaore he raruraru i te kernel 5.3.1. Tena pea kei te uru atu te kaikohikohi ki tetahi taurangi paetata he rereke i te mara. Moral - i runga i te kohanga nui, ma te whakangwari i te waehere ka awhina.

Ko nga mahi arowhai roa mo te kororia o te kaitirotiro; O MAX_CSUM_BYTES i raro nei.

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

Ka horahia te kete

Ka whakakiia e matou seqnum и acknum, tautuhia ACK (SYN kua tautuhia):

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

Hurihia nga tauranga TCP, IP me nga wahitau MAC. Ko te whare pukapuka paerewa kaore i te waatea mai i te kaupapa XDP, na memcpy() — he tonotono e huna ana i te 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);

Te tataunga arowhai

Ko nga arowhai IPv4 me TCP e hiahia ana ki te taapiri i nga kupu 16-bit katoa i roto i nga pane, ka tuhia te rahi o nga pane ki roto, ara, i te wa o te whakahiato kaore i te mohiotia. He raru tenei na te mea karekau te kaikorero e peke i te kopae noa tae noa ki te taurangi rohenga. Engari he iti te rahi o nga pane: tae atu ki te 64 paita ia. Ka taea e koe te hanga i te kapiti me te maha o nga whitiwhitinga, ka mutu moata.

Ka kite ahau kei reira RFC 1624 me pehea te tatau ano i te moni arowhai mena ka hurihia nga kupu tuturu o nga paatete. Heoi, ehara te tikanga i te ao katoa, a, ka uaua ake te whakatinanatanga.

Taumahi tātai taki:

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

Ahakoa size manatokohia e te waehere waea, ko te tikanga putanga tuarua e tika ana kia taea ai e te kaitirotiro te whakamatau i te otinga o te riu.

Mo nga kupu 32-bit, ka mahia he putanga ngawari ake:

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

Ma te tatau ano i nga kaute me te whakahoki ano i te kete:

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;

mahi carry() ka hanga i te kaute moka-32 o nga kupu 16-bit, e ai ki a RFC 791.

Tirohanga ruru ringaringa TCP

Ka whakatau tika te tātari i tetahi hononga ki netcat, mokowhiti ana i te ACK whakamutunga, i whakautua e Linux me te putea RST, na te mea kaore i whiwhi te puranga whatunga i te SYN - i hurihia ki te SYNACK ka whakahokia mai - a mai i te tirohanga o te OS, ka tae mai he kete kaore e pa ana ki nga hononga tuwhera.

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

He mea nui ki te tirotiro me nga tono katoa me te mataki tcpdump i runga i xdp-remote no te mea, hei tauira, hping3 e kore e whakautu ki nga utu arowhai he.

Mai i te tirohanga a XDP, he mea iti te haki. Ko te algorithm o te tatauranga he maamaa, he whakaraerae pea ki tetahi kaitukino. Ko te kernel Linux, hei tauira, e whakamahi ana i te SipHash cryptographic, engari ko tana whakatinanatanga mo te XDP he maamaa kei tua atu i te waahanga o tenei tuhinga.

I puta mo nga TODO hou e pa ana ki te taunekeneke o waho:

  • Kaore e taea e te papatono XDP te rokiroki cookie_seed (te wahi ngaro o te tote) i roto i te taurangi o te ao, ka hiahia koe ki te rokiroki i roto i te kakano, ko te uara ka whakahoutia i ia wa mai i te kaihanga pono.

  • Mena ka rite te pihikete SYN ki te paatete ACK, kaore koe e hiahia ki te tuhi i tetahi karere, engari me mahara koe ki te IP o te kiritaki kua whakamanahia kia haere tonu ai nga paatete mai i a ia.

Whakamana e te kiritaki tika:

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

I tuhia e nga rakau te haere o te haki (flags=0x2 ko SYN flags=0x10 he 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

I te mea kaore he rarangi o nga IP kua tirohia, karekau he whakamarumaru ki te waipuke SYN ake, engari koinei te urupare ki te waipuke ACK i whakarewahia e tenei whakahau:

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

Ngā tāurunga rangitaki:

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

mutunga

I etahi wa ka whakaatuhia te eBPF whanui me te XDP hei taputapu a te kaiwhakahaere matatau atu i te papa whanaketanga. Ae ra, he taputapu te XDP mo te whakararu i te tukatuka paatete kernel, ehara i te mea he rereke ki te tapae kernel, penei i te DPDK me etahi atu whiringa maataki kernel. I tetahi atu taha, ka taea e XDP te whakatinana i nga arorau uaua, he mea ngawari ki te whakahou me te kore he okiokinga ki te tukatuka waka. Karekau te kaitirotiro e hanga raru nui, ko au ake karekau au e paopao penei mo nga waahanga o te waehere mokowāmahi.

I te wahanga tuarua, mena he pai te kaupapa, ka whakaotihia e matou te ripanga o nga kiritaki kua whakamanahia me te wawahi i nga hononga, ka whakatinanahia nga porotiti me te tuhi i tetahi taputapu mokowāmahi hei whakahaere i te tātari.

He Tohutoro:

Source: will.com

Tāpiri i te kōrero