Skip to content
Closed
107 changes: 107 additions & 0 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1897,6 +1897,113 @@ 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: |
sudo apt update
sudo apt -y install \
libpcre2-dev \
build-essential \
autoconf \
automake \
llvm-19-dev \
clang-19 \
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 \
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
# 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-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-19"
CXX: "clang++-19"
RUSTFLAGS: "-C instrument-coverage"
CFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0"
CXXFLAGS: "-fprofile-instr-generate -fcoverage-mapping -O0"
- run: |
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 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)
runs-on: ubuntu-latest
Expand Down
198 changes: 198 additions & 0 deletions .github/workflows/netns/afp-ips-netns-bridge.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#!/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 "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=$3

# dump some info
echo "* printing some diagnostics..."
ip netns list
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
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/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=300 --preserve-status 240 \
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"

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.10.20 --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.10.20/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.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

# 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

# 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
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
ip netns exec $dutns \
${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket
wait $SURIPID

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
1 change: 1 addition & 0 deletions .github/workflows/netns/drop-icmp.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop icmp any any -> any any (sid:1;)
Loading
Loading