You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/qa/live/netns/afp-ips-netns-bond-bridge2.sh

416 lines
15 KiB
Bash

#!/bin/bash
# Script to test live IPS capabilities for AF_PACKET. Test with multiple networks and multiple
# bonds all handled by a single suricata.
#
# Uses 3 network namespaces:
# - client
# - server
# - dut
#
# Dut is where Suricata will run:
#
# [ client1 ]$clientif1 \ / $dutclientif1[ ]$dutserverif1 \ / $serverif1[ server1 ]
# [ ]#clientif2 - bond - $dutclientif2[ ]$dutserverif2 - bond - $serverif2[ ]
# [ dut ]
# [ client2 ]$clientif1 - bond - $dutclientif1[ ]$dutserverif1 - bond - $serverif1[ server2 ]
# [ ]$clientif2 / \ $dutclientif2[ ]$dutserverif2 / \ $serverif2[ ]
#
# 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"
dutns=dut
clientns1=client1
serverns1=server1
clientip1="10.10.10.10/24"
serverip1='10.10.10.20/24'
clientif1=client1
serverif1=server1
dutclientif1=dut1_clnt
dutserverif1=dut1_srvr
clientns2=client2
serverns2=server2
clientip2="10.20.10.10/24"
serverip2='10.20.10.20/24'
clientif2=client2
serverif2=server2
dutclientif2=dut2_clnt
dutserverif2=dut2_srvr
mtu=9000
echo "* removing old namespaces..."
NAMESPACES=$(ip netns list|cut -d' ' -f1)
for NS in $NAMESPACES; do
if [ $NS = $dutns ] || [ $NS = $clientns1 ] || [ $NS = $serverns1 ] ||
[ $NS = $clientns2 ] || [ $NS = $serverns2 ]; 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 $clientns1
ip netns add $serverns1
ip netns add $clientns2
ip netns add $serverns2
ip netns add $dutns
echo "* creating namespaces... done"
#diagnostics output
echo "* list namespaces..."
ip netns list
ip netns exec $clientns1 ip ad
ip netns exec $serverns1 ip ad
ip netns exec $clientns1 ip ad
ip netns exec $serverns1 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-a$clientif1 type veth peer name ptp-a$dutclientif1
ip link add ptp-b$clientif1 type veth peer name ptp-b$dutclientif1
ip link add ptp-a$serverif1 type veth peer name ptp-a$dutserverif1
ip link add ptp-b$serverif1 type veth peer name ptp-b$dutserverif1
ip link add ptp-a$clientif2 type veth peer name ptp-a$dutclientif2
ip link add ptp-b$clientif2 type veth peer name ptp-b$dutclientif2
ip link add ptp-a$serverif2 type veth peer name ptp-a$dutserverif2
ip link add ptp-b$serverif2 type veth peer name ptp-b$dutserverif2
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-a$clientif1 netns $clientns1
ip link set ptp-b$clientif1 netns $clientns1
ip link set ptp-a$serverif1 netns $serverns1
ip link set ptp-b$serverif1 netns $serverns1
ip link set ptp-a$dutclientif1 netns $dutns
ip link set ptp-b$dutclientif1 netns $dutns
ip link set ptp-a$dutserverif1 netns $dutns
ip link set ptp-b$dutserverif1 netns $dutns
ip link set ptp-a$clientif2 netns $clientns2
ip link set ptp-b$clientif2 netns $clientns2
ip link set ptp-a$serverif2 netns $serverns2
ip link set ptp-b$serverif2 netns $serverns2
ip link set ptp-a$dutclientif2 netns $dutns
ip link set ptp-b$dutclientif2 netns $dutns
ip link set ptp-a$dutserverif2 netns $dutns
ip link set ptp-b$dutserverif2 netns $dutns
echo "* map virtual ethernet interfaces to their namespaces... done"
echo "* setting mtu to $mtu"
ip netns exec $clientns1 ip link set ptp-a$clientif1 mtu $mtu
ip netns exec $clientns1 ip link set ptp-b$clientif1 mtu $mtu
ip netns exec $serverns1 ip link set ptp-a$serverif1 mtu $mtu
ip netns exec $serverns1 ip link set ptp-b$serverif1 mtu $mtu
ip netns exec $dutns ip link set ptp-a$dutclientif1 mtu $mtu
ip netns exec $dutns ip link set ptp-b$dutclientif1 mtu $mtu
ip netns exec $dutns ip link set ptp-a$dutserverif1 mtu $mtu
ip netns exec $dutns ip link set ptp-b$dutserverif1 mtu $mtu
ip netns exec $clientns2 ip link set ptp-a$clientif2 mtu $mtu
ip netns exec $clientns2 ip link set ptp-b$clientif2 mtu $mtu
ip netns exec $serverns2 ip link set ptp-a$serverif2 mtu $mtu
ip netns exec $serverns2 ip link set ptp-b$serverif2 mtu $mtu
ip netns exec $dutns ip link set ptp-a$dutclientif2 mtu $mtu
ip netns exec $dutns ip link set ptp-b$dutclientif2 mtu $mtu
ip netns exec $dutns ip link set ptp-a$dutserverif2 mtu $mtu
ip netns exec $dutns ip link set ptp-b$dutserverif2 mtu $mtu
echo "* setting mtu to $mtu... done"
# bonds need to be created in the namespace
echo "* creating bonds..."
ip netns exec $clientns1 ip link add bond-$clientif1 type bond mode active-backup
ip netns exec $clientns1 ip link set ptp-a$clientif1 master bond-$clientif1
ip netns exec $clientns1 ip link set ptp-b$clientif1 master bond-$clientif1
ip netns exec $clientns1 ip link set bond-$clientif1 mtu $mtu
ip netns exec $dutns ip link add bond-$dutclientif1 type bond mode active-backup
ip netns exec $dutns ip link set ptp-a$dutclientif1 master bond-$dutclientif1
ip netns exec $dutns ip link set ptp-b$dutclientif1 master bond-$dutclientif1
ip netns exec $dutns ip link set bond-$dutclientif1 mtu $mtu
ip netns exec $serverns1 ip link add bond-$serverif1 type bond mode active-backup
ip netns exec $serverns1 ip link set ptp-a$serverif1 master bond-$serverif1
ip netns exec $serverns1 ip link set ptp-b$serverif1 master bond-$serverif1
ip netns exec $serverns1 ip link set bond-$serverif1 mtu $mtu
ip netns exec $dutns ip link add bond-$dutserverif1 type bond mode active-backup
ip netns exec $dutns ip link set ptp-a$dutserverif1 master bond-$dutserverif1
ip netns exec $dutns ip link set ptp-b$dutserverif1 master bond-$dutserverif1
ip netns exec $dutns ip link set bond-$dutserverif1 mtu $mtu
ip netns exec $clientns2 ip link add bond-$clientif2 type bond mode active-backup
ip netns exec $clientns2 ip link set ptp-a$clientif2 master bond-$clientif2
ip netns exec $clientns2 ip link set ptp-b$clientif2 master bond-$clientif2
ip netns exec $clientns2 ip link set bond-$clientif2 mtu $mtu
ip netns exec $dutns ip link add bond-$dutclientif2 type bond mode active-backup
ip netns exec $dutns ip link set ptp-a$dutclientif2 master bond-$dutclientif2
ip netns exec $dutns ip link set ptp-b$dutclientif2 master bond-$dutclientif2
ip netns exec $dutns ip link set bond-$dutclientif2 mtu $mtu
ip netns exec $serverns2 ip link add bond-$serverif2 type bond mode active-backup
ip netns exec $serverns2 ip link set ptp-a$serverif2 master bond-$serverif2
ip netns exec $serverns2 ip link set ptp-b$serverif2 master bond-$serverif2
ip netns exec $serverns2 ip link set bond-$serverif2 mtu $mtu
ip netns exec $dutns ip link add bond-$dutserverif2 type bond mode active-backup
ip netns exec $dutns ip link set ptp-a$dutserverif2 master bond-$dutserverif2
ip netns exec $dutns ip link set ptp-b$dutserverif2 master bond-$dutserverif2
ip netns exec $dutns ip link set bond-$dutserverif2 mtu $mtu
echo "* creating bonds... done"
echo "* list namespaces and interfaces within them..."
ip netns list
ip netns exec $clientns1 ip ad
ip netns exec $serverns1 ip ad
ip netns exec $clientns2 ip ad
ip netns exec $serverns2 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 interfaces..."
ip netns exec $clientns1 ip addr add $clientip1 dev bond-$clientif1
ip netns exec $clientns1 ethtool -K bond-$clientif1 rx off tx off
ip netns exec $clientns1 ip link set bond-$clientif1 up
ip netns exec $clientns2 ip addr add $clientip2 dev bond-$clientif2
ip netns exec $clientns2 ethtool -K bond-$clientif2 rx off tx off
ip netns exec $clientns2 ip link set bond-$clientif2 up
echo "* setup client interfaces... done"
echo "* setup server interfaces..."
ip netns exec $serverns1 ip addr add $serverip1 dev bond-$serverif1
ip netns exec $serverns1 ethtool -K bond-$serverif1 rx off tx off
ip netns exec $serverns1 ip link set bond-$serverif1 up
ip netns exec $serverns2 ip addr add $serverip2 dev bond-$serverif2
ip netns exec $serverns2 ethtool -K bond-$serverif2 rx off tx off
ip netns exec $serverns2 ip link set bond-$serverif2 up
echo "* setup server interfaces... done"
echo "* setup dut interfaces..."
ip netns exec $dutns ethtool -K bond-$dutclientif1 rx off tx off
ip netns exec $dutns ethtool -K bond-$dutserverif1 rx off tx off
ip netns exec $dutns ip link set bond-$dutclientif1 up
ip netns exec $dutns ip link set bond-$dutserverif1 up
ip netns exec $dutns ethtool -K bond-$dutclientif2 rx off tx off
ip netns exec $dutns ethtool -K bond-$dutserverif2 rx off tx off
ip netns exec $dutns ip link set bond-$dutclientif2 up
ip netns exec $dutns ip link set bond-$dutserverif2 up
echo "* setup dut interfaces... done"
# set first rule file
cp qa/live/netns/drop-icmp.rules suricata.rules
RULES="suricata.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 default-rule-path=. --runmode=$RUNMODE -S $RULES &
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 $serverns1 \
tshark -i bond-$serverif1 -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 $serverns1 \
caddy file-server --domain 10.10.10.20 --browse &
CADDYPID=$!
sleep 10
echo "* starting Caddy in the \"server1\" namespace... done"
echo "* starting Caddy..."
# Start Caddy in the server namespace
timeout --kill-after=240 --preserve-status 120 \
ip netns exec $serverns2 \
caddy file-server --domain 10.20.10.20 --browse &
CADDYPID2=$!
sleep 10
echo "* starting Caddy in the \"server2\" namespace... done"
echo "* running curl in the \"client1\" namespace..."
ip netns exec $clientns1 \
curl -O https://10.10.10.20/index.html
echo "* running curl in the \"client1\" namespace... done"
echo "* running curl in the \"client2\" namespace..."
ip netns exec $clientns2 \
curl -O https://10.20.10.20/index.html
echo "* running curl in the \"client2\" namespace... done"
echo "* running wget in the \"client\" namespace..."
ip netns exec $clientns1 \
wget https://10.10.10.20/index.html
echo "* running wget in the \"client\" namespace... done"
ping_ip=$(echo $serverip1|cut -f1 -d'/')
echo "* running hping3 $ping_ip in the \"client\" namespace..."
set +e
ip netns exec $clientns1 \
hping3 -c 10 -1 -f -d 15000 $ping_ip
PINGRES=$?
set -e
echo "* running ping in the \"client1\" namespace... done"
# pings should have been dropped, so ping reports error
if [ $PINGRES != 1 ]; then
echo "ERROR ping should have failed"
RES=1
fi
ping_ip=$(echo $serverip2|cut -f1 -d'/')
echo "* running ping $ping_ip in the \"client2\" namespace..."
set +e
ip netns exec $clientns2 \
ping -c 10 $ping_ip
PINGRES=$?
set -e
echo "* running ping in the \"client2\" 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')
HPING_DROP_RECS=$(jq -c 'select(.event_type == "drop" and .src_ip == "10.10.10.10")' ./eve.json | wc -l)
PING_DROP_RECS=$(jq -c 'select(.event_type == "drop" and .src_ip == "10.20.10.10")' ./eve.json | wc -l)
echo "ACCEPTED $ACCEPTED BLOCKED $BLOCKED KERNEL_PACKETS $KERNEL_PACKETS"
echo "HPING_DROP_RECS $HPING_DROP_RECS PING_DROP_RECS $PING_DROP_RECS"
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
if [ $PING_DROP_RECS -lt 10 ]; then
echo "ERROR should have seen 10+ ping drop logs"
RES=1
fi
# hping test sets frags and per reassmebled packet we log 2 drop logs currently
if [ $HPING_DROP_RECS -lt 20 ]; then
echo "ERROR should have seen 20+ hping drop logs"
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
kill -INT $CADDYPID2
wait $CADDYPID
CADDYRES=$?
wait $CADDYPID2
CADDYRES2=$?
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 ] || [ $CADDYRES2 -ne 0 ]; then
echo "WARNING Caddy exited with error $CADDYRES/$CADDYRES2"
fi
echo "* dumping some stats..."
cat ./eve.json | jq --arg IFACE "bond-$dutclientif1" -c 'select(.tls and .in_iface==$IFACE)'|tail -n1|jq
cat ./eve.json | jq --arg IFACE "bond-$dutclientif2" -c 'select(.tls and .in_iface==$IFACE)'|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