From patchwork Tue Jul 29 10:41:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4339 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:b86:b0:671:5a2c:6455 with SMTP id mw6csp103433mab; Tue, 29 Jul 2025 03:41:27 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVwJWDiLKF1/v5hIVniC4I7RK3JVTMKrMc23o2wVzO0xQZ8YW7cYGP1Ew5Wih2DoNvvh8+yaS932XA=@openvpn.net X-Google-Smtp-Source: AGHT+IFcN/eh95LIpCgoOkpXBYwPLAYngN6Hf/4Lh2Bwk63zR4EewEKYkmcrUalrB88PpKDbUnuN X-Received: by 2002:a05:6870:880f:b0:2b8:fab0:33c with SMTP id 586e51a60fabf-30701acf854mr9078310fac.23.1753785687134; Tue, 29 Jul 2025 03:41:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1753785687; cv=none; d=google.com; s=arc-20240605; b=OBxqxDIV4b4nuthb4NtgHfVkWQFP279bMd2j5s7fozuAKudzw1G9/8GwqNG3sN7H+M pAmOXHEKRnAz3s1sT7KDeRj7hq6vmroBCUPH/W3zFrvPgQrOwn0f0GnUr9mMWpQaPz9L ArhS1+ezox2AWYTl+7ie5+P3ywBeq7Mq25cVFMtGWUuILofayo8T3oevfiLCB6+G9B91 pFRvCo+zW9L1WmHC4z583mPeEYMQtyBPs1uJJ01103k7T3eN5NbQzbiT14oh/1vo5jWb hXtJdTHnZwdX+yGD7o2CidXRBG5EEyUO6NHsB+nrZA5n0/QPey4CWg/waZdT9ONxuHjd DEVA== 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=7nfA+Rm04Z/i/D8N6ihkn45ttLCl7yIAMC2HzvM13yQ=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=ZPFUw6hfqsBMP7nsSW2X280L+XW031H+hd3rE8cissU+JyjGkxU4Fj9YO64P4+weJo AfGn+5ywMBEe2qVTq1LLTGiMHOkfoSdjywS60KO08APuBiTSo3AgUCJLznARloC7GLFc tDLmlXO7yb/9HXQQALStaHcms5iY3nxhkUnZ4qifBmEcjQcJz3f7KEtlD1dPeSl9w1x8 3ha1licAQ4Mm8v5VrxnHbMKm+wiNkZ+S0wSg6bktvrya25NMc0xCl0jSdyjobjxOKD1U FEFwXp+H4YjOLSlMBIn9yE9wZ7tT6c7GKRXjPIlHN7rgpsNl6QiCKHy4XwplcEgFH/rD AS+A==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=G9VIhyUt; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=g6CQiHTA; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=V1nqU6V1; 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-74147f82a48si3026046a34.108.2025.07.29.03.41.26 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Jul 2025 03:41: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=pass header.i=@lists.sourceforge.net header.s=beta header.b=G9VIhyUt; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=g6CQiHTA; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=V1nqU6V1; 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=7nfA+Rm04Z/i/D8N6ihkn45ttLCl7yIAMC2HzvM13yQ=; b=G9VIhyUtDu5gPjteRGdmVQlRiV py+U1xmjRtmTxWgmJyzMZvQes3KlKVHMa5YSar0sSu1BQ3vsJ8k3MMsIU5P0bLcMGG9mklINUZ0WQ SSt0sbY0h+bEZqg/1FvVSw9jt4p9Kz3wC6993yQLIynrSe68y63+rsHomS9eACBkY1wY=; 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 1ughlt-0002Im-5E; Tue, 29 Jul 2025 10:41:25 +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 1ughlr-0002Ig-Tu for openvpn-devel@lists.sourceforge.net; Tue, 29 Jul 2025 10:41:23 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:Content-Type:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc: 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=hrSzjoXkbhBZhYGg1rbnUnXoNg0rRgdzbnb+JiOXxCI=; b=g6CQiHTAicnexHaRBgU7ez8n/f DPvox0wKf5ewnBOheFtyNplCZRXMB5gU+Gt/sCKpRs7ml30eMjnLWu2mDWJO2JYHjFDpFo66k3u7l JuPF30HKvCyWvUv9ULMZjp2wE1L2o2HY4OpmJ57qeO8gcSwgckbh8Z1NzoVb5Ycnq18k=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc: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=hrSzjoXkbhBZhYGg1rbnUnXoNg0rRgdzbnb+JiOXxCI=; b=V1nqU6V1tIdokhRaYqIbEYSRbO +nodEy4K5mD9gzoRb0qq932aVVAgqbirNWxijmQvEr5cLXoLlYLcqZkPwDQ71JP7XolRXenxEBMxB b/Wa8FjzGQpIWrVshs2ojodjSw8Lr8pfkB/adVqBsi4kxXLGH7pofRA5PsK8uRYCWUPg=; Received: from [193.149.48.143] (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 1ughlq-0003cK-Ix for openvpn-devel@lists.sourceforge.net; Tue, 29 Jul 2025 10:41:23 +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 56TAfBV9027733 for ; Tue, 29 Jul 2025 12:41:11 +0200 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 56TAfB87027732 for openvpn-devel@lists.sourceforge.net; Tue, 29 Jul 2025 12:41:11 +0200 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Tue, 29 Jul 2025 12:41:01 +0200 Message-ID: <20250729104110.27704-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.49.0 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: Marco Baffo When the function receives an option to update, it first checks whether it has already received an option of the same type within the same update message. If it has already received it, it simply call [...] 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: 1ughlq-0003cK-Ix Subject: [Openvpn-devel] [PATCH v23] PUSH_UPDATE: Added update_option() function. 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?1838977580778467319?= X-GMAIL-MSGID: =?utf-8?q?1838977580778467319?= From: Marco Baffo When the function receives an option to update, it first checks whether it has already received an option of the same type within the same update message. If it has already received it, it simply calls add_option(), otherwise it deletes all the values ​​already present regarding that option. Change-Id: Ia45c99e6df7b3ad24020c10b8a9b3577984ecdc2 Signed-off-by: Marco Baffo Acked-by: Gert Doering --- 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/+/810 This mail reflects revision 23 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 3a8ce86..f056263 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5372,6 +5372,20 @@ struct env_set *es); static void +update_option(struct context *c, + struct options *options, + char *p[], + bool is_inline, + const char *file, + int line, + const int level, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es, + unsigned int *update_options_found); + +static void read_config_file(struct options *options, const char *file, int level, @@ -5557,6 +5571,7 @@ int line_num = 0; const char *file = "[PUSH-OPTIONS]"; const int msglevel = D_PUSH_ERRORS|M_OPTERR; + unsigned int update_options_found = 0; while (buf_parse(buf, ',', line, sizeof(line))) { @@ -5602,6 +5617,11 @@ remove_option(c, options, p, false, file, line_num, msglevel, permission_mask, option_types_found, es); } + else + { + update_option(c, options, p, false, file, line_num, 0, msglevel, + permission_mask, option_types_found, es, &update_options_found); + } } } return true; @@ -5740,6 +5760,13 @@ return options->forward_compatible ? M_WARN : msglevel; } +#define RESET_OPTION_ROUTES(option_ptr, field) \ + if (option_ptr) \ + { \ + option_ptr->field = NULL; \ + option_ptr->flags = 0; \ + } + /** * @brief Resets options found in the PUSH_UPDATE message that are preceded by the `-` flag. * This function is used in push-updates to reset specified options. @@ -5794,11 +5821,7 @@ delete_routes_v4(c->c1.route_list, c->c1.tuntap, ROUTE_OPTION_FLAGS(&c->options), es, &c->net_ctx); - if (options->routes) - { - options->routes->routes = NULL; - options->routes->flags = 0; - } + RESET_OPTION_ROUTES(options->routes, routes); } } else if (streq(p[0], "route-ipv6") && !p[1]) @@ -5809,11 +5832,7 @@ delete_routes_v6(c->c1.route_ipv6_list, c->c1.tuntap, ROUTE_OPTION_FLAGS(&c->options), es, &c->net_ctx); - if (options->routes_ipv6) - { - options->routes_ipv6->routes_ipv6 = NULL; - options->routes_ipv6->flags = 0; - } + RESET_OPTION_ROUTES(options->routes_ipv6, routes_ipv6); } } else if (streq(p[0], "route-gateway") && !p[1]) @@ -5933,6 +5952,303 @@ msg(msglevel, "Error occurred trying to remove %s option", p[0]); } + +static bool +check_route_option(struct options *options, char *p[], const int msglevel, bool pull_mode) +{ + rol_check_alloc(options); + if (pull_mode) + { + if (!ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */ + { + msg(msglevel, "route parameter network/IP '%s' must be a valid address", p[1]); + return false; + } + if (p[2] && !ip_addr_dotted_quad_safe(p[2])) /* FQDN -- must be IP address */ + { + msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]); + return false; + } + if (p[3] && !ip_or_dns_addr_safe(p[3], options->allow_pull_fqdn) && !is_special_addr(p[3])) /* FQDN -- may be DNS name */ + { + msg(msglevel, "route parameter gateway '%s' must be a valid address", p[3]); + return false; + } + } + return true; +} + + +static bool +check_route6_option(struct options *options, char *p[], const int msglevel, bool pull_mode) +{ + rol6_check_alloc(options); + if (pull_mode) + { + if (!ipv6_addr_safe_hexplusbits(p[1])) + { + msg(msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); + return false; + } + if (p[2] && !ipv6_addr_safe(p[2])) + { + msg(msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); + return false; + } + /* p[3] is metric, if present */ + } + return true; +} + +static bool +check_dns_option(struct options *options, char *p[], const int msglevel, bool pull_mode) +{ + if (streq(p[1], "search-domains") && p[2]) + { + dns_domain_list_append(&options->dns_options.search_domains, &p[2], &options->dns_options.gc); + } + else if (streq(p[1], "server") && p[2] && p[3] && p[4]) + { + long priority; + if (!dns_server_priority_parse(&priority, p[2], pull_mode)) + { + msg(msglevel, "--dns server: invalid priority value '%s'", p[2]); + return false; + } + + struct dns_server *server = dns_server_get(&options->dns_options.servers, priority, &options->dns_options.gc); + + if (streq(p[3], "address") && p[4]) + { + for (int i = 4; p[i]; ++i) + { + if (!dns_server_addr_parse(server, p[i])) + { + msg(msglevel, "--dns server %ld: malformed address or maximum exceeded '%s'", priority, p[i]); + return false; + } + } + } + else if (streq(p[3], "resolve-domains")) + { + dns_domain_list_append(&server->domains, &p[4], &options->dns_options.gc); + } + else if (streq(p[3], "dnssec") && !p[5]) + { + if (streq(p[4], "yes")) + { + server->dnssec = DNS_SECURITY_YES; + } + else if (streq(p[4], "no")) + { + server->dnssec = DNS_SECURITY_NO; + } + else if (streq(p[4], "optional")) + { + server->dnssec = DNS_SECURITY_OPTIONAL; + } + else + { + msg(msglevel, "--dns server %ld: malformed dnssec value '%s'", priority, p[4]); + return false; + } + } + else if (streq(p[3], "transport") && !p[5]) + { + if (streq(p[4], "plain")) + { + server->transport = DNS_TRANSPORT_PLAIN; + } + else if (streq(p[4], "DoH")) + { + server->transport = DNS_TRANSPORT_HTTPS; + } + else if (streq(p[4], "DoT")) + { + server->transport = DNS_TRANSPORT_TLS; + } + else + { + msg(msglevel, "--dns server %ld: malformed transport value '%s'", priority, p[4]); + return false; + } + } + else if (streq(p[3], "sni") && !p[5]) + { + server->sni = p[4]; + } + else + { + msg(msglevel, "--dns server %ld: unknown option type '%s' or missing or unknown parameter", priority, p[3]); + return false; + } + } + else + { + msg(msglevel, "--dns: unknown option type '%s' or missing or unknown parameter", p[1]); + return false; + } + return true; +} + +/** + * @brief Processes an option to update. It first checks whether it has already + * received an option of the same type within the same update message. + * If the option has already been received, it calls add_option(). + * Otherwise, it deletes all existing values related to that option before calling add_option(). + * + * @param c The context structure. + * @param options A pointer to the options structure. + * @param p An array of strings containing the options and their parameters. + * @param is_inline A boolean indicating if the option is inline. + * @param file The file where the function is called. + * @param line The line number where the function is called. + * @param level The level of the option. + * @param msglevel The message level for logging. + * @param permission_mask The permission mask used by VERIFY_PERMISSION(). + * @param option_types_found A pointer to the variable where the flags corresponding to the options found are stored. + * @param es The environment set structure. + * @param update_options_found A pointer to the variable where the flags corresponding to the update options found are stored, + * used to check if an option of the same type has already been processed by update_option() within the same push-update message. + */ +static void +update_option(struct context *c, + struct options *options, + char *p[], + bool is_inline, + const char *file, + int line, + const int level, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es, + unsigned int *update_options_found) +{ + const bool pull_mode = BOOL_CAST(permission_mask & OPT_P_PULL_MODE); + ASSERT(MAX_PARMS >= 7); + + if (streq(p[0], "route") && p[1] && !p[5]) + { + if (!(*update_options_found & OPT_P_U_ROUTE)) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + if (!check_route_option(options, p, msglevel, pull_mode)) + { + goto err; + } + if (c->c1.route_list) + { + delete_routes_v4(c->c1.route_list, c->c1.tuntap, + ROUTE_OPTION_FLAGS(&c->options), + es, &c->net_ctx); + RESET_OPTION_ROUTES(options->routes, routes); + } + *update_options_found |= OPT_P_U_ROUTE; + } + } + else if (streq(p[0], "route-ipv6") && p[1] && !p[4]) + { + if (!(*update_options_found & OPT_P_U_ROUTE6)) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + if (!check_route6_option(options, p, msglevel, pull_mode)) + { + goto err; + } + if (c->c1.route_ipv6_list) + { + delete_routes_v6(c->c1.route_ipv6_list, c->c1.tuntap, + ROUTE_OPTION_FLAGS(&c->options), + es, &c->net_ctx); + RESET_OPTION_ROUTES(options->routes_ipv6, routes_ipv6); + } + *update_options_found |= OPT_P_U_ROUTE6; + } + } + else if (streq(p[0], "redirect-gateway") || streq(p[0], "redirect-private")) + { + if (!(*update_options_found & OPT_P_U_REDIR_GATEWAY)) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + if (options->routes) + { + options->routes->flags = 0; + } + if (options->routes_ipv6) + { + options->routes_ipv6->flags = 0; + } + *update_options_found |= OPT_P_U_REDIR_GATEWAY; + } + } + else if (streq(p[0], "dns") && p[1]) + { + if (!(*update_options_found & OPT_P_U_DNS)) + { + VERIFY_PERMISSION(OPT_P_DHCPDNS); + if (!check_dns_option(options, p, msglevel, pull_mode)) + { + goto err; + } + gc_free(&options->dns_options.gc); + CLEAR(options->dns_options); + *update_options_found |= OPT_P_U_DNS; + } + } +#if defined(_WIN32) || defined(TARGET_ANDROID) + else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) + { + if (!(*update_options_found & OPT_P_U_DHCP)) + { + struct tuntap_options *o = &options->tuntap_options; + VERIFY_PERMISSION(OPT_P_DHCPDNS); + + o->domain = NULL; + o->netbios_scope = NULL; + o->netbios_node_type = 0; + o->dns6_len = 0; + CLEAR(o->dns6); + o->dns_len = 0; + CLEAR(o->dns); + o->wins_len = 0; + CLEAR(o->wins); + o->ntp_len = 0; + CLEAR(o->ntp); + o->nbdd_len = 0; + CLEAR(o->nbdd); + while (o->domain_search_list_len-- > 0) + { + o->domain_search_list[o->domain_search_list_len] = NULL; + } + o->disable_nbt = 0; + o->dhcp_options = 0; +#if defined(TARGET_ANDROID) + o->http_proxy_port = 0; + o->http_proxy = NULL; +#endif + *update_options_found |= OPT_P_U_DHCP; + } + } +#else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ + else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) + { + if (!(*update_options_found & OPT_P_U_DHCP)) + { + VERIFY_PERMISSION(OPT_P_DHCPDNS); + delete_all_dhcp_fo(options, &es->list); + *update_options_found |= OPT_P_U_DHCP; + } + } +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ + add_option(options, p, is_inline, file, line, + level, msglevel, permission_mask, + option_types_found, es); + return; +err: + msg(msglevel, "Error occurred trying to update %s option", p[0]); +} + static void set_user_script(struct options *options, const char **script, @@ -7296,45 +7612,18 @@ else if (streq(p[0], "route") && p[1] && !p[5]) { VERIFY_PERMISSION(OPT_P_ROUTE); - rol_check_alloc(options); - if (pull_mode) + if (!check_route_option(options, p, msglevel, pull_mode)) { - if (!ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */ - { - msg(msglevel, "route parameter network/IP '%s' must be a valid address", p[1]); - goto err; - } - if (p[2] && !ip_addr_dotted_quad_safe(p[2])) /* FQDN -- must be IP address */ - { - msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]); - goto err; - } - if (p[3] && !ip_or_dns_addr_safe(p[3], options->allow_pull_fqdn) && !is_special_addr(p[3])) /* FQDN -- may be DNS name */ - { - msg(msglevel, "route parameter gateway '%s' must be a valid address", p[3]); - goto err; - } - /* p[4] is metric, if specified */ + goto err; } add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4], options->route_default_table_id); } else if (streq(p[0], "route-ipv6") && p[1] && !p[4]) { VERIFY_PERMISSION(OPT_P_ROUTE); - rol6_check_alloc(options); - if (pull_mode) + if (!check_route6_option(options, p, msglevel, pull_mode)) { - if (!ipv6_addr_safe_hexplusbits(p[1])) - { - msg(msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); - goto err; - } - if (p[2] && !ipv6_addr_safe(p[2])) - { - msg(msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); - goto err; - } - /* p[3] is metric, if specified */ + goto err; } add_route_ipv6_to_option_list(options->routes_ipv6, p[1], p[2], p[3], options->route_default_table_id); } @@ -8422,90 +8711,8 @@ else if (streq(p[0], "dns") && p[1]) { VERIFY_PERMISSION(OPT_P_DHCPDNS); - - if (streq(p[1], "search-domains") && p[2]) + if (!check_dns_option(options, p, msglevel, pull_mode)) { - dns_domain_list_append(&options->dns_options.search_domains, &p[2], &options->dns_options.gc); - } - else if (streq(p[1], "server") && p[2] && p[3] && p[4]) - { - long priority; - if (!dns_server_priority_parse(&priority, p[2], pull_mode)) - { - msg(msglevel, "--dns server: invalid priority value '%s'", p[2]); - goto err; - } - - struct dns_server *server = dns_server_get(&options->dns_options.servers, priority, &options->dns_options.gc); - - if (streq(p[3], "address") && p[4]) - { - for (int i = 4; p[i]; ++i) - { - if (!dns_server_addr_parse(server, p[i])) - { - msg(msglevel, "--dns server %ld: malformed address or maximum exceeded '%s'", priority, p[i]); - goto err; - } - } - } - else if (streq(p[3], "resolve-domains")) - { - dns_domain_list_append(&server->domains, &p[4], &options->dns_options.gc); - } - else if (streq(p[3], "dnssec") && !p[5]) - { - if (streq(p[4], "yes")) - { - server->dnssec = DNS_SECURITY_YES; - } - else if (streq(p[4], "no")) - { - server->dnssec = DNS_SECURITY_NO; - } - else if (streq(p[4], "optional")) - { - server->dnssec = DNS_SECURITY_OPTIONAL; - } - else - { - msg(msglevel, "--dns server %ld: malformed dnssec value '%s'", priority, p[4]); - goto err; - } - } - else if (streq(p[3], "transport") && !p[5]) - { - if (streq(p[4], "plain")) - { - server->transport = DNS_TRANSPORT_PLAIN; - } - else if (streq(p[4], "DoH")) - { - server->transport = DNS_TRANSPORT_HTTPS; - } - else if (streq(p[4], "DoT")) - { - server->transport = DNS_TRANSPORT_TLS; - } - else - { - msg(msglevel, "--dns server %ld: malformed transport value '%s'", priority, p[4]); - goto err; - } - } - else if (streq(p[3], "sni") && !p[5]) - { - server->sni = p[4]; - } - else - { - msg(msglevel, "--dns server %ld: unknown option type '%s' or missing or unknown parameter", priority, p[3]); - goto err; - } - } - else - { - msg(msglevel, "--dns: unknown option type '%s' or missing or unknown parameter", p[1]); goto err; } }