praesidium contra DDoS oppugnationes in XDP scribimus. Pars nuclei

Expressa Data Path (XDP) technologiae permittit ut processus temere commercii in Linux interfaces perficiendas permittat antequam fasciculi nuclei retis nuclei intrant. Applicatio XDP - tutelae contra DDoS impetus (CloudFlare), Filtra complexa, statistica collectio (Netflix). Progressiones XDP ab eBPF machinae virtualis efficiuntur, ideo restrictiones habent in utroque codice et functiones nuclei praesto secundum genus colum.

Articulus intendit supplere defectus plurium materiarum in XDP. Primum codicem paratum praebent qui lineamenta XDP statim praetermittit: paratus est ad verificationem vel nimis simplex est ad difficultates causandas. Cum ergo codicem tuum de integro scribere conaris, nescis quid agere cum erroribus typicis. Secundo modos localiter probandi XDP sine VM et ferramenta non operiuntur, non obstante quod suos foveas habent. Textus programmatibus notis cum retis et Linux destinatur qui intersunt XDP et eBPF.

In hac parte, singillatim intelligemus quomodo XDP colum collectum sit et quomodo eum experiatur, tunc scribemus simplicem versionem notae SYN crustulorum mechanismum in gradu processus fasciculi. Nos non creare "album album" sed
verificatur clientes, custodi calculis et colum - satis tigna administrare.

Scribemus in C - non est similis, sed practicus est. Totum codicem in GitHub per nexum in fine praesto est et dividitur in committit secundum gradus in articulo descriptos.

Renuntiationem. Per decursum huius articuli, minimam solutionem explicabimus ad repellendos DDoS impetus, quia hoc munus reale est pro XDP et peritia mea area. Praecipuum tamen propositum est technologiam intelligere, hoc non est dux ad tutelam paratam efficiendam. In codice consequat non optimized et nonnullas nuances omittit.

XDP Brevis Overview

Tantum puncta cardinis effingam ut documenta et articulos exsistentes non duplicent.

Ita, colum code in nucleum oneratur. Reditus fasciculi ad colum transmittuntur. Quam ob rem colum statuere debet: fasciculum in nucleum transi.XDP_PASS) Gutta packet (XDP_DROP) Vel mitte (XDP_TX). Colamentum sarcinam mutare potest, hoc praesertim verum est XDP_TX. Etiam programmata abortum facere potes (XDP_ABORTED) et sarcinam retexere, sed hoc analogum est assert(0) — ad debugging.

eBPF (extenta Berkley Packet Filter) machina virtualis consulto simplex facta est ut nucleus inspicere possit codicem non ansam et aliorum memoriam non laedat. Cumulativo constrictas et compescit;

  • Ansae (retro) prohibentur.
  • BIBLIOTHECA data est, sed munera nulla (omnia C functiones inlineari debent).
  • Memoria accessuum extra ACERVUM et quiddam conleci prohibentur.
  • Magnitudo codicis circumscripta est, sed in usu hoc non est valde significatum.
  • Tantum vocat ad munera specialia nuclei (eBPF adiutores) permissa.

Expansis et insertis filtrum hoc spectat:

  1. Source codice (eg * kernel.c) Obiectum compilata (kernel.o) pro architectura machinae virtualis eBPF. Compilatio ad eBPF, sicut Octobre MMXIX, adiuvatur Clang et promittitur in GCC 2019.
  2. Si hoc obiectum codice continet structuras nucleos (exempli gratia tabulae et calculi), eorum IDs substituuntur a cyphras, quod significat talem codicem exsecutioni mandari non posse. Priusquam in nucleum oneraveris, necesse est has cyphras reponere cum IDs objectorum specificorum per nucleos vocatos creatos (coniunge codicem). Hoc cum exterioribus utilitatibus facere potes, vel programmata scribere potes quae speciale colum ligant et cumulat.
  3. Programma onustum nucleus certificat. Absentia cyclorum et defectus super fasciculum et limites acervos coercetur. Si uerificans probare non potest codicem esse verum, propositum reicitur — necesse est ut ei placere possit.
  4. Post prospere verificationem, nucleus fabricae obiecti architecturae eBPF compingit in codice machinae pro architecturae systematis (mox-in tempore).
  5. Progressio ad interface adiungitur et incipit processus facis.

Cum XDP in nucleum decurrit, debugging tigna utens vestigiis exercetur et, re vera, facis quae programma vel filamenta generat. Nihilominus, eBPF efficit ut codicem receptam ad systema tutandum sit, ut experiri potes cum XDP directe in Linux locali tuo.

Praeparans Opera

conventus

Clang non potest directe producere codicem objectum ad architecturam eBPF, ergo processus duobus gradibus consistit:

  1. Compile C code ad LLVM bytecode (clang -emit-llvm).
  2. Convertere bytecode ad eBPF rem codice (llc -march=bpf -filetype=obj).

Cum colum scribebat, duo fasciculi cum functionibus auxiliaribus et macros utiles erunt ex kernel probat. Aliquam sit amet quam acinum versionem aequare (KVER). Download eos 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 pro Linux Arch (nucleo 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 iter ad acinum caput continet; ARCH — architecturae systematis. Viae et instrumenta distributiones leviter variari possunt.

Exemplum differentiae pro Debian 10 (nucleo 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 directorium cum capitis auxiliis et pluribus directoriis cum nucleo capitis connectere. Symbolum __KERNEL__ significat UAPI (usoris API) capitis capita pro codice kernel definiri, cum colum in nucleo supplicium sit.

Stack praesidium potest erret (-fno-stack-protector), quia eBPF codicis uerificatiuum adhuc pro ACERVUS violationes limitum coercet. In optimizations statim vertere valet, quia magnitudo eBPF bytecode limitatur.

Incipiamus filtrum quod omnia facis et nihil agit;

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

bigas make orationes xdp_filter.o. Ubi nunc ea conaris?

Test scamnum

Stare debet duos interfaces includere: ex quibus colum erit et ex quo fasciculi mittentur. Hae machinis Linux plenae discendae sunt cum IPS propriis ut inspicias quomodo applicationes regulares cum nostro colum labore operantur.

Devices Veth (Aethernet virtualis) nobis aptae sunt: ​​haec sunt bina interfaces virtualis retis "connexa" directe inter se. Eos sic creare potes (in hac sectione omnia mandata ip peraguntur e root):

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

est xdp-remote и xdp-local - fabrica nomina. On xdp-local (192.0.2.1/24) filtrum apponetur, with xdp-remote (192.0.2.2/24) commercium ineuntes mittentur. Difficultas tamen est: interfaces in eadem machina sunt, et Linux commercium ad unum per alterum non mittet. Hoc solvere potes praecepta cum captiosae iptablessed sarcinas mutare, quod debugging incommodum est. Praestat spatiis retis uti (infra netns).

Spatium retis continet interfaces, tabulas fugandas, et regulas NetFilter separatas a similibus objectis in aliis netnis. Uterque processus in spatio nominali decurrit et solum ad objecta netns illius aditum habet. Defalta ratio spatii retis unius pro omnibus obiectis habet, ut in Linux laborare potes nec de rete cognoscere.

Novo spatio nominali faciamus xdp-test ac movere ibi xdp-remote.

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

Tum processus currit in xdp-testnon "videbit" xdp-local remanebit in netns per defaltam et cum missum fasciculum ad 192.0.2.1 transibit xdp-remotequia sola interface in 192.0.2.0/24 huic processui pervia est. Hoc etiam in oppositum operatur.

Cum inter netns moveatur, interface descendit et electronica amittit. Configurare interface in rete, currere debes ip ... in hoc imperio spatio nominali 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

Ut vides, hoc non est diversum ab occasu xdp-local per default spatio nominali:

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

Si curris tcpdump -tnevi xdp-local, videre potes e xdp-testtraduntur huic instrumenti;

ip netns exec xdp-test   ping 192.0.2.1

Convenit mittere concham xdp-test. Repositorium habet scriptum quod automates cum stante operantur, exempli gratia, possis stare cum mandato sudo ./stand up ac delere sudo ./stand down.

Tracing

Filtrum cum fabrica sic coniungitur:

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

clavem -force opus est ut novam programma coniungat si alius iam coniunctus est. "Nihil evangelium est bonum nuntium" non est de hoc mandato, conclusio est in omni casu voluminosa. indicant verbose ad libitum, sed cum eo apparet relatio in opere codicis verificantis cum indice conventus:

Verifier analysis:

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

Progressio ab interface reserare:

ip link set dev xdp-local xdp off

In scripto haec sunt mandata sudo ./stand attach и sudo ./stand detach.

Colamentum apponendo, efficere potes ut ping currere pergit, sed opus facit propositum? Addamus omnia. Officium bpf_trace_printk() similis printf()sed tantum sustinet ad tria argumenta praeter exemplar et limi- tium elenchum. Macro bpf_printk() simpliciorem vocationem.

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

Output accedit ad vestigium nuclei canalis, quod fieri debet;

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

Videre nuntium filum:

cat /sys/kernel/debug/tracing/trace_pipe

Utrumque praeceptum vocant sudo ./stand log.

Ping nunc felis nunc ut hoc nuntios:

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

Si verificantis output inspicias, miras calculos animadvertes;

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

Ita est, quod programmata eBPF non habent sectionem datam, ergo unicus modus chordae formatae immediatae rationes mandatorum VM encode est;

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

Quam ob rem, debug output valde bloats codicem consequens.

Mittens XDP Packets

Filtrum mutemus: omnes fasciculos ineuntes remittat. Haec falsa ex parte retis, cum inscriptiones in capite mutare necesse esset, nunc opus in principio magni momenti est.

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

Launch tcpdump on xdp-remote. Ostendere idem exitus et ineuntes ICMP Echo Request et desinere ostendens ICMP Echo Respondere. Sed non ostendit. Evenit ut opus XDP_TX in progressio on xdp-local oportet,ad par interface xdp-remote programma etiam adsignatum, etsi vacuum, et elevatum.

Unde hoc noui?

Semita of a sarcina in nucleo vestigium Mechanismus perf eventus permittit obiter, eadem machina virtuali utens, hoc est, eBPF, pro discontionibus cum eBPF.

Debes ex malo facere, quia nihil est aliud facere ex malo.

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

Quid est signum 6?

$ errno 6
ENXIO 6 No such device or address

munus veth_xdp_flush_bq() accipit errorem codice e veth_xdp_xmit(), ubi quaerere per ENXIO et commentarium reperies.

Reddamus minimum filter (XDP_PASS) In file xdp_dummy.c, fac cum fac , liga eam cum xdp-remote:

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

autem tcpdump ostendit quid sit expectandum;

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

Si modo ARPs loco ostenduntur, Filtra tollere debes (hoc facit sudo ./stand detach) Dimitte pingtunc filtra pone et iterum conare. Quaestio est quod colum XDP_TX valet tam in ARP et si ACERVUS
spatiis nominalibus xdp-test curo "obliviscere" MAC inscriptionem 192.0.2.1, hanc IP solvere non poterit.

DE PECCATO quaestio

Ad certum negotium transeamus: scribe machina crustula SYN in XDP.

SYN Diluvium remanet impetus popularis DDoS, cujus essentia talis est. Cum nexus constituitur (TCP handshake), minister syn accipit, facultates allocet ad futuram connexionem, respondet cum fasciculo SYNACK et ACK exspectat. Percussor tantum millia SYN packets secundas mittit ex inscriptionibus spoofed ab unoquoque exercitu in botnet multi-mille-strong. Servus in adventu fasciculi statim facultates collocare cogitur, sed eas post tempus magnum dimittit: proinde, memoria vel limites defatigati sunt, novi nexus non recipiuntur, et servitium perpendat.

Si facultates in SYN fasciculo non collocant, sed tantum cum fasciculo SYNACK respondes, quomodo tunc ministra potest intelligere fasciculum ACK qui postea venit ad syn fasciculum qui non servatus est? Post omnes, oppugnator etiam fictus ACKs generare potest. Syn crustulum punctum encode est in . seqnum nexum parametri ut detraheret inscriptiones portuum et mutans salem. Si ACK curo venerit antequam sal mutatum sit, iterum computare potes et cum eo compara acknum. Forge acknum oppugnator non potest, cum sal secretum includit, nec tempus erit per illud ex limitata canali.

SYN crustulum in Linux nucleo iam diu impletum est, ac etiam sponte fieri potest si SYNs nimis cito perveniat ac obuiatur.

Educational programmata TCP handshake

TCP transmissio data praebet ut rivus bytes, exempli gratia, petitiones HTTP super TCP transmittuntur. rivus in frusta dilabitur. Omnes TCP packets habent vexilla logica et numeri seriei 32-bit;

  • Compositio vexillorum munus particularis sarcinae determinat. SYN Vexillum indicat hunc esse primum fasciculum in nexu mittentis. Vexillum ACK significat Mittens accepit omnem nexum data usque ad byte acknum. Fasciculus plura vexilla habere potest et ab eorum compositione dicitur, verbi gratia synacki fasciculus.

  • Sequentia numerus (seqnum) designat offsets in notitia fluminis primi byte qui in hac fasciculo transmittitur. Exempli gratia, si in primo fasciculo cum X bytes notitiarum hic numerus fuerit N, in altera fasciculus cum novis data N+X erit. In nexu principio, passim uterque numerus hunc eligit.

  • Agnitio numeri - idem cinguli ac seqnum, sed non determinat numerum byte transmissi, sed numerum primi byte a recipiente, quem mittens non vidit.

In principio nexu, partes consentire debent seqnum и acknum. Cliens mittit syn fasciculum cum suis seqnum = X. Servus cum fasciculo SYNACK respondet, ubi suum commemorat seqnum = Y et exponit acknum = X + 1. Cliens synack respondet cum fasciculo ACK, ubi seqnum = X + 1, acknum = Y + 1. Post haec ipsa translationis notitia incipit.

Si par acceptum fasciculum non agnoscit, TCP post tempus resilit.

Cur SYN crustula non semper adhibentur?

Uno modo, si SYNACK vel ACK perierit, exspectandum erit ut iterum mittendus - nexus quae retardabit. Secundo in sarcina SYN - et in ea tantum! — nonnullae optiones transmittuntur quae ulteriorem nexum operationis afficiunt. Sine memoria advenientis SYN packets, ministra sic optiones has negligit, cliens eas in proximas fasciculos non mittet. TCP operari in hoc casu potest, sed saltem in initio, qualitas connexionis decrescet.

Ex perspectiva fasciculis, progressio XDP sequentia facere debet:

  • respondere SYN with synack with crustulum ;
  • respondent ACK cum RST (disconnect);
  • abiicias reliquas facis.

Pseudocode algorithmus una cum sarcina parsing :

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

Unus (*) puncta ubi debes statum systematis administrare - in primo stadio sine illis facere potes, solum exsequendo handshake TCP cum generatione syn crustulum ut seqnum.

In macula (**)dum mensam non habemus, fasciculum omittemus.

Exsequens TCP handshake

Parsing in sarcina et probari in codice

Non opus est structurarum network header: Aer (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) Et TCP (uapi/linux/tcp.h). Hoc coniungere potui propter errores relatos atomic64_tDebebam imitari definitiones necessarias in codice.

Munera omnia quae in C in luce sunt ad promptitudinem inclinari debent in puncto vocationis, cum eBPF verificantis in nucleo vetat regressionem, id est, re vera, ansas et functiones vocat.

#define INTERNAL static __attribute__((always_inline))

Macro LOG() disables excudendi in emissione constructum.

Propositum est TRADUCTOR officiorum. Quisque accipit fasciculum in quo vari um caput extulit, v.gr. process_ether() Expectat ut impleatur ether. Fundatur in eventus analysis campi, munus fasciculum ad altiorem gradum transire potest. Effectus functionis actio est XDP. Nunc, SYN and ACK tracto omnes facis.

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

Animum duco ad reprimenda A et B. Si commentabis A, propositum aedificabis, sed error verificationis erit cum oneratione:

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!

Clavis filum invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Sunt viae executionis quando tertiae decimae byte ab initio quiddam est extra conleci. Difficile est intelligere ex enumeratione quam de linea loquimur, sed est numerus instructus (12) et disassembler ostendens lineas fontium codicem;

llvm-objdump -S xdp_filter.o | less

Hic demonstrat lineam

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

Ex quo patet quod quaestio est ether. Etiam id semper velit.

Ad primum ergo syn

Propositum in hac statu est rectam synacam generare cum certo seqnumquae in posterum a SYN crustulum restituetur. Omnes mutationes fieri in process_tcp_syn() et locis circumiacentibus.

Sarcina verificationis

Incommode hic versus est notissimus, vel potius commentarius;

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

Cum primam versionem codicis scriberet, 5.1 nucleus adhibitus est, cuius differentia pro uerificante erat. data_end и (const void*)ctx->data_end. In tempore scribendi nucleus hoc problema 5.3.1 non habuit. Fieri potest ut compilator accederet variabilis localis aliter quam campus. Fabulae moralis: Simplicius signum adiuvare potest cum multum nidificans est.

Proxima sunt exercitatione longitudo coercens ad gloriam uerificantis; O* MAX_CSUM_BYTES inferius.

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

Explicans sarcina

Implemus seqnum и acknumpone ACK (SYN iam positum);

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

Swap TCP portus, IP oratio et MAC inscriptiones. Vexillum bibliothecae XDP a programmatis XDP adiri non est memcpy() — a tortor quae intus Clang abscondit.

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

Recalculum checksums

IPv4 et TCP checksums additamenta omnium verborum 16-parum in capite requirunt, et capitum magnitudo in illis inscripta est, id est tempore compilationis incognita. Hoc problema est quia uerificans normalem ansam ad terminum variabilis non praetermittet. Magnitudo autem capitis finitur: usque ad 64 bytes singulas. Ansam facere potes cum certo numero iterationum, quae mane finire possunt.

Quod est " RFC 1624 quomodo ad checksum ex parte recalculare, si modo certa verba fasciculorum mutantur. Sed modus non est universalis, et difficilius exsecutionem ponere.

Checksum munus calculi:

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

Etsi size verificatur in vocatione Codicis, condicio secundae exitus necessaria est ut uerificans perfectionem ansa probare possit.

Pro 32-bis verbis, versio simplicior impletur;

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

Actu recalculing checksums and mittendis packet back:

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;

munus carry() facit checksum ex summa 32-bitrum verborum 16 bis, secundum RFC 791'.

TCP handshake verificationem

Colum recte constituit nexum cum netcat, carens finali ACK, cui Linux cum RST fasciculum respondit, quia ACERVUS retis syn acceptam non accepit, conversus ad SYNACK et remissus - et ex parte OS, fasciculus pervenit qui ad apertum non relatum est. hospites.

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

Aliquam sit amet applicationes flexas plenas inhibere et observare tcpdump on xdp-remote quia, e.g. hping3 non respondet falsa checksums.

Ex parte XDP ipsa verificationis levis est. Calculus algorithmus est primitivus et verisimile vulnerabilis ad oppugnatorem sophisticum. Linux nucleus, exempli gratia, SipHash cryptographico utitur, sed exsecutio eius pro XDP clare excedit ambitum huius articuli.

Introducti ad novos TODOs ad communicationem externum pertinentes:

  • XDP progressio potest abscondere cookie_seed (partem secreti salis) in variabili globali repositione opus est in nucleo cuius valor periodice renovabitur a certo generante.

  • Si SYN crustulum par in ACK conleci, nuntium imprimere non debes, sed IP clientis verificati memento ut pergas transitum ex eo.

Legitima clientis verificationem:

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

Haec omnia monstrant quod reprehendo Transierunt (flags=0x2 — Hoc est, SYN; flags=0x10 est 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

Dum nullus est index IPS verificatorum, nullum praesidium erit ab ipso diluvio SYN, sed hic est reactionem ad diluvium ACK ab hoc mandato immissum;

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

Log entries:

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

conclusio,

Interdum eBPF in genere et XDP in particulari magis exhibentur instrumentum administratoris provectum quam ut suggestum evolutionis. Re quidem, XDP instrumentum est ut processus nuclei fasciculorum impediat, et non alterutrum cum acervo nucleo, sicut DPDK et aliae nuclei praetermittant bene. Ex altera parte, XDP permittit te ad logicam satis complexam efficiendam, quae praeterea facile est sine intermissione in negocii processui renovare. Verificans magnas difficultates non creat, personaliter, non recuso hoc pro partibus usoris usoris.

In altera parte, si locus iucundus est, mensam de clientibus et disiunctis verificatis complebimus, calculis deducendi et utilitatem usoris scribemus ad colum administrandum.

references:

Source: www.habr.com

Add a comment