Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2152,7 +2152,13 @@ jobs:
LLVM_PROFILE_FILE: "/tmp/nfq-ips-workers.profraw"
- run: llvm-profdata-19 merge -o nfq-ips-workers.profdata /tmp/nfq-ips-workers.profraw

- run: llvm-profdata-19 merge -o combined.profdata afp-ips.profdata nfq-ips.profdata afp-ips-autofp.profdata nfq-ips-workers.profdata afp-ips-bond1.profdata afp-ips-bond2.profdata
- run: |
./qa/live/netns/afp-fw-netns-bridge.sh "2" "workers" "qa/live/netns/fw-netns.yaml"
env:
LLVM_PROFILE_FILE: "/tmp/afp-fw-netns-bridge.profraw"
- run: llvm-profdata-19 merge -o afp-fw-netns-bridge.profdata /tmp/afp-fw-netns-bridge.profraw

- run: llvm-profdata-19 merge -o combined.profdata afp-ips.profdata nfq-ips.profdata afp-ips-autofp.profdata nfq-ips-workers.profdata afp-ips-bond1.profdata afp-ips-bond2.profdata afp-fw-netns-bridge.profdata
- run: llvm-cov-19 export ./src/suricata -instr-profile=combined.profdata -format=lcov --ignore-filename-regex="^(/github/home/.cargo/.*|/usr/.*|/rustc/.*)" --skip-branches > coverage.lcov
- name: Upload coverage.lcov artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
Expand Down
14 changes: 14 additions & 0 deletions doc/userguide/rules/header-keywords.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
.. role:: example-rule-emphasis

Ethernet Keywords
-----------------

eth.hdr
^^^^^^^

Sticky buffer to match on the whole Ethernet header.

Example rule:

.. container:: example-rule

alert ether any any -> any any (msg:"ARP packet"; :example-rule-emphasis:`eth.hdr; content:"|08 06|"; offset:12; depth:2;` sid:1234; rev:5;)

IP Keywords
-----------

Expand Down
268 changes: 268 additions & 0 deletions qa/live/netns/afp-fw-netns-bridge.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
#!/bin/bash

# Script to test live Firewall capabilities for AF_PACKET.
#
# Uses 3 network namespaces:
# - client
# - server
# - 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.

# Call with following arguments:
# 1st: "2" or "3" to indicate the tpacket version.
# 2nd: runmode string (single/autofp/workers)
# 3rd: suricata yaml to use

set -e
set -x

