1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# Copyright (C) 2020-2025 OpenVPN, Inc. 4# 5# Author: Ralf Lici <ralf@mandelbit.com> 6# Antonio Quartulli <antonio@openvpn.net> 7 8#set -x 9set -eE 10 11MARK=1056 12MARK_DROP_COUNTER=0 13 14source ./common.sh 15 16ovpn_test_finished=0 17 18ovpn_test_exit() { 19 ovpn_cleanup 20 modprobe -r ovpn || true 21 22 if [ "${ovpn_test_finished}" -eq 0 ]; then 23 ktap_print_totals 24 fi 25} 26 27ovpn_mark_prepare_network() { 28 local p 29 local peer_ns 30 31 for p in $(seq 0 "${OVPN_NUM_PEERS}"); do 32 ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}" 33 done 34 35 for p in $(seq 0 3); do 36 ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \ 37 "${p}" 5.5.5.$((p + 1))/24 38 done 39 40 ovpn_cmd_ok "create server-side multi-peer with fwmark" \ 41 ip netns exec ovpn_peer0 "${OVPN_CLI}" new_multi_peer tun0 1 \ 42 ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}" 43 for p in $(seq 1 3); do 44 ovpn_cmd_ok "install server key for peer ${p}" \ 45 ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \ 46 "${p}" 1 0 "${OVPN_ALG}" 0 data64.key 47 done 48 49 for p in $(seq 1 3); do 50 ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}" 51 done 52 53 for p in $(seq 1 3); do 54 peer_ns="ovpn_peer${p}" 55 ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ 56 ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \ 57 "${p}" 60 120 58 ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ 59 ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \ 60 tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120 61 done 62} 63 64ovpn_mark_run_baseline_traffic() { 65 local p 66 67 for p in $(seq 1 3); do 68 ovpn_cmd_ok "send baseline traffic to peer ${p}" \ 69 ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \ 70 5.5.5.$((p + 1)) 71 done 72} 73 74ovpn_mark_add_drop_rule() { 75 ovpn_log "Adding an nftables drop rule based on mark value ${MARK}" 76 77 ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \ 78 ruleset 79 ovpn_cmd_ok "create nft filter table" ip netns exec ovpn_peer0 nft \ 80 "add table inet filter" 81 ovpn_cmd_ok "create nft filter output chain" \ 82 ip netns exec ovpn_peer0 nft "add chain inet filter output { \ 83 type filter hook output priority 0; policy accept; }" 84 ovpn_cmd_ok "add nft drop rule for mark ${MARK}" \ 85 ip netns exec ovpn_peer0 nft add rule inet filter output \ 86 meta mark == "${MARK}" \ 87 counter drop 88 89 MARK_DROP_COUNTER=$(ip netns exec ovpn_peer0 nft list chain inet \ 90 filter output | sed -n 's/.*packets \([0-9]*\).*/\1/p') 91 if [ -z "${MARK_DROP_COUNTER}" ]; then 92 printf '%s\n' "unable to read nft drop counter" 93 return 1 94 fi 95} 96 97ovpn_mark_verify_drop_traffic() { 98 local p 99 local ping_output 100 local lost_packets 101 local total_count 102 103 for p in $(seq 1 3); do 104 if ping_output=$(ip netns exec ovpn_peer0 ping -qfc 500 -w 1 \ 105 5.5.5.$((p + 1)) 2>&1); then 106 printf '%s\n' "expected ping to peer ${p} to fail \ 107 after nft drop rule" 108 return 1 109 fi 110 ovpn_log "${ping_output}" 111 lost_packets=$(echo "${ping_output}" | \ 112 awk '/packets transmitted/ { print $1 }') 113 if [ -z "${lost_packets}" ]; then 114 printf '%s\n' "unable to parse lost packets for peer \ 115 ${p}" 116 return 1 117 fi 118 MARK_DROP_COUNTER=$((MARK_DROP_COUNTER + lost_packets)) 119 done 120 121 total_count=$(ip netns exec ovpn_peer0 nft list chain inet filter \ 122 output | sed -n 's/.*packets \([0-9]*\).*/\1/p') 123 if [ -z "${total_count}" ]; then 124 printf '%s\n' "unable to read final nft drop counter" 125 return 1 126 fi 127 if [ "${MARK_DROP_COUNTER}" -ne "${total_count}" ]; then 128 printf '%s\n' "expected ${MARK_DROP_COUNTER} drops, got \ 129 ${total_count}" 130 return 1 131 fi 132} 133 134ovpn_mark_remove_drop_rule() { 135 ovpn_log "Removing the drop rule" 136 137 ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \ 138 ruleset 139} 140 141ovpn_mark_verify_traffic_recovery() { 142 local p 143 144 sleep 1 145 for p in $(seq 1 3); do 146 ovpn_cmd_ok "send recovery traffic to peer ${p}" \ 147 ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \ 148 5.5.5.$((p + 1)) 149 done 150} 151 152trap ovpn_test_exit EXIT 153trap ovpn_stage_err ERR 154 155ktap_print_header 156ktap_set_plan 6 157 158ovpn_cleanup 159modprobe -q ovpn || true 160 161ovpn_run_stage "setup marked network topology" ovpn_mark_prepare_network 162ovpn_run_stage "run baseline traffic" ovpn_mark_run_baseline_traffic 163ovpn_run_stage "install nft mark drop rule" ovpn_mark_add_drop_rule 164ovpn_run_stage "drop marked traffic and count packets" \ 165 ovpn_mark_verify_drop_traffic 166ovpn_run_stage "remove nft drop rule" ovpn_mark_remove_drop_rule 167ovpn_run_stage "traffic recovers after drop removal" \ 168 ovpn_mark_verify_traffic_recovery 169 170ovpn_test_finished=1 171ktap_finished 172