2025년 4월 28일 월요일

eBPF & XDP 기반의 고속 네트워크 프로그래밍(2)

이번 시간에는 지난 시간에 이어 eBPF & XDP 기반의 고속 네트워크 프로그래밍에 관한 얘기(2번째 시간)를 좀 더 해 보고자 한다. 😎

목차
1. eBPF & XDP
2. Suricata IPS와 XDP Bypass
3. XDP 기반의 DDoS Mitigator
4. References


DDoS Attack을 차단하라 !
Suricata IPS(XDP Bypass)를 넘어서 FastNetMon(AF_XDP 기반)의 BGP Blackhole 까지 ~


1. eBPF & XDP
eBPF(Extended Berkeley Packet Filter)는 사용자가 만든 프로그램을 실행하여 커널 기능을 확장시켜 주는 커널 내 가상 머신(virtual machine)이다. 이전 posting을 통해 한차례 소개한 바 있다.

https://slowbootkernelhacks.blogspot.com/2024/10/ebpf-xdp.html

공식 home page에도 관련 내용이 아주 쉽게 잘 정리되어 있다.

[그림 1.1]  eBPF의 개념도 [출처 - 참고문헌 14]

[그림 1.2]  eBPF의 개념도 - workflow [출처 - 참고문헌 26]

가상 머신(virtual machine)이다 보니, 11개의 Register set, Stack, Map(key value store - 사용자 영역/kernel 간 공유) 등이 준비되어 있다.

[그림 1.3]  cBPF vs eBPF 가상 Machine [출처 - 참고문헌 26]

한편, XDP(eXpress Data Path)는 eBPF로 할 수 있는 여러 기능 중에서, 고성능 packet 처리와 관련한 기술(hooking 기법 이용 - software offload layer로 볼 수 있음)을 말한다. 유사한 기술로는 (PF_RING, Netmap 등 여러가지가 있지만) DPDK가 대표적이다(탁월하다).

[그림 1.4]  XDP의 개념도(1) [출처 - 참고문헌 14]

XDP를 통해 network 성능이 향상되는 근본적인 이유는, NIC(network interface card)으로 부터 전달된 packet이 (매우 많은 함수 호출 단계를 거친 후에 도달하는) network stack을 거치기 이전 단계에서 처리가 가능하기 때문이다.

[그림 1.5]  XDP의 개념도(2) [출처 - 참고문헌 26]


[그림 1.6]  XDP의 개념도(3) [출처 - 참고문헌 13]

XDP는 NIC driver로부터 전달받은 packet을 가로채어(hooking) 필요한 처리(eBPF VM 내에서 실행)을 하게 되는데, 그 결과에 따라서 패킷을 DROP하거나, 자신의 NIC으로 다시 돌려 보내거나(TX), 아니면 이웃한 NIC으로 전달(REDIRECT)할 수가 있다. 물론 이도 저도 아닌 상황이라면,  원래의 흐름대로 network stack으로 전달(PASS)하기도 한다.

  • XDP_PASS: let the packet continue to the kernel network stack
  • XDP_DROP: silently drop the packet
  • XDP_ABORTED: drop the packet with trace point exception
  • XDP_TX: bounce the packet back to the same NIC it arrived on
  • XDP_REDIRECT: redirect the packet to another NIC or user space socket via the AF_XDP address family
📌 정확한 의미 전달을 위해 원문을 그대로 옮겨 보았다. 😋

 
[그림 1.7]  XDP의 개념도(4) [출처 - 참고문헌 13]
📌 XDP가 DPDK와 결정적으로 다른 점은 kernel network stack을 그대로 이용할 수 있다는 점이다.

한편, 패킷을 AF_XDP를 통해 userspace로 올려 줄 경우에도, 아래 그림과 같이 REDIRECT 기능을 이용하면 된다(3장 참조).

[그림 1.8] XDP와 AF_XDP의 관계 [출처 - 참고문헌 6]

마지막으로, 사용자 영역의 program과 XDP program(일반적으로는 eBPF program) 간에 정보를 공유하기 위해서는 BPF MAP(key-value store)이 사용된다.
 
 
[그림 1.9] eBPF maps [출처 - 참고문헌 15]