if [ $# -ne "3" ]; then
echo "ERROR call with 3 args: tpacket version (2/3), runmode (single/autofp/workers) and yaml"
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"

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

echo "* removing old namespaces..."
NAMESPACES=$(ip netns list|cut -d' ' -f1)
for NS in $NAMESPACES; do
if [ $NS = $dutns ] || [ $NS = $clientns ] || [ $NS = $serverns ]; then
ip netns delete $NS
fi
done
echo "* removing old namespaces... 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

# 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..."
iface=ptp-$clientif
ip netns exec $clientns ip addr add $clientip dev $iface
ip netns exec $clientns ethtool -K $iface rx off tx off
ip netns exec $clientns sysctl -w net.ipv6.conf.$iface.disable_ipv6=1
ip netns exec $clientns ip link set $iface up
echo "* setup client interface... done"

echo "* setup server interface..."
iface=ptp-$serverif
ip netns exec $serverns ip addr add $serverip dev $iface
ip netns exec $serverns ethtool -K $iface rx off tx off
ip netns exec $serverns sysctl -w net.ipv6.conf.$iface.disable_ipv6=1
ip netns exec $serverns ip link set $iface 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 sysctl -w net.ipv6.conf.ptp-$dutclientif.disable_ipv6=1
ip netns exec $dutns sysctl -w net.ipv6.conf.ptp-$dutserverif.disable_ipv6=1
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 qa/live/netns/firewall1.rules firewall.rules
RULES="firewall.rules"

cat firewall.rules

echo "* starting Suricata in the \"dut\" namespace..."
# Start Suricata in the dut namespace, then SIGINT after 240 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 firewall.rule-path=. \
--set default-rule-path=. --runmode=$RUNMODE &
SURIPID=$!
sleep 10
echo "* starting Suricata... done"

echo "* starting tshark on in the server namespace..."
timeout --kill-after=240 --preserve-status 180 \
ip netns exec $serverns \
tshark -i ptp-$serverif -T json > tshark-server.json &
TSHARKSERVERPID=$!
sleep 5
echo "* starting tshark on in the server namespace... done, pid $TSHARKSERVERPID"

echo "* starting Caddy..."
# Start Caddy in the server namespace
timeout --kill-after=240 --preserve-status 120 \
ip netns exec $serverns \
caddy file-server --browse &
CADDYPID=$!
sleep 10
echo "* starting Caddy in the \"server\" namespace... done"

echo "* running curl in the \"client\" namespace..."
set +e
timeout --kill-after=30 --preserve-status 15 \
ip netns exec $clientns \
curl -O http://10.10.10.20/index.html
CURLRES=$?
set -e
echo "* running curl in the \"client\" namespace... done: $CURLRES"

echo "* running wget in the \"client\" namespace..."
set +e
timeout --kill-after=30 --preserve-status 15 \
ip netns exec $clientns \
wget http://10.10.10.20/index.html
WGETRES=$?
set -e
echo "* running wget in the \"client\" namespace... done"

ping_ip=$(echo $serverip|cut -f1 -d'/')
echo "* running ping $ping_ip in the \"client\" namespace..."
set +e
ip netns exec $clientns \
ping -c 10 $ping_ip
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

echo "* shutting down tshark..."
kill -INT $TSHARKSERVERPID
wait $TSHARKSERVERPID
echo "* shutting down tshark... done"

ACCEPTED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.accepted')
BLOCKED=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.ips.blocked')
KERNEL_PACKETS=$(jq -c 'select(.event_type == "stats")' ./eve.json | tail -n1 | jq '.stats.capture.kernel_packets')
echo "ACCEPTED $ACCEPTED BLOCKED $BLOCKED KERNEL_PACKETS $KERNEL_PACKETS"

if [ $KERNEL_PACKETS -eq 0 ]; then
echo "ERROR no packets captured"
RES=1
fi
if [ $ACCEPTED -eq 0 ]; then
echo "ERROR should have seen non-0 accepted"
RES=1
fi
if [ $BLOCKED -lt 10 ]; then
echo "ERROR should have seen 10+ blocked"
RES=1
fi

# validate that we didn't receive pings
SERVER_RECV_PING=$(jq -c '.[]' ./tshark-server.json|jq 'select(._source.layers.icmp."icmp.type"=="8")'|wc -l)
echo "* server pings received check (should be 0): $SERVER_RECV_PING"
if [ $SERVER_RECV_PING -ne 0 ]; then
jq '.[]' ./tshark-server.json | jq 'select(._source.layers.icmp)'
RES=1
fi
echo "* server pings received check... done"

echo "* shutting down..."
set +e
kill -INT $CADDYPID
wait $CADDYPID
CADDYRES=$?
set -e
ip netns exec $dutns \
${SURICATASC} -c "shutdown" /var/run/suricata/suricata-command.socket
wait $SURIPID
echo "* shutting down... done"

# Caddy sometimes exits uncleanly. Warn about it but otherwise
# it can be ignored.
if [ $CADDYRES -ne 0 ]; then
echo "WARNING Caddy exited with error $CADDYRES"
fi

echo "* dumping some stats..."
cat ./eve.json | jq -c 'select(.http)'|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 "* dumping some stats... done"


echo "* done: $RES"
exit $RES
15 changes: 15 additions & 0 deletions qa/live/netns/firewall1.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
accept:packet arp:all any any -> any any (alert; sid:200;)

# allow session setup
accept:hook tcp:all any any <> any 80 (flow:not_established; alert; sid:1021;)

# pass rest of the flow to
accept:hook tcp:all any any <> any 80 (flow:established; alert; sid:1023;)
#accept:hook ip:all any any <> any any (alert; sid:1024;)

# default drop

accept:hook http1:request_started any any -> any any (alert; sid:100;)
accept:hook http1:request_line any any -> any any (http.method; content:"GET"; http.uri; content:"/"; alert; sid:101;)
accept:tx http1:request_headers any any -> any any (http.user_agent; content:"wget"; nocase; alert; sid:102;)

Loading
Loading