From 819629e2a5ca27a24648abbc73f2632b825403c9 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 29 Jun 2022 14:17:30 -0400 Subject: [PATCH] Find a free port for management interface Bind a socket and then close to identify a free port and use it when starting openvpn.exe. Try port = offset + config-index is first, matching the current usage, and fallback to a dynamic port if the former fails. Trac: #1051 Signed-off-by: Selva Nair --- misc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ misc.h | 9 +++++++++ openvpn.c | 2 ++ 3 files changed, 62 insertions(+) diff --git a/misc.c b/misc.c index cc213ae..154ae75 100644 --- a/misc.c +++ b/misc.c @@ -773,3 +773,54 @@ set_openssl_env_vars() } } } + +/* + * Find a free port to bind and return it in addr.sin_port + */ +BOOL +find_free_tcp_port(SOCKADDR_IN *addr) +{ + BOOL ret = false; + SOCKADDR_IN addr_bound; + WSADATA wsaData; + int len = sizeof(*addr); + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + { + return ret; + } + + u_short old_port = addr->sin_port; + + SOCKET sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sk == INVALID_SOCKET) + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"%hs: socket open failed", __func__); + goto out; + } + while (bind(sk, (SOCKADDR *) addr, len)) + { + if (addr->sin_port == 0) + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"%hs: bind to dynamic port failed", __func__); + goto out; + } + addr->sin_port = 0; + } + if (getsockname(sk, (SOCKADDR *) &addr_bound, &len)) + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"%hs: getsockname failed", __func__); + goto out; + } + + ret = true; + +out: + if (sk != INVALID_SOCKET) + { + closesocket(sk); + } + addr->sin_port = ret ? addr_bound.sin_port : old_port; + WSACleanup(); + return ret; +} diff --git a/misc.h b/misc.h index 732d803..5039ce3 100644 --- a/misc.h +++ b/misc.h @@ -89,4 +89,13 @@ void set_openssl_env_vars(void); /* Return escaped copy of a string */ char *escape_string(const char *str); +/** + * Find a free port to bind to + * @param addr : Address to bind to -- if port >0 it's tried first. + * On return the port is set to the one found. + * @returns true on success, false on error. In case of error + * addr is unchanged. + */ +BOOL find_free_tcp_port(SOCKADDR_IN *addr); + #endif diff --git a/openvpn.c b/openvpn.c index b5974d6..ce6e975 100644 --- a/openvpn.c +++ b/openvpn.c @@ -2193,6 +2193,8 @@ StartOpenVPN(connection_t *c) /* Create a management interface password */ GetRandomPassword(c->manage.password, sizeof(c->manage.password) - 1); + find_free_tcp_port(&c->manage.skaddr); + /* Construct command line -- put log first */ _sntprintf_0(cmdline, _T("openvpn --log%ls \"%ls\" --config \"%ls\" " "--setenv IV_GUI_VER \"%hs\" --setenv IV_SSO openurl,crtext --service %ls 0 --auth-retry interact "