17b80d8a3SRalf Lici#!/bin/bash 27b80d8a3SRalf Lici# SPDX-License-Identifier: GPL-2.0 37b80d8a3SRalf Lici# Copyright (C) 2020-2025 OpenVPN, Inc. 47b80d8a3SRalf Lici# 57b80d8a3SRalf Lici# Author: Ralf Lici <ralf@mandelbit.com> 67b80d8a3SRalf Lici# Antonio Quartulli <antonio@openvpn.net> 77b80d8a3SRalf Lici 87b80d8a3SRalf Lici#set -x 91be93bb9SRalf Liciset -eE 107b80d8a3SRalf Lici 117b80d8a3SRalf LiciMARK=1056 121be93bb9SRalf LiciMARK_DROP_COUNTER=0 137b80d8a3SRalf Lici 147b80d8a3SRalf Licisource ./common.sh 157b80d8a3SRalf Lici 161be93bb9SRalf Liciovpn_test_finished=0 171be93bb9SRalf Lici 181be93bb9SRalf Liciovpn_test_exit() { 197c29665aSRalf Lici ovpn_cleanup 201be93bb9SRalf Lici modprobe -r ovpn || true 217b80d8a3SRalf Lici 221be93bb9SRalf Lici if [ "${ovpn_test_finished}" -eq 0 ]; then 231be93bb9SRalf Lici ktap_print_totals 241be93bb9SRalf Lici fi 251be93bb9SRalf Lici} 261be93bb9SRalf Lici 271be93bb9SRalf Liciovpn_mark_prepare_network() { 281be93bb9SRalf Lici local p 291be93bb9SRalf Lici local peer_ns 307b80d8a3SRalf Lici 317c29665aSRalf Lici for p in $(seq 0 "${OVPN_NUM_PEERS}"); do 321be93bb9SRalf Lici ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}" 337b80d8a3SRalf Lici done 347b80d8a3SRalf Lici 357b80d8a3SRalf Lici for p in $(seq 0 3); do 361be93bb9SRalf Lici ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \ 371be93bb9SRalf Lici "${p}" 5.5.5.$((p + 1))/24 387b80d8a3SRalf Lici done 397b80d8a3SRalf Lici 401be93bb9SRalf Lici ovpn_cmd_ok "create server-side multi-peer with fwmark" \ 411be93bb9SRalf Lici ip netns exec ovpn_peer0 "${OVPN_CLI}" new_multi_peer tun0 1 \ 421be93bb9SRalf Lici ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}" 437b80d8a3SRalf Lici for p in $(seq 1 3); do 441be93bb9SRalf Lici ovpn_cmd_ok "install server key for peer ${p}" \ 451be93bb9SRalf Lici ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \ 461be93bb9SRalf Lici "${p}" 1 0 "${OVPN_ALG}" 0 data64.key 477b80d8a3SRalf Lici done 487b80d8a3SRalf Lici 497b80d8a3SRalf Lici for p in $(seq 1 3); do 501be93bb9SRalf Lici ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}" 517b80d8a3SRalf Lici done 527b80d8a3SRalf Lici 537b80d8a3SRalf Lici for p in $(seq 1 3); do 541be93bb9SRalf Lici peer_ns="ovpn_peer${p}" 551be93bb9SRalf Lici ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ 561be93bb9SRalf Lici ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \ 571be93bb9SRalf Lici "${p}" 60 120 581be93bb9SRalf Lici ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ 591be93bb9SRalf Lici ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \ 601be93bb9SRalf Lici tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120 617b80d8a3SRalf Lici done 621be93bb9SRalf Lici} 637b80d8a3SRalf Lici 641be93bb9SRalf Liciovpn_mark_run_baseline_traffic() { 651be93bb9SRalf Lici local p 667b80d8a3SRalf Lici 677b80d8a3SRalf Lici for p in $(seq 1 3); do 681be93bb9SRalf Lici ovpn_cmd_ok "send baseline traffic to peer ${p}" \ 69*7f114497SRalf Lici ip netns exec ovpn_peer0 ping -qfc 100 -w 3 \ 701be93bb9SRalf Lici 5.5.5.$((p + 1)) 717b80d8a3SRalf Lici done 721be93bb9SRalf Lici} 737b80d8a3SRalf Lici 741be93bb9SRalf Liciovpn_mark_add_drop_rule() { 751be93bb9SRalf Lici ovpn_log "Adding an nftables drop rule based on mark value ${MARK}" 761be93bb9SRalf Lici 771be93bb9SRalf Lici ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \ 781be93bb9SRalf Lici ruleset 791be93bb9SRalf Lici ovpn_cmd_ok "create nft filter table" ip netns exec ovpn_peer0 nft \ 801be93bb9SRalf Lici "add table inet filter" 811be93bb9SRalf Lici ovpn_cmd_ok "create nft filter output chain" \ 821be93bb9SRalf Lici ip netns exec ovpn_peer0 nft "add chain inet filter output { \ 831be93bb9SRalf Lici type filter hook output priority 0; policy accept; }" 841be93bb9SRalf Lici ovpn_cmd_ok "add nft drop rule for mark ${MARK}" \ 851be93bb9SRalf Lici ip netns exec ovpn_peer0 nft add rule inet filter output \ 861be93bb9SRalf Lici meta mark == "${MARK}" \ 877b80d8a3SRalf Lici counter drop 887b80d8a3SRalf Lici 891be93bb9SRalf Lici MARK_DROP_COUNTER=$(ip netns exec ovpn_peer0 nft list chain inet \ 901be93bb9SRalf Lici filter output | sed -n 's/.*packets \([0-9]*\).*/\1/p') 911be93bb9SRalf Lici if [ -z "${MARK_DROP_COUNTER}" ]; then 921be93bb9SRalf Lici printf '%s\n' "unable to read nft drop counter" 931be93bb9SRalf Lici return 1 947b80d8a3SRalf Lici fi 951be93bb9SRalf Lici} 967b80d8a3SRalf Lici 971be93bb9SRalf Liciovpn_mark_verify_drop_traffic() { 981be93bb9SRalf Lici local p 991be93bb9SRalf Lici local ping_output 1001be93bb9SRalf Lici local lost_packets 1011be93bb9SRalf Lici local total_count 1027b80d8a3SRalf Lici 1037b80d8a3SRalf Lici for p in $(seq 1 3); do 104*7f114497SRalf Lici if ping_output=$(ip netns exec ovpn_peer0 ping -qfc 100 -w 1 \ 1051be93bb9SRalf Lici 5.5.5.$((p + 1)) 2>&1); then 1061be93bb9SRalf Lici printf '%s\n' "expected ping to peer ${p} to fail \ 1071be93bb9SRalf Lici after nft drop rule" 1081be93bb9SRalf Lici return 1 1091be93bb9SRalf Lici fi 1101be93bb9SRalf Lici ovpn_log "${ping_output}" 1111be93bb9SRalf Lici lost_packets=$(echo "${ping_output}" | \ 1121be93bb9SRalf Lici awk '/packets transmitted/ { print $1 }') 1131be93bb9SRalf Lici if [ -z "${lost_packets}" ]; then 1141be93bb9SRalf Lici printf '%s\n' "unable to parse lost packets for peer \ 1151be93bb9SRalf Lici ${p}" 1161be93bb9SRalf Lici return 1 1171be93bb9SRalf Lici fi 1181be93bb9SRalf Lici MARK_DROP_COUNTER=$((MARK_DROP_COUNTER + lost_packets)) 1197b80d8a3SRalf Lici done 1207b80d8a3SRalf Lici 1211be93bb9SRalf Lici total_count=$(ip netns exec ovpn_peer0 nft list chain inet filter \ 1221be93bb9SRalf Lici output | sed -n 's/.*packets \([0-9]*\).*/\1/p') 1231be93bb9SRalf Lici if [ -z "${total_count}" ]; then 1241be93bb9SRalf Lici printf '%s\n' "unable to read final nft drop counter" 1251be93bb9SRalf Lici return 1 1261be93bb9SRalf Lici fi 1271be93bb9SRalf Lici if [ "${MARK_DROP_COUNTER}" -ne "${total_count}" ]; then 1281be93bb9SRalf Lici printf '%s\n' "expected ${MARK_DROP_COUNTER} drops, got \ 1291be93bb9SRalf Lici ${total_count}" 1301be93bb9SRalf Lici return 1 1311be93bb9SRalf Lici fi 1321be93bb9SRalf Lici} 1331be93bb9SRalf Lici 1341be93bb9SRalf Liciovpn_mark_remove_drop_rule() { 1351be93bb9SRalf Lici ovpn_log "Removing the drop rule" 1361be93bb9SRalf Lici 1371be93bb9SRalf Lici ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \ 1381be93bb9SRalf Lici ruleset 1391be93bb9SRalf Lici} 1401be93bb9SRalf Lici 1411be93bb9SRalf Liciovpn_mark_verify_traffic_recovery() { 1421be93bb9SRalf Lici local p 1431be93bb9SRalf Lici 1441be93bb9SRalf Lici sleep 1 1451be93bb9SRalf Lici for p in $(seq 1 3); do 1461be93bb9SRalf Lici ovpn_cmd_ok "send recovery traffic to peer ${p}" \ 147*7f114497SRalf Lici ip netns exec ovpn_peer0 ping -qfc 100 -w 3 \ 1481be93bb9SRalf Lici 5.5.5.$((p + 1)) 1491be93bb9SRalf Lici done 1501be93bb9SRalf Lici} 1511be93bb9SRalf Lici 1521be93bb9SRalf Licitrap ovpn_test_exit EXIT 1531be93bb9SRalf Licitrap ovpn_stage_err ERR 1541be93bb9SRalf Lici 1551be93bb9SRalf Liciktap_print_header 1561be93bb9SRalf Liciktap_set_plan 6 1571be93bb9SRalf Lici 1587c29665aSRalf Liciovpn_cleanup 1591be93bb9SRalf Licimodprobe -q ovpn || true 1607b80d8a3SRalf Lici 1611be93bb9SRalf Liciovpn_run_stage "setup marked network topology" ovpn_mark_prepare_network 1621be93bb9SRalf Liciovpn_run_stage "run baseline traffic" ovpn_mark_run_baseline_traffic 1631be93bb9SRalf Liciovpn_run_stage "install nft mark drop rule" ovpn_mark_add_drop_rule 1641be93bb9SRalf Liciovpn_run_stage "drop marked traffic and count packets" \ 1651be93bb9SRalf Lici ovpn_mark_verify_drop_traffic 1661be93bb9SRalf Liciovpn_run_stage "remove nft drop rule" ovpn_mark_remove_drop_rule 1671be93bb9SRalf Liciovpn_run_stage "traffic recovers after drop removal" \ 1681be93bb9SRalf Lici ovpn_mark_verify_traffic_recovery 1691be93bb9SRalf Lici 1701be93bb9SRalf Liciovpn_test_finished=1 1711be93bb9SRalf Liciktap_finished 172