From patchwork Sat Oct 11 08:22:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4498 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:7d42:b0:72f:f16c:e055 with SMTP id fr2csp826933mab; Sat, 11 Oct 2025 01:22:36 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWgp+3xL9WdS/bicjqNuc0xt/l+SBYRLk1boWrKKbKJTV0333BYhpxABjT15yAVbLO6GhUKmRIKehg=@openvpn.net X-Google-Smtp-Source: AGHT+IFfOpwdAi5HxHgaSk3kPNCdFyqgAnV1FbL3dIc0uV2RwLXIoiXGUhZHRkGwy0s1h7f2cBwV X-Received: by 2002:a05:6808:1185:b0:441:8f74:f2d with SMTP id 5614622812f47-4418f742138mr3646105b6e.55.1760170956477; Sat, 11 Oct 2025 01:22:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1760170956; cv=none; d=google.com; s=arc-20240605; b=igsArXpPAa3llF0lySb9idN9S6dXP34sC9tEW1p4vodUBn9q3WP/ZzRl1RM0dXbueU QanlcbhyklTEESZWd2XPJZjhCEgJOBGd/l4uBjytI7t/2hTZtwU8NuWuvz3+Uj6NQ45W b9G0o2PmSf9KcN+EKu2n+PcjAg1tEBGVPKsaokDrYd1bhVwsHiMJgJJIstP1xa9aSu1V WYberygvxQREmQrmmgy2+W0Y8C1ChzrTbNBLF7T/WiBfnLZdq+L0l6lqhvvznFS2Rbvi 8EWTFLRpvFEc3cGiK2CnOyTNEPcRhSqOsolq+nEPQ8FOflWl3ukrcwlRWvSFqTi50f8Y VyEg== 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:dkim-signature; bh=KIVz8FapuFXcLJzNQ1Y4pUG8qAUwUk50y0Vm5LLIZpk=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=bA8hQa5eXYgEwRQ3UXTvqYowPi1gPjwwbbk1/dT8+ArJgJjO16WiP0IS4gKkP2JOdS qXcwWuLRAzW76zkXvuxht+7nz7LHkhNTGwhlyPcsj3yL8Ua4n+WRRSmnM/ebz7Ry8Lxe aHUv2mzkjfZWElVjErLOQxvhEaCNUZ3d/09rOT06ss9wku4joxMBhrOZ6hZ6vsu+mzYq 1TQ0Okhx9ufLzaN4sXS7z1oAdjYtG75hfWMoJ+4Czj9CmOdh5J4N6KY6iVskUAs8AS9v I1U+mXEIWEaWiVl5dK/CPjYrAOFJ8jLl6CarPtmVsFyei00W1UbZLD9f9ujUbUjFC73g eRLQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=i+8P+MWs; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=J1M9Tkyn; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=BhI9TUf2; 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-441989a9638si1003920b6e.216.2025.10.11.01.22.36 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 11 Oct 2025 01:22:36 -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=pass header.i=@lists.sourceforge.net header.s=beta header.b=i+8P+MWs; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=J1M9Tkyn; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=BhI9TUf2; 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 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=KIVz8FapuFXcLJzNQ1Y4pUG8qAUwUk50y0Vm5LLIZpk=; b=i+8P+MWslmyVRwJcoT79GE+X+0 wV5XWItaz4zDj55rBG/gdNqE+alK8nKTCNQm54+bTzKXvkiZ4Gntqu4umc6WMgesGO4maGuuoov/k xv3cOy1MHrvkmjVnwYKo4RbCT+Gd07hI57f4FNOR14VmilDY6wnh9pOlAXJUgxNrle8o=; 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 1v7Us5-0004vj-G4; Sat, 11 Oct 2025 08:22:33 +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 1v7Us3-0004us-Fo for openvpn-devel@lists.sourceforge.net; Sat, 11 Oct 2025 08:22:31 +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=eOZsx8l6PjRe5ZSro7omiQkM/e3Ambz2JJk7D7vdqPY=; b=J1M9TkynwqMd2PwS5tSB8e5Yby 9HvsMBVJlnqlUUvAoztlJu6Myl5xPN8DaWXbmmaeY6XPsmt7KUcINmZgalCKhDJxKBrFWvBqWh1be 1qtsYelj2mXDoskrK9PV6iaT6IBK7pE+VfYz+50GKBQJgwfJfMsKEmyN+dRaF50TTiRE=; 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=eOZsx8l6PjRe5ZSro7omiQkM/e3Ambz2JJk7D7vdqPY=; b=BhI9TUf23DQuHZVBa1ix3ygCOw yrqEdFTsj63iD5Sn4pTWJkUR79LrRyImFtgQ5cuD92dfDOfRVC55jRmfK3QQXZjYkl3uRtsdX0fAK zEVCRnNDqXjVgiMyWALNFt5a68wb9VbX1xPk9MeMXJ9oQwlMHpmETGBXnxmTl/WczYDQ=; Received: from [193.149.48.134] (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 1v7Us1-0002fi-Te for openvpn-devel@lists.sourceforge.net; Sat, 11 Oct 2025 08:22:31 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.18.1/8.18.1) with ESMTP id 59B8MIbR027587 for ; Sat, 11 Oct 2025 10:22:18 +0200 Received: (from gert@localhost) by blue.greenie.muc.de (8.18.1/8.18.1/Submit) id 59B8MIdc027586 for openvpn-devel@lists.sourceforge.net; Sat, 11 Oct 2025 10:22:18 +0200 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Sat, 11 Oct 2025 10:22:11 +0200 Message-ID: <20251011082217.27568-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.49.1 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: 1.3 (+) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", 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: Frank Lichtenheld Seems suitably related and tun.c is one of the huge ones. In preparation of adding UTs for the code. Content analysis details: (1.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 1.3 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1v7Us1-0002fi-Te Subject: [Openvpn-devel] [PATCH v1] Move build_dhcp_options_string from tun to dhcp 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?1845673020956205512?= X-GMAIL-MSGID: =?utf-8?q?1845673020956205512?= From: Frank Lichtenheld Seems suitably related and tun.c is one of the huge ones. In preparation of adding UTs for the code. Change-Id: I62a8f62b9c0938cfcb99d184b07034515c076303 Signed-off-by: Frank Lichtenheld Acked-by: Gert Doering Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1265 --- 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/+/1265 This mail reflects revision 1 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering diff --git a/src/openvpn/dhcp.c b/src/openvpn/dhcp.c index 850a4b6..653127d 100644 --- a/src/openvpn/dhcp.c +++ b/src/openvpn/dhcp.c @@ -185,3 +185,203 @@ } return 0; } + +#if defined(_WIN32) + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +/* + * Convert DHCP options from the command line / config file + * into a raw DHCP-format options string. + */ + +static void +write_dhcp_u8(struct buffer *buf, const int type, const int data, bool *error) +{ + if (!buf_safe(buf, 3)) + { + *error = true; + msg(M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); + return; + } + buf_write_u8(buf, type); + buf_write_u8(buf, 1); + buf_write_u8(buf, data); +} + +static void +write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, + const unsigned int len, bool *error) +{ + if (len > 0) + { + int i; + const int size = len * sizeof(uint32_t); + + if (!buf_safe(buf, 2 + size)) + { + *error = true; + msg(M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); + return; + } + if (size < 1 || size > 255) + { + *error = true; + msg(M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); + return; + } + buf_write_u8(buf, type); + buf_write_u8(buf, size); + for (i = 0; i < len; ++i) + { + buf_write_u32(buf, data[i]); + } + } +} + +static void +write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error) +{ + const int len = strlen(str); + if (!buf_safe(buf, 2 + len)) + { + *error = true; + msg(M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); + return; + } + if (len < 1 || len > 255) + { + *error = true; + msg(M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); + return; + } + buf_write_u8(buf, type); + buf_write_u8(buf, len); + buf_write(buf, str, len); +} + +/* + * RFC3397 states that multiple searchdomains are encoded as follows: + * - at start the length of the entire option is given + * - each subdomain is preceded by its length + * - each searchdomain is separated by a NUL character + * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with + * 0x1D 0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00 + */ +static void +write_dhcp_search_str(struct buffer *buf, const int type, const char *const *str_array, + int array_len, bool *error) +{ + char tmp_buf[256]; + int i; + int len = 0; + int label_length_pos; + + for (i = 0; i < array_len; i++) + { + const char *ptr = str_array[i]; + + if (strlen(ptr) + len + 1 > sizeof(tmp_buf)) + { + *error = true; + msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options"); + return; + } + /* Loop over all subdomains separated by a dot and replace the dot + * with the length of the subdomain */ + + /* label_length_pos points to the byte to be replaced by the length + * of the following domain label */ + label_length_pos = len++; + + while (true) + { + if (*ptr == '.' || *ptr == '\0') + { + tmp_buf[label_length_pos] = (len - label_length_pos) - 1; + label_length_pos = len; + if (*ptr == '\0') + { + break; + } + } + tmp_buf[len++] = *ptr++; + } + /* And close off with an extra NUL char */ + tmp_buf[len++] = 0; + } + + if (!buf_safe(buf, 2 + len)) + { + *error = true; + msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options"); + return; + } + if (len > 255) + { + *error = true; + msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes"); + return; + } + + buf_write_u8(buf, type); + buf_write_u8(buf, len); + buf_write(buf, tmp_buf, len); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +bool +build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o) +{ + bool error = false; + if (o->domain) + { + write_dhcp_str(buf, 15, o->domain, &error); + } + + if (o->netbios_scope) + { + write_dhcp_str(buf, 47, o->netbios_scope, &error); + } + + if (o->netbios_node_type) + { + write_dhcp_u8(buf, 46, o->netbios_node_type, &error); + } + + write_dhcp_u32_array(buf, 6, (uint32_t *)o->dns, o->dns_len, &error); + write_dhcp_u32_array(buf, 44, (uint32_t *)o->wins, o->wins_len, &error); + write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error); + write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error); + + if (o->domain_search_list_len > 0) + { + write_dhcp_search_str(buf, 119, o->domain_search_list, o->domain_search_list_len, &error); + } + + /* the MS DHCP server option 'Disable Netbios-over-TCP/IP + * is implemented as vendor option 001, value 002. + * A value of 001 means 'leave NBT alone' which is the default */ + if (o->disable_nbt) + { + if (!buf_safe(buf, 8)) + { + msg(M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); + return false; + } + buf_write_u8(buf, 43); + buf_write_u8(buf, 6); /* total length field */ + buf_write_u8(buf, 0x001); + buf_write_u8(buf, 4); /* length of the vendor specified field */ + buf_write_u32(buf, 0x002); + } + return !error; +} + +#endif /* defined(_WIN32) */ diff --git a/src/openvpn/dhcp.h b/src/openvpn/dhcp.h index af5c2c4..8e15a39 100644 --- a/src/openvpn/dhcp.h +++ b/src/openvpn/dhcp.h @@ -84,4 +84,10 @@ in_addr_t dhcp_extract_router_msg(struct buffer *ipbuf); +#if defined(_WIN32) +#include "tun.h" + +bool build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o); +#endif + #endif /* ifndef DHCP_H */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index e35f889..097b9e8 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -45,6 +45,7 @@ #include "win32.h" #include "wfp_block.h" #include "networking.h" +#include "dhcp.h" #include "memdbg.h" @@ -5554,202 +5555,6 @@ return ret; } -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - -/* - * Convert DHCP options from the command line / config file - * into a raw DHCP-format options string. - */ - -static void -write_dhcp_u8(struct buffer *buf, const int type, const int data, bool *error) -{ - if (!buf_safe(buf, 3)) - { - *error = true; - msg(M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); - return; - } - buf_write_u8(buf, type); - buf_write_u8(buf, 1); - buf_write_u8(buf, data); -} - -static void -write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, - const unsigned int len, bool *error) -{ - if (len > 0) - { - int i; - const int size = len * sizeof(uint32_t); - - if (!buf_safe(buf, 2 + size)) - { - *error = true; - msg(M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); - return; - } - if (size < 1 || size > 255) - { - *error = true; - msg(M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); - return; - } - buf_write_u8(buf, type); - buf_write_u8(buf, size); - for (i = 0; i < len; ++i) - { - buf_write_u32(buf, data[i]); - } - } -} - -static void -write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error) -{ - const int len = strlen(str); - if (!buf_safe(buf, 2 + len)) - { - *error = true; - msg(M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); - return; - } - if (len < 1 || len > 255) - { - *error = true; - msg(M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); - return; - } - buf_write_u8(buf, type); - buf_write_u8(buf, len); - buf_write(buf, str, len); -} - -/* - * RFC3397 states that multiple searchdomains are encoded as follows: - * - at start the length of the entire option is given - * - each subdomain is preceded by its length - * - each searchdomain is separated by a NUL character - * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with - * 0x1D 0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00 - */ -static void -write_dhcp_search_str(struct buffer *buf, const int type, const char *const *str_array, - int array_len, bool *error) -{ - char tmp_buf[256]; - int i; - int len = 0; - int label_length_pos; - - for (i = 0; i < array_len; i++) - { - const char *ptr = str_array[i]; - - if (strlen(ptr) + len + 1 > sizeof(tmp_buf)) - { - *error = true; - msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options"); - return; - } - /* Loop over all subdomains separated by a dot and replace the dot - * with the length of the subdomain */ - - /* label_length_pos points to the byte to be replaced by the length - * of the following domain label */ - label_length_pos = len++; - - while (true) - { - if (*ptr == '.' || *ptr == '\0') - { - tmp_buf[label_length_pos] = (len - label_length_pos) - 1; - label_length_pos = len; - if (*ptr == '\0') - { - break; - } - } - tmp_buf[len++] = *ptr++; - } - /* And close off with an extra NUL char */ - tmp_buf[len++] = 0; - } - - if (!buf_safe(buf, 2 + len)) - { - *error = true; - msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options"); - return; - } - if (len > 255) - { - *error = true; - msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes"); - return; - } - - buf_write_u8(buf, type); - buf_write_u8(buf, len); - buf_write(buf, tmp_buf, len); -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -static bool -build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o) -{ - bool error = false; - if (o->domain) - { - write_dhcp_str(buf, 15, o->domain, &error); - } - - if (o->netbios_scope) - { - write_dhcp_str(buf, 47, o->netbios_scope, &error); - } - - if (o->netbios_node_type) - { - write_dhcp_u8(buf, 46, o->netbios_node_type, &error); - } - - write_dhcp_u32_array(buf, 6, (uint32_t *)o->dns, o->dns_len, &error); - write_dhcp_u32_array(buf, 44, (uint32_t *)o->wins, o->wins_len, &error); - write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error); - write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error); - - if (o->domain_search_list_len > 0) - { - write_dhcp_search_str(buf, 119, o->domain_search_list, o->domain_search_list_len, &error); - } - - /* the MS DHCP server option 'Disable Netbios-over-TCP/IP - * is implemented as vendor option 001, value 002. - * A value of 001 means 'leave NBT alone' which is the default */ - if (o->disable_nbt) - { - if (!buf_safe(buf, 8)) - { - msg(M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); - return false; - } - buf_write_u8(buf, 43); - buf_write_u8(buf, 6); /* total length field */ - buf_write_u8(buf, 0x001); - buf_write_u8(buf, 4); /* length of the vendor specified field */ - buf_write_u32(buf, 0x002); - } - return !error; -} - static void fork_dhcp_action(struct tuntap *tt) {