αα αα αααα·ααααΆ eXpress Data Path (XDP) α’αα»ααααΆαα±ααααααΎαααΆαα ααΆα αα αααααααααΌαααΆαα’αα»αααααα ααΎα ααα»α αααααΆααααΈαα»α αα»αααααααα ααααααααΆαα αΌααα αααα»αααααααααΆαααΊαααα αααααα·ααΈ XDP - ααΆαααΆαααΆααααααΆααααΉαααΆαααΆααααα αΆα DDoS (CloudFlare) ααααααααα»αααααΆα ααΆααααααΌααααα·αα· (Netflix) α αααααα·ααΈ XDP ααααΌαααΆαααααα·ααααα·ααααααΆαααΈααα·αααα·α eBPF ααΌα αααααα½αααααΆαααΆαααΉααααααΉαααΆααααΌααααααα½ααα αα·ααα»αααΆαααΊααααααααΆαα’αΆαααααααΎαααααααααααα
α’ααααααααααΆαααααααααααααα ααα»α ααααααΆααααααααΆααααΆα αααΎααα ααΎ XDP α ααΈαα½α αα½αααααααααααααΌααααααααααα½α ααΆααααα ααααααααααααααα·ααααααα XDP ααααΆααα ααΆααααΌαααΆααααα ααααααΆααααΆααααααααααΆαα α¬ααΆααααααααααα»αααΆααααααααα αΆα αα αααα’αααααααΆααΆααααααααΌαααααα’αααααΈααααΌα α’ααααα·αααΉαααΆααααΌαααααΎα’αααΈααΆαα½αααα α»αααααααΆααα ααΈααΈα αα·ααΈααΎααααΈααΆααααα XDP αααα»ααααα»ααααααααΆα VM αα·ααααααααΉααα·αααααΌαααΆααααααααααααα ααΎαααααΈααΆαα½αααααΆαααα α»αααααΆαααααα½ααααααα α’ααααααααααααΌαααΆαααααα»ααα»ααααααΆααα’αααααααααααααα·ααΈαααααααΆαααααααΆα αα·αααΈαα»α αααα αΆααα’αΆααααααααΎ XDP αα·α eBPF α
αα
αααα»ααααααααα ααΎαααΉαααααααΆααααα’α·αα’αααΈαααααααααααα XDP ααααΌαααΆααααααΌααααα»α αα·αααααααΆαααααααΆ αααααΆααααααΎαααΉααααααααααααΆααααααααααααΆαααΌααΈ SYN ααααααΈααααΆααα
ααααα·αααααΎαααΆααααα
ααααααααΆαα ααΎαααΉααα·ααααααΎα "αααααΈα" αα
α‘αΎααα
α’αα·αα·αααααααΆααααααααααΆαα αααααΆααααα αα·ααααααααααααααα - αααααα ααα»αααααααααΆααα
ααΎαβααΉαβαααααβααΆ C - ααΆβαα·αβααΆααααααβαα ααα»ααααβααΆβααΆβααΆαβα’αα»ααααβααΆαααααααα ααΌαααΆααα’ααααΆααα ααΎ GitHub ααΆαααααααααααΆαααα α α»ααααα αα α αΎαααααΌαααΆααααα αααα ααΆααΆααααααααΉαααααΆαααααΆααααΆααααααΆααα·αααααΆαα αααα»αα’αααααα
ααΆαααα·αααα αααα»αα’αα‘α»ααααααα’αααααααα αααα»αααΉααααααΎααααααααααΆαααααΆαααΌα ααΎααααΈαααααααΆααααΆαααΆααααα αΆαααα DDoS ααΈααααααααααΊααΆαα·α αα ααΆαααΆααααααααααααΆαα XDP αα·ααααααααααΆααααααααα»αα αααααΆαααΆαααΆααααα ααααα ααααΆααααΊααααΌααααααΈαα αα αααα·ααααΆααα αα·ααααααΆααΆαααααΆαααΎααααΈαααααΎαααΆαααΆαααΆααααααααααα½α ααΆααααα αααααα ααΌααααααααα·αααααΌαααΆαααααΎα±αααααααΎααα α αΎααα»αα ααααΌαα ααα»α αα½αα ααα½αα
αα·αααααΆαααΌαα αααααα XDP
αααα»αααΉαααΌααααααΆααααα ααα»α ααααΆαααααα»ααααα ααΎααααΈαα»αα±ααα ααααα―αααΆα αα·αα’ααααααααααΆαααααΆααα
ααΌα
αααα ααΌααααααααααΌαααΆααααα»ααα
αααα»αααΊαααα αααα
ααααααααΆαα
αΌαααααΌαααΆααααααΌααα
αααααα ααΆαααααα αααααααααΌαααααααΎααΆααααααα
α
α·αααα αααααΌααααα
ααααααααΆααα
αααα»αααΊααα (XDP_PASS
) αααααΆαααααα
αα (XDP_DROP
) α¬ααααΎααΆαααα·α (XDP_TX
) αααααα’αΆα
ααααΆααααααΌααααα
αα αααααΆααΆααα·αααΆαα·ααααααααΆαα XDP_TX
. α’αααααα’αΆα
αααααααααααα·ααΈ (XDP_ABORTED
) α αΎαααααααααα
ααα‘αΎααα·α ααα»αααααααααΊααααααααααΆ assert(0)
- αααααΆααααΆαααααα α»αα
αααΆαααΈααα·αααα·α eBPF (extended Berkley Packet Filter) ααααΌαααΆααααααΎαα‘αΎααααα ααααΆααΆαααα ααΎααααΈα±ααααΊαααα’αΆα αα·αα·αααααΎαααΆααΌααα·αααααα·ααα»α αα·ααα·αααααΎα±ααααΌα ααΆαα αα αΆαααααα’ααααααα ααΆαααΉααααααΉα αα·αααΆααααα½ααα·αα·αααααααααα
- ααααα·ααα»α (ααααααα) ααααΌαααΆαα αΆαααΆααα
- ααΆαααααααααΆαααα·αααααα ααα»αααααα·αααΆααα»αααΆααα (αα»αααΆα C ααΆααα’ααααααΌαααααΆαααααα»ααα½α)α
- ααΆαα αΌαααααΎα’αααα αα αΆααα ααΆααααα ααα αα·αααα·ααααααα’αΆαααααααα ααααααααΆαααααΌαααΆαα αΆαααΆααα
- ααα αβααΌαβααΆαβααααα·α ααα»ααααβαααα»αβααΆαβα’αα»ααααβαααβαα·αβααΌαβααααΆααβααα
- ααΆαααααΆαα α αα ααΆαααα»αααΆαααΊααααα·ααα (α’ααααααα½α eBPF) ααα»ααααααααααααΌαααΆαα’αα»ααααΆαα
ααΆααα ααΆ αα·αααα‘αΎααααααααΎααα ααΌα αααα
- ααΌαααααα (α§
kernel.c
) ααααΌαααΆαα αααααααΆααααα» (kernel.o
) αααααΆααααααΆαααααααααααΆαααΈααα·αααα·α eBPF α αα·αααααΉααααα»ααΆ ααααΆα 2019 ααΆαα ααααααα eBPF ααααΌαααΆαααΆααααααα Clang αα·αααΆααααααΆαα αααα»α GCC 10.1 α - ααααα·αααΎααΌαααααα»αααααΆαααΆαα α αα ααΆαααα ααΆααααααααααΊααα (α§ααΆα ααα ααΆααΆα αα·αααααα) ααααααααΆαααααααα½αααααααΌαααΆααααα½αααααααααΌααα αααααΆααααααΆααΌααααααααα·αα’αΆα ααααα·ααααα·ααΆαααα αα»αααααααα»ααα αααα»αααΊααα α’αααααααΌααααα½ααααααΌαααααΆαααααααΆαα½αααΉαααααααααΆααααααααα»ααΆααααΆαααααααΆααααααΎαααΆααααααΆαα α ααΌααααααααΊααα (ααααΆααααΌα)α α’αααα’αΆα ααααΎααΌα αααααΆαα½αα§αααααααααΎααααΆααααΆααααα α¬α’αααα’αΆα ααααααααααα·ααΈαααααΉαααααΆαα αα·ααααα»ααααααααΆααααΆαααα½αα
- ααΊααααααααααααΆαααααααα·ααΈαααααΆααααα»αα α’ααααααΆααααααα αα·αααΆααααΆααααααα»αααΆαααΎαααΈαααα ααααααααΆα αα·αααααααααααααααΌαααΆααα·αα·αααα ααααα·αααΎα’ααααααααααααΆαααα·αα’αΆα αααα αΆαααΆαααααΌαααααΉαααααΌααα αααααα·ααΈααααΌαααΆαααα·ααα - α’αααααααΌαααα’αΆα ααααΆααα α·αααααΆααα
- αααααΆααααΈααΆααααααααααΆααααααααααα ααΊαααα αααααααΌαααααα»ααααΆαααααααα eBPF αα ααΆααΌααααΆαααΈααααααΆααααααΆαααααααααααααααα (ααααΆαααααα αααα»ααααααααΆ)α
- αααααα·ααΈααααΆαααα α ααα»α αααααΆαα α αΎαα αΆααααααΎαααααΎαααΆααααα ααααααααΆαα
α αΆααααΆααααΈ XDP ααααΎαααΆααα αααα»αααΊααα ααΆαααααΆααααα α»αααααΌαααΆαα’αα»αααααααααααΎαααααα ααα»ααΆαααΆα α αΎαααΆααΆααα·α αααα ααααααααΆαααααααααα·ααΈα ααααα α¬αααααΎαα ααααααΆαααΆααααα eBPF ααΆααΆααΆααΌααααααΆαααΆαααααΊααΆααα»ααααα·ααΆααααααΆαααααααααα ααΌα ααααα’αααα’αΆα αα·αααααααΆαα½α XDP αααααααΆαααα ααΎααΈαα»α αααα»ααααα»αααααα’αααα
ααΆααααα αααα·ααααΆα
ααααα·ααΆα
Clang αα·αα’αΆα αααααΎαααΌαααααα»αααααααΆαααααααΆααααααΆαααααααα eBPF ααΆααα ααΌα ααααααααΎαααΆαααΆαααΈαααα αΆαα
- α
αααααααΌα C αα
ααΆ LLVM bytecode (
clang -emit-llvm
). - ααααα bytecode αα
eBPF object code (
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
Makefile αααααΆαα Arch Linux (ααΊααα 5.3.7)α
CLANG ?= clang
LLC ?= llc
KDIR ?= /lib/modules/$(shell uname -r)/build
ARCH ?= $(subst x86_64,x86,$(shell uname -m))
CFLAGS =
-Ihelpers
-I$(KDIR)/include
-I$(KDIR)/include/uapi
-I$(KDIR)/include/generated/uapi
-I$(KDIR)/arch/$(ARCH)/include
-I$(KDIR)/arch/$(ARCH)/include/generated
-I$(KDIR)/arch/$(ARCH)/include/uapi
-I$(KDIR)/arch/$(ARCH)/include/generated/uapi
-D__KERNEL__
-fno-stack-protector -O2 -g
xdp_%.o: xdp_%.c Makefile
$(CLANG) -c -emit-llvm $(CFLAGS) $< -o - |
$(LLC) -march=bpf -filetype=obj -o $@
.PHONY: all clean
all: xdp_filter.o
clean:
rm -f ./*.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
ααααΆααβααβααΆαα½αβααααααΆβαααα½α αα·αβααβαα½αβα
ααα½αβααΆαα½αβααααααΆβααΊαααα αα·αα·ααααααααΆ __KERNEL__
ααΆααααααΆ ααααααΆ UAPI (userspace 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
. ααΆααααααα
α―ααΆα₯α‘αΌαααα?
ααααΆααααα
ααααααααααααΌααααα½ααααα αΌαα ααα»α αααααΆααααΈαα αααααΉαααΆαααααα αα·αααΈαααα ααααααααΆαααΆαα½αααΉαααααΌαααΆαααααΎα ααΆαααααααααΌαααααΆα§αααααααΈαα»α ααααααααΆαα½αααΉα IPs ααααΆαααααααα½ααα ααΎααααΈαα·αα·αααααΎαααΆααΎαααααα·ααΈααααααΆααααΎαααΆαααΆαα½ααααααααααααΎαα
α§ααααααααααααα veth (virtual Ethernet) ααΊαααααααααααΆααααΎαα ααΆαααααααΊααΆααΌααα
ααα»α
αααααΆαααααααΆααα·αααα·α "ααΆαααααΆαα" αααααααΆαααα
ααααΆαα
αα·ααα
ααα α’αααα’αΆα
αααααΎααα½αααΆααΌα
ααα (αα
αααα»ααααααααα ααΆααααααααΆααΆααα’ααα 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) α
ααΆα
αααα
αΌαααΉαααααΌαααΆαααααΎα ααααααΆαααΆααααα ααΆααααα αΆαα½αα α
ααα»α
αααααΆααααΊαα
ααΎαααΆαααΈααααα½α α αΎαααΈαα»α
ααΉααα·ααααααΌαα
ααΆα
ααα
ααΆαααα½ααααα»αα
αααααα½αααΆααΆααααα§αααααααααααααα α’αααα’αΆα
αααααααΆαααΆαααααααΎα
αααΆαααααα·α
iptables
ααα»αααααα½αααααΉαααααΌαααααΆααααααΌααααα
αα αααααΆααΆααα’αΆαααα’α½ααααααΆααααΆαααααα α»αα ααΆααΆααΆααααααΎααααα»αααΆαααααΎα
αααααααααααααααΆα (αααααΆαα netns) α
α αααααααααααααααΆαααΆααααα»αααα ααα»α αααααΆαα ααΆααΆαααΆαααααΌα αα·αα αααΆαα NetFilter αααααΆα αααααΆαααΈααααα»ααααααααααΆαα αααα»α netns ααααααααα ααααΎαααΆαααΈαα½ααααααΎαααΆααααα»α namespace α αΎαααΆααα·αααα·α αΌαααααΎααααααα»αα netns αααα ααΆαααααΆαααΎα ααααααααααΆαααα αααααΆααααα½ααααααΆααααααα»ααΆααα’αα ααΌα ααααα’αααα’αΆα ααααΎααΆααα αααα»αααΈαα»α α αΎααα·αααΉαα’αααΈ netns ααα
ααααααααΎα namespace ααααΈα 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 α’αΆα
α
αΌαααααΎαααΆαααΆααααα»αααααΎαααΆααααα αααααααααΎαααΆααααα»ααα·ααα
αααα»αα
αα
αααααααΆααααΈαααΆα netns α
ααα»α
αααααΆααααααΆααα
α»α α αΎαααΆαααααα’αΆααααααΆαααααααΆα ααΎααααΈααααααα
ααΆααααααααα
ααα»α
αααααΆαααα
αααα»α netns α’αααααααΌαααααΎαααΆα ip ...
αα
αααα»α namespace ααΆααααααααΆαααα 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
αα
αααα»α namespace ααααΆαααΎαα
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
. ααααΆααααΆαααααααΈααααααααΎαααΆααααααααααααααααααΆαα½α stand; α§ααΆα ααα α’αααα’αΆα
ααααααα
ααΆαααααααααααααααααΎααΆααααααααΆ 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()
ααα»ααααααΆααααααα’αΆαα»αααααααΈααα»ααααα αααα
ααΈααααΌ αα·ααααααΈαααααααα’ααααααααΆααα αααΆααααΌ 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 Echo Request α
αα αα·αα
αΌαααΌα
ααααΆ α αΎαααααααα αΆα ICMP Echo Reply α ααα»ααααααΆαα·ααααα αΆαααα ααΆααααααΆαααααΆααααΆαααΆα 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])
<...>
ααΎαααααΌα α¦ ααΆα’αααΈ?
$ 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
ααααα·αααΎααΆααα ARPs ααααΌαααΆααααα αΆααααα½ααα·α α’αααααααΌααααααααα
αα (ααΆααΎαα‘αΎα sudo ./stand detach
), αααβαα
ping
αααααΆαααααααααααααα α αΎαααααΆααΆααααααααα αααα αΆααΊααΆααααα XDP_TX
ααΆααα»ααααΆαααΆαααα
ααΎ ARP αα·αααααα·αααΎααα
α
αααααααααα xdp-test
αααααααααααΎααααΈ "ααααααα
" α’αΆααααααΆα MAC 192.0.2.1 ααΆααΉααα·αα’αΆα
αααααααΆα IP αααααΆαααα
ααΆααααααΎααααα αΆ
α αΌααααααα αα·α αα ααΆααααααΆααααααΆααα αααααααααααΆαααΌααΈ SYN αα ααΎ XDP α
ααΉαααααα SYN αα ααααΆααΆαααΆααααα αΆα DDoS ααααααα·αα αααααααΉαααΆαααΆαααΌα ααΆααααααα αα ααααααααΆααααααΆααααααΌαααΆααααααΎαα‘αΎα (ααΆαα αΆαααα TCP) αααΆαααΈαααααα½αααΆα SYN αααα ααααααΆααααααΆααααΆααααααΆααααΆαααα’ααΆαα ααααΎαααααΆαα½ααααα αα SYNACK α αΎααααα αΆα ACK α α’αααααΆααααα αΆαααααΆααααααααΎαααα αα SYN ααΆααααΆαααααα»ααα½ααα·ααΆααΈααΈα’αΆααααααΆααααααααααΆαααΈαααΆαααΈαααΈαα½αααα αααα»α botnet αααααΆααααααΆααα αααΎαααΆααα αααΆαααΈαααααααΌαααΆααααααα±αααααα ααααααΆαααααΆαααα αααααΆαααααααααααα ααααααααΆα ααα»αααααααα αααα½αααΆαααααΆααααΈα’αααααα αααΎαααΆαααααα α’αααα αα αΆα α¬ααααααααααααΌαααΆαα’αα ααΆααααααΆααααααΈαα·αααααΌαααΆαααα½ααα α αΎαααααΆααααααααα·αα’αΆα ααααΎααΆαααα
ααααα·αααΎα’ααααα·ααααα
ααααααΆααααααα’ααααΎαααα
ααααααααΆα SYN ααα»ααααααααΆααααααααΎαααααΆαα½ααααα
ααααααααΆα SYNACK ααα ααΎαααΆαααΈαααα’αΆα
ααααααααααααΆααΆαααα
ααααααααΆα ACK αααααΆαααααααα
αααααααααααα
ααΎαααα
ααααααααΆα SYN ααααα·αααααΌαααΆααααααΆαα»α? αααΆαααΆαα·α α’αααααΆααααα αΆαααα’αΆα
αααααΎα ACKs αααααααααΆααααααα α
ααα»α
ααααΌααΈ SYN ααΊααΆαα’αα·αααΌαααΆα
αΌα seqnum
αααΆαααΆααααααααααΆααααααΆααααΆ hash ααα’αΆααααααΆα α
ααα αα·αααΆαααααΆααααααΌαα’ααα·αα ααααα·αααΎ ACK α’αΆα
ααααααα»ααααα’ααα·αααααΌαααΆαααααΆααααααΌα α’αααα’αΆα
ααααΆ hash ααααααα α αΎαααααααααααΆααΆαα½α acknum
. αααααααααα acknum
α’αααααΆααααα αΆααα·αα’αΆα
αα αααααα’ααα·ααα½ααααα
αΌαα’αΆααααααΆαα α αΎαααΉααα·αααΆααααααααΆααΎααααΈααααααααΆαα αααααΆαααΆαααααΆααααααα
ααΌααΈ SYN ααααΌαααΆαα’αα»ααααααΆααΌαααα αΎααα αααα»αααΊαααααΈαα»α α αΎααααααΆααα’αΆα ααΎαααααΎαααΆααααααααααααααααα· ααααα·αααΎ SYNs αααααααΏαααα αα·αααΆαααα αααα
αααααα·ααΈα’ααααα’αααΈααΆαα αΆαααα 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 αα·ααααααααααΎ?
ααΈαα½α ααααα·αααΎ SYNACK α¬ ACK ααααΌαααΆαααΆααααα α’αααααΉαααααΌααααα αΆαααΆααααΌαααΆαααααΎααααααα - ααΆαααα‘αΎαααΆααααααΆααααΉαααα α»αα ααΈααΈααα αααα»ααααα αα SYN - α αΎαααΆααααα αααα»αααΆααα»ααααα! - αααααΎααα½αα ααα½αααααΌαααΆααααααΌα ααααααααΆαααααααααα·ααααα·ααΆααααααααααααααΆααααααΆααα ααααα·αα αΆααααα αα SYN α αΌααα ααΌα αααααααΆαααΈααααα·αα’αΎααΎαααααΎαααΆααααααα α’αα·αα·ααααΉααα·αααααΎαα½αααΆαα αααα»ααααα αααααααΆααααα TCP α’αΆα ααααΎαααΆααααα»αααααΈααα ααα»αααααααΆαα αα ααΆαααα ααααΆααααΆαααααΌα αα»αααΆαααααΆααααααΆααααΉαααα α»αα
αα αααα»ααααααααααααααα αααααααα·ααΈ XDP ααααΌαααααΎααΌα ααΆαααααα:
- ααααΎααααα SYN ααΆαα½α SYNACK ααΆαα½αααΌααΈ;
- ααααΎααααα ααΉα ACK ααΆαα½α RST (ααααΆα α);
- αααα αααααα ααααααα αααα
Pseudocode αα algorithm αα½αααΆαα½αααΉαααΆαααααααα ααα
ΠΡΠ»ΠΈ ΡΡΠΎ Π½Π΅ Ethernet,
ΠΏΡΠΎΠΏΡΡΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ.
ΠΡΠ»ΠΈ ΡΡΠΎ Π½Π΅ IPv4,
ΠΏΡΠΎΠΏΡΡΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ.
ΠΡΠ»ΠΈ Π°Π΄ΡΠ΅Ρ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠ΅Π½Π½ΡΡ
, (*)
ΡΠΌΠ΅Π½ΡΡΠΈΡΡ ΡΡΠ΅ΡΡΠΈΠΊ ΠΎΡΡΠ°Π²ΡΠΈΡ
ΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ,
ΠΏΡΠΎΠΏΡΡΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ.
ΠΡΠ»ΠΈ ΡΡΠΎ Π½Π΅ TCP,
ΡΠ±ΡΠΎΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ. (**)
ΠΡΠ»ΠΈ ΡΡΠΎ SYN,
ΠΎΡΠ²Π΅ΡΠΈΡΡ SYN-ACK Ρ cookie.
ΠΡΠ»ΠΈ ΡΡΠΎ ACK,
Π΅ΡΠ»ΠΈ Π² acknum Π»Π΅ΠΆΠΈΡ Π½Π΅ cookie,
ΡΠ±ΡΠΎΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ.
ΠΠ°Π½Π΅ΡΡΠΈ Π² ΡΠ°Π±Π»ΠΈΡΡ Π°Π΄ΡΠ΅Ρ Ρ N ΠΎΡΡΠ°Π²ΡΠΈΡ
ΡΡ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ. (*)
ΠΡΠ²Π΅ΡΠΈΡΡ RST. (**)
Π ΠΎΡΡΠ°Π»ΡΠ½ΡΡ
ΡΠ»ΡΡΠ°ΡΡ
ΡΠ±ΡΠΎΡΠΈΡΡ ΠΏΠ°ΠΊΠ΅Ρ.
αα½αα (*)
α
ααα»α
αααα’αααααααΌαααΆαααΎααααΈαααααααααααααΆαααΆαααααααααααααααΌαααΆααααααΆαα - αα
ααααΆααααΆαααααΌαα’αααα’αΆα
ααααΎααΆααααααααΆααα½αααΆαααααααΆααααα’αα»ααααααΆαα
αΆαααα TCP ααΆαα½αααΉαααΆααααααΎαααΌααΈ SYN ααΆ seqnum α
αα
βααΉαβαααααα (**)
αααααααααααΎααα·αααΆααα» ααΎαααΉααααααααα
ααααααααΆαα
ααΆαα’αα»ααααααΆαα αΆαααα TCP
ααααααα αα αα·ααααααααααΆαααααααΌα
ααΎαααΉαααααΌαααΆααα
ααΆααααααααααααααΆαααααΆαα α’ααΈααΊααα·α (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) αα·αα§ααααααααααααααααα αΆααααααΆααααααΌααααααα
llvm-objdump -S xdp_filter.o | less
αααα»αααααΈαααααΆα ααα’α»ααα αααααΆαα
LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));
αααααααΎα±ααααΆα
αααΆααααΆαααα αΆααΊ ether
. ααΆααΉααααααααΌα
αααα
ααααΎααααα SYN
ααααα
αα
ααααΆααααΆααααααΊααΎααααΈαααααΎααααα
αα SYNACK ααααΉαααααΌαααΆαα½αααΉαααααα½αα seqnum
αααααΉαααααΌαααΆααααα½ααα
αααα’ααΆαααααααΌααΈ SYN α ααΆαααααΆααααααΌαααΆααα’ααααΎαα‘αΎααα
αααα»α 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 ααααΈαα½ααα α’αααα’αΆα αααααΎαααααα·ααα»αααΆαα½αααΉαα ααα½ααααααααΆαααααΎααααα αααα’αΆα αααα αααα»αα
αααα»ααααααααΆααααΆααΆα
αα»αααΆαααααΆ 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;
}
αααααΈααΆ size
ααααΌαααΆααααααααααΆααααααααααΌαα α
ααΌααααα ααααααααα
ααααΈααΈαααΊα
αΆαααΆα
αααΎααααΈα±ααα’ααααααααααααΆααα’αΆα
αααααΆααααΈααΆααααα
ααααααααα·ααα»αα
αααααΆααααΆααα 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()
αααααΎαααΌααααααΆααααααααΈααααΌα 32 αααΈαααααΆααα 16 αααΈα ααααα
ααΆα RFC 791 α
ααΆααααααααααΆααααΆαα αΆαααα TCP
ααααααααααΎαααΆααααααΆαααααΆαααααΉαααααΌαααΆαα½α netcat
ααΆαα ACK α
α»αααααα αααααΈαα»α
ααΆαααααΎαααααΆαα½ααααα
ααααααααΆα RST α
αΆααααΆααααΈααααααααΆααα·αααα½αααΆα SYN - ααΆααααΌαααΆαααααααααα
ααΆ 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 cookie
ααΆααααααα XDP ααΆααααααααααΆαααααα½αααΆααΊαα·αααααΆααα αααα½ααααααααΆαααΆαααααΆααΊααΆαααααααααα α αΎαααααααΆααΆααααααααα ααααα’αααααΆααααα αΆαααααααΎαα ααΆα§ααΆα ααα ααΊαααααΈαα»α ααααΎααΌαααααΈα SipHash ααα»ααααααΆαα’αα»ααααααααααΆαααααΆαα XDP ααΊα α½αααΈαα·ααΆαααΆαααα’ααααααααα
ααααΆααααααΆαα TODOs ααααΈααΆααααααΉαααααΆααααααααΆααααα α
-
αααααα·ααΈ XDP αα·αα’αΆα αααααΆαα»αααΆαααα
cookie_seed
(ααααααααααΆααααα’ααα·α) αα αααα»αα’αααααα α’αααααααΌαααΆαααΆααααα»ααα αααα»αααΊααα ααααααααααΉαααααΌαααΆαααααΎαα αα α»ααααααααΆαααΆαααααΆααααΈαααΆαααΈαααααΎααααα’αΆα αα»αα α·αααααΆαα -
ααααα·αααΎααΌααΈ SYN ααααΌαααααΆαα αααα»ααααα ααααααααΆα 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
ααααααααααα·αααΆααααααΈ IPs αααααΆααααααααααΆαα ααΆααΉααα·αααΆαααΆαααΆαααΆαααΈααΉαααααα 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 α’αα»ααααΆαα±ααα’αααα’αα»αααααααααα·ααααΆαααααα»αααααΆα αααααΎαααΈααααα ααα ααΆααΆααααα½ααααα»αααΆαααααΎαα αα α»ααααααααΆαααααα·αααΆαααΆαααααΆααααα»αααααΎαααΆαα ααΆα αααα αααααα·ααΈαααααααααΆαααα·ααααααΎααααα αΆαααααααααΆαααα αααα»αααΉααα·αααα·αααα αααααααααααααΌαααααααααααΎααααΆααααα
αα αααα»ααααααααΈααΈα ααααα·αααΎαααααΆααααα½αα±ααα αΆααα’αΆαααααα ααΎαααΉααααααααΆααΆαα’αα·αα·αααααααΆααααααααααΆαα αα·αααΆαααααΆα α α’αα»ααααααΆαααΆαα αα·ααααααα§αααααααααΎααααΆααααααααααααΎααααΆααααΎααααΈααααααααααααααα
α―αααΆαααα:
ααΌααααααααα ααΎ GitHub bpfrace αααααΉαααααα ααααα»αααααααααα BPF αα·α XDP ααΆααααααα XDP PoC: α ααααααα eBPF ααΈ Rust
ααααα: www.habr.com