mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-08-08 09:21:48 +08:00
Allow using no-udp option in vhosts
Signed-off-by: Grigory Trenin <grigory.trenin@gmail.com>
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
- Aligned default values for 'keepalive', 'rekey-time', 'cookie-timeout',
|
||||
'auth-timeout', 'ban-reset-time', 'max-ban-score', and
|
||||
'switch-to-tcp-timeout' with the values documented in sample.config
|
||||
- The `no-udp` option can now be used to disable DTLS for specific vhosts.
|
||||
Previously it was only available in per-user or per-group config.
|
||||
|
||||
|
||||
* Version 1.4.1 (released 2026-02-28)
|
||||
|
||||
@@ -677,6 +677,16 @@ route = 192.168.0.0/255.255.0.0
|
||||
# [scope: vhost user]
|
||||
no-route = 192.168.5.0/255.255.255.0
|
||||
|
||||
# Whether to disable DTLS (UDP) for client connections. If set to true,
|
||||
# the server will only accept TCP connections and will not negotiate DTLS.
|
||||
# This can be useful for clients behind restrictive firewalls or NATs that
|
||||
# have issues with UDP, or to enforce TCP-only operation for specific vhosts.
|
||||
#
|
||||
# This setting can be overridden per vhost, user, or group.
|
||||
#
|
||||
# [scope: vhost user]
|
||||
#no-udp = false
|
||||
|
||||
# If set, the script /usr/libexec/ocserv-fw will be called to restrict
|
||||
# the user to its allowed routes and prevent him from accessing
|
||||
# any other routes. In case of defaultroute, the no-routes are restricted.
|
||||
|
||||
@@ -1308,6 +1308,8 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name,
|
||||
READ_STRING(config->camouflage_secret);
|
||||
} else if (strcmp(name, "camouflage_realm") == 0) {
|
||||
READ_STRING(config->camouflage_realm);
|
||||
} else if (strcmp(name, "no-udp") == 0) {
|
||||
READ_TF(config->no_udp);
|
||||
} else {
|
||||
if (reload == 0)
|
||||
fprintf(stderr,
|
||||
|
||||
@@ -338,7 +338,7 @@ static void apply_default_config(sec_mod_instance_st *sec_mod_instance,
|
||||
vhost_cfg_st *vhost = proc->vhost;
|
||||
|
||||
if (!gc->has_no_udp) {
|
||||
gc->no_udp = (vhost->perm_config.udp_port != 0) ? 0 : 1;
|
||||
gc->no_udp = vhost->perm_config.config->no_udp;
|
||||
gc->has_no_udp = 1;
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -767,6 +767,16 @@ static int forward_udp_to_owner(main_server_st *s, struct listener_st *listener)
|
||||
}
|
||||
|
||||
if (proc_to_send != 0) {
|
||||
if (GETPCONFIG(s)->udp_port == 0 ||
|
||||
proc_to_send->config->no_udp) {
|
||||
mslog(s, proc_to_send, LOG_WARNING,
|
||||
"Received UDP packet from %s while UDP is disabled for this client. "
|
||||
"Possible cause: compromised worker or incorrect worker match.",
|
||||
human_addr((struct sockaddr *)&cli_addr,
|
||||
cli_addr_size, tbuf, sizeof(tbuf)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
UdpFdMsg msg = UDP_FD_MSG__INIT;
|
||||
|
||||
if (now - proc_to_send->udp_fd_receive_time <=
|
||||
|
||||
@@ -381,6 +381,8 @@ struct cfg_st {
|
||||
bool camouflage; /* [scope: vhost] */
|
||||
char *camouflage_secret; /* [scope: vhost] */
|
||||
char *camouflage_realm; /* [scope: vhost] */
|
||||
|
||||
bool no_udp; /* [scope: vhost user] */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+2
-2
@@ -787,8 +787,8 @@ static int recv_cookie_auth_reply(worker_st *ws)
|
||||
ws, msg->ipv6_local);
|
||||
}
|
||||
|
||||
if (msg->config->no_udp != 0)
|
||||
WSPCONFIG(ws)->udp_port = 0;
|
||||
if (msg->config->has_no_udp)
|
||||
WSCONFIG(ws)->no_udp = msg->config->no_udp;
|
||||
|
||||
/* routes */
|
||||
if (check_if_default_route(msg->config->routes,
|
||||
|
||||
+2
-1
@@ -2131,7 +2131,8 @@ static int connect_handler(worker_st *ws)
|
||||
DTLS_ACTIVE(ws)->udp_state = UP_DISABLED;
|
||||
DTLS_INACTIVE(ws)->udp_state = UP_DISABLED;
|
||||
|
||||
if (WSPCONFIG(ws)->udp_port != 0 && req->master_secret_set != 0) {
|
||||
if (WSPCONFIG(ws)->udp_port != 0 && !WSCONFIG(ws)->no_udp &&
|
||||
req->master_secret_set != 0) {
|
||||
memcpy(ws->master_secret, req->master_secret, TLS_MASTER_SIZE);
|
||||
DTLS_ACTIVE(ws)->udp_state = UP_WAIT_FD;
|
||||
DTLS_INACTIVE(ws)->udp_state = UP_WAIT_FD;
|
||||
|
||||
@@ -246,7 +246,6 @@ def main():
|
||||
# are per-user only and don't appear in the global sample.config — skip those.
|
||||
PER_USER_ONLY = {
|
||||
"iroute", "hostname", "explicit-ipv4", "explicit-ipv6",
|
||||
"no-udp",
|
||||
"ipv4-dns", "ipv6-dns", "ipv4-nbns", "ipv6-nbns",
|
||||
}
|
||||
for opt in sorted(user_in_code):
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
auth = plain[@SRCDIR@/data/test-no-udp.passwd]
|
||||
isolate-workers = @ISOLATE_WORKERS@
|
||||
max-ban-score = 0
|
||||
max-clients = 16
|
||||
listen-proxy-proto = false
|
||||
max-same-clients = 2
|
||||
tcp-port = @PORT@
|
||||
udp-port = @PORT@
|
||||
keepalive = 32400
|
||||
dpd = 440
|
||||
try-mtu-discovery = false
|
||||
server-cert = @SRCDIR@/certs/server-cert.pem
|
||||
server-key = @SRCDIR@/certs/server-key.pem
|
||||
tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE:%COMPAT"
|
||||
auth-timeout = 40
|
||||
socket-file = ./ocserv-socket
|
||||
occtl-socket-file = @OCCTL_SOCKET@
|
||||
use-occtl = true
|
||||
run-as-user = @USERNAME@
|
||||
run-as-group = @GROUP@
|
||||
device = vpns
|
||||
default-domain = example.com
|
||||
ipv4-dns = 192.168.1.1
|
||||
ipv4-network = @VPNNET@
|
||||
ipv6-network = @VPNNET6@
|
||||
ping-leases = false
|
||||
|
||||
[vhost:udp-restricted.example.com]
|
||||
no-udp = true
|
||||
auth = plain[passwd=@SRCDIR@/data/test-no-udp.passwd]
|
||||
config-per-user = @SRCDIR@/user-config/
|
||||
ca-cert = @SRCDIR@/certs/ca.pem
|
||||
server-cert = @SRCDIR@/certs/server-cert.pem
|
||||
server-key = @SRCDIR@/certs/server-key.pem
|
||||
ipv4-network = @VPNNET@
|
||||
ipv6-network = @VPNNET6@
|
||||
@@ -0,0 +1,3 @@
|
||||
noudp1:*:$5$FTX0hYx4Ns2EyUQJ$eSquiS6eIuqvS7lmVV37RTDGaoyK64l6UE8B370XZx.
|
||||
noudp2:*:$5$O504PV8Po56eV95.$lMKsgC1qidOOSubv9J12Tq0YDtqygzAc7/fAWB/c8T3
|
||||
noudp3:*:$5$pza6pL8iS67.T5jd$aWJuSF0GeoK3f5B8KaVoU4QtYKLARU2ktX3KAX6fuz8
|
||||
+1
-1
@@ -240,7 +240,7 @@ if get_option('root-tests')
|
||||
'test-user-config', 'test-append-routes', 'test-ban',
|
||||
'multiple-routes', 'json', 'test-udp-listen-host',
|
||||
'test-max-same-1', 'test-vhost-udp-port-inheritance',
|
||||
'apple-ios', 'ipv6-iface',
|
||||
'apple-ios', 'ipv6-iface', 'test-no-udp',
|
||||
'disconnect-user', 'disconnect-user2', 'terminate-commands',
|
||||
'ping-leases', 'test-ban-local', 'test-client-bypass-protocol',
|
||||
'ipv6-small-net', 'test-camouflage', 'test-camouflage-norealm',
|
||||
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2026 Grigory Trenin
|
||||
#
|
||||
# This file is part of ocserv.
|
||||
#
|
||||
# ocserv is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
# ocserv is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Test no-udp option
|
||||
|
||||
OCCTL="${OCCTL:-../src/occtl/occtl}"
|
||||
OCCTL_SOCKET=./occtl-no-udp-$$.socket
|
||||
SERV="${SERV:-../src/ocserv}"
|
||||
srcdir=${srcdir:-.}
|
||||
PIDFILE=ocserv-pid.$$.tmp
|
||||
CLIPID=oc-pid.$$.tmp
|
||||
PATH=${PATH}:/usr/sbin
|
||||
OUTFILE=occtl-no-udp.$$.tmp
|
||||
|
||||
echo "Testing no-udp option..."
|
||||
|
||||
finish() {
|
||||
set +e
|
||||
echo " * Cleaning up..."
|
||||
test -n "${PID}" && kill ${PID} >/dev/null 2>&1
|
||||
test -n "${PIDFILE}" && rm -f ${PIDFILE} >/dev/null 2>&1
|
||||
test -n "${CLIPID}" && kill $(cat ${CLIPID}) >/dev/null 2>&1
|
||||
test -n "${CLIPID}" && rm -f ${CLIPID} >/dev/null 2>&1
|
||||
test -n "${CONFIG}" && rm -f ${CONFIG} >/dev/null 2>&1
|
||||
rm -f ${OUTFILE}
|
||||
}
|
||||
|
||||
connect_vhost() {
|
||||
VHOST=$1
|
||||
USERNAME=$2
|
||||
|
||||
echo " * Connecting to ${VHOST} at ${ADDRESS}:${PORT}..."
|
||||
( echo ${USERNAME} | ${CMDNS1} ${OPENCONNECT} ${VHOST}:${PORT} --resolve ${VHOST}:${ADDRESS} -u ${USERNAME} --servercert=pin-sha256:xp3scfzy3rOQsv9NcOve/8YVVv+pHr4qNCXEXrNl5s8= -s ${srcdir}/scripts/vpnc-script --pid-file=${CLIPID} --passwd-on-stdin -b )
|
||||
if test $? != 0;then
|
||||
fail $PID "Could not connect to server"
|
||||
fi
|
||||
|
||||
${OCCTL} -s ${OCCTL_SOCKET} show user ${USERNAME} >${OUTFILE}
|
||||
if test $? != 0;then
|
||||
cat ${OUTFILE}
|
||||
fail $PID "occtl show user ${USERNAME} failed!"
|
||||
fi
|
||||
|
||||
grep -i "Username: ${USERNAME}" ${OUTFILE} >/dev/null
|
||||
if test $? != 0;then
|
||||
cat ${OUTFILE}
|
||||
fail $PID "Username missing in occtl show user output"
|
||||
fi
|
||||
|
||||
grep -i "vhost: ${VHOST}" ${OUTFILE} >/dev/null
|
||||
if test $? != 0;then
|
||||
cat ${OUTFILE}
|
||||
fail $PID "Session associated with wrong vhost (expected: ${VHOST})"
|
||||
fi
|
||||
|
||||
if grep -i "DTLS cipher:" ${OUTFILE} >/dev/null;then
|
||||
HAVE_DTLS=1
|
||||
else
|
||||
HAVE_DTLS=0
|
||||
fi
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
kill "$(cat ${CLIPID})" 2>/dev/null || true
|
||||
rm -f "${CLIPID}"
|
||||
sleep 3
|
||||
# Restore NS1 routing in case vpnc-script failed to run during server-initiated disconnect
|
||||
reset_client_routes
|
||||
}
|
||||
|
||||
. `dirname $0`/common.sh
|
||||
. `dirname $0`/random-net.sh
|
||||
. `dirname $0`/ns.sh
|
||||
|
||||
eval "${GETPORT}"
|
||||
|
||||
# Run server
|
||||
update_config test-no-udp.config
|
||||
if test "$VERBOSE" = 1;then
|
||||
DEBUG="-d 3"
|
||||
fi
|
||||
|
||||
${CMDNS2} ${SERV} -p ${PIDFILE} -f -c ${CONFIG} ${DEBUG} & PID=$!
|
||||
|
||||
sleep 4
|
||||
|
||||
echo "*** Test 1 - UDP enabled"
|
||||
connect_vhost default noudp1
|
||||
if test "${HAVE_DTLS}" = 0;then
|
||||
fail $PID "DTLS session was not established with default vhost"
|
||||
fi
|
||||
disconnect
|
||||
|
||||
echo "*** Test 2 - UDP disabled per vhost"
|
||||
connect_vhost udp-restricted.example.com noudp2
|
||||
if test "${HAVE_DTLS}" = 1;then
|
||||
fail $PID "DTLS session established despite being disabled for this vhost"
|
||||
fi
|
||||
disconnect
|
||||
|
||||
echo "*** Test 3 - UDP disabled per vhost, but enabled per-user"
|
||||
connect_vhost udp-restricted.example.com noudp3
|
||||
if test "${HAVE_DTLS}" = 0;then
|
||||
fail $PID "DTLS session failed to establish despite user-level override"
|
||||
fi
|
||||
disconnect
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1 @@
|
||||
no-udp = false
|
||||
Reference in New Issue
Block a user