testing/selftests: add test tool and scripts for ovpn module

The ovpn-cli tool can be compiled and used as selftest for the ovpn
kernel module.

[NOTE: it depends on libmedtls for decoding base64-encoded keys]

ovpn-cli implements the netlink and RTNL APIs and can thus be integrated
in any script for more automated testing.

Along with the tool, a bunch of scripts are provided that perform basic
functionality tests by means of network namespaces.
These scripts take part to the kselftest automation.

The output of the scripts, which will appear in the kselftest
reports, is a list of steps performed by the scripts plus some
output coming from the execution of `ping`, `iperf` and `ovpn-cli`
itself.
In general it is useful only in case of failure, in order to
understand which step has failed and why.

Please note: since peer sockets are tied to the userspace
process that created them (i.e. exiting the process will result
in closing the socket), every run of ovpn-cli that created
one will go to background and enter pause(), waiting for the
signal which will allow it to terminate.
Termination is accomplished at the end of each script by
issuing a killall command.

Cc: linux-kselftest@vger.kernel.org
Cc: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
Link: https://patch.msgid.link/20250415-b4-ovpn-v26-23-577f6097b964@openvpn.net
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Antonio Quartulli 2025-04-15 13:17:40 +02:00 committed by Paolo Abeni
parent b756861e6e
commit 959bc330a4
16 changed files with 2722 additions and 0 deletions

View File

@ -18134,6 +18134,7 @@ T: git https://github.com/OpenVPN/linux-kernel-ovpn.git
F: Documentation/netlink/specs/ovpn.yaml
F: drivers/net/ovpn/
F: include/uapi/linux/ovpn.h
F: tools/testing/selftests/net/ovpn/
OPENVSWITCH
M: Aaron Conole <aconole@redhat.com>

View File

@ -71,6 +71,7 @@ TARGETS += net/hsr
TARGETS += net/mptcp
TARGETS += net/netfilter
TARGETS += net/openvswitch
TARGETS += net/ovpn
TARGETS += net/packetdrill
TARGETS += net/rds
TARGETS += net/tcp_ao

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0+
ovpn-cli

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020-2025 OpenVPN, Inc.
#
CFLAGS = -pedantic -Wextra -Wall -Wl,--no-as-needed -g -O0 -ggdb $(KHDR_INCLUDES)
VAR_CFLAGS = $(shell pkg-config --cflags libnl-3.0 libnl-genl-3.0 2>/dev/null)
ifeq ($(VAR_CFLAGS),)
VAR_CFLAGS = -I/usr/include/libnl3
endif
CFLAGS += $(VAR_CFLAGS)
LDLIBS = -lmbedtls -lmbedcrypto
VAR_LDLIBS = $(shell pkg-config --libs libnl-3.0 libnl-genl-3.0 2>/dev/null)
ifeq ($(VAR_LDLIBS),)
VAR_LDLIBS = -lnl-genl-3 -lnl-3
endif
LDLIBS += $(VAR_LDLIBS)
TEST_FILES = common.sh
TEST_PROGS = test.sh \
test-chachapoly.sh \
test-tcp.sh \
test-float.sh \
test-close-socket.sh \
test-close-socket-tcp.sh
TEST_GEN_FILES := ovpn-cli
include ../../lib.mk

View File