<XDP 관련 내용 요약>
  • XDP는 network interface에 대한 hooking을 통해 NIC이 수신한 패킷을 network stack(kernel)으로 전달하기 전에 미리 처리하는 기술이다.
  • XDP는 수신 패킷(rx)에 대한 처리만 정의하고 있다. 따라서, 송신 패킷(tx)에 대해서는 hooking 처리하지 않는다.
  • NIC으로 부터 수신된 패킷은 XDP_DROP, XDP_TX, XDP_REDIRECT, XDP_PASS, XDP_ABORTED 등의 action을 통해 그 운명이 결정된다.
  • XDP의 action을 결정하는데 사용자 영역의 program이 영향(도움)을 주기 위해서는 BPF map(key-value store)을 통해 필요한 정보를 XDP(kernel code)와 공유해야 한다.
  • XDP에서 사용자 영역으로 패킷을 전달하고자 할 경우에도 XDP_REDIRECT를 이용해야 한다. 또한, 이웃한 NIC으로의 REDIRECT 상황과 구분하기 위해 BPF_MAP_TYPE_XSKMAP라는 MAP type 정보를 이용한다.
  • AF_XDP는 AF_PACKET 처럼 kernel에 추가된 socket family로, XDP와 연계하여 userspace에서 고속 패킷 처리가 가능하도록 해준다.

지금까지 몇 장의 그림을 통해 간략하게 eBPF와 XDP의 개념을 살펴 보았다. (위의 그림을 제공해 주신) 원저자분들께 심심한 감사의 마음을 표한다. 👍


2. Suricata IPS와 XDP Bypass

이번 장에서는 지난 시간(DPDK 기반 IPS)과는 달리, (상대적으로 조금은 느릴 것으로 예상되지만) AF_PACKET을 기반으로 Suricata IPS를 구성해 보고자 한다. 또한 여기에 XDP bypass 기능을 추가해 보고, 어떻게 동작하는지 확인해 보도록 하자.
[그림 2.1] Suricata IPS와 eBPF XDP(1)

2.1 AF_PACKET 기반의 Suricata IPS와 XDP Bypass
아래 그림은 NIC driver에 eBPF code(정확히는 XDP code)가 attach된 상태에서 Suricata(userspace application)와 eBPF code가 Flow Table(BPF Map)을 통해 상호 작용하는 모습을 보여준다.


[그림 2.2] Suricata IPS와 eBPF XDP(2) [출처 - 참고문헌 12]

AF_PACKET 기반으로 IPS를 구성한다는 것은 아래 그림과 같이 eth0 interface로 유입된 패킷(rx packet)을 tcp/ip stack을 통해 socket(AF_PACKET address family)에서 읽어들인 후, raw socket 형태로 반대편 인터페이스인 eth1으로 내보내는(send 혹은write) 것을 말한다. 물론 이에는 반대 방향 즉, eth1 interface를 통해 읽어들인 패킷을 tcp/ip stack을 거친 후, eth0 interface로 다시 내보내는 것도 포함된다.

[그림 2.3] AF_PACKET 기반 Suricata IPS mode [출처 - 참고문헌 12]

한편, XDP bypass는 아래 그림과 같이 eth0 interface로 들어온 패킷을 kernel tcp/ip stack을 거치지 않고, 곧바로 반대편 eth1 interface로 전달하거나, 반대로 eth1 interface로 들어온 패킷을 eth0 interface로 내보내는 것을 말한다.

 
[그림 2.4] XDP Bypass mode [출처 - 참고문헌 12]


2.2 Suricata build 및 동작 확인하기

AF_PACKET 기반 Suricata IPS를 위한 테스트 환경은 다음과 같다. 😜

<Testbed>

PC(Ubuntu 22.04 LTS/dhcp client) ---> [enp1s0] Suricata IPS [enp4s0] ---> Access Point --> Internet

이 상태에서 source code를 build한 후, 돌려 보도록 하자.

<Ubuntu 24.04 LTS Server>
git clone https://github.com/libbpf/libbpf.git
$ cd libbpf/src/
$ make
$ sudo make install
$ sudo make install_headers
$ sudo ldconfig

$ git clone https://github.com/OISF/suricata.git
  -> XDP bypass 기능을 사용하여 위해 suricata 최신 코드를 이용하기로 한다.
$ cd suricata && ./scripts/bundle.sh
$ ./autogen.sh
$ ./configure --enable-ebpf --enable-ebpf-build --with-clang=/usr/bin/clang --enable-non-bundled-htp --with-libhtp-includes=/usr/local/include --with-libhtp-libraries=/usr/local/lib
$ make clean && make
$ sudo make install-full
$ sudo ldconfig

$ sudo mkdir -p /usr/local/libexec/suricata/ebpf/
$ sudo cp ebpf/xdp_filter.bpf /usr/local/libexec/suricata/ebpf/
  -> xdp bypass code를 복사해 준다.
$ sudo vi /usr/local/etc/suricata/suricata.yaml
  -> 아래와 같이 af-packet를 기반으로 하는 ips mode 설정을 한다.
...
af-packet:
  - interface: enp1s0
     threads: 1
     cluster-id: 99
     cluster-type: cluster_qm
     defrag: no
     buffer-size: 64535
     copy-mode: ips
     copy-iface: enp4s0

 - interface: enp4s0
    threads: 1
    cluster-id: 98
    defrag: no
    cluster-type: cluster_flow
    copy-mode: ips
    copy-iface: enp1s0
    buffer-size: 64535

...

자, 모든 준비가 끝났으니, suricata를 ips mode로 구동 시켜 보자.

$ sudo /usr/local/bin/suricata -c /usr/local/etc/suricata/suricata.yaml --af-packet
Notice: suricata: This is Suricata version 8.0.0-rc1-dev (ca429ef5e 2025-04-12) running in SYSTEM mode [LogVersion:suricata.c:1159]
Error: affinity: worker-cpu-set: upper bound (2) of cpu set is too high, only 2 cpu(s) [BuildCpusetWithCallback:util-affinity.c:128]
Warning: runmodes: disabling livedev.use-for-tracking with IPS mode. See ticket #6726. [RunModeEngineIsIPS:runmodes.c:388]
Notice: threads: Threads created -> W: 2 FM: 1 FR: 1   Engine started. [TmThreadWaitOnThreadRunning:tm-threads.c:1954]

  -> 현재 test 중인 장비의 cpu 갯수가 2개 뿐이다. 일단 위의 에러는 무시하도록 한다.

OK, 이상태에서 PC에서 internet 연결을 시도해 보니, 예상대로 잘 동작한다. 😎

2.3 Suricata IPS 성능 시험하기 #1 - AF_PACKET mode
그럼, AF_PACKET 기반의 suricata IPS의 packet forwarding 성능(throughput)은 어느 정도나 될까 ?

 
[그림 2.5] AF_PACKET 기반의 IPS 성능 시험을 위한 Testbed

위와 같이 구성한 후, iperf3로 간단히 확인해 보니, 2.5GbE 환경에서 대략 1Gbps 정도가 나온다. 그렇다면, 1GbE 환경이라면 대략 400Mbps 정도가 나온다는 얘기가 되는데... 😓

 
[그림 2.6] Suricata IPS(af_packet mode) 성능 시험 결과 - 2.5GbE 환경

2.4 Suricata IPS 성능 시험하기 #2 - XDP bypass mode
이번에는 XDP를 통해 곧 바로 이웃 NIC으로 bypass 하는 경우의 시험을 진행해 보도록 하자.

sudo vi /usr/local/etc/suricata/suricata.yaml
  -> 아래와 같이 xdp bypass 설정을 추가해 준다.
...
af-packet:
  - interface: enp1s0
     threads: 1
     cluster-id: 99
     cluster-type: cluster_qm
     defrag: no
     buffer-size: 64535
     copy-mode: ips
     copy-iface: enp4s0
     xdp-mode: driver
     xdp-filter-file:  /usr/local/libexec/suricata/ebpf/xdp_filter.bpf
     bypass: yes
     ring-size: 200000

 - interface: enp4s0
    threads: 1
    cluster-id: 98
    defrag: no
    cluster-type: cluster_flow
    copy-mode: ips
    copy-iface: enp1s0
    buffer-size: 64535
    xdp-mode: driver
    xdp-filter-file:  /usr/local/libexec/suricata/ebpf/xdp_filter.bpf
    bypass: yes
    ring-size: 200000

...
stream:
  memcap: 64mb
  bypass: true
  #memcap-policy: ignore
  checksum-validation: yes      # reject incorrect csums
  midstream: false
  #midstream-policy: ignore
  midstream-policy: bypass  
  inline: auto                  # auto will use inline mode in IPS mode, yes or no set it statically
  reassembly:
    # experimental TCP urgent handling logic
    #urgent:
    #  policy: inline           # drop, inline, oob (1 byte, see RFC 6093, 3.1), gap
    #  oob-limit-policy: drop
    memcap: 256mb
    #memcap-policy: ignore
    depth: 1mb                  # reassemble 1mb into a stream
    toserver-chunk-size: 2560
    toclient-chunk-size: 2560
    randomize-chunk-size: yes
...

ip link show
  -> xdp code가 ethernet interface에 정상적으로 attach된 경우에는 아래와 같이 xdp 표시가 보여야 한다.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:e0:1d:6b:bb:44 brd ff:ff:ff:ff:ff:ff
    prog/xdp id 27
3: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:e0:1d:6b:bb:45 brd ff:ff:ff:ff:ff:ff
4: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:e0:1d:6b:bb:46 brd ff:ff:ff:ff:ff:ff
5: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:e0:1d:6b:bb:47 brd ff:ff:ff:ff:ff:ff
    prog/xdp id 29


OK, 이상태에서 PC에서 internet을 연결해 보니, 역시나 잘 연결된다. 😎

아래와 같이 성능 시험을 위한 환경을 다시 구축한 후, iperf3를 사용하여 XDP Bypass 성능을 측정해 보도록 하자.

 
[그림 2.7] XDP Bypass 기반의 IPS 성능 시험을 위한 Testbed

