@@ -10,6 +10,7 @@
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
@@ -129,6 +130,7 @@ struct ovpn_ctx {
__u32 keepalive_interval;
__u32 keepalive_timeout;
+ int mssfix;
enum ovpn_key_direction key_dir;
enum ovpn_key_slot key_slot;
@@ -732,6 +734,8 @@ 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);
+ if (ovpn->mssfix >= 0)
+ NLA_PUT_U16(ctx->nl_msg, OVPN_A_PEER_MSSFIX, ovpn->mssfix);
nla_nest_end(ctx->nl_msg, attr);
ret = ovpn_nl_msg_send(ctx, NULL);
@@ -1730,13 +1734,15 @@ 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> <mssfix>: 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,
+ "\tmssfix: TCP MSS value to clamp SYN packets to (0 disables, -1 leaves unchanged)\n");
fprintf(stderr, "* del_peer <iface> <peer_id>: delete peer\n");
fprintf(stderr, "\tiface: ovpn interface name\n");
@@ -2307,7 +2313,7 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[])
}
break;
case CMD_SET_PEER:
- if (argc < 6)
+ if (argc < 7)
return -EINVAL;
ovpn->peer_id = strtoul(argv[3], NULL, 10);
@@ -2329,6 +2335,14 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[])
"keepalive interval value out of range\n");
return -1;
}
+
+ errno = 0;
+ ovpn->mssfix = strtol(argv[6], NULL, 10);
+ if (errno == ERANGE || ovpn->mssfix < -1 ||
+ ovpn->mssfix > UINT16_MAX) {
+ fprintf(stderr, "mssfix value out of range\n");
+ return -1;
+ }
break;
case CMD_DEL_PEER:
if (argc < 4)
@@ -2442,6 +2456,7 @@ int main(int argc, char *argv[])
memset(&ovpn, 0, sizeof(ovpn));
ovpn.sa_family = AF_UNSPEC;
ovpn.cipher = OVPN_CIPHER_ALG_NONE;
+ ovpn.mssfix = -1;
ovpn.cmd = ovpn_parse_cmd(argv[1]);
if (ovpn.cmd == CMD_INVALID) {
@@ -41,10 +41,10 @@ ovpn_prepare_network() {
peer_ns="ovpn_peer${p}"
ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
- ${p} 60 120
+ ${p} 60 120 -1
ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
- tun${p} $((p + OVPN_ID_OFFSET)) 60 120
+ tun${p} $((p + OVPN_ID_OFFSET)) 60 120 -1
done
}
@@ -54,10 +54,10 @@ ovpn_mark_prepare_network() {
peer_ns="ovpn_peer${p}"
ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \
- "${p}" 60 120
+ "${p}" 60 120 -1
ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \
- tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120
+ tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120 -1
done
}
@@ -49,10 +49,10 @@ ovpn_prepare_network() {
peer_ns="ovpn_peer${p}"
ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
- ${p} 60 120
+ ${p} 60 120 -1
ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
- tun${p} $((p + OVPN_ID_OFFSET)) 60 120
+ tun${p} $((p + OVPN_ID_OFFSET)) 60 120 -1
done
}
@@ -142,6 +142,66 @@ ovpn_run_iperf() {
wait "${iperf_pid}" || return 1
}
+ovpn_run_mssfix_flow() {
+ local filter
+ local iperf_pid
+ local direction="$1"
+ local mssfix="$2"
+ local tcpdump_pid
+
+ filter="tcp and src host 5.5.5.1 and dst host 5.5.5.2"
+ filter="${filter} and tcp[tcpflags] & tcp-syn != 0"
+
+ ovpn_run_bg iperf_pid ip netns exec ovpn_peer1 iperf3 -1 -s
+ sleep 1
+
+ timeout 3s ip netns exec ovpn_peer1 tcpdump --immediate-mode -l -p \
+ -vv -nn -i tun1 -c 1 "${filter}" 2>&1 |
+ grep -iq "mss ${mssfix}" &
+ tcpdump_pid=$!
+ sleep 0.3
+
+ ovpn_cmd_ok "run ${direction} mssfix TCP flow" \
+ ip netns exec ovpn_peer0 iperf3 -t 1 -c 5.5.5.2
+
+ ovpn_cmd_ok "capture ${direction} mssfix TCP SYN" wait "${tcpdump_pid}"
+ ovpn_cmd_ok "finish ${direction} mssfix TCP server" wait "${iperf_pid}"
+}
+
+ovpn_run_mssfix() {
+ local peer0_id=$((1 + OVPN_ID_OFFSET))
+
+ # peer0 will clamp MSS for packets exchanged with peer1
+ ovpn_cmd_ok "set peer0 mssfix for peer 1" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 1 \
+ 60 120 900
+
+ ovpn_cmd_fail "reject invalid peer0 mssfix for peer 1" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 1 \
+ 60 120 20
+
+ ovpn_cmd_ok "clear peer1 mssfix for peer ${peer0_id}" \
+ ip netns exec ovpn_peer1 ${OVPN_CLI} set_peer tun1 \
+ "${peer0_id}" 60 120 0
+
+ ovpn_run_mssfix_flow "TX" 900
+
+ ovpn_cmd_ok "clear peer0 mssfix for peer 1" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 1 \
+ 60 120 0
+
+ # peer1 will clamp MSS for packets exchanged with peer0
+ ovpn_cmd_ok "set peer1 mssfix for peer ${peer0_id}" \
+ ip netns exec ovpn_peer1 ${OVPN_CLI} set_peer tun1 \
+ "${peer0_id}" 60 120 901
+
+ ovpn_run_mssfix_flow "RX" 901
+
+ ovpn_cmd_ok "clear peer1 mssfix for peer ${peer0_id}" \
+ ip netns exec ovpn_peer1 ${OVPN_CLI} set_peer tun1 \
+ "${peer0_id}" 60 120 0
+}
+
ovpn_run_key_rollover() {
local p
local peer_ns
@@ -259,11 +319,11 @@ ovpn_run_timeouts() {
# Non-fatal: this may fail in some protocol modes.
ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \
ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
- ${p} 3 3
+ ${p} 3 3 -1
peer_ns="ovpn_peer${p}"
ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \
state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
- tun${p} $((p + OVPN_ID_OFFSET)) 0 0
+ tun${p} $((p + OVPN_ID_OFFSET)) 0 0 -1
done
# wait for peers to timeout
sleep 5
@@ -274,7 +334,7 @@ ovpn_run_timeouts() {
peer_ns="ovpn_peer${p}"
ovpn_cmd_ok "set peer${p} P2P timeout" \
ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
- tun${p} $((p + OVPN_ID_OFFSET)) 3 3
+ tun${p} $((p + OVPN_ID_OFFSET)) 3 3 -1
done
sleep 5
}
@@ -293,9 +353,9 @@ 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
@@ -307,6 +367,7 @@ ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic
[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \
ovpn_run_float_mode
ovpn_run_stage "run iperf throughput" ovpn_run_iperf
+ovpn_run_stage "run mssfix TCP SYN clamp" ovpn_run_mssfix
ovpn_run_stage "run key rollout" ovpn_run_key_rollover
ovpn_run_stage "query peers" ovpn_run_queries
ovpn_run_stage "query missing peer fails" ovpn_query_peer_missing
Extend ovpn-cli set_peer to pass the peer mssfix attribute. Use -1 as the selftest CLI sentinel for leaving mssfix unchanged, so existing timeout-only peer updates can keep omitting the netlink attribute. Add an ovpn test stage that configures mssfix on each side of a peer pair and verifies the MSS advertised on TCP SYN packets seen on the tunnel device. This covers both TX-side and RX-side clamping, and also checks that an invalid non-zero MSS value is rejected. Signed-off-by: Ralf Lici <ralf@mandelbit.com> --- tools/testing/selftests/net/ovpn/ovpn-cli.c | 19 ++++- .../selftests/net/ovpn/test-close-socket.sh | 4 +- tools/testing/selftests/net/ovpn/test-mark.sh | 4 +- tools/testing/selftests/net/ovpn/test.sh | 75 +++++++++++++++++-- 4 files changed, 89 insertions(+), 13 deletions(-)