@ -0,0 +1,92 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020-2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
UDP_PEERS_FILE=${UDP_PEERS_FILE:-udp_peers.txt}
TCP_PEERS_FILE=${TCP_PEERS_FILE:-tcp_peers.txt}
OVPN_CLI=${OVPN_CLI:-./ovpn-cli}
ALG=${ALG:-aes}
PROTO=${PROTO:-UDP}
FLOAT=${FLOAT:-0}
create_ns() {
ip netns add peer${1}
}
setup_ns() {
MODE="P2P"
if [ ${1} -eq 0 ]; then
MODE="MP"
for p in $(seq 1 ${NUM_PEERS}); do
ip link add veth${p} netns peer0 type veth peer name veth${p} netns peer${p}
ip -n peer0 addr add 10.10.${p}.1/24 dev veth${p}
ip -n peer0 link set veth${p} up
ip -n peer${p} addr add 10.10.${p}.2/24 dev veth${p}
ip -n peer${p} link set veth${p} up
done
fi
ip netns exec peer${1} ${OVPN_CLI} new_iface tun${1} $MODE
ip -n peer${1} addr add ${2} dev tun${1}
ip -n peer${1} link set tun${1} up
}
add_peer() {
if [ "${PROTO}" == "UDP" ]; then
if [ ${1} -eq 0 ]; then
ip netns exec peer0 ${OVPN_CLI} new_multi_peer tun0 1 ${UDP_PEERS_FILE}
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 ${ALG} 0 \
data64.key
done
else
ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} 1 10.10.${1}.1 1
ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} ${1} 1 0 ${ALG} 1 \
data64.key
fi
else
if [ ${1} -eq 0 ]; then
(ip netns exec peer0 ${OVPN_CLI} listen tun0 1 ${TCP_PEERS_FILE} && {
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 \
${ALG} 0 data64.key
done
}) &
sleep 5
else
ip netns exec peer${1} ${OVPN_CLI} connect tun${1} ${1} 10.10.${1}.1 1 \
data64.key
fi
fi
}
cleanup() {
# some ovpn-cli processes sleep in background so they need manual poking
killall $(basename ${OVPN_CLI}) 2>/dev/null || true
# netns peer0 is deleted without erasing ifaces first
for p in $(seq 1 10); do
ip -n peer${p} link set tun${p} down 2>/dev/null || true
ip netns exec peer${p} ${OVPN_CLI} del_iface tun${p} 2>/dev/null || true
done
for p in $(seq 1 10); do
ip -n peer0 link del veth${p} 2>/dev/null || true
done
for p in $(seq 0 10); do
ip netns del peer${p} 2>/dev/null || true
done
}
if [ "${PROTO}" == "UDP" ]; then
NUM_PEERS=${NUM_PEERS:-$(wc -l ${UDP_PEERS_FILE} | awk '{print $1}')}
else
NUM_PEERS=${NUM_PEERS:-$(wc -l ${TCP_PEERS_FILE} | awk '{print $1}')}
fi

View File

@ -0,0 +1,10 @@
CONFIG_NET=y
CONFIG_INET=y
CONFIG_STREAM_PARSER=y
CONFIG_NET_UDP_TUNNEL=y
CONFIG_DST_CACHE=y
CONFIG_CRYPTO=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_CHACHA20POLY1305=y
CONFIG_OVPN=m

View File

@ -0,0 +1,5 @@
jRqMACN7d7/aFQNT8S7jkrBD8uwrgHbG5OQZP2eu4R1Y7tfpS2bf5RHv06Vi163CGoaIiTX99R3B
ia9ycAH8Wz1+9PWv51dnBLur9jbShlgZ2QHLtUc4a/gfT7zZwULXuuxdLnvR21DDeMBaTbkgbai9
uvAa7ne1liIgGFzbv+Bas4HDVrygxIxuAnP5Qgc3648IJkZ0QEXPF+O9f0n5+QIvGCxkAUVx+5K6
KIs+SoeWXnAopELmoGSjUpFtJbagXK82HfdqpuUxT2Tnuef0/14SzVE/vNleBNu2ZbyrSAaah8tE
BofkPJUBFY+YQcfZNM5Dgrw3i+Bpmpq/gpdg5w==

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
1 5.5.5.2
2 5.5.5.3
3 5.5.5.4
4 5.5.5.5
5 5.5.5.6

View File

@ -0,0 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
ALG="chachapoly"
source test.sh

View File

@ -0,0 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
PROTO="TCP"
source test-close-socket.sh

View File

