From patchwork Sun Mar 9 12:50:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4172 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:41ba:b0:60a:d70a:d3c7 with SMTP id a26csp511394mad; Sun, 9 Mar 2025 05:51:07 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVaKN6v3qDtR3l/j3do8N/MLccrkPqQ37VdXWsf/gZKu3JSB+CpvveD4mQgqjH1WjFNHid8r7741iM=@openvpn.net X-Google-Smtp-Source: AGHT+IGvdpkxMleqzXhqmp6M4ln/GzTBDBJE+77QIV8csk7Sctt+A/Wr+PpYJ4caNoW10zzBKLYM X-Received: by 2002:a05:6830:6d17:b0:72a:15c8:206e with SMTP id 46e09a7af769-72a37c4d849mr5340692a34.25.1741524667421; Sun, 09 Mar 2025 05:51:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1741524667; cv=none; d=google.com; s=arc-20240605; b=EdUdDn0THESZBGHdx3pWrdGH2N01E5x0kMva+yR4cEe5GOtsXl1kyaI/zT+16Csybt eCq/XjAAllp3t8+1BhTnrgLzVKP9PyE0HRn8WY8sMlxmvYrrCK6rxbnPmeRBaocJQLI8 B513HwpVxel9TB3EIX8Buo4uASriFP8B3RKGFnnc1tu9mg+QTmfRxTO3UAZRk9o/alEN /rTm5PnVL3uvFaGUiSPSRIIC5OWoU0ZYMScie7zg8U2cMgiAUPxS7gH4DO+ntsC+YJyi b9vlhM/AiQr5/wKKBGh9Mqt65AqBaO3Z/Qibt1/KqjJmWjpOgMg4cVOFp6Gosy5GJjt5 4d/g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature; bh=NRILmnXyeo44rHoPJSn04LRp395Ohkp9H9VXMpnehGI=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=KXmW0NAWxWxDj6khIcqU+iojYqdSW0Kd2r3d0UONpTIpQLTuOjXR9a8fG2xqGQTcdd IoO1v43V8OIkm+54UzZdPmbduoENSW/HdQnwenJNN5Fq0ennHlR8bufujFJq2nEXCdDN Tr7US3ewlf2bqP3cgZHKeRPTrrsXkgvVqXThUT5n/sH1AW1Yh06CjdGYstQ9t5HbcoLP yJpt5vfx6bRVo+0+2a5bsgAyoLicD83N0LneyfsdxRsAKjhS331aWbiNM403GAgWvGvc 4e7x5j+afhCa7mg+mjh5HMvH3nNPgSjt9T+rGGwvq3Ov04BVY7vgx+o7Mwsme4j53o1M ON1Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=e+fsDDIJ; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=SZlQILDG; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 46e09a7af769-72b827dc4c0si502768a34.14.2025.03.09.05.51.07 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 09 Mar 2025 05:51:07 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=e+fsDDIJ; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=SZlQILDG; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1trG7U-0006Yc-ML; Sun, 09 Mar 2025 12:51:05 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1trG7R-0006Y1-2j for openvpn-devel@lists.sourceforge.net; Sun, 09 Mar 2025 12:51:01 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=esRKkqg3X9w8D4xD1cP86E0UtZ6U1ZPpBngqycg6pLg=; b=e+fsDDIJxIFKn08WTPR4GoUZ8x gAnAZ6u/9kprU1r7hbzRqGtOWaYMWIxkHOzNcYqJXSsA0k/I+YqVrfXSbDPfCns9NHbtVnd0V2YvZ UDT5oXBFXiR5YskhsKClg3Cfe0mwr5s5EP+5tv3IigRoFX6FS1I2QnsZWqJm7e+Yhd6M=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=esRKkqg3X9w8D4xD1cP86E0UtZ6U1ZPpBngqycg6pLg=; b=SZlQILDG5kk432XcBL3B5fjzGv V/PvlNZssbDPZivRH3jwhAnngUixQr3fHiAop6pDTgQKgl8wiFZmd84aPefv95qJ3VDMqoM5o1+3G Ycvs6jvC42b0I422UxFr96Ch7ox+6N/VMmsz9eG/aBO2qi5qapAxzCw97onVd39B30P4=; Received: from dhcp-174.greenie.muc.de ([193.149.48.174] helo=blue.greenie.muc.de) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1trG7D-0002Ur-UR for openvpn-devel@lists.sourceforge.net; Sun, 09 Mar 2025 12:50:59 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.17.1.9/8.17.1.9) with ESMTP id 529CofXj005052 for ; Sun, 9 Mar 2025 13:50:41 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 529CofBB005051 for openvpn-devel@lists.sourceforge.net; Sun, 9 Mar 2025 13:50:41 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Sun, 9 Mar 2025 13:50:40 +0100 Message-ID: <20250309125040.5041-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Heiko Hund Instead of spawning a netsh process, set the name server addresses directly in the registry hive of the VPN interface. This is a first step to get rid of the use of command line tools in the service and move to a more API driven style of modifying the VPN adapter configuration. Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [193.149.48.174 listed in bl.score.senderscore.com] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [193.149.48.174 listed in sa-trusted.bondedsender.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1trG7D-0002Ur-UR Subject: [Openvpn-devel] [PATCH v12] dns: do not use netsh to set name server addresses X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1826120969444554391?= X-GMAIL-MSGID: =?utf-8?q?1826120969444554391?= From: Heiko Hund Instead of spawning a netsh process, set the name server addresses directly in the registry hive of the VPN interface. This is a first step to get rid of the use of command line tools in the service and move to a more API driven style of modifying the VPN adapter configuration. Change-Id: Id2bed0908e84c19b8fb6fe806376316793e550b4 Signed-off-by: Heiko Hund Acked-by: Lev Stipakov --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/825 This mail reflects revision 12 of this Change. Acked-by according to Gerrit (reflected above): Lev Stipakov diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index a76d908..13a6091 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1024,65 +1024,6 @@ } /** - * Run the command: netsh interface $proto $action dns $if_name $addr [validate=no] - * @param action "delete" or "add" - * @param proto "ipv6" or "ip" - * @param if_name "name_of_interface" - * @param addr IPv4 (for proto = ip) or IPv6 address as a string - * - * If addr is null and action = "delete" all addresses are deleted. - */ -static DWORD -netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr) -{ - DWORD err = 0; - int timeout = 30000; /* in msec */ - wchar_t argv0[MAX_PATH]; - wchar_t *cmdline = NULL; - - if (!addr) - { - if (wcscmp(action, L"delete") == 0) - { - addr = L"all"; - } - else /* nothing to do -- return success*/ - { - goto out; - } - } - - /* Path of netsh */ - swprintf(argv0, _countof(argv0), L"%ls\\%ls", get_win_sys_path(), L"netsh.exe"); - - /* cmd template: - * netsh interface $proto $action dns $if_name $addr [validate=no] - */ - const wchar_t *fmt = L"netsh interface %ls %ls dns \"%ls\" %ls"; - - /* max cmdline length in wchars -- include room for worst case and some */ - size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; - cmdline = malloc(ncmdline*sizeof(wchar_t)); - if (!cmdline) - { - err = ERROR_OUTOFMEMORY; - goto out; - } - - swprintf(cmdline, ncmdline, fmt, proto, action, if_name, addr); - - if (IsWindows7OrGreater()) - { - wcscat_s(cmdline, ncmdline, L" validate=no"); - } - err = ExecCommand(argv0, cmdline, timeout); - -out: - free(cmdline); - return err; -} - -/** * Run the command: netsh interface ip $action wins $if_name [static] $addr * @param action "delete", "add" or "set" * @param if_name "name_of_interface" @@ -1139,22 +1080,6 @@ return err; } -/* Delete all IPv4 or IPv6 dns servers for an interface */ -static DWORD -DeleteDNS(short family, wchar_t *if_name) -{ - wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; - return netsh_dns_cmd(L"delete", proto, if_name, NULL); -} - -/* Add an IPv4 or IPv6 dns server to an interface */ -static DWORD -AddDNS(short family, wchar_t *if_name, wchar_t *addr) -{ - wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; - return netsh_dns_cmd(L"add", proto, if_name, addr); -} - static BOOL CmpWString(LPVOID item, LPVOID str) { @@ -1818,11 +1743,115 @@ return err; } +/** + * Return the interfaces registry key for the specified address family + * + * @param family the internet address family to open the key for + * @param key PHKEY to return the key in + * @return BOOL to indicate success or failure + */ +static BOOL +GetInterfacesKey(short family, PHKEY key) +{ + PCSTR itfs_key = family == AF_INET6 + ? "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces" + : "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; + + LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS, key); + if (err) + { + *key = INVALID_HANDLE_VALUE; + MsgToEventLog(M_SYSERR, TEXT("GetInterfacesKey: " + "could not open interfaces registry key for family %d (%lu)"), + family, err); + } + + return err ? FALSE : TRUE; +} + +/** + * Set the DNS name servers in a registry interface configuration + * + * @param itf_id the interface id to set the servers for + * @param family internet address family to set the servers for + * @param value the value to set the name servers to + * + * @return DWORD NO_ERROR on success, a Windows error code otherwise + */ +static DWORD +SetNameServersValue(PCWSTR itf_id, short family, PCSTR value) +{ + DWORD err; + + HKEY itfs; + if (!GetInterfacesKey(family, &itfs)) + { + return ERROR_FILE_NOT_FOUND; + } + + HKEY itf = INVALID_HANDLE_VALUE; + err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf); + if (err) + { + MsgToEventLog(M_SYSERR, TEXT("SetNameServersValue: " + "could not open interface key for %s family %d (%lu)"), + itf_id, family, err); + goto out; + } + + err = RegSetValueExA(itf, "NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1); + if (err) + { + MsgToEventLog(M_SYSERR, TEXT("SetNameServersValue: " + "could not set name servers '%S' for %s family %d (%lu)"), + value, itf_id, family, err); + } + +out: + if (itf != INVALID_HANDLE_VALUE) + { + RegCloseKey(itf); + } + if (itfs != INVALID_HANDLE_VALUE) + { + RegCloseKey(itfs); + } + return err; +} + +/** + * Set the DNS name servers in a registry interface configuration + * + * @param itf_id the interface id to set the servers for + * @param family internet address family to set the servers for + * @param addrs comma separated list of name server addresses + * + * @return DWORD NO_ERROR on success, a Windows error code otherwise + */ +static DWORD +SetNameServers(PCWSTR itf_id, short family, PCSTR addrs) +{ + return SetNameServersValue(itf_id, family, addrs); +} + +/** + * Delete all DNS name servers from a registry interface configuration + * + * @param itf_id the interface id to clear the servers for + * @param family internet address family to clear the servers for + * + * @return DWORD NO_ERROR on success, a Windows error code otherwise + */ +static DWORD +ResetNameServers(PCWSTR itf_id, short family) +{ + return SetNameServersValue(itf_id, family, ""); +} + static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists) { DWORD err = 0; - wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */ undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6; int addr_len = msg->addr_len; @@ -1844,10 +1873,11 @@ msgptr->domains[_countof(msg->domains)-1] = '\0'; } - wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */ - if (!wide_name) + WCHAR iid[64]; + err = InterfaceIdString(msg->iface.name, iid, _countof(iid)); + if (err) { - return ERROR_OUTOFMEMORY; + return err; } /* We delete all current addresses before adding any @@ -1855,12 +1885,12 @@ */ if (addr_len > 0 || msg->header.type == msg_del_dns_cfg) { - err = DeleteDNS(msg->family, wide_name); + err = ResetNameServers(iid, msg->family); if (err) { - goto out; + return err; } - free(RemoveListItem(&(*lists)[undo_type], CmpWString, wide_name)); + free(RemoveListItem(&(*lists)[undo_type], CmpAny, iid)); } if (msg->header.type == msg_del_dns_cfg) @@ -1872,40 +1902,43 @@ err = SetDnsSearchDomains(msg->iface.name, NULL, &gpol, lists); } ApplyDnsSettings(gpol); - goto out; /* job done */ + return err; /* job done */ } - for (int i = 0; i < addr_len; ++i) - { - if (msg->family == AF_INET6) - { - RtlIpv6AddressToStringW(&msg->addr[i].ipv6, addr); - } - else - { - RtlIpv4AddressToStringW(&msg->addr[i].ipv4, addr); - } - err = AddDNS(msg->family, wide_name, addr); - if (i == 0 && err) - { - goto out; - } - /* We do not check for duplicate addresses, so any error in adding - * additional addresses is ignored. - */ - } - - err = 0; - if (msg->addr_len > 0) { - wchar_t *tmp_name = _wcsdup(wide_name); - if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name)) + /* prepare the comma separated address list */ + CHAR addrs[256]; /* large enough to hold four IPv4 / IPv6 address strings */ + size_t offset = 0; + for (int i = 0; i < addr_len; ++i) { - free(tmp_name); - DeleteDNS(msg->family, wide_name); - err = ERROR_OUTOFMEMORY; - goto out; + if (i != 0) + { + addrs[offset++] = ','; + } + if (msg->family == AF_INET6) + { + RtlIpv6AddressToStringA(&msg->addr[i].ipv6, addrs + offset); + } + else + { + RtlIpv4AddressToStringA(&msg->addr[i].ipv4, addrs + offset); + } + offset += strlen(addrs); + } + + err = SetNameServers(iid, msg->family, addrs); + if (err) + { + return err; + } + + wchar_t *tmp_iid = _wcsdup(iid); + if (!tmp_iid || AddListItem(&(*lists)[undo_type], tmp_iid)) + { + free(tmp_iid); + ResetNameServers(iid, msg->family); + return ERROR_OUTOFMEMORY; } } @@ -1916,8 +1949,6 @@ } ApplyDnsSettings(gpol); -out: - free(wide_name); return err; } @@ -2298,11 +2329,11 @@ break; case undo_dns4: - DeleteDNS(AF_INET, item->data); + ResetNameServers(item->data, AF_INET); break; case undo_dns6: - DeleteDNS(AF_INET6, item->data); + ResetNameServers(item->data, AF_INET6); break; case undo_domains: