Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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