@ -0,0 +1,45 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020-2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
#set -x
set -e
source ./common.sh
cleanup
modprobe -q ovpn || true
for p in $(seq 0 ${NUM_PEERS}); do
create_ns ${p}
done
for p in $(seq 0 ${NUM_PEERS}); do
setup_ns ${p} 5.5.5.$((${p} + 1))/24
done
for p in $(seq 0 ${NUM_PEERS}); do
add_peer ${p}
done
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 60 120
done
sleep 1
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
done
ip netns exec peer0 iperf3 -1 -s &
sleep 1
ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
cleanup
modprobe -r ovpn || true

View File

@ -0,0 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
FLOAT="1"
source test.sh

View File

@ -0,0 +1,9 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
PROTO="TCP"
source test.sh

View File

@ -0,0 +1,113 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2020-2025 OpenVPN, Inc.
#
# Author: Antonio Quartulli <antonio@openvpn.net>
#set -x
set -e
source ./common.sh
cleanup
modprobe -q ovpn || true
for p in $(seq 0 ${NUM_PEERS}); do
create_ns ${p}
done
for p in $(seq 0 ${NUM_PEERS}); do
setup_ns ${p} 5.5.5.$((${p} + 1))/24
done
for p in $(seq 0 ${NUM_PEERS}); do
add_peer ${p}
done
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 60 120
done
sleep 1
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
done
if [ "$FLOAT" == "1" ]; then
# make clients float..
for p in $(seq 1 ${NUM_PEERS}); do
ip -n peer${p} addr del 10.10.${p}.2/24 dev veth${p}
ip -n peer${p} addr add 10.10.${p}.3/24 dev veth${p}
done
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer${p} ping -qfc 500 -w 3 5.5.5.1
done
fi
ip netns exec peer0 iperf3 -1 -s &
sleep 1
ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
echo "Adding secondary key and then swap:"
for p in $(seq 1 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 2 1 ${ALG} 0 data64.key
ip netns exec peer${p} ${OVPN_CLI} new_key tun${p} ${p} 2 1 ${ALG} 1 data64.key
ip netns exec peer${p} ${OVPN_CLI} swap_keys tun${p} ${p}
done
sleep 1
echo "Querying all peers:"
ip netns exec peer0 ${OVPN_CLI} get_peer tun0
ip netns exec peer1 ${OVPN_CLI} get_peer tun1
echo "Querying peer 1:"
ip netns exec peer0 ${OVPN_CLI} get_peer tun0 1
echo "Querying non-existent peer 10:"
ip netns exec peer0 ${OVPN_CLI} get_peer tun0 10 || true
echo "Deleting peer 1:"
ip netns exec peer0 ${OVPN_CLI} del_peer tun0 1
ip netns exec peer1 ${OVPN_CLI} del_peer tun1 1
echo "Querying keys:"
for p in $(seq 2 ${NUM_PEERS}); do
ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} ${p} 1
ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} ${p} 2
done
echo "Deleting peer while sending traffic:"
(ip netns exec peer2 ping -qf -w 4 5.5.5.1)&
sleep 2
ip netns exec peer0 ${OVPN_CLI} del_peer tun0 2
# following command fails in TCP mode
# (both ends get conn reset when one peer disconnects)
ip netns exec peer2 ${OVPN_CLI} del_peer tun2 2 || true
echo "Deleting keys:"
for p in $(seq 3 ${NUM_PEERS}); do
ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} ${p} 1
ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} ${p} 2
done
echo "Setting timeout to 3s MP:"
for p in $(seq 3 ${NUM_PEERS}); do
ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true
ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 0 0
done
# wait for peers to timeout
sleep 5
echo "Setting timeout to 3s P2P:"
for p in $(seq 3 ${NUM_PEERS}); do
ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} ${p} 3 3
done
sleep 5
cleanup
modprobe -r ovpn || true

View File

@ -0,0 +1,5 @@
1 10.10.1.2 1 5.5.5.2
2 10.10.2.2 1 5.5.5.3
3 10.10.3.2 1 5.5.5.4
4 10.10.4.2 1 5.5.5.5
5 10.10.5.2 1 5.5.5.6