1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# Copyright (C) 2020-2025 OpenVPN, Inc. 4# 5# Author: Antonio Quartulli <antonio@openvpn.net> 6 7#set -x 8set -eE 9 10source ./common.sh 11 12ovpn_test_finished=0 13 14ovpn_test_exit() { 15 ovpn_cleanup 16 modprobe -r ovpn || true 17 18 if [ "${ovpn_test_finished}" -eq 0 ]; then 19 ktap_print_totals 20 fi 21} 22 23ovpn_prepare_network() { 24 local p 25 local peer_ns 26 27 for p in $(seq 0 ${OVPN_NUM_PEERS}); do 28 ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}" 29 done 30 31 for p in $(seq 0 ${OVPN_NUM_PEERS}); do 32 ovpn_cmd_ok "start notification listener peer${p}" \ 33 ovpn_setup_listener "${p}" 34 # starting all YNL listeners back-to-back can intermittently 35 # stall their startup so serialize launches a bit 36 sleep 0.5 37 done 38 39 for p in $(seq 0 ${OVPN_NUM_PEERS}); do 40 ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \ 41 "${p}" 5.5.5.$((p + 1))/24 "${MTU}" 42 done 43 44 for p in $(seq 0 ${OVPN_NUM_PEERS}); do 45 ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}" 46 done 47 48 for p in $(seq 1 ${OVPN_NUM_PEERS}); do 49 peer_ns="ovpn_peer${p}" 50 ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ 51 ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \ 52 ${p} 60 120 53 ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ 54 ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ 55 tun${p} $((p + OVPN_ID_OFFSET)) 60 120 56 done 57} 58 59ovpn_new_test_peer() { 60 local peer_id="$1" 61 62 shift 63 ip netns exec ovpn_peer0 "${OVPN_CLI}" new_peer tun0 \ 64 "${peer_id}" none 65000 10.10.1.2 1 "$@" 65} 66 67ovpn_set_peer_vpn_addr() { 68 ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \ 69 "$1" 60 120 "$2" 70} 71 72ovpn_run_vpn_addr_validation() { 73 local addr 74 local peer1_addr4 75 local test_peer_id=$((OVPN_NUM_PEERS + 1)) 76 local test_peer_addr6="2001:db8::2" 77 # Do not include 0.0.0.0 or :: here. They are invalid on creation, but 78 # clear one address family on update and are valid if the other remains. 79 local -a invalid_addrs=( 80 "127.0.0.1" 81 "224.0.0.1" 82 "255.255.255.255" 83 "::1" 84 "::192.0.2.1" 85 "::ffff:192.0.2.1" 86 "ff02::1" 87 ) 88 89 peer1_addr4=$(ovpn_peer_vpn_addr 1) 90 91 ovpn_cmd_fail "reject peer without VPN address" \ 92 ovpn_new_test_peer "${test_peer_id}" 93 94 for addr in "0.0.0.0" "::" "${invalid_addrs[@]}"; do 95 ovpn_cmd_fail "reject new peer VPN address ${addr}" \ 96 ovpn_new_test_peer "${test_peer_id}" "${addr}" 97 done 98 99 ovpn_cmd_fail "reject duplicate IPv4 address on peer creation" \ 100 ovpn_new_test_peer "${test_peer_id}" "${peer1_addr4}" 101 ovpn_cmd_fail "reject clearing the last peer VPN address" \ 102 ovpn_set_peer_vpn_addr 1 0.0.0.0 103 104 for addr in "${invalid_addrs[@]}"; do 105 ovpn_cmd_fail "reject updated peer VPN address ${addr}" \ 106 ovpn_set_peer_vpn_addr 1 "${addr}" 107 done 108 109 ovpn_cmd_fail "reject duplicate IPv4 address on peer update" \ 110 ovpn_set_peer_vpn_addr 2 "${peer1_addr4}" 111 112 ovpn_cmd_ok "add peer IPv6 address" \ 113 ovpn_set_peer_vpn_addr 1 "${test_peer_addr6}" 114 ovpn_cmd_fail "reject duplicate IPv6 address on peer creation" \ 115 ovpn_new_test_peer "${test_peer_id}" "${test_peer_addr6}" 116 ovpn_cmd_fail "reject duplicate IPv6 address on peer update" \ 117 ovpn_set_peer_vpn_addr 2 "${test_peer_addr6}" 118 119 ovpn_cmd_ok "clear peer IPv4 address" \ 120 ovpn_set_peer_vpn_addr 1 0.0.0.0 121 ovpn_cmd_fail "reject clearing the remaining peer IPv6 address" \ 122 ovpn_set_peer_vpn_addr 1 :: 123 ovpn_cmd_ok "restore peer IPv4 address" \ 124 ovpn_set_peer_vpn_addr 1 "${peer1_addr4}" 125 ovpn_cmd_ok "clear peer IPv6 address" \ 126 ovpn_set_peer_vpn_addr 1 :: 127} 128 129ovpn_run_basic_traffic() { 130 local p 131 local header1 132 local header2 133 local peer_ns 134 local raddr 135 local tcpdump_pid1 136 local tcpdump_pid2 137 local tcpdump_timeout="1.5s" 138 139 for p in $(seq 1 ${OVPN_NUM_PEERS}); do 140 # The first part of the data packet header consists of: 141 # - TCP only: 2 bytes for the packet length 142 # - 5 bits for opcode ("9" for DATA_V2) 143 # - 3 bits for key-id ("0" at this point) 144 # - 12 bytes for peer-id: 145 # - with asymmetric ID: "${p}" one way and "${p} + 9" the 146 # other way 147 # - with symmetric ID: "${p}" both ways 148 header1=$(printf "0x4800000%x" ${p}) 149 header2=$(printf "0x4800000%x" $((p + OVPN_ID_OFFSET))) 150 raddr="" 151 if [ "${OVPN_PROTO}" == "UDP" ]; then 152 raddr=$(awk "NR == ${p} {print \$3}" \ 153 "${OVPN_UDP_PEERS_FILE}") 154 fi 155 peer_ns="ovpn_peer${p}" 156 157 timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \ 158 tcpdump --immediate-mode -p -ni veth${p} -c 1 \ 159 "$(ovpn_build_capture_filter "${header1}" "${raddr}")" \ 160 >/dev/null 2>&1 & 161 tcpdump_pid1=$! 162 timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \ 163 tcpdump --immediate-mode -p -ni veth${p} -c 1 \ 164 "$(ovpn_build_capture_filter "${header2}" "${raddr}")" \ 165 >/dev/null 2>&1 & 166 tcpdump_pid2=$! 167 168 sleep 0.3 169 ovpn_cmd_ok "send baseline traffic to peer ${p}" \ 170 ip netns exec ovpn_peer0 \ 171 ping -qfc 100 -w 3 5.5.5.$((p + 1)) 172 ovpn_cmd_ok "send large-payload traffic to peer ${p}" \ 173 ip netns exec ovpn_peer0 \ 174 ping -qfc 100 -s 3000 -w 3 5.5.5.$((p + 1)) 175 176 wait "${tcpdump_pid1}" || return 1 177 wait "${tcpdump_pid2}" || return 1 178 done 179} 180 181ovpn_run_lan_traffic() { 182 ovpn_cmd_ok "ping LAN behind peer1" \ 183 ip netns exec ovpn_peer0 ping -qfc 100 -w 3 "${OVPN_LAN_IP}" 184} 185 186ovpn_run_float_mode() { 187 local p 188 local peer_ns 189 190 for p in $(seq 1 ${OVPN_NUM_PEERS}); do 191 peer_ns="ovpn_peer${p}" 192 ovpn_cmd_ok "float: remove old transport address on peer${p}" \ 193 ip -n "${peer_ns}" addr del 10.10.${p}.2/24 dev veth${p} 194 ovpn_cmd_ok "float: add new transport address on peer${p}" \ 195 ip -n "${peer_ns}" addr add 10.10.${p}.3/24 dev veth${p} 196 done 197 for p in $(seq 1 ${OVPN_NUM_PEERS}); do 198 peer_ns="ovpn_peer${p}" 199 ovpn_cmd_ok "ping tunnel after float peer ${p}" \ 200 ip netns exec "${peer_ns}" ping -qfc 100 -w 3 5.5.5.1 201 done 202} 203 204ovpn_run_iperf() { 205 local iperf_pid 206 207 ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s 208 sleep 1 209 210 ovpn_cmd_ok "run iperf throughput flow" \ 211 ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1 212 wait "${iperf_pid}" || return 1 213} 214 215ovpn_run_key_rollover() { 216 local p 217 local peer_ns 218 219 ovpn_log "Adding secondary key and then swap:" 220 221 for p in $(seq 1 ${OVPN_NUM_PEERS}); do 222 peer_ns="ovpn_peer${p}" 223 ovpn_cmd_ok "add secondary key on peer0 for peer ${p}" \ 224 ip netns exec ovpn_peer0 ${OVPN_CLI} new_key tun0 \ 225 ${p} 2 1 ${OVPN_ALG} 0 data64.key 226 ovpn_cmd_ok "add secondary key on peer${p} for peer ${p}" \ 227 ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${p} \ 228 $((p + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 \ 229 data64.key 230 ovpn_cmd_ok "swap keys on peer${p}" \ 231 ip netns exec "${peer_ns}" ${OVPN_CLI} swap_keys \ 232 tun${p} $((p + OVPN_ID_OFFSET)) 233 done 234} 235 236ovpn_run_queries() { 237 ovpn_log "Querying all peers:" 238 239 ovpn_cmd_ok "query all peers from peer0" \ 240 ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 241 ovpn_cmd_ok "query all peers from peer1" \ 242 ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1 243 244 ovpn_log "Querying peer 1:" 245 246 ovpn_cmd_ok "query peer 1 from peer0" \ 247 ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 1 248} 249 250ovpn_query_peer_missing() { 251 ovpn_log "Querying non-existent peer 20:" 252 253 ovpn_cmd_fail "query missing peer 20 on peer0" \ 254 ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 20 255} 256 257ovpn_run_peer_cleanup() { 258 local p 259 local peer_ns 260 261 ovpn_log "Deleting peer 1:" 262 263 ovpn_cmd_ok "delete peer1 on peer0" \ 264 ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 1 265 ovpn_cmd_ok "delete peer1 on peer1" \ 266 ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 \ 267 $((1 + OVPN_ID_OFFSET)) 268 269 ovpn_log "Querying keys:" 270 271 for p in $(seq 2 ${OVPN_NUM_PEERS}); do 272 peer_ns="ovpn_peer${p}" 273 ovpn_cmd_ok "query peer${p} key 1" \ 274 ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \ 275 $((p + OVPN_ID_OFFSET)) 1 276 ovpn_cmd_ok "query peer${p} key 2" \ 277 ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \ 278 $((p + OVPN_ID_OFFSET)) 2 279 done 280} 281 282ovpn_run_traffic_delete_peer() { 283 local ping_pid 284 285 ovpn_log "Deleting peer while sending traffic:" 286 287 ovpn_run_bg ping_pid ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1 288 sleep 2 289 ovpn_cmd_ok "delete peer0 peer 2" \ 290 ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 2 291 292 if [ "${OVPN_PROTO}" == "TCP" ]; then 293 # In TCP mode this command is expected to fail for both peers. 294 ovpn_cmd_mayfail "delete peer2 peer 2 (TCP non-fatal)" \ 295 ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 \ 296 $((2 + OVPN_ID_OFFSET)) 297 else 298 ovpn_cmd_ok "delete peer2 peer 2" ip netns exec ovpn_peer2 \ 299 ${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET)) 300 fi 301 302 wait "${ping_pid}" || true 303} 304 305ovpn_run_key_cleanup() { 306 local p 307 local peer_ns 308 309 ovpn_log "Deleting keys:" 310 311 for p in $(seq 3 ${OVPN_NUM_PEERS}); do 312 peer_ns="ovpn_peer${p}" 313 ovpn_cmd_ok "delete key 1 for peer${p}" \ 314 ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \ 315 $((p + OVPN_ID_OFFSET)) 1 316 ovpn_cmd_ok "delete key 2 for peer${p}" \ 317 ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \ 318 $((p + OVPN_ID_OFFSET)) 2 319 done 320} 321 322ovpn_run_timeouts() { 323 local p 324 local peer_ns 325 326 ovpn_log "Setting timeout to 3s MP:" 327 328 for p in $(seq 3 ${OVPN_NUM_PEERS}); do 329 # Non-fatal: this may fail in some protocol modes. 330 ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \ 331 ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \ 332 ${p} 3 3 333 peer_ns="ovpn_peer${p}" 334 ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \ 335 state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ 336 tun${p} $((p + OVPN_ID_OFFSET)) 0 0 337 done 338 # wait for peers to timeout 339 sleep 5 340 341 ovpn_log "Setting timeout to 3s P2P:" 342 343 for p in $(seq 3 ${OVPN_NUM_PEERS}); do 344 peer_ns="ovpn_peer${p}" 345 ovpn_cmd_ok "set peer${p} P2P timeout" \ 346 ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ 347 tun${p} $((p + OVPN_ID_OFFSET)) 3 3 348 done 349 sleep 5 350} 351 352ovpn_run_notifications() { 353 local p 354 355 for p in $(seq 0 ${OVPN_NUM_PEERS}); do 356 ovpn_cmd_ok "validate listener output for peer ${p}" \ 357 ovpn_compare_ntfs "${p}" 358 done 359} 360 361trap ovpn_test_exit EXIT 362trap ovpn_stage_err ERR 363 364ktap_print_header 365if [ "${OVPN_FLOAT}" == "1" ]; then 366 ktap_set_plan 14 367else 368 ktap_set_plan 13 369fi 370 371ovpn_cleanup 372modprobe -q ovpn || true 373 374ovpn_run_stage "setup network topology" ovpn_prepare_network 375ovpn_run_stage "validate peer VPN addresses" ovpn_run_vpn_addr_validation 376ovpn_run_stage "run baseline data traffic" ovpn_run_basic_traffic 377ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic 378[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \ 379 ovpn_run_float_mode 380ovpn_run_stage "run iperf throughput" ovpn_run_iperf 381ovpn_run_stage "run key rollout" ovpn_run_key_rollover 382ovpn_run_stage "query peers" ovpn_run_queries 383ovpn_run_stage "query missing peer fails" ovpn_query_peer_missing 384ovpn_run_stage "peer lifecycle and key queries" ovpn_run_peer_cleanup 385ovpn_run_stage "delete peer while traffic" ovpn_run_traffic_delete_peer 386ovpn_run_stage "delete stale keys" ovpn_run_key_cleanup 387ovpn_run_stage "check timeout behavior" ovpn_run_timeouts 388ovpn_run_stage "validate notification output" ovpn_run_notifications 389 390ovpn_test_finished=1 391ktap_finished 392