Exercise peer VPN address validation through both peer creation and
update. Check missing, unspecified, duplicate, multicast, broadcast,
loopback, IPv4-compatible and IPv4-mapped addresses.
Temporarily configure a peer with both address families to verify that
either family can be cleared while the other remains configured, then
restore the original addresses before running the existing traffic
tests.
Extend ovpn-cli peer updates with an optional VPN address and preserve
peer creation errors so the negative tests can observe rejected netlink
requests.
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
tools/testing/selftests/net/ovpn/common.sh | 13 ++++
tools/testing/selftests/net/ovpn/ovpn-cli.c | 54 ++++++++++-----
tools/testing/selftests/net/ovpn/test.sh | 75 ++++++++++++++++++++-
3 files changed, 123 insertions(+), 19 deletions(-)
@@ -136,6 +136,19 @@ ovpn_create_ns() {
ip netns add "ovpn_peer${1}"
}
+ovpn_peer_vpn_addr() {
+ local peer="$1"
+ local file
+
+ if [ "${OVPN_PROTO}" == "UDP" ]; then
+ file="${OVPN_UDP_PEERS_FILE}"
+ else
+ file="${OVPN_TCP_PEERS_FILE}"
+ fi
+
+ awk -v peer="${peer}" '$1 == peer {print $NF; exit}' "${file}"
+}
+
ovpn_setup_ns() {
local peer="ovpn_peer${1}"
local server_ns="ovpn_peer0"
@@ -650,6 +650,26 @@ static int ovpn_connect(struct ovpn_ctx *ovpn)
return ret;
}
+static int ovpn_nl_put_vpn_addr(struct nl_msg *msg,
+ const struct ovpn_ctx *ovpn)
+{
+ if (!ovpn->peer_ip_set)
+ return 0;
+
+ switch (ovpn->peer_ip.in4.sin_family) {
+ case AF_INET:
+ return nla_put_u32(msg, OVPN_A_PEER_VPN_IPV4,
+ ovpn->peer_ip.in4.sin_addr.s_addr);
+ case AF_INET6:
+ return nla_put(msg, OVPN_A_PEER_VPN_IPV6,
+ sizeof(struct in6_addr),
+ &ovpn->peer_ip.in6.sin6_addr);
+ default:
+ fprintf(stderr, "Invalid family for peer address\n");
+ return -EAFNOSUPPORT;
+ }
+}
+
static int ovpn_new_peer(struct ovpn_ctx *ovpn, bool is_tcp)
{
struct nlattr *attr;
@@ -691,22 +711,9 @@ static int ovpn_new_peer(struct ovpn_ctx *ovpn, bool is_tcp)
}
}
- if (ovpn->peer_ip_set) {
- switch (ovpn->peer_ip.in4.sin_family) {
- case AF_INET:
- NLA_PUT_U32(ctx->nl_msg, OVPN_A_PEER_VPN_IPV4,
- ovpn->peer_ip.in4.sin_addr.s_addr);
- break;
- case AF_INET6:
- NLA_PUT(ctx->nl_msg, OVPN_A_PEER_VPN_IPV6,
- sizeof(struct in6_addr),
- &ovpn->peer_ip.in6.sin6_addr);
- break;
- default:
- fprintf(stderr, "Invalid family for peer address\n");
- goto nla_put_failure;
- }
- }
+ ret = ovpn_nl_put_vpn_addr(ctx->nl_msg, ovpn);
+ if (ret)
+ goto nla_put_failure;
nla_nest_end(ctx->nl_msg, attr);
@@ -732,6 +739,10 @@ static int ovpn_set_peer(struct ovpn_ctx *ovpn)
ovpn->keepalive_interval);
NLA_PUT_U32(ctx->nl_msg, OVPN_A_PEER_KEEPALIVE_TIMEOUT,
ovpn->keepalive_timeout);
+
+ ret = ovpn_nl_put_vpn_addr(ctx->nl_msg, ovpn);
+ if (ret)
+ goto nla_put_failure;
nla_nest_end(ctx->nl_msg, attr);
ret = ovpn_nl_msg_send(ctx, NULL);
@@ -1730,13 +1741,14 @@ static void usage(const char *cmd)
fprintf(stderr, "\tmark: socket FW mark value\n");
fprintf(stderr,
- "* set_peer <iface> <peer_id> <keepalive_interval> <keepalive_timeout>: set peer attributes\n");
+ "* set_peer <iface> <peer_id> <keepalive_interval> <keepalive_timeout> [vpnaddr]: set peer attributes\n");
fprintf(stderr, "\tiface: ovpn interface name\n");
fprintf(stderr, "\tpeer_id: peer ID of the peer to modify\n");
fprintf(stderr,
"\tkeepalive_interval: interval for sending ping messages\n");
fprintf(stderr,
"\tkeepalive_timeout: time after which a peer is timed out\n");
+ fprintf(stderr, "\tvpnaddr: peer VPN IP\n");
fprintf(stderr, "* del_peer <iface> <peer_id>: delete peer\n");
fprintf(stderr, "\tiface: ovpn interface name\n");
@@ -2090,6 +2102,8 @@ static int ovpn_run_cmd(struct ovpn_ctx *ovpn)
return ret;
ret = ovpn_new_peer(ovpn, false);
+ if (ret < 0)
+ return ret;
ovpn_waitbg();
break;
case CMD_NEW_MULTI_PEER:
@@ -2331,6 +2345,12 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[])
"keepalive interval value out of range\n");
return -1;
}
+
+ if (argc > 6) {
+ ret = ovpn_parse_remote(ovpn, NULL, NULL, argv[6]);
+ if (ret < 0)
+ return -1;
+ }
break;
case CMD_DEL_PEER:
if (argc < 4)
@@ -56,6 +56,76 @@ ovpn_prepare_network() {
done
}
+ovpn_new_test_peer() {
+ local peer_id="$1"
+
+ shift
+ ip netns exec ovpn_peer0 "${OVPN_CLI}" new_peer tun0 \
+ "${peer_id}" none 65000 10.10.1.2 1 "$@"
+}
+
+ovpn_set_peer_vpn_addr() {
+ ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \
+ "$1" 60 120 "$2"
+}
+
+ovpn_run_vpn_addr_validation() {
+ local addr
+ local peer1_addr4
+ local test_peer_id=$((OVPN_NUM_PEERS + 1))
+ local test_peer_addr6="2001:db8::2"
+ # Do not include 0.0.0.0 or :: here. They are invalid on creation, but
+ # clear one address family on update and are valid if the other remains.
+ local -a invalid_addrs=(
+ "127.0.0.1"
+ "224.0.0.1"
+ "255.255.255.255"
+ "::1"
+ "::192.0.2.1"
+ "::ffff:192.0.2.1"
+ "ff02::1"
+ )
+
+ peer1_addr4=$(ovpn_peer_vpn_addr 1)
+
+ ovpn_cmd_fail "reject peer without VPN address" \
+ ovpn_new_test_peer "${test_peer_id}"
+
+ for addr in "0.0.0.0" "::" "${invalid_addrs[@]}"; do
+ ovpn_cmd_fail "reject new peer VPN address ${addr}" \
+ ovpn_new_test_peer "${test_peer_id}" "${addr}"
+ done
+
+ ovpn_cmd_fail "reject duplicate IPv4 address on peer creation" \
+ ovpn_new_test_peer "${test_peer_id}" "${peer1_addr4}"
+ ovpn_cmd_fail "reject clearing the last peer VPN address" \
+ ovpn_set_peer_vpn_addr 1 0.0.0.0
+
+ for addr in "${invalid_addrs[@]}"; do
+ ovpn_cmd_fail "reject updated peer VPN address ${addr}" \
+ ovpn_set_peer_vpn_addr 1 "${addr}"
+ done
+
+ ovpn_cmd_fail "reject duplicate IPv4 address on peer update" \
+ ovpn_set_peer_vpn_addr 2 "${peer1_addr4}"
+
+ ovpn_cmd_ok "add peer IPv6 address" \
+ ovpn_set_peer_vpn_addr 1 "${test_peer_addr6}"
+ ovpn_cmd_fail "reject duplicate IPv6 address on peer creation" \
+ ovpn_new_test_peer "${test_peer_id}" "${test_peer_addr6}"
+ ovpn_cmd_fail "reject duplicate IPv6 address on peer update" \
+ ovpn_set_peer_vpn_addr 2 "${test_peer_addr6}"
+
+ ovpn_cmd_ok "clear peer IPv4 address" \
+ ovpn_set_peer_vpn_addr 1 0.0.0.0
+ ovpn_cmd_fail "reject clearing the remaining peer IPv6 address" \
+ ovpn_set_peer_vpn_addr 1 ::
+ ovpn_cmd_ok "restore peer IPv4 address" \
+ ovpn_set_peer_vpn_addr 1 "${peer1_addr4}"
+ ovpn_cmd_ok "clear peer IPv6 address" \
+ ovpn_set_peer_vpn_addr 1 ::
+}
+
ovpn_run_basic_traffic() {
local p
local header1
@@ -293,15 +363,16 @@ trap ovpn_stage_err ERR
ktap_print_header
if [ "${OVPN_FLOAT}" == "1" ]; then
- ktap_set_plan 13
+ ktap_set_plan 14
else
- ktap_set_plan 12
+ ktap_set_plan 13
fi
ovpn_cleanup
modprobe -q ovpn || true
ovpn_run_stage "setup network topology" ovpn_prepare_network
+ovpn_run_stage "validate peer VPN addresses" ovpn_run_vpn_addr_validation
ovpn_run_stage "run baseline data traffic" ovpn_run_basic_traffic
ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic
[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \