eXpress Data Path (XDP) ãã¯ãããžãŒã«ããããã±ãããã«ãŒãã« ãããã¯ãŒã¯ ã¹ã¿ãã¯ã«å ¥ãåã«ãLinux ã€ã³ã¿ãŒãã§ã€ã¹äžã§ã©ã³ãã ãã©ãã£ãã¯åŠçãå®è¡ã§ããŸãã XDP ã®ã¢ããªã±ãŒã·ã§ã³ - DDoS æ»æã«å¯Ÿããä¿è· (CloudFlare)ãè€éãªãã£ã«ã¿ãŒãçµ±èšåé (Netflix)ã XDP ããã°ã©ã 㯠eBPF ä»®æ³ãã·ã³ã«ãã£ãŠå®è¡ãããããããã£ã«ã¿ãŒ ã¿ã€ãã«å¿ããŠã³ãŒããšäœ¿çšå¯èœãªã«ãŒãã«æ©èœã®äž¡æ¹ã«å¶éããããŸãã
ãã®èšäºã¯ãXDP ã«é¢ããå€æ°ã®è³æã®æ¬ ç¹ãè£ãããšãç®çãšããŠããŸãã ãŸããXDP ã®æ©èœãå³åº§ã«ãã€ãã¹ããæ¢è£œã®ã³ãŒããæäŸãããŠããŸããæ€èšŒçšã«æºåãããŠããããåçŽãããŠåé¡ãçºçããªãå¯èœæ§ããããŸãã ã³ãŒããæåããäœæããããšãããšãå žåçãªãšã©ãŒãã©ãããã°ãããããããŸããã 第 XNUMX ã«ãVM ãããŒããŠã§ã¢ã䜿çšããã« XDP ãããŒã«ã«ã§ãã¹ãããæ¹æ³ã«ã€ããŠã¯ãããããã®èœãšãç©Žãããã«ãããããããåãäžããããŠããŸããã ãã®ããã¹ãã¯ããããã¯ãŒã¯ãš Linux ã«ç²ŸéããXDP ãš eBPF ã«èå³ã®ããããã°ã©ãã察象ãšããŠããŸãã
ãã®ããŒãã§ã¯ãXDP ãã£ã«ã¿ãŒã®çµã¿ç«ãŠæ¹æ³ãšãã¹ãæ¹æ³ã詳现ã«ç解ããŠãããããç¥ãããŠãã SYN Cookie ã¡ã«ããºã ã®åçŽãªããŒãžã§ã³ããã±ããåŠçã¬ãã«ã§äœæããŸãã ããã¯ã€ããªã¹ããã¯ãŸã äœæããŸãã
ã¯ã©ã€ã¢ã³ããæ€èšŒããã«ãŠã³ã¿ãŒãä¿æãããã£ã«ã¿ãŒã管çãã - ååãªãã°ã
C ã§æžããŸããããããã§ã¯ãããŸããããå®çšçã§ãã ãã¹ãŠã®ã³ãŒãã¯ãæåŸã«ãããªã³ã¯ãä»ã㊠GitHub ã§å ¥æã§ããèšäºã§èª¬æãããŠãã段éã«åŸã£ãŠã³ãããã«åå²ãããŠããŸãã
å 責äºé ã ãã㯠XDP ãšç§ã®å°éåéã«ãšã£ãŠçŸå®çãªã¿ã¹ã¯ã§ããããããã®èšäºã§ã¯ DDoS æ»æãåé¿ããããã®ãã ãœãªã¥ãŒã·ã§ã³ãéçºããŸãã ãã ããäž»ãªç®çã¯ãã¯ãããžãŒãç解ããããšã§ãããããã¯æ¢è£œã®ä¿è·ãäœæããããã®ã¬ã€ãã§ã¯ãããŸããã ãã¥ãŒããªã¢ã«ã®ã³ãŒãã¯æé©åãããŠããããããã€ãã®ãã¥ã¢ã³ã¹ãçç¥ãããŠããŸãã
XDP ã®æŠèŠ
ããã¥ã¡ã³ããæ¢åã®èšäºãšéè€ããªãããã«ãéèŠãªãã€ã³ãã®ã¿ã説æããŸãã
ãããã£ãŠããã£ã«ã¿ãŒ ã³ãŒããã«ãŒãã«ã«ããŒããããŸãã åä¿¡ãã±ããã¯ãã£ã«ã¿ãŒã«æž¡ãããŸãã ãã®çµæããã£ã«ã¿ãŒã¯ãã±ãããã«ãŒãã«ã«æž¡ããã©ããã決å®ããå¿
èŠããããŸã (XDP_PASS
)ããã±ããããããã(XDP_DROP
) ãŸãã¯è¿éããŠãã ãã (XDP_TX
ïŒã ãã£ã«ã¿ãŒã¯ããã±ãŒãžãå€æŽããå¯èœæ§ããããŸããããã¯ç¹ã«æ¬¡ã®å Žåã«åœãŠã¯ãŸããŸãã XDP_TX
ã ããã°ã©ã ãäžæ¢ããããšãã§ããŸã (XDP_ABORTED
) ããŠããã±ãŒãžããªã»ããããŸãããããã¯é¡äŒŒããŠããŸã assert(0)
- ãããã°çšã
eBPF (æ¡åŒµããŒã¯ã¬ãŒ ãã±ãã ãã£ã«ã¿ãŒ) ä»®æ³ãã·ã³ã¯ãã³ãŒããã«ãŒãããŠããªãããä»ã®ãŠãŒã¶ãŒã®ã¡ã¢ãªã«æå·ãäžããŠããªãããã«ãŒãã«ããã§ãã¯ã§ããããã«ãæå³çã«ã·ã³ãã«ã«äœãããŠããŸãã 环ç©çãªå¶éãšãã§ãã¯:
- ã«ãŒãïŒéæ¹åïŒã¯çŠæ¢ãããŠããŸãã
- ããŒã¿çšã®ã¹ã¿ãã¯ã¯ãããŸãããé¢æ°ã¯ãããŸãã (ãã¹ãŠã® C é¢æ°ãã€ã³ã©ã€ã³åããå¿ èŠããããŸã)ã
- ã¹ã¿ãã¯ããã³ãã±ãããããã¡å€ã®ã¡ã¢ãªã¢ã¯ã»ã¹ã¯çŠæ¢ãããŠããŸãã
- ã³ãŒã ãµã€ãºã¯å¶éãããŠããŸãããå®éã«ã¯ããã¯ããŸãéèŠã§ã¯ãããŸããã
- ç¹å¥ãªã«ãŒãã«é¢æ° (eBPF ãã«ããŒ) ã®åŒã³åºãã®ã¿ãèš±å¯ãããŸãã
ãã£ã«ã¿ãŒã®èšèšãšã€ã³ã¹ããŒã«ã¯æ¬¡ã®ããã«ãªããŸãã
- ãœãŒã¹ã³ãŒã (äŸ:
kernel.c
) ã¯ãªããžã§ã¯ã (kernel.o
) eBPF ä»®æ³ãã·ã³ ã¢ãŒããã¯ãã£ã®å Žåã 2019 幎 10.1 æã®æç¹ã§ãeBPF ãžã®ã³ã³ãã€ã«ã¯ Clang ã§ãµããŒããããŠãããGCC XNUMX ã§çŽæãããŠããŸãã - ãã®ãªããžã§ã¯ã ã³ãŒãã«ã«ãŒãã«æ§é (ããŒãã«ãã«ãŠã³ã¿ãŒãªã©) ãžã®åŒã³åºããå«ãŸããŠããå Žåããããã® ID ã¯ãŒãã«çœ®ãæããããŸããããã¯ããã®ãããªã³ãŒãã¯å®è¡ã§ããªãããšãæå³ããŸãã ã«ãŒãã«ã«ããŒãããåã«ããããã®ãŒãããã«ãŒãã«åŒã³åºããéããŠäœæãããç¹å®ã®ãªããžã§ã¯ãã® ID ã«çœ®ãæãã (ã³ãŒãããªã³ã¯ãã) å¿ èŠããããŸãã ããã¯ãå€éšãŠãŒãã£ãªãã£ã䜿çšããŠå®è¡ããããšããç¹å®ã®ãã£ã«ã¿ãŒããªã³ã¯ããŠããŒãããããã°ã©ã ãäœæããããšãã§ããŸãã
- ã«ãŒãã«ã¯ããŒããããããã°ã©ã ãæ€èšŒããŸãã ãµã€ã¯ã«ããªãããšãããã³ãã±ãããšã¹ã¿ãã¯ã®å¢çãè¶ ããŠããªãããšããã§ãã¯ãããŸãã æ€èšŒè ãã³ãŒããæ£ããããšã蚌æã§ããªãå Žåãããã°ã©ã ã¯æåŠãããŸããæ€èšŒè ãæºè¶³ãããããšãã§ããå¿ èŠããããŸãã
- æ€èšŒãæåãããšãã«ãŒãã«ã¯ eBPF ã¢ãŒããã¯ãã£ã®ãªããžã§ã¯ã ã³ãŒããã·ã¹ãã ã¢ãŒããã¯ãã£ã®ãã·ã³ ã³ãŒãã«ã³ã³ãã€ã«ããŸã (ãžã£ã¹ãã€ã³ã¿ã€ã )ã
- ããã°ã©ã ã¯ã€ã³ã¿ãŒãã§ã€ã¹ã«æ¥ç¶ãããã±ããã®åŠçãéå§ããŸãã
XDP ã¯ã«ãŒãã«å ã§å®è¡ãããããããããã°ã¯ãã¬ãŒã¹ ãã°ãšãå®éã«ã¯ããã°ã©ã ããã£ã«ã¿ãªã³ã°ãŸãã¯çæãããã±ããã䜿çšããŠå®è¡ãããŸãã ãã ããeBPF ã¯ããŠã³ããŒããããã³ãŒããã·ã¹ãã ã«å¯ŸããŠå®å šã§ããããšãä¿èšŒãããããããŒã«ã« Linux äžã§ XDP ãçŽæ¥å®éšã§ããŸãã
ç°å¢ã®æºå
çµç«
Clang 㯠eBPF ã¢ãŒããã¯ãã£ã®ãªããžã§ã¯ã ã³ãŒããçŽæ¥çæã§ããªããããããã»ã¹ã¯ XNUMX ã€ã®ã¹ãããã§æ§æãããŸãã
- C ã³ãŒãã LLVM ãã€ãã³ãŒãã«ã³ã³ãã€ã«ããŸã (
clang -emit-llvm
). - ãã€ãã³ãŒãã eBPF ãªããžã§ã¯ã ã³ãŒãã«å€æ (
llc -march=bpf -filetype=obj
).
ãã£ã«ã¿ãŒãäœæããå Žåãè£å©é¢æ°ãšãã¯ããå«ãããã€ãã®ãã¡ã€ã«ã圹ã«ç«ã¡ãŸãã KVER
ïŒã ããããããŠã³ããŒãããŠãã ãã 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
Arch Linux (ã«ãŒãã« 5.3.7) ã® Makefile:
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
ã«ãŒãã«ããããŒãžã®ãã¹ãå«ãŸããŸãã ARCH
- ã·ã¹ãã ã¢ãŒããã¯ãã£ãŒã ãã¹ãšããŒã«ã¯ãã£ã¹ããªãã¥ãŒã·ã§ã³éã§è¥å¹²ç°ãªãå ŽåããããŸãã
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
XNUMX ã€ã®ãã£ã¬ã¯ããªãè£å©ããããŒã§æ¥ç¶ããè€æ°ã®ãã£ã¬ã¯ããªãã«ãŒãã« ããããŒã§æ¥ç¶ããŸãã ã·ã³ãã« __KERNEL__
ãã£ã«ã¿ãŒã¯ã«ãŒãã«ã§å®è¡ããããããUAPI (ãŠãŒã¶ãŒç©ºé API) ããããŒãã«ãŒãã« ã³ãŒãã«å¯ŸããŠå®çŸ©ãããŠããããšãæå³ããŸãã
ã¹ã¿ãã¯ä¿è·ãç¡å¹ã«ããããšãã§ããŸã (-fno-stack-protector
)ãeBPF ã³ãŒãæ€èšŒããŒã«ã¯äŸç¶ãšããŠã¹ã¿ãã¯ç¯å²å€ã®éåããã§ãã¯ããããã§ãã eBPF ãã€ãã³ãŒãã®ãµã€ãºã«ã¯å¶éããããããããã«æé©åãæå¹ã«ãã䟡å€ããããŸãã
ãã¹ãŠã®ãã±ãããééãããäœãè¡ããªããã£ã«ã¿ãŒããå§ããŸãããã
#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";
ããŒã make
éãã xdp_filter.o
ã ä»ã©ãã§è©ŠããŠã¿ãŸãããïŒ
ãã¹ãã¹ã¿ã³ã
ã¹ã¿ã³ãã«ã¯ XNUMX ã€ã®ã€ã³ã¿ãŒãã§ã€ã¹ãå«ãŸããŠããå¿ èŠããããŸãããã£ã«ã¿ãŒãååšããã€ã³ã¿ãŒãã§ã€ã¹ãšãã±ãããéä¿¡ãããã€ã³ã¿ãŒãã§ã€ã¹ã§ãã éåžžã®ã¢ããªã±ãŒã·ã§ã³ããã£ã«ã¿ãŒã§ã©ã®ããã«åäœãããã確èªããã«ã¯ããããã¯ç¬èªã® IP ãæã€æ¬æ Œç㪠Linux ããã€ã¹ã§ããå¿ èŠããããŸãã
veth (ä»®æ³ã€ãŒãµããã) ã¿ã€ãã®ããã€ã¹ãé©ããŠããŸãããããã¯ãäºãã«çŽæ¥ãæ¥ç¶ããããä»®æ³ãããã¯ãŒã¯ ã€ã³ã¿ãŒãã§ã€ã¹ã®ãã¢ã§ãã 次ã®ããã«äœæã§ããŸã (ãã®ã»ã¯ã·ã§ã³ã§ã¯ãã¹ãŠã®ã³ãã³ã ip
ããå®è¡ãããŸã root
):
ip link add xdp-remote type veth peer name xdp-local
ãã㯠xdp-remote
О xdp-local
â ããã€ã¹åã ã®äž xdp-local
(192.0.2.1/24) ãã£ã«ã¿ãŒãæ·»ä»ãããŸãã xdp-remote
(192.0.2.2/24) åä¿¡ãã©ãã£ãã¯ãéä¿¡ãããŸãã ãã ããåé¡ããããŸããã€ã³ã¿ãŒãã§ã€ã¹ã¯åããã·ã³äžã«ãããLinux ã¯äžæ¹ã®ã€ã³ã¿ãŒãã§ã€ã¹ã«ããäžæ¹ã®ã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠãã©ãã£ãã¯ãéä¿¡ããŸããã é£ããã«ãŒã«ã䜿ãã°è§£æ±ºã§ãã iptables
ãã ããããã±ãŒãžãå€æŽããå¿
èŠãããããããããã°ã«ã¯äžäŸ¿ã§ãã ãããã¯ãŒã¯åå空é (以äžãnetns) ã䜿çšããããšããå§ãããŸãã
ãããã¯ãŒã¯åå空éã«ã¯ãä»ã®ãããäžã®åæ§ã®ãªããžã§ã¯ãããåé¢ãããäžé£ã®ã€ã³ã¿ãŒãã§ã€ã¹ãã«ãŒãã£ã³ã° ããŒãã«ãããã³ NetFilter ã«ãŒã«ãå«ãŸããŠããŸãã åããã»ã¹ã¯ããŒã ã¹ããŒã¹å ã§å®è¡ããããã®ãããã®ãªããžã§ã¯ãã«ã®ã¿ã¢ã¯ã»ã¹ã§ããŸãã ããã©ã«ãã§ã¯ãã·ã¹ãã ã«ã¯ãã¹ãŠã®ãªããžã§ã¯ãã«å¯ŸããŠåäžã®ãããã¯ãŒã¯åå空éããããããnetns ã«ã€ããŠç¥ããªããŠã Linux ã§äœæ¥ã§ããŸãã
æ°ããåå空éãäœæããŸããã xdp-test
ãããŠããã«ç§»åããŸã xdp-remote
.
ip netns add xdp-test
ip link set dev xdp-remote netns xdp-test
次ã«ãããã»ã¹ãå®è¡ãããŸã xdp-test
ããèŠããŸããã xdp-local
(ããã©ã«ãã§ã¯ netns ã«æ®ããŸã)ããã±ããã 192.0.2.1 ã«éä¿¡ããå Žåã¯ééããŸãã xdp-remote
ããã¯ããã®ããã»ã¹ã«ã¢ã¯ã»ã¹ã§ãã 192.0.2.0/24 äžã®å¯äžã®ã€ã³ã¿ãŒãã§ã€ã¹ã ããã§ãã ããã¯éæ¹åã«ãæ©èœããŸãã
netn éã移åãããšãã€ã³ã¿ãŒãã§ã€ã¹ãããŠã³ããã¢ãã¬ã¹ã倱ãããŸãã netns ã§ã€ã³ã¿ãŒãã§ã€ã¹ãèšå®ããã«ã¯ã次ãå®è¡ããå¿
èŠããããŸãã ip ...
ãã®ã³ãã³ãåå空é㧠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
ã芧ã®ãšãããããã¯èšå®ãšå€ãããŸãã xdp-local
ããã©ã«ãã®åå空éã§ã¯æ¬¡ã®ããã«ãªããŸãã
ip address add 192.0.2.1/24 dev xdp-local
ip link set xdp-local up
èµ°ãã° tcpdump -tnevi xdp-local
ãããã±ãããéä¿¡ãããããšãããããŸãã xdp-test
ããã®ã€ã³ã¿ãŒãã§ã€ã¹ã«é
ä¿¡ãããŸãã
ip netns exec xdp-test ping 192.0.2.1
ã§ã·ã§ã«ãèµ·åãããšäŸ¿å©ã§ã xdp-test
ã ãªããžããªã«ã¯ãã¹ã¿ã³ãã®æäœãèªååããã¹ã¯ãªãããå«ãŸããŠããŸããããšãã°ã次ã®ã³ãã³ãã§ã¹ã¿ã³ããæ§æã§ããŸãã sudo ./stand up
ãããŠãããåé€ããŸã sudo ./stand down
.
ãã¬ãŒã¹
ãã£ã«ã¿ãŒã¯æ¬¡ã®ããã«ããã€ã¹ã«é¢é£ä»ããããŸãã
ip -force link set dev xdp-local xdp object xdp_filter.o verbose
ã㌠-force
å¥ã®ããã°ã©ã ããã§ã«ãªã³ã¯ãããŠããå Žåã¯ãæ°ããããã°ã©ã ããªã³ã¯ããå¿
èŠããããŸãã ããã¥ãŒã¹ããªãã®ã¯è¯ããã¥ãŒã¹ã ããšããã®ã¯ãã®åœä»€ã«é¢ãããã®ã§ã¯ãªãããããã«ããŠãçµè«ã¯èšå€§ã§ãã 瀺ã verbose
ãªãã·ã§ã³ã§ãããããã䜿çšãããšãã¢ã»ã³ã㪠ãªã¹ããå«ãã³ãŒã ããªãã¡ã€ã¢ã®åäœã«é¢ããã¬ããŒãã衚瀺ãããŸãã
Verifier analysis:
0: (b7) r0 = 2
1: (95) exit
ã€ã³ã¿ãŒãã§ã€ã¹ããããã°ã©ã ã®ãªã³ã¯ã解é€ããŸãã
ip link set dev xdp-local xdp off
ã¹ã¯ãªããã§ã¯æ¬¡ã®ã³ãã³ãã䜿çšãããŸã sudo ./stand attach
О sudo ./stand detach
.
ãã£ã«ã¿ãŒãåãä»ããããšã§ã ping
ã¯å®è¡ãç¶ããŠããŸãããããã°ã©ã ã¯åäœããŸãã? ãã°ãè¿œå ããŠã¿ãŸãããã é¢æ° bpf_trace_printk()
printf()
ããã ãããã¿ãŒã³ä»¥å€ã®æ倧 XNUMX ã€ã®åŒæ°ãšãéãããæå®åã®ãªã¹ãã®ã¿ããµããŒãããŸãã 倧ãã bpf_printk()
é話ãç°¡çŽ åãããŸãã
SEC("prog")
int xdp_main(struct xdp_md* ctx) {
+ bpf_printk("got packet: %pn", ctx);
return XDP_PASS;
}
åºåã¯ã«ãŒãã« ãã¬ãŒã¹ ãã£ãã«ã«éãããŸããããããæå¹ã«ããå¿ èŠããããŸãã
echo -n 1 | sudo tee /sys/kernel/debug/tracing/options/trace_printk
ã¡ãã»ãŒãž ã¹ã¬ããã衚瀺:
cat /sys/kernel/debug/tracing/trace_pipe
ãããã®ã³ãã³ãã¯ã©ã¡ããåŒã³åºããè¡ããŸã sudo ./stand log
.
Ping ã«ãã次ã®ãããªã¡ãã»ãŒãžãããªã¬ãŒãããããã«ãªããŸãã
<...>-110930 [004] ..s1 78803.244967: 0: got packet: 00000000ac510377
æ€èšŒè ã®åºåãããèŠããšãå¥åŠãªèšç®ã«æ°ã¥ãã§ãããã
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
<...>
å®éãeBPF ããã°ã©ã ã«ã¯ããŒã¿ ã»ã¯ã·ã§ã³ããªãããããã©ãŒãããæååããšã³ã³ãŒãããå¯äžã®æ¹æ³ã¯ VM ã³ãã³ãã®çŽæ¥åŒæ°ã§ãã
$ python -c "import binascii; print(bytes(reversed(binascii.unhexlify('0a7025203a74656b63617020746f67'))))"
b'got packet: %pn'
ãã®ããããããã°åºåã«ãã£ãŠçµæã®ã³ãŒããå€§å¹ ã«è¥å€§åããŸãã
XDP ãã±ããã®éä¿¡
ãã£ã«ã¿ãå€æŽããŸãããããã¹ãŠã®åä¿¡ãã±ãããéãè¿ãããã«ããŸãã ããããŒå ã®ã¢ãã¬ã¹ãå€æŽããå¿ èŠããããããããã¯ãããã¯ãŒã¯ã®èŠ³ç¹ããã¯æ£ãããããŸããããååãšããŠãã®äœæ¥ã¯éèŠã§ãã
bpf_printk("got packet: %pn", ctx);
- return XDP_PASS;
+ return XDP_TX;
}
æã¡äžã tcpdump
Ма xdp-remote
ã åäžã®çºä¿¡ããã³åä¿¡ ICMP ãšã³ãŒèŠæ±ã衚瀺ãããICMP ãšã³ãŒå¿çã®è¡šç€ºãåæ¢ãããŸãã ããããããã¯è¡šç€ºãããŸããã ä»äºã®ããã§ããããšãå€æ XDP_TX
ã®çªçµã§ xdp-local
xdp-remote
ããšãããã空ã§ãã£ãŠããããã°ã©ã ãå²ãåœãŠããã圌ã¯è²ãŠãããŸããã
ã©ããã£ãŠãããç¥ã£ãã®ã§ãã?
ä»ã«åãçããã®ããªãã®ã§ãæªããåãçãŸãªããã°ãªããŸããã
$ 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])
<...>
ã³ãŒã6ãšã¯äœã§ãã?
$ errno 6
ENXIO 6 No such device or address
æ©èœ veth_xdp_flush_bq()
ïœãããšã©ãŒã³ãŒããåãåããŸã veth_xdp_xmit()
ãããã§æ€çŽ¢ ENXIO
ãããŠã³ã¡ã³ããèŠã€ããŸãã
æå°ãã£ã«ã¿ãŒã埩å
ããŸããã (XDP_PASS
) ãã¡ã€ã«å
xdp_dummy.c
ãããã Makefile ã«è¿œå ãããã€ã³ãããŸã xdp-remote
:
ip netns exec remote
ip link set dev int xdp object dummy.o
ä» tcpdump
æåŸ
ãããå
容ã瀺ããŸãã
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
代ããã« ARP ã®ã¿ã衚瀺ãããå Žåã¯ããã£ã«ã¿ãŒãåé€ããå¿
èŠããããŸã (ããã«ããã sudo ./stand detach
ïŒã ææŸã ping
ããã£ã«ã¿ãŒãèšå®ããŠåè©Šè¡ããŠãã ããã åé¡ã¯ãã£ã«ã¿ãŒã§ã XDP_TX
ARP ãšã¹ã¿ãã¯ã®äž¡æ¹ã§æå¹ã§ã
åå空é xdp-test
MAC ã¢ãã¬ã¹ 192.0.2.1 ããå¿ãããããšãã§ãããšããŠãããã® IP ã解決ããããšã¯ã§ããŸããã
åé¡ã®å®åŒå
åè¿°ã®ã¿ã¹ã¯ã«é²ã¿ãŸããããXDP äžã§ SYN Cookie ã¡ã«ããºã ãäœæããŸãã
SYN ãã©ããã¯äŸç¶ãšããŠäººæ°ã®ãã DDoS æ»æã§ããããã®æ¬è³ªã¯æ¬¡ã®ãšããã§ãã æ¥ç¶ã確ç«ããããš (TCP ãã³ãã·ã§ã€ã¯)ããµãŒããŒã¯ SYN ãåä¿¡ããä»åŸã®æ¥ç¶ã«ãªãœãŒã¹ãå²ãåœãŠãSYNACK ãã±ããã§å¿çããACK ãåŸ ã¡ãŸãã æ»æè ã¯ãæ°åã®åŒ·åãªããããããå ã®åãã¹ãã®ã¹ããŒãã£ã³ã°ãããã¢ãã¬ã¹ãã XNUMX ç§ãããæ°åã® SYN ãã±ãããéä¿¡ããã ãã§ãã ãµãŒããŒã¯ãã±ããã®å°ççŽåŸã«åŒ·å¶çã«ãªãœãŒã¹ãå²ãåœãŠãŸããã倧ããªã¿ã€ã ã¢ãŠãåŸã«ãªãœãŒã¹ã解æŸããŸãããã®çµæãã¡ã¢ãªãŸãã¯å¶éã䜿ãæããããæ°ããæ¥ç¶ãåãå ¥ããããããµãŒãã¹ãå©çšã§ããªããªããŸãã
SYN ãã±ããã«åºã¥ããŠãªãœãŒã¹ãå²ãåœãŠããSYNACK ãã±ããã§ã®ã¿å¿çããå ŽåããµãŒããŒã¯ãåŸããå°çãã ACK ãã±ãããä¿åãããŠããªã SYN ãã±ãããåç
§ããŠããããšãã©ã®ããã«ç解ã§ããã§ããããã çµå±ã®ãšãããæ»æè
ã¯åœã® ACK ãçæããããšãã§ããŸãã SYN Cookie ã®ãã€ã³ãã¯ãããã次ã®ããã«ãšã³ã³ãŒãããããšã§ãã seqnum
ã¢ãã¬ã¹ãããŒããå€æŽãœã«ãã®ããã·ã¥ãšããŠã®æ¥ç¶ãã©ã¡ãŒã¿ã ãœã«ããå€æŽãããåã« ACK ããªããšãå°çããå Žåã¯ãããã·ã¥ãå床èšç®ããŠã次ãšæ¯èŒã§ããŸãã acknum
ã ãã©ãŒãž acknum
ãœã«ãã«ã¯ç§å¯ãå«ãŸããŠãããããæ»æè
ã¯ãããè¡ãããšãã§ããŸããããŸãããã£ãã«ãéãããŠããããããããåé¡ããæéããããŸããã
SYN Cookie ã¯é·ãé Linux ã«ãŒãã«ã«å®è£ ãããŠãããSYN ãããŸãã«ãæ©ã倧éã«å°çããå Žåã«èªåçã«æå¹ã«ããããšãã§ããŸãã
TCPãã³ãã·ã§ã€ã¯ã«é¢ããæè²ããã°ã©ã
TCP ã¯ããã€ãã®ã¹ããªãŒã ãšããŠããŒã¿éä¿¡ãæäŸããŸããããšãã°ãHTTP ãªã¯ãšã¹ã㯠TCP çµç±ã§éä¿¡ãããŸãã ã¹ããªãŒã ã¯ãã±ããã«åå²ãããŠéä¿¡ãããŸãã ãã¹ãŠã® TCP ãã±ããã«ã¯è«çãã©ã°ãš 32 ãããã®ã·ãŒã±ã³ã¹çªå·ããããŸãã
-
ãã©ã°ã®çµã¿åããã«ãã£ãŠãç¹å®ã®ããã±ãŒãžã®åœ¹å²ã決ãŸããŸãã SYN ãã©ã°ã¯ããããæ¥ç¶äžã®éä¿¡è ã®æåã®ãã±ããã§ããããšã瀺ããŸãã ACK ãã©ã°ã¯ãéä¿¡è ããã€ããŸã§ã®ãã¹ãŠã®æ¥ç¶ããŒã¿ãåä¿¡ããããšãæå³ããŸãã
acknum
ã ãã±ããã«ã¯è€æ°ã®ãã©ã°ãå«ããããšãã§ãããããã®çµã¿åããã«ãã£ãŠåŒã³åºãããŸã (SYNACK ãã±ãããªã©)ã -
ã·ãŒã±ã³ã¹çªå· (seqnum) ã¯ããã®ãã±ããã§éä¿¡ãããæåã®ãã€ãã®ããŒã¿ ã¹ããªãŒã å ã®ãªãã»ãããæå®ããŸãã ããšãã°ãX ãã€ãã®ããŒã¿ãå«ãæåã®ãã±ããã§ãã®æ°å€ã N ã ã£ãå Žåãæ°ããããŒã¿ãå«ã次ã®ãã±ããã§ã¯ N+X ã«ãªããŸãã æ¥ç¶ã®éå§æã«ãåæ¹ããã®çªå·ãã©ã³ãã ã«éžæããŸãã
-
確èªå¿ççªå· (acknum) - seqnum ãšåããªãã»ããã§ãããéä¿¡ããããã€ãæ°ã§ã¯ãªããéä¿¡è ãèªèããŠããªãåä¿¡è ããã®æåã®ãã€ãã®æ°ã決å®ããŸãã
æ¥ç¶ã®éå§æã«ãåœäºè
ã¯åæããå¿
èŠããããŸã seqnum
О acknum
ã ã¯ã©ã€ã¢ã³ã㯠SYN ãã±ãããéä¿¡ããŸãã seqnum = X
ã ãµãŒããŒã¯ SYNACK ãã±ããã§å¿çãããã®ãã±ããã«ãã®ãã±ãããèšé²ãããŸãã seqnum = Y
ãããŠæŽé²ããŸã acknum = X + 1
ã ã¯ã©ã€ã¢ã³ã㯠SYNACK ã«å¯Ÿã㊠ACK ãã±ããã§å¿çããŸãã seqnum = X + 1
, acknum = Y + 1
ã ãã®åŸãå®éã®ããŒã¿è»¢éãå§ãŸããŸãã
ãã¢ããã±ããã®åä¿¡ã確èªããªãå ŽåãTCP ã¯ã¿ã€ã ã¢ãŠãåŸã«ãã±ãããåéä¿¡ããŸãã
SYN Cookie ãåžžã«äœ¿çšãããªãã®ã¯ãªãã§ãã?
ãŸããSYNACK ãŸã㯠ACK ã倱ãããå Žåãå床éä¿¡ããããŸã§åŸ ã€å¿ èŠããããæ¥ç¶ã»ããã¢ãããé ããªããŸãã 次ã«ãSYN ããã±ãŒãžå ã§ã®ã¿ã§ãã â æ¥ç¶ã®ãã®åŸã®åäœã«åœ±é¿ãäžããå€ãã®ãªãã·ã§ã³ãéä¿¡ãããŸãã ãããã£ãŠãåä¿¡ SYN ãã±ãããèšæ¶ããªãå ŽåããµãŒããŒã¯ãããã®ãªãã·ã§ã³ãç¡èŠããã¯ã©ã€ã¢ã³ãã¯æ¬¡ã®ãã±ããã§ããããéä¿¡ããŸããã ãã®å ŽåãTCP ã¯æ©èœããŸãããå°ãªããšãåæ段éã§ã¯æ¥ç¶ã®å質ãäœäžããŸãã
ããã±ãŒãžã®èŠ³ç¹ããèŠããšãXDP ããã°ã©ã ã¯æ¬¡ã®ããšãè¡ãå¿ èŠããããŸãã
- SYN ã«å¯Ÿã㊠Cookie ã䜿çšãã SYNACK ã§å¿çããŸãã
- ACK ã«å¯Ÿã㊠RST (åæ) ã§å¿çããŸãã
- æ®ãã®ãã±ãããç Žæ£ããŸãã
ã¢ã«ãŽãªãºã ã®æ¬äŒŒã³ãŒããšããã±ãŒãžè§£æ:
ÐÑлО ÑÑП Ме Ethernet,
пÑПпÑÑÑОÑÑ Ð¿Ð°ÐºÐµÑ.
ÐÑлО ÑÑП Ме IPv4,
пÑПпÑÑÑОÑÑ Ð¿Ð°ÐºÐµÑ.
ÐÑлО аЎÑÐµÑ Ð² ÑаблОÑе пÑПвеÑеММÑÑ
, (*)
ÑЌеМÑÑОÑÑ ÑÑеÑÑОк ПÑÑавÑОÑ
ÑÑ Ð¿ÑПвеÑПк,
пÑПпÑÑÑОÑÑ Ð¿Ð°ÐºÐµÑ.
ÐÑлО ÑÑП Ме TCP,
ÑбÑПÑОÑÑ Ð¿Ð°ÐºÐµÑ. (**)
ÐÑлО ÑÑП SYN,
ПÑвеÑОÑÑ SYN-ACK Ñ cookie.
ÐÑлО ÑÑП ACK,
еÑлО в acknum Ð»ÐµÐ¶ÐžÑ ÐœÐµ cookie,
ÑбÑПÑОÑÑ Ð¿Ð°ÐºÐµÑ.
ÐаМеÑÑО в ÑаблОÑÑ Ð°ÐŽÑÐµÑ Ñ N ПÑÑавÑОÑ
ÑÑ Ð¿ÑПвеÑПк. (*)
ÐÑвеÑОÑÑ RST. (**)
РПÑÑалÑÐœÑÑ
ÑлÑÑаÑÑ
ÑбÑПÑОÑÑ Ð¿Ð°ÐºÐµÑ.
XNUMX (*)
ã·ã¹ãã ã®ç¶æ
ã管çããå¿
èŠãããç®æã¯ããŒã¯ãããŠããŸããæåã®æ®µéã§ã¯ãã·ãŒã±ã³ã¹çªå·ãšã㊠SYN Cookie ãçæã㊠TCP ãã³ãã·ã§ã€ã¯ãå®è£
ããã ãã§ãããŒã¯ãªãã§æžã¿ãŸãã
ãã®å Žã§ (**)
ãããŒãã«ããªãéã¯ãã±ãããã¹ãããããŸãã
TCPãã³ãã·ã§ã€ã¯ã®å®è£
ããã±ãŒãžã解æããŠã³ãŒããæ€èšŒãã
ãããã¯ãŒã¯ ããããŒæ§é ãå¿
èŠã«ãªããŸã: Ethernet (uapi/linux/if_ether.h
)ãIPv4 (uapi/linux/ip.h
) ããã³ TCP (uapi/linux/tcp.h
ïŒã åŸè
ã¯ãé¢é£ãããšã©ãŒã®ããæ¥ç¶ã§ããŸããã§ããã atomic64_t
, å¿
èŠãªå®çŸ©ãã³ãŒãã«ã³ããŒããå¿
èŠããããŸããã
èªã¿ãããããããã« C ã§åŒ·èª¿è¡šç€ºãããŠãããã¹ãŠã®é¢æ°ã¯ãåŒã³åºãæç¹ã§ã€ã³ã©ã€ã³åããå¿ èŠããããŸããããã¯ãã«ãŒãã«å ã® eBPF ããªãã¡ã€ã¢ãããã¯ãã©ãã¯ãã€ãŸãã«ãŒããé¢æ°åŒã³åºããçŠæ¢ããŠããããã§ãã
#define INTERNAL static __attribute__((always_inline))
倧ãã LOG()
ãªãªãŒã¹ ãã«ãã§ã¯å°å·ãç¡å¹ã«ããŸãã
ããã°ã©ã ã¯æ©èœã®äŒéæ段ã§ãã ããããã¯ãããšãã°ã察å¿ããã¬ãã«ã®ããããŒã匷調衚瀺ããããã±ãããåä¿¡ããŸãã process_ether()
æºããããããšãæåŸ
ããŠããŸã ether
ã ãã£ãŒã«ã解æã®çµæã«åºã¥ããŠããã®é¢æ°ã¯ãã±ãããäžäœã¬ãã«ã«æž¡ãããšãã§ããŸãã é¢æ°ã®çµæ㯠XDP ã¢ã¯ã·ã§ã³ã§ãã çŸæç¹ã§ã¯ãSYN ãã³ãã©ãŒãš ACK ãã³ãã©ãŒã¯ãã¹ãŠã®ãã±ãããæž¡ããŸãã
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);
}
A ãš B ã®ããŒã¯ãä»ããŠãããã§ãã¯ã«æ³šç®ããŠãã ãããA ãã³ã¡ã³ãã¢ãŠããããšãããã°ã©ã ã¯ãã«ããããŸãããããŒãæã«æ€èšŒãšã©ãŒãçºçããŸãã
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!
ããŒæåå invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0)
: ãããã¡ã®å
é ãã 12 çªç®ã®ãã€ãããã±ããã®å€åŽã«ããå Žåãå®è¡ãã¹ãååšããŸãã ãªã¹ãããã¯ã©ã®è¡ã«ã€ããŠè©±ããŠããã®ããç解ããã®ã¯é£ããã§ãããåœä»€çªå· (XNUMX) ãšãœãŒã¹ ã³ãŒãã®è¡ã瀺ãéã¢ã»ã³ãã©ããããŸãã
llvm-objdump -S xdp_filter.o | less
ãã®å Žåãããã¯æ¬¡ã®è¡ãæããŸã
LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));
ããã«ãããåé¡ã¯æ¬¡ã®ãšããã§ããããšãæããã§ã ether
ã ãã€ããããªæãã ããã
SYNããã«è¿ä¿¡
ãã®æ®µéã§ã®ç®æšã¯ãåºå®ãããæ£ãã SYNACK ãã±ãããçæããããšã§ãã seqnum
ãå°æ¥çã«ã¯ SYN Cookie ã«çœ®ãæããããäºå®ã§ãã ãã¹ãŠã®å€åã¯ä»¥äžã§çºçããŸã process_tcp_syn()
ãšãã®åšèŸºå°åã
ããã±ãŒãžã®æ€èšŒ
å¥åŠãªããšã«ãæã泚ç®ã«å€ããè¡ããŸãã¯ãã®ã³ã¡ã³ãã¯æ¬¡ã®ãšããã§ãã
/* Required to verify checksum calculation */
const void* data_end = (const void*)ctx->data_end;
ã³ãŒãã®æåã®ããŒãžã§ã³ãäœæãããšããããªãã¡ã€ã¢ã«ã¯ 5.1 ã«ãŒãã«ã䜿çšãããŸããã data_end
О (const void*)ctx->data_end
ã ãã®èšäºã®å·çæç¹ã§ã¯ãã«ãŒãã« 5.3.1 ã«ã¯ãã®åé¡ã¯ãããŸããã§ããã ã³ã³ãã€ã©ããã£ãŒã«ããšã¯ç°ãªãæ¹æ³ã§ããŒã«ã«å€æ°ã«ã¢ã¯ã»ã¹ããŠããå¯èœæ§ããããŸãã ãã®è©±ã®æèš: ãã¹ããå€ãå Žåã«ã¯ãã³ãŒããåçŽåããããšã圹ç«ã¡ãŸãã
次ã«ãæ€èšŒè
ã®æ å
ãè³ããã«ãŒãã³ã®é·ããã§ãã¯ã§ãã â MAX_CSUM_BYTES
以äžã
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 */
}
ããã±ãŒãžãå±éãã
åããŸã seqnum
О acknum
ãACKãèšå®ããŸã(SYNã¯ãã§ã«èšå®ãããŠããŸã):
const u32 cookie = 42;
tcp->ack_seq = bpf_htonl(bpf_ntohl(tcp->seq) + 1);
tcp->seq = bpf_htonl(cookie);
tcp->ack = 1;
TCP ããŒããIP ã¢ãã¬ã¹ãMAC ã¢ãã¬ã¹ã亀æããŸãã XDP ããã°ã©ã ããã¯æšæºã©ã€ãã©ãªã«ã¢ã¯ã»ã¹ã§ããªãããã memcpy()
â Clang çµã¿èŸŒã¿é¢æ°ãé衚瀺ã«ãããã¯ãã
const u16 temp_port = tcp->source;
tcp->source = tcp->dest;
tcp->dest = temp_port;
const u32 temp_ip = ip->saddr;
ip->saddr = ip->daddr;
ip->daddr = temp_ip;
struct ethhdr temp_ether = *ether;
memcpy(ether->h_dest, temp_ether.h_source, ETH_ALEN);
memcpy(ether->h_source, temp_ether.h_dest, ETH_ALEN);
ãã§ãã¯ãµã ã®åèšç®
IPv4 ããã³ TCP ãã§ãã¯ãµã ã§ã¯ãããããŒå ã®ãã¹ãŠã® 16 ããã ã¯ãŒããè¿œå ããå¿ èŠããããããããŒã®ãµã€ãºã¯ããããŒã«æžã蟌ãŸããŸããã€ãŸããã³ã³ãã€ã«æã«ã¯äžæã§ãã ããªãã¡ã€ã¢ã¯å¢çå€æ°ãžã®éåžžã®ã«ãŒããã¹ãããããªãããããããåé¡ãšãªããŸãã ãã ããããããŒã®ãµã€ãºã¯å¶éãããŠãããããããæ倧 64 ãã€ãã§ãã åºå®ã®å埩åæ°ã§ã«ãŒããäœæããæ©æã«çµäºããããšãã§ããŸãã
ãããããšã«æ³šæããŠãã ãã
ãã§ãã¯ãµã èšç®æ©èœïŒ
#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;
}
ããã§ã size
åŒã³åºãã³ãŒãã«ãã£ãŠæ€èšŒããããšãæ€èšŒè
ãã«ãŒãã®å®äºã蚌æã§ããããã« XNUMX çªç®ã®çµäºæ¡ä»¶ãå¿
èŠã«ãªããŸãã
32 ããã ã¯ãŒãã®å Žåã¯ãããåçŽãªããŒãžã§ã³ãå®è£ ãããŠããŸãã
INTERNAL u32
sum16_32(u32 v) {
return (v >> 16) + (v & 0xffff);
}
å®éã«ãã§ãã¯ãµã ãåèšç®ããŠãã±ãããéãè¿ããŸãã
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;
æ©èœ carry()
RFC 32 ã«åŸã£ãŠã16 ããã ã¯ãŒãã® 791 ãããã®åèšãããã§ãã¯ãµã ãäœæããŸãã
TCPãã³ãã·ã§ã€ã¯æ€èšŒ
ãã£ã«ã¿ãŒã¯æ£ããæ¥ç¶ã確ç«ããŸãã netcat
ãããã¯ãŒã¯ ã¹ã¿ãã¯ã SYN ãåä¿¡ããªãã£ããããLinux ã RST ãã±ããã§å¿çããæåŸã® ACK ãæ¬ èœããŠããŸãã - SYNACK ã«å€æãããŠéãè¿ãããŸãã - ãããŠãOS ã®èŠ³ç¹ããã¯ããªãŒãã³ã«é¢ä¿ã®ãªããã±ãããå°çããŸããæ¥ç¶ã
$ sudo ip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer
æ¬æ Œçãªã¢ããªã±ãŒã·ã§ã³ã§ç¢ºèªãã芳å¯ããããšãéèŠã§ã tcpdump
Ма xdp-remote
ãªããªããäŸãã°ã hping3
äžæ£ãªãã§ãã¯ãµã ã«ã¯å¿çããŸããã
SYNã¯ãããŒ
XDP ã®èŠ³ç¹ããã¯ãæ€èšŒèªäœã¯ç°¡åã§ãã èšç®ã¢ã«ãŽãªãºã ã¯åå§çã§ãããé«åºŠãªæ»æè ã«å¯ŸããŠè匱ã§ããå¯èœæ§ããããŸãã ããšãã°ãLinux ã«ãŒãã«ã¯æå·å SipHash ã䜿çšããŸãããXDP ãžã®ãã®å®è£ ã¯æããã«ãã®èšäºã®ç¯å²ãè¶ ããŠããŸãã
å€éšéä¿¡ã«é¢é£ããæ°ãã TODO ã®ããã«å°å ¥ãããŸããã
-
XDP ããã°ã©ã ã¯ä¿åã§ããŸãã
cookie_seed
(ãœã«ãã®ç§å¯ã®éšå) ãã°ããŒãã«å€æ°ã«å«ããã«ã¯ãã«ãŒãã«å ã«ã¹ãã¬ãŒãžãå¿ èŠã§ãããã®å€ã¯ä¿¡é Œã§ãããžã§ãã¬ãŒã¿ãŒããå®æçã«æŽæ°ãããŸãã -
SYN Cookie ã ACK ãã±ããå ã§äžèŽããå Žåãã¡ãã»ãŒãžãåºåããå¿ èŠã¯ãããŸããããæ€èšŒãããã¯ã©ã€ã¢ã³ãããã®ãã±ããã®åãæž¡ããç¶ããããã«ãæ€èšŒãããã¯ã©ã€ã¢ã³ãã® IP ãèŠããŠãããŠãã ããã
æ£èŠã®ã¯ã©ã€ã¢ã³ãã®æ€èšŒ:
$ sudoip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer
ãã°ã«ã¯ããã§ãã¯ãæåããããšã瀺ãããŠããŸã (flags=0x2
- SYNã§ãã flags=0x10
㯠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
æ€èšŒæžã¿ IP ã®ãªã¹ãããªããããSYNââ ãã©ããèªäœããã®ä¿è·ã¯ãããŸãããã次ã®ã³ãã³ãã«ãã£ãŠéå§ããã ACK ãã©ããã«å¯Ÿããåå¿ã¯æ¬¡ã®ãšããã§ãã
sudo ip netns exec xdp-test hping3 --flood -A -s 1111 -p 2222 192.0.2.1
ãã°ãšã³ããª:
Ether(proto=0x800)
IP(src=0x15bd11a dst=0x15bd11e proto=6)
TCP(sport=3236 dport=2222 flags=0x10)
cookie mismatch
ãŸãšã
eBPF äžè¬ãšç¹ã« XDP ã¯ãéçºãã©ãããã©ãŒã ãšããŠãããé«åºŠãªç®¡çè ããŒã«ãšããŠæ瀺ãããããšããããŸãã å®éãXDP ã¯ã«ãŒãã«ã«ãããã±ããã®åŠçã劚害ããããŒã«ã§ãããDPDK ããã®ä»ã®ã«ãŒãã« ãã€ãã¹ ãªãã·ã§ã³ã®ãããªã«ãŒãã« ã¹ã¿ãã¯ã®ä»£æ¿ããŒã«ã§ã¯ãããŸããã äžæ¹ãXDP ã䜿çšãããšãéåžžã«è€éãªããžãã¯ãå®è£ ã§ããããã«ããã©ãã£ãã¯åŠçãäžæããããšãªãç°¡åã«æŽæ°ã§ããŸãã ãã®æ€èšŒããŒã«ã¯å€§ããªåé¡ãåŒãèµ·ãããŸããããå人çã«ã¯ããŠãŒã¶ãŒç©ºéã³ãŒãã®äžéšã«ã€ããŠã¯ãããæåŠããŸããã
XNUMX çªç®ã®éšåã§ã¯ããããã¯ãèå³æ·±ãå Žåã¯ãæ€èšŒãããã¯ã©ã€ã¢ã³ããšåæã®è¡šãäœæããã«ãŠã³ã¿ãŒãå®è£ ãããã£ã«ã¿ãŒã管çãããŠãŒã¶ãŒç©ºéãŠãŒãã£ãªãã£ãäœæããŸãã
ãªã³ã¯ïŒ
GitHub äžã®å®å šãªã³ãŒã bpftrace ããŒãã·ãŒã BPF ããã³ XDP ãªãã¡ã¬ã³ã¹ ã¬ã€ã XDP ãã¥ãŒããªã¢ã« PoC: Rust ãã eBPF ãžã®ã³ã³ãã€ã«
åºæïŒ habr.com