와우, 동일한 환경에서 2.3Gbps 정도(거의 line speed)의 성능이 나오는 것을 알 수 있다. 캬~ XDP 정말 대단하다. 😘

 
[그림 2.8] Suricata IPS(XDP bypass mode) 성능 시험 결과 - 2.5GbE 환경
📌 여기에는 기록하지 않았지만, 이 경우 CPU 사용량도 측정해 보니, 최대 50%를 넘지 않았다.

지금까지 AF_PACKET을 기반으로 하는 Suricata IPS와 XDP bypass 기능을 살펴 보고, 어찌 동작하는지 확인해 보았다.


3. XDP 기반의 DDoS Mitigator
Suricata IPS 기능을 이용하면 signature를 기반으로 어느 정도의 DDoS attack 차단이 가능하다. 하지만, signature 기반의 차단 방식에는 한계(signature의 지속적인 update 필요)가 있는 만큼, 이 장에서는 FastNetMon이라는 DDoS mitigation용 open source project를 테스트해 보고, 상용 제품으로 활용 가능한지 타진해 보고자 한다. 💣💣💣 💢


[그림 3.1] DDoS Attack의 개요


3.1 FastNetMon project 소개
DDoS mitigation system관련 source code를 찾던 중, XDP(AF_XDP)를 지원하는 아주 괜찮은 녀석(?)이 있어서 소개해 보고자 한다. 이름하여 FastNetMon~

 
사실, FastNetMon은 XDP(AF_XDP) 외에도 아래와 같은 다양한 capturing 방식을 지원한다. 근데, 희한하게도 DPDK는 지원하지 않는다. 😓
  • NetFlow v5, v9, v9 Lite
  • IPFIX
  • sFlow v5
  • PCAP
  • AF_PACKET (recommended)
  • AF_XDP (XDP based capture)
  • Netmap (deprecated, still supported only for FreeBSD)
  • PF_RING / PF_RING ZC (deprecated, available only for CentOS 6 in 1.2.0)

아래 그림은 FastNetMon을 사용하는 경우의 대략적인 네트워크 구성을 보여준다.

[그림 3.2] FastNetMon 네트워크 구성 Overview [출처 - 참고문헌 21]

DDoS Attack 차단 시스템은 왠지 좀 거대한(?) 느낌이 있다. 이전 posting에서 잠시 언급하고 넘어간 Gatekeeper를 보아도 이런 느낌을 지울 수가 없다. 💣
 
[그림 3.3] Gatekeeper의 개요 [출처 - 참고문헌 25]
📌 Gatekeeper는 DDoS attack을 BGP blackhole을 통해 차단하는 gatekeeper와 attack을 감지하는 grantor로 구성되어 있다.


<여기서 잠깐 - BGP Blackhole에 관하여>
_________________________________________________________________________________
Router 기능 중에는 nexthop을 Null0로 가도록 설정하여, 특정 트래픽을 더 이상 이동(라우팅)시키지 않고, 바로 drop시키는 기능이 있다. 예를 들어, 아래와 같은 routing 규칙을 추가하면, 192.0.2.1/32로 가는 모든 패킷은 더 이상 라우팅되지 않고 drop되게 된다.
ip route 192.0.2.1 255.255.255.255 Null0
 
재밌는 것은 이 기능을 BGP protocol과 연계하여 사용할 경우, DDoS Attack을 막아낼 수가 있는데, 이를 BGP blackhole이라고 한다. 만일 DDoS attack을 detection할 수 있는 장치가 (target server 근처의) Router에 연결되어 있을 경우, BGP protocol을 이용하여 target(victim) server로 향하는 트래픽이 blackhole로 향하도록 주변 BGP router 들에게 통보해주게 되면, DDoS packet이 target server까지 전달되지 않고, 이전 단계에서 차단될 수 있다.

[그림 3.4] BGP Blackhole을 이용하여 DDoS Attack 차단하기 [출처 - 참고문헌 22]

이와 관련한 자세한 사항은 아래 link를 참조하기 바란다.

_________________________________________________________________________________

3.2 FastNetMon source code build 하기
참고로, FastNetMon wiki page에는 아래와 같이 docker 상에서 build할 것을 권고(?)하고 있으나, 여기서는 Ubuntu 22.04 LTS 환경에서 직접 build하는 방법을 소개해 보기로 하겠다.

<Docker 환경에서의 build>

<참고용 Dockerfile>

<Ubuntu 22.04 LTS>
$ sudo update
$ sudo apt-get install -y --no-install-recommends build-essential git ca-certificates cmake libssl-dev \
capnproto libcapnp-dev libelf-dev libbpf-dev libpcap-dev libgrpc-dev libgrpc++-dev libprotobuf-dev \
protobuf-compiler libprotoc-dev libprotobuf-dev protobuf-compiler-grpc libboost-dev \
libboost-serialization-dev libboost-thread-dev libboost-regex-dev libboost-program-options-dev \
libmongoc-dev liblog4cpp5-dev libncurses5-dev
    
$ sudo apt-get install -y --no-install-recommends libabsl-dev

<FastNetMon build>
$ git clone https://github.com/pavel-odintsov/fastnetmon
$ cd src
$ mkdir build; cd build
$ cmake ..
$ make
...
[ 80%] Built target afpacket_plugin
[ 81%] Building CXX object CMakeFiles/xdp_plugin.dir/xdp_plugin/xdp_collector.cpp.o
/mnt/hdd/workspace/XDP/fastnetmon/src/xdp_plugin/xdp_collector.cpp: In function ‘void start_xdp_collection(process_packet_pointer)’:
/mnt/hdd/workspace/XDP/fastnetmon/src/xdp_plugin/xdp_collector.cpp:571:25: error: ‘bpf_object__next_program’ was not declared in this scope; did you mean ‘bpf_object__unpin_programs’?
  571 |     bpf_program* prog = bpf_object__next_program(obj, NULL);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~
      |                         bpf_object__unpin_programs
make[2]: *** [CMakeFiles/xdp_plugin.dir/build.make:76: CMakeFiles/xdp_plugin.dir/xdp_plugin/xdp_collector.cpp.o] 오류 1
make[1]: *** [CMakeFiles/Makefile2:685: CMakeFiles/xdp_plugin.dir/all] 오류 2
make: *** [Makefile:156: all] 오류 2

아무래도 libbpf-dev package가 좀 오래전 버젼인 듯 하다. 따라서 lastest version code를 내려 받아 직접 설치하기로 한다.

$ git clone https://github.com/libbpf/libbpf.git
$ cd src
make
$ sudo make install
$ sudo make install_headers
$ sudo ldconfig
_____________________________________

$ make
  -> 어라, 계속해서 bpf 관련 에러가 난다.
...
[ 92%] Linking CXX static library libinfluxdb_metrics.a
[ 92%] Built target influxdb_metrics
[ 93%] Building CXX object CMakeFiles/fastnetmon.dir/fastnetmon.cpp.o
[ 95%] Linking CXX executable fastnetmon
/usr/bin/ld: libxdp_plugin.a(xdp_collector.cpp.o): in function `start_xdp_collection(void (*)(simple_packet_t&))':
xdp_collector.cpp:(.text+0x4f76): undefined reference to `bpf_object__next_program'
/usr/bin/ld: xdp_collector.cpp:(.text+0x5a18): undefined reference to `bpf_xdp_attach'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/fastnetmon.dir/build.make:168: fastnetmon] 오류 1
make[1]: *** [CMakeFiles/Makefile2:200: CMakeFiles/fastnetmon.dir/all] 오류 2
make: *** [Makefile:156: all] 오류 2

확인해 보니, (오래된 버젼인) libbpf-dev package는 /usr/lib/x86_64-linux-gnu에 설치가 되어 있고, 위에서 source code를 build하여 설치한 버젼은  /usr/lib64 아래에 설치가 된다. 따라서 기존 libbpf-dev package를 삭제 후, 다시 make를 해 보니, 문제가 해결된다.

chyi@earth:/usr/lib64$ ls -l libbpf*
-rw-r--r-- 1 root root 3652734  4월 23 12:40 libbpf.a
lrwxrwxrwx 1 root root      11  4월 23 12:40 libbpf.so -> libbpf.so.1
lrwxrwxrwx 1 root root      15  4월 23 12:40 libbpf.so.1 -> libbpf.so.1.6.0
-rwxr-xr-x 1 root root 1830400  4월 23 12:40 libbpf.so.1.6.0

$ make
 -> OK, build가 끝났다.

$ ls -aF
./                       libafpacket_plugin.a         libgobgp_action.a                 libnetflow_v5_collector.a
../                      libattribute_pb_cc.a         libgobgp_api_client_grpc_pb_cc.a  libnetflow_v9_collector.a
CMakeCache.txt           libbgp_protocol.a            libgobgp_api_client_pb_cc.a       libnetwork_data_structures.a
CMakeFiles/              libbgp_protocol_flow_spec.a  libgobgp_client.a                 libpatricia.a
CPackConfig.cmake        libexabgp_action.a           libgraphite_metrics.a             libpcap_plugin.a
CPackSourceConfig.cmake  libexample_plugin.a          libiana_ip_protocols.a            libprotobuf_traffic_format.a
Makefile                 libfast_library.a            libinfluxdb_metrics.a             libsflow_plugin.a
cmake_install.cmake      libfastnetmon_api.a          libipfix_collector.a              libsimple_packet_capnp.a
compile_commands.json    libfastnetmon_grpc_pb_cc.a   libipfix_rfc.a                    libsimple_packet_parser_ng.a
fastnetmon*              libfastnetmon_logic.a        liblibsflow.a                     libspeed_counters.a
fastnetmon.service       libfastnetmon_pb_cc.a        libnetflow.a                      libtraffic_data_library.a
fastnetmon_api_client*   libfastnetmon_pcap_format.a  libnetflow_plugin.a               libxdp_plugin.a
fastnetmon_client*       libfilter.a                  libnetflow_template.a

3.3 FastNetMon 돌려 보기
아래와 같은 시험 환경에서 fastnetmon이 DDoS attack을 감지하는지 확인해 보도록 하자.
[그림 3.5] FastNetMon 시험 환경

<Testbed>

FastNetMon [enp4s0] | PC(Ubuntu 22.04 LTS) --> Access Point --> Internet

앞서 3.2절에서 build한 내용을 이용할 수도 있지만, 일단은 fastnetmon의 전체적인 동작 방식(service file, configuration file, log 위치 등)을 이해할 필요가 있으므로, 여기에서는 fastnetmon site에서 제공하는 방법을 이용해 설치를 진행해 보기로 한다.

<FastNetMon 설치하기>
$ wget https://storage.googleapis.com/community-installer/installer -Oinstaller
sudo chmod +x installer
sudo ./installer -install_community_edition
12:48:13 Will log all installation process details into file: /tmp/fastnetmon_install_900.log
12:48:13 Installer build git version is: No version specified build time is: Unknown
12:48:13 Default outgoing IPv4 address is: 192.168.8.132
12:48:13 Cannot get default outgoing IPv6 with error: Could not get default routing for test IP: network is unreachable
12:48:13 Installer binary modify time: 2025-03-28 03:00:48 +0000 UTC
12:48:14 Latest version of installer: 2025-04-22 14:28:10 +0000 UTC
12:48:14 We published new version of installer, please download it again using: 
12:48:14 wget https://install.fastnetmon.com/installer -Oinstaller
12:48:14 sudo chmod +x installer
12:48:14 And then start installer again
12:48:14 Install FastNetMon Community edition
12:48:15 Starting installation of FastNetMon Community 1.2.9
12:48:15 Apply sysctl configuration changes
12:48:15 Old configuration file /etc/sysctl.d/10-network-security.conf is already exists, showing differences
12:48:15 - 
12:48:15 - # Turn on Source Address Verification in all interfaces to
12:48:15 - # prevent some spoofing attacks.
12:48:15 - net.ipv4.conf.default.rp_filter=2
12:48:15 - net.ipv4.conf.all.rp_filter=2
12:48:15 + # FastNetMon requires this feature disabled because if you want to listen for sFlow,
12:48:15 + # Netflow data from multiple interfaces it will block all packets.
12:48:15 + net.ipv4.conf.default.rp_filter=0
12:48:15 + net.ipv4.conf.all.rp_filter=0
12:48:15 + # We need to increase UDP buffer size to avoid packet loss during bursts from routers and switches
12:48:15 + net.core.rmem_default=34078720
12:48:15 + net.core.rmem_max=34078720
12:48:15 + # Turn on SYN-flood protections.  Starting with 2.6.26, there is no loss
12:48:15 + # of TCP functionality/features under normal conditions.  When flood
12:48:15 + # protections kick in under high unanswered-SYN load, the system
12:48:15 + # should remain more stable, with a trade off of some loss of TCP
12:48:15 + # functionality/features (e.g. TCP Window scaling).
12:48:15 + net.ipv4.tcp_syncookies=1
12:48:15 Disable rp_filter for all interfaces
12:48:15 Installing on Ubuntu 24.04 platform
12:48:15 Update package manager cache
12:48:25 Installing libncurses dependency package
12:48:25 Download binary package
12:48:33 Install binary
12:48:44 Successfully installed FastNetMon Community edition
12:48:44 If you want to install Grafana which provides traffic reports via web interface please run following command: sudo ./installer -install_graphic_stack_community
  -> 아주 간단하게 설치가 끝난다.

$ sudo service fastnetmon status
● fastnetmon.service - FastNetMon - DoS/DDoS analyzer with sFlow/Netflow/mirror support
     Loaded: loaded (/usr/lib/systemd/system/fastnetmon.service; disabled; preset: enabled)
     Active: active (running) since Wed 2025-04-23 12:48:44 UTC; 1min 55s ago
   Main PID: 1175 (fastnetmon)
      Tasks: 14 (limit: 9302)
     Memory: 4.6M (peak: 5.1M)
        CPU: 441ms
     CGroup: /system.slice/fastnetmon.service
             └─1175 /opt/fastnetmon-community/app/bin/fastnetmon

$ ps -efT|grep fastnetmon
root        1262    1262       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1274       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1275       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1276       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1277       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1278       1  0 05:44 ?        00:00:04 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1279       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1280       1  0 05:44 ?        00:00:05 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1281       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1282       1  0 05:44 ?        00:00:18 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1283       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1284       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1285       1  1 05:44 ?        00:02:24 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1286       1  0 05:44 ?        00:00:02 /opt/fastnetmon-community/app/bin/fastnetmon
root        1262    1287       1  0 05:44 ?        00:00:00 /opt/fastnetmon-community/app/bin/fastnetmon
  -> (처음 시작 부터) 15개 정도의 thread가 뜬다.

sudo vi /etc/fastnetmon.conf 
  -> 우선은 아래와 같이 configuration file을 수정하여 af_packet mode에서 제대로 동작하는지 먼저 시험해 보도록 하자.
...
mirror_afpacket = on
...

sudo service fastnetmon restart
  -> fastnetmon service를 재구동시킨다.

이 상태에서 약식으로 DDoS attack을 시도(PC -> FastNetMon Box)해 보자.
$ sudo hping3 -S -p 22 --flood --rand-source 192.168.8.132
  -> Linux PC -> FastNetMon Box 방향으로 DDoS packet을 쏘아 보자.

fastnetmon_client
  -> pps, flows 값이 변하면서 제대로 동작하는 듯 보인다.
  -> fastnetmon_client는 /opt/fastnetmon-community/app/bin 아래에 설치되어 있다.

[그림 3.6] fastnetmon_client 실행 모습 - af_packet mode

앞서 언급한 것 처럼, FastNetMon은 다양한 packet capture 방법을 지원한다. 그 중에서 제일 관심이 가는 부분은 역시  XDP & AF_XDP 모드이므로, 이를 기반으로 fastnetmon을 다시 구동시켜 보도록 하자.

[그림 3.7] XDP와 AF_XDP의 관계 [출처 - 참고문헌 6]
📌 개념적으로 상단의 Application이 FastNetMon에 해당하는 것으로 이해하면 된다.

우선 fastnetmon source code 중, xdp_plugin code를 추가로 build하도록 한다.

<xdp code build>
git clone https://github.com/pavel-odintsov/fastnetmon
cd fastnetmon/src/xdp_plugin
clang -g -O2 -Wall --target=bpf -c xdp_kernel.c -o xdp_kernel.o
  ->  이후, xdp_kernel.o 파일을 /opt/fastnetmon-community/xdp/xdp_kernel.o에 복사한다.

다음으로, af_xdp 관련 설정을 enable 시킨다.
sudo vi /etc/fastnetmon.conf 
  -> 아래와 같이 configuration을 수정하도록 하자.
...
mirror_afpacket = off
mirror_afxdp = on
poll_mode_xdp = on
force_native_mode_xdp = on
microcode_xdp_path = /opt/fastnetmon-community/xdp/xdp_kernel.o
interfaces = enp4s0
...

sudo service fastnetmon restart
  -> fastnetmon service를 재구동시킨다.

tail -f /var/log/fastnetmon.log
  -> log를 확인한다.

2025-04-24 01:41:44,375 [INFO] Run banlist cleanup thread, we will awake every 60 seconds
2025-04-24 01:41:44,375 [INFO] XDP plugin started
2025-04-24 01:41:44,378 [INFO] We support only single interface and will use enp4s0
2025-04-24 01:41:44,378 [INFO] Interface in non promisc mode now, switch it on
2025-04-24 01:41:44,378 [INFO] Will use native XDP mode
2025-04-24 01:41:44,394 [INFO] API server listening on 127.0.0.1:50052
2025-04-24 01:41:44,453 [INFO] Allocating 268435456 bytes
2025-04-24 01:41:44,704 [INFO] Correctly bind socket
2025-04-24 01:41:44,704 [INFO] Correctly created socket: 16
2025-04-24 01:41:44,704 [INFO] Start traffic processing

이 상태에서 DDoS attack을 다시 시도(PC -> FastNetMon Box)해 보자.
$ sudo hping3 -S -p 22 --flood --rand-source 192.168.8.132
HPING 192.168.8.132 (wlp1s0 192.168.8.132): S set, 40 headers + 0 data bytes
hping in flood mode, no replies will be shown

$ sudo hping3 --udp --flood -p 80 192.168.8.132 --rand-source
HPING 192.168.8.132 (wlp1s0 192.168.8.132): udp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown

fastnetmon_client
  -> 역시, pps 및 flows 값에 변화가 보인다. 😎

[그림 3.8] fastnetmon_client 실행 모습 - af_xdp mode

이 상태에서 CPU 사용율을 확인해 보면 다음과 같다. xdp thread의 cpu 사용율이 올라가는 것은 어느 정도 예상했으나, 그 밖에도 ksoftirqd/0 thread의 사용율도 꽤나 높게 올라간다(아무래도 AF_XDP와 연관이 있는 듯 보임).

[그림 3.9] top -H 명령 실행 모습 - af_xdp mode

hping3 명령으로 --random-source option을 주어 돌려 보았는데, 이걸 잡아내는 걸 보니, FastNetMon 나름 쓸만한 것 같다. 😍

참고로, 아래 명령을 통해 notify_about_attack.sh 파일을 설치하게 되면, DDoS attack 감지 시, mail을 통해 이 사실을 전달 받을 수도 있다.

$ sudo wget https://raw.githubusercontent.com/pavel-odintsov/fastnetmon/master/src/notify_about_attack.sh -O/usr/local/bin/notify_about_attack.sh
$ sudo chmod 755 /usr/local/bin/notify_about_attack.sh

3.4 FastMetMon의 대략적인 코드 분석
끝으로, fastnetmon source 코드를 살짝 들여다 보았는데, C++로 작성된 코드가 이해하기 쉽도록 잘 설계되어 있는 느낌이다. ☆☆☆☆☆ 👍

[그림 3.10] fastnetmon main code 흐름 개요도
📌 대략적으로 분석해 본 것이라 잘못 이해된 부분이 있을 수 있다. 또한 graphite, influxdb, clickhouse 등 외부 서버와의 연동 부분은 그림에서 빠져있다.

3.5 FastMetMon과 Suricata IPS와의 결합
지금부터는 FastNetMon을 DDoS Detection용으로 하고, Suricata IPS(XDP bypass)를 DDoS Mitigator로 하는 시스템을 설계/구상해 보고자 한다.

[그림 3.11] 서버 전용 DDoS Mitigation System(1)


[그림 3.12] 서버 전용 DDoS Mitigation System(2)


[그림 3.13] 서버 전용 DDoS Mitigation System(3)


아래와 같은 barebone router에 위와 같은 ddos mitigation engine을 올려 보면 어떨까 ? 너무 흔한가 ? 😂
[그림 3.14] 8 Ports Barebone Router [출처 - 참고문헌 18]


To be continued...


4. References
[1] https://github.com/xdp-project/xdp-paper/blob/main/xdp-the-express-data-path.pdf
[2] https://github.com/xdp-project/xdp-tutorial
[3] https://www.minzkn.com/moniwiki/wiki.php/XDP
[4] Understanding Delays in AF XDP-based Applications, Killian Castillon du Perron
[5] https://medium.com/high-performance-network-programming/recapitulating-af-xdp-ef6c1ebead8
[6] https://docs.ngkore.com/blogs/afxdp/afxdp.html
[7] https://github.com/zoidyzoidzoid/awesome-ebpf
[8] https://github.com/MeherRushi/FlowSentryX?tab=readme-ov-file
[9] https://docs.suricata.io/en/latest/capture-hardware/af-xdp.html#
[10] https://github.com/dorkamotorka/transparent-proxy-ebpf
[11] https://www.youtube.com/watch?v=yGA95Mzgk8w
[12] https://www.stamus-networks.com/hubfs/Library/Documents%20%28PDFs%29/StamusNetworks-WP-eBF-XDP-092021-1.pdf
[13] https://www.datadoghq.com/blog/xdp-intro/
[14] https://media.frnog.org/FRnOG_28/FRnOG_28-3.pdf 
[15] https://webthesis.biblio.polito.it/9047/1/tesi.pdf
[16] https://lpc.events/event/2/contributions/71/attachments/17/9/presentation-lpc2018-xdp-tutorial.pdf
[17] https://ebpf-go.dev/guides/getting-started/#ebpf-c-program
[18] https://www.alibaba.com/product-detail/Intel-N100-Desktop-Rackmount-Network-Device_1601391543460.html?spm=a2700.details-description.0.0.7b77V7LcV7LcVw
[19] https://www.labellerr.com/blog/ddos-attack-detection/
[20] https://github.com/pavel-odintsov/fastnetmon
[21] https://archive.nanog.org/sites/default/files/OpenSource-DDoS.pdf
[22] https://www.anthony-balitrand.fr/2024/03/20/leveraging-bgp-to-mitigate-network-attacks-a-comprehensive-guide/
[23] https://thibautprobst.fr/en/posts/rtbh/
[24] https://raw.githubusercontent.com/wiki/AltraMayor/gatekeeper/docs/Cody-Thesis-Slides.pdf
[25] https://raw.githubusercontent.com/wiki/AltraMayor/gatekeeper/docs/Gatekeeper-Tech-Report.pdf
[26] https://homepages.dcc.ufmg.br/~mmvieira/so/papers/Fast_Packet_Processing_with_eBPF_and_XDP.pdf
[27] And, Google~


Slowboot
bigGate Company