From patchwork Wed Mar 12 10:11:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4177 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:a706:b0:60a:d70a:d3c7 with SMTP id hl6csp130100mab; Wed, 12 Mar 2025 03:12:28 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCUkKZtA8r9UXO9Jr9SmVALs+RoYucd2enO88hLaKu9UzL/5fle468ZwHcbekWFXhtp0ViYtufjdpCc=@openvpn.net X-Google-Smtp-Source: AGHT+IHlxZbHWhu+KCa4k/FhiqJwyx8JCEQ3eGL+R0IhOA+UoRGAYpMSfPFzgkJ5xjCY2ktOn3d+ X-Received: by 2002:a05:6808:138a:b0:3fb:2e8f:4dd8 with SMTP id 5614622812f47-3fb2e8f5084mr1829578b6e.15.1741774347943; Wed, 12 Mar 2025 03:12:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1741774347; cv=none; d=google.com; s=arc-20240605; b=GqD2t0dQWVwB03mvLZ/YHM7yMfc1EqD31773TYntkXo36hEbvxuaQ4pkaov1Py/ceZ eWDb2RY4aqbz3wXSirNWq3DRW4FZGXqSzQ/BK+Kr0Kglowp0L/cOvVqA7My5YlBdE4Wi KDRB9PfemoqQe/0XruPJL+zZJ8Jd9VcOk6x5u7NO2Ms+B4taRp6d4EPUNJTccEoUmJ32 Le5mB1cPVnlxqNYgwwdPATTxVSb1ESkBrZVQF4VPCeHfW4OnSRax2FTr5/PT85yYuWYc ArcXK+4VP54pY1LawXzuHxYZYez5kiCUJ4qEh7EYwCG0DIPrnAQAABMGwKysDxEWVr7L fvrQ== 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=oCz5c7f1IqcsFUiX9ieOKD51ZwkLJVIoQ/6v6L+CnCI=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=P2qUm0P86yMhTs4ojCrJx6Xdybd7tnu748Q0T54hBHiHsVwYRjifGciBFnEy+A/5Ft QjxZWIZOrP+lrGpmCv+6nsylGAChfVRVnSpooWxJP2uiSQ14iNgLl6RYTDZITWPFmaFw PbVnsf1UE841e3pJDvCh5ssYNKboDhss3i3MLwopugvWL1LJVIyuAATsaTWXcQ8rmW+q 5OWrfcVIoZ+ZNli/OkyopwyHLDv8yLnDvbbsh4FJtPR/5b2v7HLqtT/LUUSn+4CqirrL ybALZowXvLG3Z8MLdomP8G43oE4CB4WsIfrs71r1m8/+GcepAeGh2+SUm0Nh2mNh04Hm pDRQ==; 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="dnGFlL/g"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Y1QgsHpi; 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 5614622812f47-3f6a400caf6si5142666b6e.76.2025.03.12.03.12.27 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 12 Mar 2025 03:12:27 -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="dnGFlL/g"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Y1QgsHpi; 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-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1tsJ4Z-0005hg-SN; Wed, 12 Mar 2025 10:12:23 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1tsJ4Y-0005hX-1q for openvpn-devel@lists.sourceforge.net; Wed, 12 Mar 2025 10:12:22 +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=rCkCuL1Y5Y8dBX5DpGFh+HWYrKcuw/TemL5MS6g7DZ0=; b=dnGFlL/gOnfZM1ie/lplYejP4H png9XAjDS3TFWDEIixPAkqDxZ4GjxsmVHiYBMbYVwzmmM/uvKc4ik7pt532opLi6CCpk5BuR1tesm xjUGA9pktU+bLL2HwxtQyllW/Pjbkv3OU4qo5cxvniz4AmYo7qRDVPHRFAnLMNLr5DUA=; 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=rCkCuL1Y5Y8dBX5DpGFh+HWYrKcuw/TemL5MS6g7DZ0=; b=Y1QgsHpi/PshFQEIB1kc8GVbAb aSOqcKE6FRI0SdDi7sywEr5vNXR0p5K/gRNgtq8fNYcMk5qEWLux+uYfZaSy44wjwX99LoXvYFpjC wqz7oUfCb9cFjeXWtlj3ErL4HqvPsoUWGkSkcMrIL/1BZV2GlfaVF3B704V8sr12Ysn0=; 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 1tsJ4M-0000pT-0H for openvpn-devel@lists.sourceforge.net; Wed, 12 Mar 2025 10:12:21 +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 52CABuU0005784 for ; Wed, 12 Mar 2025 11:11:56 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 52CABuUN005783 for openvpn-devel@lists.sourceforge.net; Wed, 12 Mar 2025 11:11:56 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Wed, 12 Mar 2025 11:11:50 +0100 Message-ID: <20250312101156.5756-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_CERTIFIED_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-accredit.habeas.com] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record X-Headers-End: 1tsJ4M-0000pT-0H Subject: [Openvpn-devel] [PATCH v13] 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?1826382778961951948?= 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 13 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 606ca4b..d5a749a 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) { @@ -1819,11 +1744,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; @@ -1845,10 +1874,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 @@ -1856,12 +1886,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) @@ -1873,40 +1903,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; } } @@ -1917,8 +1950,6 @@ } ApplyDnsSettings(gpol); -out: - free(wide_name); return err; } @@ -2299,11 +2330,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: