eXpress Data Path(XDP) ๊ธฐ์ ์ ์ฌ์ฉํ๋ฉด ํจํท์ด ์ปค๋ ๋คํธ์ํฌ ์คํ์ ๋ค์ด๊ฐ๊ธฐ ์ ์ Linux ์ธํฐํ์ด์ค์์ ์์ ํธ๋ํฝ ์ฒ๋ฆฌ๊ฐ ์ํ๋ ์ ์์ต๋๋ค. XDP ์ ์ฉ - DDoS ๊ณต๊ฒฉ(CloudFlare), ๋ณต์กํ ํํฐ, ํต๊ณ ์์ง(Netflix)์ผ๋ก๋ถํฐ ๋ณดํธํฉ๋๋ค. XDP ํ๋ก๊ทธ๋จ์ eBPF ๊ฐ์ ๋จธ์ ์ ์ํด ์คํ๋๋ฏ๋ก ํํฐ ์ ํ์ ๋ฐ๋ผ ์ฝ๋์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ปค๋ ๊ธฐ๋ฅ ๋ชจ๋์ ์ ํ์ด ์์ต๋๋ค.
์ด ๊ธฐ์ฌ๋ XDP์ ์๋ง์ ์๋ฃ์ ๋จ์ ์ ๋ณด์ํ๊ธฐ ์ํด ์์ฑ๋์์ต๋๋ค. ์ฒซ์งธ, XDP์ ๊ธฐ๋ฅ์ ์ฆ์ ์ฐํํ๋ ๊ธฐ์ฑ ์ฝ๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ฒ์ฆ์ ์ํด ์ค๋น๋์๊ฑฐ๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๊ธฐ์๋ ๋๋ฌด ๊ฐ๋จํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฒ์๋ถํฐ ์ฝ๋๋ฅผ ์์ฑํ๋ ค๊ณ ํ๋ฉด ์ผ๋ฐ์ ์ธ ์ค๋ฅ๋ฅผ ์ด๋ป๊ฒ ํด์ผ ํ ์ง ์ ํ ์ ์ ์์ต๋๋ค. ๋์งธ, ์์ฒด์ ์ธ ํจ์ ์ด ์์์๋ ๋ถ๊ตฌํ๊ณ VM ๋ฐ ํ๋์จ์ด ์์ด ๋ก์ปฌ์์ XDP๋ฅผ ํ ์คํธํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์ง ์์ต๋๋ค. ์ด ํ ์คํธ๋ ๋คํธ์ํน ๋ฐ Linux์ ์ต์ํ๊ณ 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๋ 10.1์ ํ์ฌ eBPF ์ปดํ์ผ์ Clang์์ ์ง์๋๋ฉฐ GCC XNUMX์์ ์ฝ์๋ฉ๋๋ค. - ์ด ๊ฐ์ฒด ์ฝ๋์ ์ปค๋ ๊ตฌ์กฐ(์: ํ ์ด๋ธ ๋ฐ ์นด์ดํฐ)์ ๋ํ ํธ์ถ์ด ํฌํจ๋ ๊ฒฝ์ฐ ํด๋น ID๋ XNUMX์ผ๋ก ๋์ฒด๋ฉ๋๋ค. ์ด๋ ํด๋น ์ฝ๋๋ฅผ ์คํํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ปค๋์ ๋ก๋ํ๊ธฐ ์ ์ ์ด๋ฌํ XNUMX์ ์ปค๋ ํธ์ถ(์ฝ๋ ๋งํฌ)์ ํตํด ์์ฑ๋ ํน์ ๊ฐ์ฒด์ ID๋ก ๋ฐ๊ฟ์ผ ํฉ๋๋ค. ์ธ๋ถ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ์ํํ ์๋ ์๊ณ ํน์ ํํฐ๋ฅผ ์ฐ๊ฒฐํ๊ณ ๋ก๋ํ๋ ํ๋ก๊ทธ๋จ์ ์์ฑํ ์๋ ์์ต๋๋ค.
- ์ปค๋์ ๋ก๋๋ ํ๋ก๊ทธ๋จ์ ํ์ธํฉ๋๋ค. ์ฃผ๊ธฐ๊ฐ ์๊ณ ํจํท ๋ฐ ์คํ ๊ฒฝ๊ณ๋ฅผ ์ด๊ณผํ์ง ๋ชปํ๋์ง ํ์ธํฉ๋๋ค. ๊ฒ์ฆ์๊ฐ ์ฝ๋๊ฐ ์ ํํ๋ค๋ ๊ฒ์ ์ฆ๋ช ํ ์ ์์ผ๋ฉด ํ๋ก๊ทธ๋จ์ด ๊ฑฐ๋ถ๋ฉ๋๋ค. ๊ฒ์ฆ์๋ฅผ ๊ธฐ์๊ฒ ํ ์ ์์ด์ผ ํฉ๋๋ค.
- ์ฑ๊ณต์ ์ผ๋ก ๊ฒ์ฆ๋ ํ ์ปค๋์ eBPF ์ํคํ ์ฒ ๊ฐ์ฒด ์ฝ๋๋ฅผ ์์คํ ์ํคํ ์ฒ์ฉ ๊ธฐ๊ณ์ด ์ฝ๋(์ ์)๋ก ์ปดํ์ผํฉ๋๋ค.
- ํ๋ก๊ทธ๋จ์ด ์ธํฐํ์ด์ค์ ์ฐ๊ฒฐ๋๊ณ ํจํท ์ฒ๋ฆฌ๋ฅผ ์์ํฉ๋๋ค.
XDP๋ ์ปค๋์์ ์คํ๋๋ฏ๋ก ์ถ์ ๋ก๊ทธ์ ์ค์ ๋ก ํ๋ก๊ทธ๋จ์ด ํํฐ๋งํ๊ฑฐ๋ ์์ฑํ๋ ํจํท์ ์ฌ์ฉํ์ฌ ๋๋ฒ๊น ์ด ์ํ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ eBPF๋ ๋ค์ด๋ก๋ํ ์ฝ๋๊ฐ ์์คํ ์ ๋ํด ์์ ํ์ง ํ์ธํ๋ฏ๋ก ๋ก์ปฌ Linux์์ ์ง์ XDP๋ฅผ ์คํํ ์ ์์ต๋๋ค.
ํ๊ฒฝ ์ค๋น
์กฐ๋ฆฝ
Clang์ eBPF ์ํคํ ์ฒ์ ๋ํ ๊ฐ์ฒด ์ฝ๋๋ฅผ ์ง์ ์์ฑํ ์ ์์ผ๋ฏ๋ก ํ๋ก์ธ์ค๋ ๋ค์ ๋ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- 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์ฉ Makefile(์ปค๋ 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(์ฌ์ฉ์ ๊ณต๊ฐ 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
. ์ง๊ธ ์ด๋์์ ์ํํด ๋ณผ ์ ์๋์?
ํ ์คํธ ๋ฒค์น
์คํ ๋์๋ ํํฐ๊ฐ ์๋ ์ธํฐํ์ด์ค์ ํจํท์ด ์ ์ก๋๋ ์ธํฐํ์ด์ค ๋ ๊ฐ๊ฐ ํฌํจ๋์ด์ผ ํฉ๋๋ค. ์ผ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด ํํฐ์ ์ด๋ป๊ฒ ์๋ํ๋์ง ํ์ธํ๋ ค๋ฉด ์์ฒด 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)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข์ต๋๋ค.
๋คํธ์ํฌ ๋ค์์คํ์ด์ค์๋ ๋ค๋ฅธ netns์ ์ ์ฌํ ๊ฐ์ฒด์ ๊ฒฉ๋ฆฌ๋ ์ผ๋ จ์ ์ธํฐํ์ด์ค, ๋ผ์ฐํ ํ ์ด๋ธ ๋ฐ NetFilter ๊ท์น์ด ํฌํจ๋์ด ์์ต๋๋ค. ๊ฐ ํ๋ก์ธ์ค๋ ๋ค์์คํ์ด์ค์์ ์คํ๋๋ฉฐ ํด๋น netns์ ๊ฐ์ฒด์๋ง ์ก์ธ์คํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ์์คํ ์๋ ๋ชจ๋ ๊ฐ์ฒด์ ๋ํ ๋จ์ผ ๋คํธ์ํฌ ๋ค์์คํ์ด์ค๊ฐ ์์ผ๋ฏ๋ก Linux์์ ์์ ํ ์ ์์ผ๋ฉฐ netns์ ๋ํด์๋ ์ ์ ์์ต๋๋ค.
์ ๋ค์์คํ์ด์ค๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. 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 ...
์ด ๋ช
๋ น ๋ค์์คํ์ด์ค์์ 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 ์ฟ ํค ๋ฉ์ปค๋์ฆ์ ์์ฑํฉ๋๋ค.
SYN Flood๋ ์ฌ์ ํ ๋๋ฆฌ ์ฌ์ฉ๋๋ DDoS ๊ณต๊ฒฉ์ผ๋ก, ๊ทธ ๋ณธ์ง์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์ฐ๊ฒฐ์ด ์ค์ ๋๋ฉด(TCP ํธ๋์ ฐ์ดํฌ) ์๋ฒ๋ SYN์ ์์ ํ๊ณ ํฅํ ์ฐ๊ฒฐ์ ์ํด ๋ฆฌ์์ค๋ฅผ ํ ๋นํ๊ณ SYNACK ํจํท์ผ๋ก ์๋ตํ๊ณ ACK๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค. ๊ณต๊ฒฉ์๋ ์์ฒ ๊ฐ์ ๊ฐ๋ ฅํ ๋ด๋ท์ ์๋ ๊ฐ ํธ์คํธ์ ์คํธํ๋ ์ฃผ์์์ ์ด๋น ์์ฒ ๊ฐ์ SYN ํจํท์ ๋ณด๋ ๋๋ค. ์๋ฒ๋ ํจํท์ด ๋์ฐฉํ์๋ง์ ๊ฐ์ ๋ก ์์์ ํ ๋นํ์ง๋ง, ์๊ฐ์ด ๋ง์ด ์ด๊ณผ๋ ํ์ ์์์ ํด์ ํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ๋ ์ ํ์ด ๋ชจ๋ ์๋ชจ๋๊ณ ์๋ก์ด ์ฐ๊ฒฐ์ด ํ์ฉ๋์ง ์์ผ๋ฉฐ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
SYN ํจํท์ ๊ธฐ๋ฐ์ผ๋ก ์์์ ํ ๋นํ์ง ์๊ณ SYNACK ํจํท์ผ๋ก๋ง ์๋ตํ๋ค๋ฉด ๋์ค์ ๋์ฐฉํ ACK ํจํท์ด ์ ์ฅ๋์ง ์์ SYN ํจํท์์ ์๋ฒ๋ โโ์ด๋ป๊ฒ ์ดํดํ ์ ์๊ฒ ๋๊ฐ? ๊ฒฐ๊ตญ ๊ณต๊ฒฉ์๋ ๊ฐ์ง ACK๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค. SYN ์ฟ ํค์ ์์ ์ ์ด๋ฅผ ์ธ์ฝ๋ฉํ๋ ๊ฒ์
๋๋ค. seqnum
์ฃผ์, ํฌํธ ๋ฐ ์ํธ ๋ณ๊ฒฝ์ ํด์์ธ ์ฐ๊ฒฐ ๋งค๊ฐ๋ณ์์
๋๋ค. ์ํธ๊ฐ ๋ณ๊ฒฝ๋๊ธฐ ์ ์ ACK๊ฐ ๋์ฐฉํ๋ค๋ฉด ํด์๋ฅผ ๋ค์ ๊ณ์ฐํ์ฌ ๋ค์๊ณผ ๋น๊ตํ ์ ์์ต๋๋ค. acknum
. ๋
ธ acknum
์ํธ์๋ ๋น๋ฐ์ด ํฌํจ๋์ด ์๊ณ ์ ํ๋ ์ฑ๋๋ก ์ธํด ์ด๋ฅผ ๋ถ๋ฅํ ์๊ฐ์ด ์๊ธฐ ๋๋ฌธ์ ๊ณต๊ฒฉ์๋ ๊ทธ๋ ๊ฒ ํ ์ ์์ต๋๋ค.
SYN ์ฟ ํค๋ ์ค๋ซ๋์ 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
. ํด๋ผ์ด์ธํธ๋ ACK ํจํท์ผ๋ก SYNACK์ ์๋ตํฉ๋๋ค. seqnum = X + 1
, acknum = Y + 1
. ๊ทธ ํ ์ค์ ๋ฐ์ดํฐ ์ ์ก์ด ์์๋ฉ๋๋ค.
ํผ์ด๊ฐ ํจํท ์์ ์ ํ์ธํ์ง ์์ผ๋ฉด TCP๋ ์๊ฐ ์ด๊ณผ ํ ํจํท์ ๋ค์ ๋ณด๋ ๋๋ค.
SYN ์ฟ ํค๊ฐ ํญ์ ์ฌ์ฉ๋์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
์ฒซ์งธ, SYNACK ๋๋ ACK๊ฐ ์์ค๋๋ฉด ๋ค์ ์ ์ก๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ์ฐ๊ฒฐ ์ค์ ์๋๊ฐ ๋๋ ค์ง๋๋ค. ๋์งธ, SYN ํจํค์ง์๋ง ์์ต๋๋ค! โ ์ฐ๊ฒฐ์ ์ถ๊ฐ ์์ ์ ์ํฅ์ ๋ฏธ์น๋ ์ฌ๋ฌ ์ต์ ์ด ์ ์ก๋ฉ๋๋ค. ๋ค์ด์ค๋ SYN ํจํท์ ๊ธฐ์ตํ์ง ์์ผ๋ฉด ์๋ฒ๋ ์ด๋ฌํ ์ต์ ์ ๋ฌด์ํ๊ณ ํด๋ผ์ด์ธํธ๋ ๋ค์ ํจํท์์ ํด๋น ์ต์ ์ ๋ณด๋ด์ง ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ TCP๊ฐ ์๋ํ ์ ์์ง๋ง ์ ์ด๋ ์ด๊ธฐ ๋จ๊ณ์์๋ ์ฐ๊ฒฐ ํ์ง์ด ์ ํ๋ฉ๋๋ค.
ํจํค์ง ๊ด์ ์์ XDP ํ๋ก๊ทธ๋จ์ ๋ค์์ ์ํํด์ผ ํฉ๋๋ค.
- ์ฟ ํค๋ฅผ ์ฌ์ฉํ์ฌ SYNACK์ผ๋ก SYN์ ์๋ตํฉ๋๋ค.
- RST(์ฐ๊ฒฐ ํด์ )๋ก ACK์ ์๋ตํฉ๋๋ค.
- ๋๋จธ์ง ํจํท์ ํ๊ธฐํฉ๋๋ค.
ํจํค์ง ๊ตฌ๋ฌธ ๋ถ์๊ณผ ํจ๊ป ์๊ณ ๋ฆฌ์ฆ์ ์์ฌ ์ฝ๋:
ะัะปะธ ััะพ ะฝะต Ethernet,
ะฟัะพะฟัััะธัั ะฟะฐะบะตั.
ะัะปะธ ััะพ ะฝะต IPv4,
ะฟัะพะฟัััะธัั ะฟะฐะบะตั.
ะัะปะธ ะฐะดัะตั ะฒ ัะฐะฑะปะธัะต ะฟัะพะฒะตัะตะฝะฝัั
, (*)
ัะผะตะฝััะธัั ััะตััะธะบ ะพััะฐะฒัะธั
ัั ะฟัะพะฒะตัะพะบ,
ะฟัะพะฟัััะธัั ะฟะฐะบะตั.
ะัะปะธ ััะพ ะฝะต TCP,
ัะฑัะพัะธัั ะฟะฐะบะตั. (**)
ะัะปะธ ััะพ SYN,
ะพัะฒะตัะธัั SYN-ACK ั cookie.
ะัะปะธ ััะพ ACK,
ะตัะปะธ ะฒ acknum ะปะตะถะธั ะฝะต cookie,
ัะฑัะพัะธัั ะฟะฐะบะตั.
ะะฐะฝะตััะธ ะฒ ัะฐะฑะปะธัั ะฐะดัะตั ั N ะพััะฐะฒัะธั
ัั ะฟัะพะฒะตัะพะบ. (*)
ะัะฒะตัะธัั RST. (**)
ะ ะพััะฐะปัะฝัั
ัะปััะฐัั
ัะฑัะพัะธัั ะฟะฐะบะตั.
ํ๋ (*)
์์คํ
์ํ๋ฅผ ๊ด๋ฆฌํด์ผ ํ๋ ์ง์ ์ด ํ์๋์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋จ๊ณ์์๋ SYN ์ฟ ํค๋ฅผ seqnum์ผ๋ก ์์ฑํ์ฌ TCP ํธ๋์
ฐ์ดํฌ๋ฅผ ๊ตฌํํ๊ธฐ๋ง ํ๋ฉด ์ด๋ฌํ ์ง์ ์์ด๋ ์ํํ ์ ์์ต๋๋ค.
ํ์ฅ์์ (**)
, ํ
์ด๋ธ์ด ์์ผ๋ฉด ํจํท์ ๊ฑด๋๋๋๋ค.
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๋ฒ์งธ ๋ฐ์ดํธ๊ฐ ํจํท ์ธ๋ถ์ผ ๋ ์คํ ๊ฒฝ๋ก๊ฐ ์์ต๋๋ค. ๋ชฉ๋ก์์ ์ฐ๋ฆฌ๊ฐ ๋งํ๋ ์ค์ ์ดํดํ๊ธฐ๋ ์ด๋ ต์ง๋ง ๋ช
๋ น ๋ฒํธ(XNUMX)์ ์์ค ์ฝ๋ ์ค์ ๋ณด์ฌ์ฃผ๋ ๋์ค์ด์
๋ธ๋ฌ๊ฐ ์์ต๋๋ค.
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๋ฐ์ดํธ๋ก ์ ํ๋ฉ๋๋ค. ๊ณ ์ ๋ ๋ฐ๋ณต ํ์๋ก ๋ฃจํ๋ฅผ ๋ง๋ค ์ ์์ผ๋ฉฐ, ์ด๋ ์ผ์ฐ ์ข ๋ฃ๋ ์ ์์ต๋๋ค.
์์์ ์ฐธ๊ณ ํฉ๋๋ค
์ฒดํฌ์ฌ ๊ณ์ฐ ๊ธฐ๋ฅ:
#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()
RFC 32์ ๋ฐ๋ผ 16๋นํธ ๋จ์ด์ 791๋นํธ ํฉ๊ณ์์ ์ฒดํฌ์ฌ์ ๋ง๋ญ๋๋ค.
TCP ํธ๋์ ฐ์ดํฌ ํ์ธ
ํํฐ๋ ๋ค์๊ณผ์ ์ฐ๊ฒฐ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ํฉ๋๋ค. netcat
, Linux๊ฐ RST ํจํท์ผ๋ก ์๋ตํ ์ต์ข
ACK๊ฐ ๋๋ฝ๋์์ต๋๋ค. ๋คํธ์ํฌ ์คํ์ด 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 ์ฟ ํค
XDP ๊ด์ ์์ ๋ณผ ๋ ๊ฒ์ฆ ์์ฒด๋ ์ฌ์ํ ๊ฒ์ ๋๋ค. ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ์ ์์์ ์ด๋ฉฐ ์ ๊ตํ ๊ณต๊ฒฉ์์๊ฒ ์ทจ์ฝํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ์๋ฅผ ๋ค์ด Linux ์ปค๋์ ์ํธํ SipHash๋ฅผ ์ฌ์ฉํ์ง๋ง XDP์ ๋ํ ๊ตฌํ์ ๋ถ๋ช ํ ์ด ๊ธฐ์ฌ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋ฉ๋๋ค.
์ธ๋ถ ํต์ ๊ณผ ๊ด๋ จ๋ ์๋ก์ด TODO๋ฅผ ์ํด ๋์ ๋์์ต๋๋ค.
-
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
ํ์ธ๋ 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๋ฅผ ์ฌ์ฉํ๋ฉด ๋งค์ฐ ๋ณต์กํ ๋ก์ง์ ๊ตฌํํ ์ ์์ผ๋ฉฐ ํธ๋ํฝ ์ฒ๋ฆฌ ์ค๋จ ์์ด ์ฝ๊ฒ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค. ๊ฒ์ฆ์๋ ํฐ ๋ฌธ์ ๋ฅผ ์ผ์ผํค์ง ์์ผ๋ฉฐ ๊ฐ์ธ์ ์ผ๋ก ์ฌ์ฉ์ ๊ณต๊ฐ ์ฝ๋์ ์ผ๋ถ์ ๋ํด ์ด๋ฅผ ๊ฑฐ๋ถํ์ง ์์ต๋๋ค.
๋ ๋ฒ์งธ ๋ถ๋ถ์์๋ ์ฃผ์ ๊ฐ ํฅ๋ฏธ๋ก์ธ ๊ฒฝ์ฐ ํ์ธ๋ ํด๋ผ์ด์ธํธ ๋ฐ ์ฐ๊ฒฐ ๋๊น ํ ์ด๋ธ์ ์์ฑํ๊ณ ์นด์ดํฐ๋ฅผ ๊ตฌํํ๋ฉฐ ํํฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ์ฌ์ฉ์ ๊ณต๊ฐ ์ ํธ๋ฆฌํฐ๋ฅผ ์์ฑํฉ๋๋ค.
๋งํฌ :
GitHub์ ์ ์ฒด ์ฝ๋ bpftrace ์นํธ ์ํธ BPF ๋ฐ XDP ์ฐธ์กฐ ๊ฐ์ด๋ XDP ํํ ๋ฆฌ์ผ PoC: Rust์์ eBPF๋ก ์ปดํ์ผ
์ถ์ฒ : habr.com