From 99b029cde8d5d26ed8db64626948b82d4b126bc3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 11:16:28 +0100 Subject: [PATCH 01/17] github-ci: add namespace based afpacket IPS test --- .github/workflows/builds.yml | 83 +++++++++ .../workflows/netns/afp-ips-netns-bridge.sh | 163 ++++++++++++++++++ .../workflows/netns/afp-ips-netns-bridge.yaml | 115 ++++++++++++ 3 files changed, 361 insertions(+) create mode 100755 .github/workflows/netns/afp-ips-netns-bridge.sh create mode 100644 .github/workflows/netns/afp-ips-netns-bridge.yaml diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index aa8117aa055a..bff70ab902cc 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1897,6 +1897,89 @@ jobs: - run: | ./qa/unix.sh "suricata-verify/" + ubuntu-latest-namespace-ips: + name: Ubuntu Latest (afpacket IPS tests in namespaces) + runs-on: ubuntu-latest + needs: [prepare-deps, prepare-cbindgen] + steps: + - name: Cache ~/.cargo + uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb + with: + path: ~/.cargo/registry + key: cargo-registry + - name: Determine number of CPUs + run: echo CPUS=$(nproc --all) >> $GITHUB_ENV + + - name: Install dependencies + run: | + apt update + apt -y install \ + libpcre2-dev \ + build-essential \ + autoconf \ + automake \ + llvm-18-dev \ + cargo \ + cbindgen \ + clang-18 \ + git \ + hwloc \ + libhwloc-dev \ + jq \ + inetutils-ping \ + libc++-dev \ + libc++abi-dev \ + libtool \ + libpcap-dev \ + libnet1-dev \ + libyaml-0-2 \ + libyaml-dev \ + libcap-ng-dev \ + libcap-ng0 \ + libmagic-dev \ + libnetfilter-queue-dev \ + libnetfilter-queue1 \ + libnfnetlink-dev \ + libnfnetlink0 \ + libnuma-dev \ + libhiredis-dev \ + libjansson-dev \ + libevent-dev \ + libevent-pthreads-2.1-7 \ + make \ + parallel \ + python3-yaml \ + rustc \ + software-properties-common \ + sudo \ + zlib1g \ + zlib1g-dev \ + exuberant-ctags \ + unzip \ + curl \ + time \ + wget \ + caddy \ + ethtool \ + iproute2 \ + dpdk-dev + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + - run: git config --global --add safe.directory /__w/suricata/suricata + - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 + with: + name: prep + path: prep + - run: ./autogen.sh + - run: ./configure --enable-dpdk --disable-shared --enable-gccprotect --localstatedir=/var --prefix=/usr --sysconfdir=/etc + env: + CC: "clang-18" + CFLAGS: "-g" + - run: make -j ${{ env.CPUS }} + env: + CC: "clang-18" + - run: | + ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" + ubuntu-24-04-asan-afpdpdk: name: Ubuntu 24.04 (afpacket and dpdk live tests with ASAN) runs-on: ubuntu-latest diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh new file mode 100755 index 000000000000..25f50076f211 --- /dev/null +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +# TODO Script to test live IPS capabilities for AF_PACKET. Starts a ping, starts suricata, +# checks stats and alerts. Then issues a reload with a new rule file, checks stats and +# new alerts. Then shuts suricata down. + +# Call with following arguments: +# 1st: "2" or "3" to indicate the tpacket version. +# 2nd: runmode string (single/autofp/workers) + +#set -e +set -x + +if [ $# -ne "2" ]; then + echo "ERROR call with 2 args: tpacket version (2/3) and runmode (single/autofp/workers)" + exit 1; +fi + +TPACKET=$1 +RUNMODE=$2 +YAML="afp-ips-netns-bridge.yaml" + +# dump some info +echo "* printing some diagnostics..." +ip netns list +uname -a +ip r +echo "* printing some diagnostics... done" + +# remove eve.json from previous run +if [ -f eve.json ]; then + rm eve.json +fi + +if [ -e ./rust/target/release/suricatasc ]; then + SURICATASC=./rust/target/release/suricatasc +else + SURICATASC=./rust/target/debug/suricatasc +fi + +RES=0 + +# we'll be creating 3 namespaces: client, server and dut. Dut is where Suricata will run: +# +# [ client ]$clientif - $dutclientif[ dut ]$dutserverif - $serverif[ server ] +# +# By copying packets between the dut interfaces, Suricata becomes the bridge. +# +clientns=client +serverns=server +dutns=dut +clientip="10.10.10.10/24" +serverip='10.10.10.20/24' +clientif=client +serverif=server +dutclientif=dut_client +dutserverif=dut_server + +# adding namespaces +echo "* creating namespaces..." +ip netns add $clientns +ip netns add $serverns +ip netns add $dutns +echo "* creating namespaces... done" + +#diagnostics output +echo "* list namespaces..." +ip netns list +ip netns exec $clientns ip ad +ip netns exec $serverns ip ad +ip netns exec $dutns ip ad +echo "* list namespaces... done" + +# create virtual ethernet link between client-dut and server-dut +# These are not yet mapped to a namespace +echo "* creating virtual ethernet devices..." +ip link add ptp-$clientif type veth peer name ptp-$dutclientif +ip link add ptp-$serverif type veth peer name ptp-$dutserverif +echo "* creating virtual ethernet devices...done" + +echo "* list interface in global namespace..." +ip link +echo "* list interface in global namespace... done" + +echo "* map virtual ethernet interfaces to their namespaces..." +ip link set ptp-$clientif netns $clientns +ip link set ptp-$serverif netns $serverns +ip link set ptp-$dutclientif netns $dutns +ip link set ptp-$dutserverif netns $dutns +echo "* map virtual ethernet interfaces to their namespaces... done" + +echo "* list namespaces and interfaces within them..." +ip netns list +ip netns exec $clientns ip ad +ip netns exec $serverns ip ad +ip netns exec $dutns ip ad +echo "* list namespaces and interfaces within them... done" + +# bring up interfaces. Client and server get IP's. +# Disable rx and tx csum offload on all sides. + +echo "* setup client interface..." +ip netns exec $clientns ip addr add $clientip dev ptp-$clientif +ip netns exec $clientns ethtool -K ptp-$clientif rx off tx off +ip netns exec $clientns ip link set ptp-$clientif up +echo "* setup client interface... done" + +echo "* setup server interface..." +ip netns exec $serverns ip addr add $serverip dev ptp-$serverif +ip netns exec $serverns ethtool -K ptp-$serverif rx off tx off +ip netns exec $serverns ip link set ptp-$serverif up +echo "* setup server interface... done" + +echo "* setup dut interfaces..." +ip netns exec $dutns ethtool -K ptp-$dutclientif rx off tx off +ip netns exec $dutns ethtool -K ptp-$dutserverif rx off tx off +ip netns exec $dutns ip link set ptp-$dutclientif up +ip netns exec $dutns ip link set ptp-$dutserverif up +echo "* setup dut interfaces... done" + +# set first rule file +#cp .github/workflows/live/icmp.rules suricata.rules + +echo "* starting Suricata in the \"dut\" namespace..." +# Start Suricata, SIGINT after 120 secords. Will close it earlier through +# the unix socket. +timeout --kill-after=240 --preserve-status 120 \ + ip netns exec dut ./src/suricata -c $YAML -l ./ --af-packet -v \ + --set default-rule-path=. --runmode=$RUNMODE --disable-detection & +SURIPID=$! +sleep 10 +echo "* starting Suricata... done" + +echo "* starting Caddy..." +# Start Caddy in the server namespace +timeout --kill-after=240 --preserve-status 120 \ + ip netns exec server caddy file-server --domain 10.10.10.20 --browse +CADDYPID=$! +sleep 10 +echo "* starting Caddy in the \"server\" namespace... done" + +echo "* running curl in the \"client\" namespace..." +curl https://10.10.10.20/ +echo "* running curl in the \"client\" namespace... done" + +# check stats and alerts +STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.capture.kernel_packets > 0') +if [ $STATSCHECK = false ]; then + echo "ERROR no packets captured" + RES=1 +fi + +kill -INT $CADDYPID +wait $PINGPID +${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket +wait $SURIPID + +cat ./eve.json | jq 'select(.tls)' +cat ./eve.json | jq 'select(.stats)|.stats.ips' +cat ./eve.json | jq 'select(.stats)|.stats.capture' + +echo "* done: $RES" +exit $RES diff --git a/.github/workflows/netns/afp-ips-netns-bridge.yaml b/.github/workflows/netns/afp-ips-netns-bridge.yaml new file mode 100644 index 000000000000..b351a89b70d3 --- /dev/null +++ b/.github/workflows/netns/afp-ips-netns-bridge.yaml @@ -0,0 +1,115 @@ +%YAML 1.1 +--- + +# Suricata configuration file. In addition to the comments describing all +# options in this file, full documentation can be found at: +# https://docs.suricata.io/en/latest/configuration/suricata-yaml.html + +# This configuration file was generated by Suricata 9.0.0-dev. +suricata-version: "9.0" + +## +## Step 1: Inform Suricata about your network +## + +vars: + # more specific is better for alert accuracy and performance + address-groups: + HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]" + #HOME_NET: "[192.168.0.0/16]" + #HOME_NET: "[10.0.0.0/8]" + #HOME_NET: "[172.16.0.0/12]" + #HOME_NET: "any" + + EXTERNAL_NET: "!$HOME_NET" + #EXTERNAL_NET: "any" + + HTTP_SERVERS: "$HOME_NET" + SMTP_SERVERS: "$HOME_NET" + SQL_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + TELNET_SERVERS: "$HOME_NET" + AIM_SERVERS: "$EXTERNAL_NET" + DC_SERVERS: "$HOME_NET" + DNP3_SERVER: "$HOME_NET" + DNP3_CLIENT: "$HOME_NET" + MODBUS_CLIENT: "$HOME_NET" + MODBUS_SERVER: "$HOME_NET" + ENIP_CLIENT: "$HOME_NET" + ENIP_SERVER: "$HOME_NET" + + port-groups: + HTTP_PORTS: "80" + SHELLCODE_PORTS: "!80" + ORACLE_PORTS: 1521 + SSH_PORTS: 22 + DNP3_PORTS: 20000 + MODBUS_PORTS: 502 + FILE_DATA_PORTS: "[$HTTP_PORTS,110,143]" + FTP_PORTS: 21 + GENEVE_PORTS: 6081 + VXLAN_PORTS: 4789 + TEREDO_PORTS: 3544 + SIP_PORTS: "[5060, 5061]" + +## +## Step 2: Select outputs to enable +## + +# Global stats configuration +stats: + enabled: yes + # The interval field (in seconds) controls the interval at + # which stats are updated in the log. + interval: 8 + # Add decode events to stats. + #decoder-events: true + # Decoder event prefix in stats. Has been 'decoder' before, but that leads + # to missing events in the eve.stats records. See issue #2225. + #decoder-events-prefix: "decoder.event" + # Add stream events as stats. + #stream-events: false + exception-policy: + #per-app-proto-errors: false # default: false. True will log errors for + # each app-proto. Warning: VERY verbose +outputs: + - eve-log: + enabled: yes + filetype: regular #regular|syslog|unix_dgram|unix_stream|redis + filename: eve.json + types: + - alert + - http: + extended: yes # enable this for extended logging information + - dns + - tls: + extended: yes # enable this for extended logging information + - files: + force-magic: no # force logging magic on all logged files + # force logging of checksums, available hash functions are md5, + # sha1 and sha256 + #force-hash: [md5] + - drop: + alerts: yes # log alerts that caused drops + flows: all # start or all: 'start' logs only a single drop + verdict: yes + - stats: + totals: yes # stats for all threads merged together + threads: no # per thread stats + deltas: no # include delta values + # Don't log stats counters that are zero. Default: true + #null-values: false # False will NOT log stats counters: 0 + - flow + +af-packet: + - interface: ptp-dut_client + cluster-id: 1 + copy-iface: ptp-dut_server + - interface: ptp-dut_server + cluster-id: 2 + copy-iface: ptp-dut_client + - interface: default + threads: 2 + cluster-type: cluster_flow + copy-mode: ips + From 1f03df626a4c1783036aef58485c0e3083f76235 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 11:35:20 +0100 Subject: [PATCH 02/17] SQUASH --- .github/workflows/builds.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index bff70ab902cc..449ad8cc8b15 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1912,8 +1912,8 @@ jobs: - name: Install dependencies run: | - apt update - apt -y install \ + sudo apt update + sudo apt -y install \ libpcre2-dev \ build-essential \ autoconf \ @@ -1978,7 +1978,7 @@ jobs: env: CC: "clang-18" - run: | - ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" + sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ubuntu-24-04-asan-afpdpdk: name: Ubuntu 24.04 (afpacket and dpdk live tests with ASAN) From c98627afdaecb115448597447afc0d932b22c79b Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 11:47:27 +0100 Subject: [PATCH 03/17] SQUASH --- .github/workflows/builds.yml | 2 +- .github/workflows/netns/afp-ips-netns-bridge.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 449ad8cc8b15..53e3e03fcb17 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1978,7 +1978,7 @@ jobs: env: CC: "clang-18" - run: | - sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" + sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ".github/workflows/netns/afp-ips-netns-bridge.yaml" ubuntu-24-04-asan-afpdpdk: name: Ubuntu 24.04 (afpacket and dpdk live tests with ASAN) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index 25f50076f211..b255ac756c43 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -11,14 +11,14 @@ #set -e set -x -if [ $# -ne "2" ]; then +if [ $# -ne "3" ]; then echo "ERROR call with 2 args: tpacket version (2/3) and runmode (single/autofp/workers)" exit 1; fi TPACKET=$1 RUNMODE=$2 -YAML="afp-ips-netns-bridge.yaml" +YAML=$3 # dump some info echo "* printing some diagnostics..." From f5042801a5017f4133883842f5dbc0be1af95327 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 12:01:16 +0100 Subject: [PATCH 04/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index b255ac756c43..f06387ba78ca 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -8,7 +8,7 @@ # 1st: "2" or "3" to indicate the tpacket version. # 2nd: runmode string (single/autofp/workers) -#set -e +set -e set -x if [ $# -ne "3" ]; then @@ -134,7 +134,7 @@ echo "* starting Suricata... done" echo "* starting Caddy..." # Start Caddy in the server namespace timeout --kill-after=240 --preserve-status 120 \ - ip netns exec server caddy file-server --domain 10.10.10.20 --browse + ip netns exec server caddy file-server --domain 10.10.10.20 --browse & CADDYPID=$! sleep 10 echo "* starting Caddy in the \"server\" namespace... done" From ff4c6a68f90f611e66a507aafb2cfc2d90279766 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 12:24:59 +0100 Subject: [PATCH 05/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index f06387ba78ca..262645e9fdc7 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -140,7 +140,8 @@ sleep 10 echo "* starting Caddy in the \"server\" namespace... done" echo "* running curl in the \"client\" namespace..." -curl https://10.10.10.20/ +ip netns exec client \ + curl https://10.10.10.20/ echo "* running curl in the \"client\" namespace... done" # check stats and alerts From 04e3772c0ceda96e4353370e0769b5420db65f06 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 12:49:37 +0100 Subject: [PATCH 06/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index 262645e9fdc7..e4fa14269ba9 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -141,9 +141,14 @@ echo "* starting Caddy in the \"server\" namespace... done" echo "* running curl in the \"client\" namespace..." ip netns exec client \ - curl https://10.10.10.20/ + curl -O https://10.10.10.20/ echo "* running curl in the \"client\" namespace... done" +echo "* running wget in the \"client\" namespace..." +ip netns exec client \ + wget https://10.10.10.20/ +echo "* running wget in the \"client\" namespace... done" + # check stats and alerts STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.capture.kernel_packets > 0') if [ $STATSCHECK = false ]; then @@ -152,7 +157,7 @@ if [ $STATSCHECK = false ]; then fi kill -INT $CADDYPID -wait $PINGPID +wait $CADDYPID ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket wait $SURIPID From cf6ebc85a432ad95c68655a11ee34bcca8a375f6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 13:09:29 +0100 Subject: [PATCH 07/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index e4fa14269ba9..ce9cd0190bbd 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -141,12 +141,12 @@ echo "* starting Caddy in the \"server\" namespace... done" echo "* running curl in the \"client\" namespace..." ip netns exec client \ - curl -O https://10.10.10.20/ + curl -O https://10.10.10.20/index.html echo "* running curl in the \"client\" namespace... done" echo "* running wget in the \"client\" namespace..." ip netns exec client \ - wget https://10.10.10.20/ + wget https://10.10.10.20/index.html echo "* running wget in the \"client\" namespace... done" # check stats and alerts From 79ddf78a4d63849d9cfc1c32d8cb47fb51cd6629 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 13:29:38 +0100 Subject: [PATCH 08/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index ce9cd0190bbd..b1a4c7414d62 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -158,7 +158,8 @@ fi kill -INT $CADDYPID wait $CADDYPID -${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket +ip netns exec dut \ + ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket wait $SURIPID cat ./eve.json | jq 'select(.tls)' From af7092ff77ad747c8332d1b1a9d3b3b3d5598c44 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 13:46:13 +0100 Subject: [PATCH 09/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index b1a4c7414d62..c813de0870cc 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -120,13 +120,14 @@ echo "* setup dut interfaces... done" # set first rule file #cp .github/workflows/live/icmp.rules suricata.rules +RULES="/dev/null" # w/o -S the unix socket won't get created? echo "* starting Suricata in the \"dut\" namespace..." # Start Suricata, SIGINT after 120 secords. Will close it earlier through # the unix socket. timeout --kill-after=240 --preserve-status 120 \ ip netns exec dut ./src/suricata -c $YAML -l ./ --af-packet -v \ - --set default-rule-path=. --runmode=$RUNMODE --disable-detection & + --set default-rule-path=. --runmode=$RUNMODE -S $RULES & SURIPID=$! sleep 10 echo "* starting Suricata... done" From 009c372948bc56cce14b6018278c4d1710f1f743 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 14:06:13 +0100 Subject: [PATCH 10/17] SQUASH nfq --- .github/workflows/builds.yml | 4 +- .../workflows/netns/afp-ips-netns-bridge.sh | 17 +- ...p-ips-netns-bridge.yaml => ips-netns.yaml} | 0 .../workflows/netns/nfq-ips-netns-route.sh | 194 ++++++++++++++++++ 4 files changed, 208 insertions(+), 7 deletions(-) rename .github/workflows/netns/{afp-ips-netns-bridge.yaml => ips-netns.yaml} (100%) create mode 100755 .github/workflows/netns/nfq-ips-netns-route.sh diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 53e3e03fcb17..d55f7ab48116 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1978,7 +1978,9 @@ jobs: env: CC: "clang-18" - run: | - sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ".github/workflows/netns/afp-ips-netns-bridge.yaml" + sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ".github/workflows/netns/ips-netns.yaml" + - run: | + sudo ./.github/workflows/netns/nfq-ips-netns-route.sh "autofp" ".github/workflows/netns/ips-netns.yaml" ubuntu-24-04-asan-afpdpdk: name: Ubuntu 24.04 (afpacket and dpdk live tests with ASAN) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index c813de0870cc..2f79c8edc44c 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -126,8 +126,9 @@ echo "* starting Suricata in the \"dut\" namespace..." # Start Suricata, SIGINT after 120 secords. Will close it earlier through # the unix socket. timeout --kill-after=240 --preserve-status 120 \ - ip netns exec dut ./src/suricata -c $YAML -l ./ --af-packet -v \ - --set default-rule-path=. --runmode=$RUNMODE -S $RULES & + ip netns exec $dutns \ + ./src/suricata -c $YAML -l ./ --af-packet -v \ + --set default-rule-path=. --runmode=$RUNMODE -S $RULES & SURIPID=$! sleep 10 echo "* starting Suricata... done" @@ -135,21 +136,25 @@ echo "* starting Suricata... done" echo "* starting Caddy..." # Start Caddy in the server namespace timeout --kill-after=240 --preserve-status 120 \ - ip netns exec server caddy file-server --domain 10.10.10.20 --browse & + ip netns exec $serverns \ + caddy file-server --domain 10.10.10.20 --browse & CADDYPID=$! sleep 10 echo "* starting Caddy in the \"server\" namespace... done" echo "* running curl in the \"client\" namespace..." -ip netns exec client \ +ip netns exec $clientns \ curl -O https://10.10.10.20/index.html echo "* running curl in the \"client\" namespace... done" echo "* running wget in the \"client\" namespace..." -ip netns exec client \ +ip netns exec $clientns \ wget https://10.10.10.20/index.html echo "* running wget in the \"client\" namespace... done" +# give stats time to get updated +sleep 10 + # check stats and alerts STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.capture.kernel_packets > 0') if [ $STATSCHECK = false ]; then @@ -159,7 +164,7 @@ fi kill -INT $CADDYPID wait $CADDYPID -ip netns exec dut \ +ip netns exec $dutns \ ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket wait $SURIPID diff --git a/.github/workflows/netns/afp-ips-netns-bridge.yaml b/.github/workflows/netns/ips-netns.yaml similarity index 100% rename from .github/workflows/netns/afp-ips-netns-bridge.yaml rename to .github/workflows/netns/ips-netns.yaml diff --git a/.github/workflows/netns/nfq-ips-netns-route.sh b/.github/workflows/netns/nfq-ips-netns-route.sh new file mode 100755 index 000000000000..d40935b91666 --- /dev/null +++ b/.github/workflows/netns/nfq-ips-netns-route.sh @@ -0,0 +1,194 @@ +#!/bin/bash + +# TODO Script to test live IPS capabilities for AF_PACKET. Starts a ping, starts suricata, +# checks stats and alerts. Then issues a reload with a new rule file, checks stats and +# new alerts. Then shuts suricata down. + +# Call with following arguments: +# 1st: "2" or "3" to indicate the tpacket version. +# 2nd: runmode string (single/autofp/workers) + +set -e +set -x + +if [ $# -ne "2" ]; then + echo "ERROR call with 2 args: runmode (single/autofp/workers) and yaml" + exit 1; +fi + +RUNMODE=$1 +YAML=$2 + +# dump some info +echo "* printing some diagnostics..." +ip netns list +uname -a +ip r +echo "* printing some diagnostics... done" + +# remove eve.json from previous run +if [ -f eve.json ]; then + rm eve.json +fi + +if [ -e ./rust/target/release/suricatasc ]; then + SURICATASC=./rust/target/release/suricatasc +else + SURICATASC=./rust/target/debug/suricatasc +fi + +RES=0 + +# we'll be creating 3 namespaces: client, server and dut. Dut is where Suricata will run: +# +# [ client ]$clientif - $dutclientif[ dut ]$dutserverif - $serverif[ server ] +# +# By routing packets between the dut interfaces, Suricata becomes the router. +# +clientns=client +serverns=server +dutns=dut +clientip="10.10.10.2/24" +clientnet="10.10.10.0/24" +serverip='10.10.20.2/24' +servernet="10.10.20.0/24" +dutclientip="10.10.10.1/24" +dutserverip='10.10.20.1/24' +clientif=client +serverif=server +dutclientif=dut_client +dutserverif=dut_server + +# adding namespaces +echo "* creating namespaces..." +ip netns add $clientns +ip netns add $serverns +ip netns add $dutns +echo "* creating namespaces... done" + +#diagnostics output +echo "* list namespaces..." +ip netns list +ip netns exec $clientns ip ad +ip netns exec $serverns ip ad +ip netns exec $dutns ip ad +echo "* list namespaces... done" + +# create virtual ethernet link between client-dut and server-dut +# These are not yet mapped to a namespace +echo "* creating virtual ethernet devices..." +ip link add ptp-$clientif type veth peer name ptp-$dutclientif +ip link add ptp-$serverif type veth peer name ptp-$dutserverif +echo "* creating virtual ethernet devices...done" + +echo "* list interface in global namespace..." +ip link +echo "* list interface in global namespace... done" + +echo "* map virtual ethernet interfaces to their namespaces..." +ip link set ptp-$clientif netns $clientns +ip link set ptp-$serverif netns $serverns +ip link set ptp-$dutclientif netns $dutns +ip link set ptp-$dutserverif netns $dutns +echo "* map virtual ethernet interfaces to their namespaces... done" + +echo "* list namespaces and interfaces within them..." +ip netns list +ip netns exec $clientns ip ad +ip netns exec $serverns ip ad +ip netns exec $dutns ip ad +echo "* list namespaces and interfaces within them... done" + +# bring up interfaces. All interfaces get IP's. + +echo "* setup client interface..." +ip netns exec $clientns ip addr add $clientip dev ptp-$clientif +ip netns exec $clientns ip link set ptp-$clientif up +echo "* setup client interface... done" + +echo "* setup server interface..." +ip netns exec $serverns ip addr add $serverip dev ptp-$serverif +ip netns exec $serverns ip link set ptp-$serverif up +echo "* setup server interface... done" + +echo "* setup dut interfaces..." +ip netns exec $dutns ip addr add $dutclientip dev ptp-$dutclientif +ip netns exec $dutns ip addr add $dutserverip dev ptp-$dutserverif +ip netns exec $dutns ip link set ptp-$dutclientif up +ip netns exec $dutns ip link set ptp-$dutserverif up +echo "* setup dut interfaces... done" + +echo "* setup client/server routes..." +# routes: +# +# client can reach servernet through the client side ip of the dut +via_ip=$(echo $dutclientip|cut -f1 -d'/') +ip netns exec $clientns ip route add $servernet via $via_ip dev ptp-$clientif +# +# server can reach clientnet through the server side ip of the dut +via_ip=$(echo $dutserverip|cut -f1 -d'/') +ip netns exec $serverns ip route add $clientnet via $via_ip dev ptp-$serverif +echo "* setup client/server routes... done" + +echo "* enabling forwarding in the dut..." +# forward all +ip netns exec $dutns sysctl net.ipv4.ip_forward=1 +ip netns exec $dutns iptables -I FORWARD 1 -j NFQUEUE +echo "* enabling forwarding in the dut... done" + +# set first rule file +#cp .github/workflows/live/icmp.rules suricata.rules +RULES="/dev/null" # w/o -S the unix socket won't get created? + +echo "* starting Suricata in the \"dut\" namespace..." +# Start Suricata, SIGINT after 120 secords. Will close it earlier through +# the unix socket. +timeout --kill-after=240 --preserve-status 120 \ + ip netns exec $dutns \ + ./src/suricata -c $YAML -l ./ -q 0 -v \ + --set default-rule-path=. --runmode=$RUNMODE -S $RULES & +SURIPID=$! +sleep 10 +echo "* starting Suricata... done" + +echo "* starting Caddy..." +# Start Caddy in the server namespace +timeout --kill-after=240 --preserve-status 120 \ + ip netns exec $serverns \ + caddy file-server --domain 10.10.20.2 --browse & +CADDYPID=$! +sleep 10 +echo "* starting Caddy in the \"server\" namespace... done" + +echo "* running curl in the \"client\" namespace..." +ip netns exec $clientns \ + curl -O https://10.10.20.2/index.html +echo "* running curl in the \"client\" namespace... done" + +echo "* running wget in the \"client\" namespace..." +ip netns exec $clientns \ + wget https://10.10.20.2/index.html +echo "* running wget in the \"client\" namespace... done" + +# give stats time to get updated +sleep 10 + +# check stats and alerts +STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.accepted > 0') +if [ $STATSCHECK = false ]; then + echo "ERROR no packets captured" + RES=1 +fi + +kill -INT $CADDYPID +wait $CADDYPID +ip netns exec $dutns \ + ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket +wait $SURIPID + +cat ./eve.json | jq 'select(.tls)' +cat ./eve.json | jq 'select(.stats)|.stats.ips' +cat ./eve.json | jq 'select(.stats)|.stats.capture' + +echo "* done: $RES" +exit $RES From 243c78f45dadf49901a98d81def92b9b342db2a6 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 14:08:32 +0100 Subject: [PATCH 11/17] SQUASH nfq --- .github/workflows/netns/ips-netns.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/netns/ips-netns.yaml b/.github/workflows/netns/ips-netns.yaml index b351a89b70d3..54052eadd54f 100644 --- a/.github/workflows/netns/ips-netns.yaml +++ b/.github/workflows/netns/ips-netns.yaml @@ -101,6 +101,9 @@ outputs: #null-values: false # False will NOT log stats counters: 0 - flow +unix-command: + enabled: auto + af-packet: - interface: ptp-dut_client cluster-id: 1 From e1b5ac2aa5cdac28c86f8ace4a83fc1d27b6b1f0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 14:39:42 +0100 Subject: [PATCH 12/17] SQUASH --- .github/workflows/netns/afp-ips-netns-bridge.sh | 5 +++++ .github/workflows/netns/nfq-ips-netns-route.sh | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index 2f79c8edc44c..7fd8fa06fec9 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -27,6 +27,11 @@ uname -a ip r echo "* printing some diagnostics... done" +NAMESPACES=$(ip netns list|cut -d' ' -f1) +for NS in $NAMESPACES; do + ip netns delete $NS +done + # remove eve.json from previous run if [ -f eve.json ]; then rm eve.json diff --git a/.github/workflows/netns/nfq-ips-netns-route.sh b/.github/workflows/netns/nfq-ips-netns-route.sh index d40935b91666..76d7a59026cc 100755 --- a/.github/workflows/netns/nfq-ips-netns-route.sh +++ b/.github/workflows/netns/nfq-ips-netns-route.sh @@ -26,6 +26,11 @@ uname -a ip r echo "* printing some diagnostics... done" +NAMESPACES=$(ip netns list|cut -d' ' -f1) +for NS in $NAMESPACES; do + ip netns delete $NS +done + # remove eve.json from previous run if [ -f eve.json ]; then rm eve.json From 6c1e7434f54d122f4e67c102f8d77b07bb62a228 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 14:49:11 +0100 Subject: [PATCH 13/17] SQUASH --- .github/workflows/builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index d55f7ab48116..9e2621d32c08 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1970,7 +1970,7 @@ jobs: name: prep path: prep - run: ./autogen.sh - - run: ./configure --enable-dpdk --disable-shared --enable-gccprotect --localstatedir=/var --prefix=/usr --sysconfdir=/etc + - run: ./configure --enable-dpdk --disable-shared --enable-gccprotect --localstatedir=/var --prefix=/usr --sysconfdir=/etc --enable-nfqueue env: CC: "clang-18" CFLAGS: "-g" From 0473819287aa5f97c45680fb1f37017dc337061e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 16:42:09 +0100 Subject: [PATCH 14/17] SQUASH icmp drop check --- .../workflows/netns/afp-ips-netns-bridge.sh | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index 7fd8fa06fec9..e06daffe6a50 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -124,13 +124,13 @@ ip netns exec $dutns ip link set ptp-$dutserverif up echo "* setup dut interfaces... done" # set first rule file -#cp .github/workflows/live/icmp.rules suricata.rules -RULES="/dev/null" # w/o -S the unix socket won't get created? +cp .github/workflows/netns/drop-icmp.rules suricata.rules +RULES="suricata.rules" echo "* starting Suricata in the \"dut\" namespace..." # Start Suricata, SIGINT after 120 secords. Will close it earlier through # the unix socket. -timeout --kill-after=240 --preserve-status 120 \ +timeout --kill-after=300 --preserve-status 240 \ ip netns exec $dutns \ ./src/suricata -c $YAML -l ./ --af-packet -v \ --set default-rule-path=. --runmode=$RUNMODE -S $RULES & @@ -157,6 +157,17 @@ ip netns exec $clientns \ wget https://10.10.10.20/index.html echo "* running wget in the \"client\" namespace... done" +set +e +ip netns exec $clientns \ + ping -c 10 10.10.10.20 +PINGRES=$? +set -e + +if [ $PINGRES != 1 ]; then + echo "ERROR ping should have failed" + RES=1 +fi + # give stats time to get updated sleep 10 @@ -166,6 +177,11 @@ if [ $STATSCHECK = false ]; then echo "ERROR no packets captured" RES=1 fi +STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.blocked != 10') +if [ $STATSCHECK = false ]; then + echo "ERROR should have seen 10 blocked" + RES=1 +fi kill -INT $CADDYPID wait $CADDYPID From 84ba3ffc09b4889b09d705802c4b2f97bab31c33 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 17:07:50 +0100 Subject: [PATCH 15/17] SQUASH icmp drop check --- .github/workflows/netns/drop-icmp.rules | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/workflows/netns/drop-icmp.rules diff --git a/.github/workflows/netns/drop-icmp.rules b/.github/workflows/netns/drop-icmp.rules new file mode 100644 index 000000000000..24578d6a786a --- /dev/null +++ b/.github/workflows/netns/drop-icmp.rules @@ -0,0 +1 @@ +drop icmp any any -> any any (sid:1;) From 22eb22a82a8a7e29f619a30a59ab60c111282b2e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 17:40:35 +0100 Subject: [PATCH 16/17] SQUASH icmp drop check --- .../workflows/netns/afp-ips-netns-bridge.sh | 7 +++-- .../workflows/netns/nfq-ips-netns-route.sh | 28 +++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/.github/workflows/netns/afp-ips-netns-bridge.sh b/.github/workflows/netns/afp-ips-netns-bridge.sh index e06daffe6a50..9f55e1b8117a 100755 --- a/.github/workflows/netns/afp-ips-netns-bridge.sh +++ b/.github/workflows/netns/afp-ips-netns-bridge.sh @@ -163,6 +163,7 @@ ip netns exec $clientns \ PINGRES=$? set -e +# pings should have been dropped, so ping reports error if [ $PINGRES != 1 ]; then echo "ERROR ping should have failed" RES=1 @@ -189,9 +190,9 @@ ip netns exec $dutns \ ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket wait $SURIPID -cat ./eve.json | jq 'select(.tls)' -cat ./eve.json | jq 'select(.stats)|.stats.ips' -cat ./eve.json | jq 'select(.stats)|.stats.capture' +cat ./eve.json | jq -c 'select(.tls)'|tail -n1|jq +cat ./eve.json | jq -c 'select(.stats)|.stats.ips'|tail -n1|jq +cat ./eve.json | jq -c 'select(.stats)|.stats.capture'|tail -n1|jq echo "* done: $RES" exit $RES diff --git a/.github/workflows/netns/nfq-ips-netns-route.sh b/.github/workflows/netns/nfq-ips-netns-route.sh index 76d7a59026cc..efe96f7df72c 100755 --- a/.github/workflows/netns/nfq-ips-netns-route.sh +++ b/.github/workflows/netns/nfq-ips-netns-route.sh @@ -142,8 +142,8 @@ ip netns exec $dutns iptables -I FORWARD 1 -j NFQUEUE echo "* enabling forwarding in the dut... done" # set first rule file -#cp .github/workflows/live/icmp.rules suricata.rules -RULES="/dev/null" # w/o -S the unix socket won't get created? +cp .github/workflows/netns/drop-icmp.rules suricata.rules +RULES="suricata.rules" echo "* starting Suricata in the \"dut\" namespace..." # Start Suricata, SIGINT after 120 secords. Will close it earlier through @@ -175,6 +175,20 @@ ip netns exec $clientns \ wget https://10.10.20.2/index.html echo "* running wget in the \"client\" namespace... done" +echo "* running ping in the \"client\" namespace..." +set +e +ip netns exec $clientns \ + ping -c 10 10.10.10.20 +PINGRES=$? +set -e +echo "* running ping in the \"client\" namespace... done" + +# pings should have been dropped, so ping reports error +if [ $PINGRES != 1 ]; then + echo "ERROR ping should have failed" + RES=1 +fi + # give stats time to get updated sleep 10 @@ -184,6 +198,11 @@ if [ $STATSCHECK = false ]; then echo "ERROR no packets captured" RES=1 fi +STATSCHECK=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.blocked != 10') +if [ $STATSCHECK = false ]; then + echo "ERROR should have seen 10 blocked" + RES=1 +fi kill -INT $CADDYPID wait $CADDYPID @@ -191,9 +210,8 @@ ip netns exec $dutns \ ${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket wait $SURIPID -cat ./eve.json | jq 'select(.tls)' -cat ./eve.json | jq 'select(.stats)|.stats.ips' -cat ./eve.json | jq 'select(.stats)|.stats.capture' +cat ./eve.json | jq -c 'select(.tls)'|tail -n1|jq +cat ./eve.json | jq -c 'select(.stats)|.stats.ips'|tail -n1|jq echo "* done: $RES" exit $RES From a5074c44295ee516df81e051589f86b29a80e8a7 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 24 Jan 2026 18:15:21 +0100 Subject: [PATCH 17/17] SQUASH try codecov --- .github/workflows/builds.yml | 42 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 9e2621d32c08..8dbcd8415a4f 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1918,10 +1918,8 @@ jobs: build-essential \ autoconf \ automake \ - llvm-18-dev \ - cargo \ - cbindgen \ - clang-18 \ + llvm-19-dev \ + clang-19 \ git \ hwloc \ libhwloc-dev \ @@ -1949,7 +1947,6 @@ jobs: make \ parallel \ python3-yaml \ - rustc \ software-properties-common \ sudo \ zlib1g \ @@ -1969,18 +1966,43 @@ jobs: with: name: prep path: prep + # packaged Rust version is too old for coverage, so get from rustup. 1.85.1 matches + # LLVM 19 + - name: Install Rust + run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.85.1 -y + - uses: ./.github/actions/install-cbindgen - run: ./autogen.sh - run: ./configure --enable-dpdk --disable-shared --enable-gccprotect --localstatedir=/var --prefix=/usr --sysconfdir=/etc --enable-nfqueue env: - CC: "clang-18" - CFLAGS: "-g" + CC: "clang-19" + CXX: "clang++-19" + RUSTFLAGS: "-C instrument-coverage" + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0" + CXXFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0" - run: make -j ${{ env.CPUS }} env: - CC: "clang-18" + CC: "clang-19" + CXX: "clang++-19" + RUSTFLAGS: "-C instrument-coverage" + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0" + CXXFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0" - run: | - sudo ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ".github/workflows/netns/ips-netns.yaml" + sudo LLVM_PROFILE_FILE=/tmp/afp-ips.profraw ./.github/workflows/netns/afp-ips-netns-bridge.sh "2" "workers" ".github/workflows/netns/ips-netns.yaml" + env: + LLVM_PROFILE_FILE: "/tmp/afp-ips.profraw" + - run: llvm-profdata-19 merge -o afp-ips.profdata /tmp/afp-ips.profraw - run: | - sudo ./.github/workflows/netns/nfq-ips-netns-route.sh "autofp" ".github/workflows/netns/ips-netns.yaml" + sudo LLVM_PROFILE_FILE=/tmp/nfq-ips.profraw ./.github/workflows/netns/nfq-ips-netns-route.sh "autofp" ".github/workflows/netns/ips-netns.yaml" + env: + LLVM_PROFILE_FILE: "/tmp/nfq-ips.profraw" + - run: llvm-profdata-19 merge -o nfq-ips.profdata /tmp/nfq-ips.profraw + - run: llvm-profdata-19 merge -o combined.profdata $(find /tmp/ -name '*.profraw') + - run: llvm-cov-19 show ./src/suricata -instr-profile=combined.profdata --show-instantiations --ignore-filename-regex="^/root/.*" > coverage.txt + - name: Upload coverage to Codecov + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de + with: + fail_ci_if_error: false + flags: netns ubuntu-24-04-asan-afpdpdk: name: Ubuntu 24.04 (afpacket and dpdk live tests with ASAN)