You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
(24) |
May
(14) |
Jun
(29) |
Jul
(33) |
Aug
(3) |
Sep
(8) |
Oct
(18) |
Nov
(1) |
Dec
(10) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(3) |
Feb
(33) |
Mar
(7) |
Apr
(28) |
May
(30) |
Jun
(5) |
Jul
(10) |
Aug
(7) |
Sep
(32) |
Oct
(41) |
Nov
(20) |
Dec
(10) |
2004 |
Jan
(24) |
Feb
(18) |
Mar
(57) |
Apr
(40) |
May
(55) |
Jun
(48) |
Jul
(77) |
Aug
(15) |
Sep
(56) |
Oct
(80) |
Nov
(74) |
Dec
(52) |
2005 |
Jan
(38) |
Feb
(42) |
Mar
(39) |
Apr
(56) |
May
(79) |
Jun
(73) |
Jul
(16) |
Aug
(23) |
Sep
(68) |
Oct
(77) |
Nov
(52) |
Dec
(27) |
2006 |
Jan
(27) |
Feb
(18) |
Mar
(51) |
Apr
(62) |
May
(28) |
Jun
(50) |
Jul
(36) |
Aug
(33) |
Sep
(47) |
Oct
(50) |
Nov
(77) |
Dec
(13) |
2007 |
Jan
(15) |
Feb
(8) |
Mar
(14) |
Apr
(18) |
May
(25) |
Jun
(16) |
Jul
(16) |
Aug
(19) |
Sep
(32) |
Oct
(17) |
Nov
(5) |
Dec
(5) |
2008 |
Jan
(64) |
Feb
(25) |
Mar
(25) |
Apr
(6) |
May
(28) |
Jun
(20) |
Jul
(10) |
Aug
(27) |
Sep
(28) |
Oct
(59) |
Nov
(37) |
Dec
(43) |
2009 |
Jan
(40) |
Feb
(25) |
Mar
(12) |
Apr
(57) |
May
(46) |
Jun
(29) |
Jul
(39) |
Aug
(10) |
Sep
(20) |
Oct
(42) |
Nov
(50) |
Dec
(57) |
2010 |
Jan
(82) |
Feb
(165) |
Mar
(256) |
Apr
(260) |
May
(36) |
Jun
(87) |
Jul
(53) |
Aug
(89) |
Sep
(107) |
Oct
(51) |
Nov
(88) |
Dec
(117) |
2011 |
Jan
(69) |
Feb
(60) |
Mar
(113) |
Apr
(71) |
May
(67) |
Jun
(90) |
Jul
(88) |
Aug
(90) |
Sep
(48) |
Oct
(64) |
Nov
(69) |
Dec
(118) |
2012 |
Jan
(49) |
Feb
(528) |
Mar
(351) |
Apr
(190) |
May
(238) |
Jun
(193) |
Jul
(104) |
Aug
(100) |
Sep
(57) |
Oct
(41) |
Nov
(47) |
Dec
(51) |
2013 |
Jan
(94) |
Feb
(57) |
Mar
(96) |
Apr
(105) |
May
(77) |
Jun
(102) |
Jul
(27) |
Aug
(81) |
Sep
(32) |
Oct
(53) |
Nov
(127) |
Dec
(65) |
2014 |
Jan
(113) |
Feb
(59) |
Mar
(104) |
Apr
(259) |
May
(70) |
Jun
(70) |
Jul
(146) |
Aug
(45) |
Sep
(58) |
Oct
(149) |
Nov
(77) |
Dec
(83) |
2015 |
Jan
(53) |
Feb
(66) |
Mar
(86) |
Apr
(50) |
May
(135) |
Jun
(76) |
Jul
(151) |
Aug
(83) |
Sep
(97) |
Oct
(262) |
Nov
(245) |
Dec
(231) |
2016 |
Jan
(131) |
Feb
(233) |
Mar
(97) |
Apr
(138) |
May
(221) |
Jun
(254) |
Jul
(92) |
Aug
(248) |
Sep
(168) |
Oct
(275) |
Nov
(477) |
Dec
(445) |
2017 |
Jan
(218) |
Feb
(217) |
Mar
(146) |
Apr
(172) |
May
(216) |
Jun
(252) |
Jul
(164) |
Aug
(192) |
Sep
(190) |
Oct
(143) |
Nov
(255) |
Dec
(182) |
2018 |
Jan
(295) |
Feb
(164) |
Mar
(113) |
Apr
(147) |
May
(64) |
Jun
(262) |
Jul
(184) |
Aug
(90) |
Sep
(69) |
Oct
(364) |
Nov
(102) |
Dec
(101) |
2019 |
Jan
(119) |
Feb
(64) |
Mar
(64) |
Apr
(102) |
May
(57) |
Jun
(154) |
Jul
(84) |
Aug
(81) |
Sep
(76) |
Oct
(102) |
Nov
(233) |
Dec
(89) |
2020 |
Jan
(38) |
Feb
(170) |
Mar
(155) |
Apr
(172) |
May
(120) |
Jun
(223) |
Jul
(461) |
Aug
(227) |
Sep
(268) |
Oct
(113) |
Nov
(56) |
Dec
(124) |
2021 |
Jan
(121) |
Feb
(48) |
Mar
(334) |
Apr
(345) |
May
(207) |
Jun
(136) |
Jul
(71) |
Aug
(112) |
Sep
(122) |
Oct
(173) |
Nov
(184) |
Dec
(223) |
2022 |
Jan
(197) |
Feb
(206) |
Mar
(156) |
Apr
(212) |
May
(192) |
Jun
(170) |
Jul
(143) |
Aug
(380) |
Sep
(182) |
Oct
(148) |
Nov
(128) |
Dec
(269) |
2023 |
Jan
(248) |
Feb
(196) |
Mar
(264) |
Apr
(36) |
May
(123) |
Jun
(66) |
Jul
(120) |
Aug
(48) |
Sep
(157) |
Oct
(198) |
Nov
(300) |
Dec
(273) |
2024 |
Jan
(271) |
Feb
(147) |
Mar
(207) |
Apr
(78) |
May
(107) |
Jun
(168) |
Jul
(151) |
Aug
(51) |
Sep
(438) |
Oct
(221) |
Nov
(302) |
Dec
(357) |
2025 |
Jan
(451) |
Feb
(219) |
Mar
(326) |
Apr
(232) |
May
(306) |
Jun
(181) |
Jul
(452) |
Aug
(166) |
Sep
|
Oct
|
Nov
|
Dec
|
From: Gert D. <ge...@gr...> - 2025-07-29 10:41:10
|
From: Marco Baffo <ma...@ma...> * Added remove_option() function and some utility functions to remove options at runtime following the push-update logic. * Added do_update() function to close and reopen the tun and apply option updates. Change-Id: I507180d7397b6959844a30908010132bc3411067 Signed-off-by: Marco Baffo <ma...@ma...> Acked-by: Gert Doering <ge...@gr...> --- 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/+/809 This mail reflects revision 23 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering <ge...@gr...> diff --git a/src/openvpn/init.c b/src/openvpn/init.c index ba1dda4..3254cc6 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2470,7 +2470,7 @@ if (pulled_options) { - if (!do_deferred_options(c, option_types_found)) + if (!do_deferred_options(c, option_types_found, false)) { msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); return false; @@ -2594,6 +2594,55 @@ return true; } +bool +do_update(struct context *c, unsigned int option_types_found) +{ + /* Not necessary since to receive the update the openvpn + * instance must be up and running but just in case + */ + if (!c->c2.do_up_ran) + { + return false; + } + + bool tt_dco_win = tuntap_is_dco_win(c->c1.tuntap); + if (tt_dco_win) + { + msg(M_NONFATAL, "dco-win doesn't yet support reopening TUN device"); + return false; + } + + if (!do_deferred_options(c, option_types_found, true)) + { + msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); + return false; + } + + do_close_tun(c, true); + + management_sleep(1); + int error_flags = 0; + c->c2.did_open_tun = do_open_tun(c, &error_flags); + update_time(); + + if (c->c2.did_open_tun) + { + /* if --route-delay was specified, start timer */ + if ((route_order(c->c1.tuntap) == ROUTE_AFTER_TUN) && c->options.route_delay_defined) + { + event_timeout_init(&c->c2.route_wakeup, c->options.route_delay, now); + event_timeout_init(&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now); + tun_standby_init(c->c1.tuntap); + } + + initialization_sequence_completed(c, error_flags); + } + + CLEAR(c->c1.pulled_options_digest_save); + + return true; +} + /* * These are the option categories which will be accepted by pull. */ @@ -2672,11 +2721,8 @@ return true; } -/* - * Handle non-tun-related pulled options. - */ bool -do_deferred_options(struct context *c, const unsigned int found) +do_deferred_options(struct context *c, const unsigned int found, const bool is_update) { if (found & OPT_P_MESSAGES) { @@ -2784,7 +2830,10 @@ /* process (potentially) pushed options */ if (c->options.pull) { - if (!check_pull_client_ncp(c, found)) + /* On PUSH_UPDATE, NCP related flags are never updated, and so the code + * would assume "no cipher pushed = NCP failed" - so, don't call it on + * updates */ + if (!is_update && !check_pull_client_ncp(c, found)) { return false; } diff --git a/src/openvpn/init.h b/src/openvpn/init.h index 5c6b9c1..25078a6 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -86,13 +86,29 @@ bool pulled_options, unsigned int option_types_found); +/** + * @brief A simplified version of the do_up() function. This function is called + * after receiving a successful PUSH_UPDATE message. It closes and reopens + * the TUN device to apply the updated options. + * + * @param c The context structure. + * @param option_types_found The options found in the PUSH_UPDATE message. + * @return true on success. + * @return false on error. + */ +bool do_update(struct context *c, unsigned int option_types_found); + unsigned int pull_permission_mask(const struct context *c); const char *format_common_name(struct context *c, struct gc_arena *gc); void reset_coarse_timers(struct context *c); -bool do_deferred_options(struct context *c, const unsigned int found); +/* + * Handle non-tun-related pulled options. + * Set `is_update` param to true to skip NCP check. + */ +bool do_deferred_options(struct context *c, const unsigned int found, const bool is_update); void inherit_context_child(struct context *dest, const struct context *src, diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index b2d2b6c..68b4da6 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2424,7 +2424,7 @@ /* * Process sourced options. */ - do_deferred_options(&mi->context, option_types_found); + do_deferred_options(&mi->context, option_types_found, false); /* * make sure we got ifconfig settings from somewhere diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 2083eae..3a8ce86 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1086,6 +1086,40 @@ gc_free(&gc); } } + +static void +delete_all_dhcp_fo(struct options *o, struct env_item **list) +{ + struct env_item *current, *prev; + + ASSERT(list); + + for (current = *list, prev = NULL; current != NULL; current = current->next) + { + char *tmp_value = NULL; + if (!strncmp(current->string, "foreign_option_", sizeof("foreign_option_")-1)) + { + tmp_value = strchr(current->string, '='); + if (tmp_value && ++tmp_value) + { + if (!strncmp(tmp_value, "dhcp-option ", sizeof("dhcp-option ")-1)) + { + if (prev) + { + prev->next = current->next; + } + else + { + *list = current->next; + } + o->foreign_option_index--; + } + } + } + prev = current; + } +} + #endif /* ifndef _WIN32 */ static in_addr_t @@ -3091,7 +3125,7 @@ opt->routes->flags |= RG_DEF1; } } -#endif +#endif /* ifdef _WIN32 */ /* * Save/Restore certain option defaults before --pull is applied. @@ -5326,6 +5360,18 @@ struct env_set *es); static void +remove_option(struct context *c, + struct options *options, + char *p[], + bool is_inline, + const char *file, + int line, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); + +static void read_config_file(struct options *options, const char *file, int level, @@ -5551,6 +5597,11 @@ add_option(options, p, false, file, line_num, 0, msglevel, permission_mask, option_types_found, es); } + else if (push_update_option_flags & PUSH_OPT_TO_REMOVE) + { + remove_option(c, options, p, false, file, line_num, msglevel, + permission_mask, option_types_found, es); + } } } return true; @@ -5689,6 +5740,199 @@ return options->forward_compatible ? M_WARN : msglevel; } +/** + * @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. + * The number of parameters `p` must always be 1. If the permission is verified, + * all related options are erased or reset to their default values. + * Upon successful permission verification (by VERIFY_PERMISSION()), + * `option_types_found` is filled with the flag corresponding to the 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 msglevel The message level. + * @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. + */ +static void +remove_option(struct context *c, + struct options *options, + char *p[], + bool is_inline, + const char *file, + int line, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) +{ + int msglevel_fc = msglevel_forward_compatible(options, msglevel); + + if (streq(p[0], "ifconfig") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_local = NULL; + options->ifconfig_remote_netmask = NULL; + } + else if (streq(p[0], "ifconfig-ipv6") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_ipv6_local = NULL; + options->ifconfig_ipv6_netbits = 0; + options->ifconfig_ipv6_remote = NULL; + } + else if (streq(p[0], "route") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + if (c->c1.route_list) + { + 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; + } + } + } + else if (streq(p[0], "route-ipv6") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + 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); + if (options->routes_ipv6) + { + options->routes_ipv6->routes_ipv6 = NULL; + options->routes_ipv6->flags = 0; + } + } + } + else if (streq(p[0], "route-gateway") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); + options->route_gateway_via_dhcp = false; + options->route_default_gateway = NULL; + } + else if (streq(p[0], "route-metric") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + options->route_default_metric = 0; + } + else if (streq(p[0], "push-continuation") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PULL_MODE); + options->push_continuation = 0; + } + else if ((streq(p[0], "redirect-gateway") || streq(p[0], "redirect-private")) && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + if (options->routes) + { + options->routes->flags = 0; + } + if (options->routes_ipv6) + { + options->routes_ipv6->flags = 0; + } + } + else if (streq(p[0], "dns") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_DHCPDNS); + gc_free(&options->dns_options.gc); + CLEAR(options->dns_options); + } + else if (streq(p[0], "topology") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->topology = TOP_UNDEF; + helper_setdefault_topology(options); + } + else if (streq(p[0], "tun-mtu") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PUSH_MTU|OPT_P_CONNECTION); + options->ce.tun_mtu = TUN_MTU_DEFAULT; + options->ce.tun_mtu_defined = false; + options->ce.occ_mtu = 0; + } + else if (streq(p[0], "block-ipv6") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + options->block_ipv6 = false; + } +#if defined(_WIN32) || defined(TARGET_ANDROID) + else if (streq(p[0], "dhcp-option") && !p[1]) + { + 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; + memset(o->dns6, 0, sizeof(o->dns6)); + o->dns_len = 0; + memset(o->dns, 0, sizeof(o->dns)); + o->wins_len = 0; + memset(o->wins, 0, sizeof(o->wins)); + o->ntp_len = 0; + memset(o->ntp, 0, sizeof(o->ntp)); + o->nbdd_len = 0; + memset(o->nbdd, 0, sizeof(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 + } +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ +#ifdef _WIN32 + else if (streq(p[0], "block-outside-dns") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_DHCPDNS); + options->block_outside_dns = false; + } +#else /* ifdef _WIN32 */ + else if (streq(p[0], "dhcp-option") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_DHCPDNS); + delete_all_dhcp_fo(options, &es->list); + } +#endif + else + { + int i; + int msglevel_unknown = msglevel_fc; + /* Check if an option is in --ignore-unknown-option and + * set warning level to non fatal */ + for (i = 0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + { + if (streq(p[0], options->ignore_unknown_option[i])) + { + msglevel_unknown = M_WARN; + break; + } + } + msg(msglevel_unknown, "Unrecognized option or missing or extra parameter(s) in %s:%d: -%s (%s)", file, line, p[0], PACKAGE_VERSION); + } + return; +err: + msg(msglevel, "Error occurred trying to remove %s option", p[0]); +} + static void set_user_script(struct options *options, const char **script, diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 858b821..22082a9 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -542,6 +542,11 @@ { msg(M_WARN, "No updatable options found in incoming PUSH_UPDATE message"); } + else if (!do_update(c, option_types_found)) + { + msg(D_PUSH_ERRORS, "Failed to update options"); + goto error; + } } } event_timeout_clear(&c->c2.push_request_interval); diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 156262a..89ebaee 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1265,7 +1265,16 @@ const struct tuntap *tt, unsigned int flags, const struct env_set *es, openvpn_net_ctx_t *ctx) { - if (rl && rl->iflags & RL_ROUTES_ADDED) + delete_routes_v4(rl, tt, flags, es, ctx); + delete_routes_v6(rl6, tt, flags, es, ctx); +} + +void +delete_routes_v4(struct route_list *rl, const struct tuntap *tt, + unsigned int flags, const struct env_set *es, + openvpn_net_ctx_t *ctx) +{ + if (rl && (rl->iflags & RL_ROUTES_ADDED)) { struct route_ipv4 *r; for (r = rl->routes; r; r = r->next) @@ -1281,8 +1290,14 @@ { clear_route_list(rl); } +} - if (rl6 && (rl6->iflags & RL_ROUTES_ADDED) ) +void +delete_routes_v6(struct route_ipv6_list *rl6, const struct tuntap *tt, + unsigned int flags, const struct env_set *es, + openvpn_net_ctx_t *ctx) +{ + if (rl6 && (rl6->iflags & RL_ROUTES_ADDED)) { struct route_ipv6 *r6; for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 237375c..b89ec9f 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -335,6 +335,16 @@ const struct env_set *es, openvpn_net_ctx_t *ctx); +void +delete_routes_v4(struct route_list *rl, const struct tuntap *tt, + unsigned int flags, const struct env_set *es, + openvpn_net_ctx_t *ctx); + +void +delete_routes_v6(struct route_ipv6_list *rl6, const struct tuntap *tt, + unsigned int flags, const struct env_set *es, + openvpn_net_ctx_t *ctx); + void setenv_routes(struct env_set *es, const struct route_list *rl); void setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6); |
From: Gert D. <ge...@gr...> - 2025-07-29 10:40:54
|
From: Marco Baffo <ma...@ma...> * Added IV_PROTO_PUSH_UPDATE flag bit to support push-updates. * Added process_incoming_push_update(), in a separate file to create tests more easily. * Modified incoming_push_message(), process_incoming_push_msg(), apply_push_options(), apply_pull_filter() to process also push-update messages. * Added the check_push_update_option_flags() function used in apply_pull_filter() to check options formatting inside push-update messages, if the options are updatables and to check for '?' and '-' flags that may be present in front of the options. The '-' flag is used to indicate that the option in question should be removed, while the '?' indicates that the option is optional and to do not generate errors if the client cannot update that option. For more info you can read the RFC at https://github.com/OpenVPN/openvpn-rfc . * Created some unit tests for the push-update message handling in test_push_update_msg.c. Change-Id: I6ecd4cb47571cc8c20e46de8595c742aeec6064a Signed-off-by: Marco Baffo <ma...@ma...> Acked-by: Gert Doering <ge...@gr...> --- 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/+/808 This mail reflects revision 22 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering <ge...@gr...> diff --git a/CMakeLists.txt b/CMakeLists.txt index efb2d2d..3866e21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,6 +534,7 @@ src/openvpn/ps.c src/openvpn/ps.h src/openvpn/push.c + src/openvpn/push_util.c src/openvpn/push.h src/openvpn/pushlist.h src/openvpn/reflect_filter.c @@ -652,6 +653,7 @@ "test_provider" "test_ssl" "test_user_pass" + "test_push_update_msg" ) if (WIN32) @@ -854,6 +856,14 @@ src/openvpn/run_command.c ) + target_sources(test_push_update_msg PRIVATE + tests/unit_tests/openvpn/mock_msg.c + tests/unit_tests/openvpn/mock_get_random.c + src/openvpn/push_util.c + src/openvpn/options_util.c + src/openvpn/otime.c + ) + if (TARGET test_argv) target_link_options(test_argv PRIVATE -Wl,--wrap=parse_line) target_sources(test_argv PRIVATE diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a5d4cdc..1e17c3f 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -117,7 +117,7 @@ proto.c proto.h \ proxy.c proxy.h \ ps.c ps.h \ - push.c push.h \ + push.c push_util.c push.h \ pushlist.h \ reflect_filter.c reflect_filter.h \ reliable.c reliable.h \ diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index dfc6708..475d142 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -2064,7 +2064,7 @@ } /* check for incoming control messages on the control channel like - * push request/reply, or authentication failure and 2FA messages */ + * push request/reply/update, or authentication failure and 2FA messages */ if (tls_test_payload_len(c->c2.tls_multi) > 0) { check_incoming_control_channel(c); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index aac8a6a..ba1dda4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2051,8 +2051,8 @@ /* possibly add routes */ if ((route_order(c->c1.tuntap) == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) { - int status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); + bool status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); *error_flags |= (status ? 0 : ISC_ROUTE_ERRORS); } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 0662b49..2083eae 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -66,6 +66,7 @@ #include <ctype.h> #include "memdbg.h" +#include "options_util.h" const char title_string[] = PACKAGE_STRING @@ -948,24 +949,6 @@ } } -struct pull_filter -{ -#define PUF_TYPE_UNDEF 0 /**< undefined filter type */ -#define PUF_TYPE_ACCEPT 1 /**< filter type to accept a matching option */ -#define PUF_TYPE_IGNORE 2 /**< filter type to ignore a matching option */ -#define PUF_TYPE_REJECT 3 /**< filter type to reject and trigger SIGUSR1 */ - int type; - int size; - char *pattern; - struct pull_filter *next; -}; - -struct pull_filter_list -{ - struct pull_filter *head; - struct pull_filter *tail; -}; - #ifndef ENABLE_SMALL static const char * @@ -5515,60 +5498,14 @@ } } -/** - * Filter an option line by all pull filters. - * - * If a match is found, the line is modified depending on - * the filter type, and returns true. If the filter type is - * reject, SIGUSR1 is triggered and the return value is false. - * In that case the caller must end the push processing. - */ -static bool -apply_pull_filter(const struct options *o, char *line) -{ - struct pull_filter *f; - - if (!o->pull_filter_list) - { - return true; - } - - /* skip leading spaces matching the behaviour of parse_line */ - while (isspace(*line)) - { - line++; - } - - for (f = o->pull_filter_list->head; f; f = f->next) - { - if (f->type == PUF_TYPE_ACCEPT && strncmp(line, f->pattern, f->size) == 0) - { - msg(D_LOW, "Pushed option accepted by filter: '%s'", line); - return true; - } - else if (f->type == PUF_TYPE_IGNORE && strncmp(line, f->pattern, f->size) == 0) - { - msg(D_PUSH, "Pushed option removed by filter: '%s'", line); - *line = '\0'; - return true; - } - else if (f->type == PUF_TYPE_REJECT && strncmp(line, f->pattern, f->size) == 0) - { - msg(M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line); - *line = '\0'; - throw_signal_soft(SIGUSR1, "Offending option received from server"); - return false; - } - } - return true; -} - bool -apply_push_options(struct options *options, +apply_push_options(struct context *c, + struct options *options, struct buffer *buf, unsigned int permission_mask, unsigned int *option_types_found, - struct env_set *es) + struct env_set *es, + bool is_update) { char line[OPTION_PARM_SIZE]; int line_num = 0; @@ -5580,14 +5517,40 @@ char *p[MAX_PARMS+1]; CLEAR(p); ++line_num; - if (!apply_pull_filter(options, line)) + unsigned int push_update_option_flags = 0; + int i = 0; + + /* skip leading spaces matching the behaviour of parse_line */ + while (isspace(line[i])) { + i++; + } + + /* If we are not in a 'PUSH_UPDATE' we just check `apply_pull_filter()` + * otherwise we must call `check_push_update_option_flags()` first + */ + if ((is_update && !check_push_update_option_flags(line, &i, &push_update_option_flags)) + || !apply_pull_filter(options, &line[i])) + { + /* In case we are in a `PUSH_UPDATE` and `check_push_update_option_flags()` + * or `apply_pull_filter()` fail but the option is flagged by `PUSH_OPT_OPTIONAL`, + * instead of restarting, we just ignore the option and we process the next one + */ + if (push_update_option_flags & PUSH_OPT_OPTIONAL) + { + continue; /* Ignoring this option */ + } + throw_signal_soft(SIGUSR1, "Offending option received from server"); return false; /* Cause push/pull error and stop push processing */ } - if (parse_line(line, p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) + + if (parse_line(&line[i], p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) { - add_option(options, p, false, file, line_num, 0, msglevel, - permission_mask, option_types_found, es); + if (!is_update) + { + add_option(options, p, false, file, line_num, 0, msglevel, + permission_mask, option_types_found, es); + } } } return true; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 56e85d7..0544ca9 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -794,6 +794,33 @@ #define MAN_CLIENT_AUTH_ENABLED(opt) (false) #endif +/* + * some PUSH_UPDATE options + */ +#define OPT_P_U_ROUTE (1<<0) +#define OPT_P_U_ROUTE6 (1<<1) +#define OPT_P_U_DNS (1<<2) +#define OPT_P_U_DHCP (1<<3) +#define OPT_P_U_REDIR_GATEWAY (1<<4) + +struct pull_filter +{ +#define PUF_TYPE_UNDEF 0 /**< undefined filter type */ +#define PUF_TYPE_ACCEPT 1 /**< filter type to accept a matching option */ +#define PUF_TYPE_IGNORE 2 /**< filter type to ignore a matching option */ +#define PUF_TYPE_REJECT 3 /**< filter type to reject and trigger SIGUSR1 */ + int type; + int size; + char *pattern; + struct pull_filter *next; +}; + +struct pull_filter_list +{ + struct pull_filter *head; + struct pull_filter *tail; +}; + void parse_argv(struct options *options, const int argc, char *argv[], @@ -862,11 +889,13 @@ void pre_connect_restore(struct options *o, struct gc_arena *gc); -bool apply_push_options(struct options *options, +bool apply_push_options(struct context *c, + struct options *options, struct buffer *buf, unsigned int permission_mask, unsigned int *option_types_found, - struct env_set *es); + struct env_set *es, + bool is_update); void options_detach(struct options *o); diff --git a/src/openvpn/options_util.c b/src/openvpn/options_util.c index 80d0c08..d317c1a 100644 --- a/src/openvpn/options_util.c +++ b/src/openvpn/options_util.c @@ -30,6 +30,8 @@ #include "options_util.h" +#include "push.h" + const char * parse_auth_failed_temp(struct options *o, const char *reason) { @@ -145,3 +147,116 @@ return (int) i; } + +static const char *updatable_options[] = { + "block-ipv6", + "block-outside-dns", + "dhcp-option", + "dns", + "ifconfig", + "ifconfig-ipv6", + "push-continuation", + "redirect-gateway", + "redirect-private", + "route", + "route-gateway", + "route-ipv6", + "route-metric", + "topology", + "tun-mtu", + "keepalive" +}; + +bool +check_push_update_option_flags(char *line, int *i, unsigned int *flags) +{ + *flags = 0; + bool opt_is_updatable = false; + char c = line[*i]; + + /* We check for '?' and '-' and + * if they are present we skip them. + */ + if (c == '-') + { + if (!(line)[*i + 1]) + { + return false; + } + *flags |= PUSH_OPT_TO_REMOVE; + c = (line)[++(*i)]; + } + if (c == '?') + { + if (!(line)[*i + 1] || (line)[*i + 1] == '-') + { + return false; + } + *flags |= PUSH_OPT_OPTIONAL; + c = (line)[++(*i)]; + } + + size_t len = strlen(&line[*i]); + int count = sizeof(updatable_options)/sizeof(char *); + for (int j = 0; j < count; ++j) + { + size_t opt_len = strlen(updatable_options[j]); + if (len < opt_len) + { + continue; + } + if (!strncmp(&line[*i], updatable_options[j], opt_len) + && (!line[*i + opt_len] || line[*i + opt_len] == ' ')) + { + opt_is_updatable = true; + break; + } + } + + if (!opt_is_updatable) + { + if (*flags & PUSH_OPT_OPTIONAL) + { + msg(D_PUSH, "Pushed option is not updatable: '%s'. Ignoring.", line); + } + else + { + msg(M_WARN, "Pushed option is not updatable: '%s'. Restarting.", line); + return false; + } + } + + return true; +} + +bool +apply_pull_filter(const struct options *o, char *line) +{ + if (!o->pull_filter_list) + { + return true; + } + + struct pull_filter *f; + + for (f = o->pull_filter_list->head; f; f = f->next) + { + if (f->type == PUF_TYPE_ACCEPT && strncmp(line, f->pattern, f->size) == 0) + { + msg(D_LOW, "Pushed option accepted by filter: '%s'", line); + return true; + } + else if (f->type == PUF_TYPE_IGNORE && strncmp(line, f->pattern, f->size) == 0) + { + msg(D_PUSH, "Pushed option removed by filter: '%s'", line); + *line = '\0'; + return true; + } + else if (f->type == PUF_TYPE_REJECT && strncmp(line, f->pattern, f->size) == 0) + { + msg(M_WARN, "Pushed option rejected by filter: '%s'.", line); + return false; + } + } + return true; +} diff --git a/src/openvpn/options_util.h b/src/openvpn/options_util.h index 2474e7f..71d51d6 100644 --- a/src/openvpn/options_util.h +++ b/src/openvpn/options_util.h @@ -50,4 +50,47 @@ int atoi_warn(const char *str, int msglevel); +/** + * Filter an option line by all pull filters. + * + * If a match is found, the line is modified depending on + * the filter type, and returns true. If the filter type is + * reject, SIGUSR1 is triggered and the return value is false. + * In that case the caller must end the push processing. + */ +bool +apply_pull_filter(const struct options *o, + char *line); + +/** + * @brief Checks the formatting and validity of options inside push-update messages. + * + * This function is used to validate and process options + * in push-update messages. It performs the following checks: + * - Determines if the options are updatable. + * - Checks for the presence of the `-` flag, which indicates that the option + * should be removed. + * - Checks for the `?` flag, which marks the option as optional and suppresses + * errors if the client cannot update it. + * - Increase the value pointed by 'i' when we encounter the `'-'` and `'?'` flags + * after validating them and updating the appropriate flags in the `flags` variable. + * - `-?option`, `-option`, `?option` are valid formats, `?-option` is not a valid format. + * - If the flags and the option are not consecutive, the option is invalid: + * `- ?option`, `-? option`, `- option` are invalid formats. + * + * @param line A pointer to an option string. This string is the option being validated. + * @param i A pointer to an integer that represents the current index in the `line` string. + * @param flags A pointer where flags will be stored: + * - `PUSH_OPT_TO_REMOVE`: Set if the `-` flag is present. + * - `PUSH_OPT_OPTIONAL`: Set if the `?` flag is present. + * + * @return true if the flags and option combination are valid. + * @return false if: + * - The `-` and `?` flags are not formatted correctly. + * - The `line` parameter is empty or `NULL`. + * - The `?` flag is absent and the option is not updatable. + */ +bool +check_push_update_option_flags(char *line, int *i, unsigned int *flags); + #endif /* ifndef OPTIONS_UTIL_H_ */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index ad8fa3d7..858b821 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -39,8 +39,6 @@ #include "ssl_util.h" #include "options_util.h" -static char push_reply_cmd[] = "PUSH_REPLY"; - /* * Auth username/password * @@ -519,21 +517,31 @@ { msg(D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); } - else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) + else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_UPDATE || status == PUSH_MSG_CONTINUATION) { c->options.push_option_types_found |= option_types_found; /* delay bringing tun/tap up until --push parms received from remote */ - if (status == PUSH_MSG_REPLY) + if (status == PUSH_MSG_REPLY || status == PUSH_MSG_UPDATE) { if (!options_postprocess_pull(&c->options, c->c2.es)) { goto error; } - if (!do_up(c, true, c->options.push_option_types_found)) + if (status == PUSH_MSG_REPLY) { - msg(D_PUSH_ERRORS, "Failed to open tun/tap interface"); - goto error; + if (!do_up(c, true, c->options.push_option_types_found)) + { + msg(D_PUSH_ERRORS, "Failed to open tun/tap interface"); + goto error; + } + } + else + { + if (!option_types_found) + { + msg(M_WARN, "No updatable options found in incoming PUSH_UPDATE message"); + } } } event_timeout_clear(&c->c2.push_request_interval); @@ -1056,11 +1064,13 @@ md_ctx_init(c->c2.pulled_options_state, "SHA256"); c->c2.pulled_options_digest_init_done = true; } - if (apply_push_options(&c->options, + if (apply_push_options(c, + &c->options, buf, permission_mask, option_types_found, - c->c2.es)) + c->c2.es, + false)) { push_update_digest(c->c2.pulled_options_state, &buf_orig, &c->options); @@ -1111,6 +1121,12 @@ return process_incoming_push_reply(c, permission_mask, option_types_found, &buf); } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_update_cmd)) + { + return process_incoming_push_update(c, permission_mask, + option_types_found, &buf); + } else { return PUSH_MSG_ERROR; diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 048b4c4..18dfcd8 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -33,9 +33,42 @@ #define PUSH_MSG_AUTH_FAILURE 4 #define PUSH_MSG_CONTINUATION 5 #define PUSH_MSG_ALREADY_REPLIED 6 +#define PUSH_MSG_UPDATE 7 + +#define push_reply_cmd "PUSH_REPLY" +#define push_update_cmd "PUSH_UPDATE" + +/* Push-update options flags */ +#define PUSH_OPT_TO_REMOVE (1<<0) +#define PUSH_OPT_OPTIONAL (1<<1) int process_incoming_push_request(struct context *c); +/** + * @brief Handles the receiving of a push-update message and applies updates to the specified options. + * + * This function processes a push-update message, validating its content and applying updates + * to the options specified in the message. It also handles split messages if the complete + * message has not yet been received. + * + * @param c The context for the operation. + * @param permission_mask The permission mask specifying which options are allowed to be pulled. + * @param option_types_found A pointer to a variable that will be filled with the types of options + * found in the message. + * @param buf A buffer containing the received message. + * + * @return + * - `PUSH_MSG_UPDATE`: The message was processed successfully, and the updates were applied. + * - `PUSH_MSG_CONTINUATION`: The message is a fragment of a larger message, and the program is + * waiting for the final part. + * - `PUSH_MSG_ERROR`: An error occurred during message processing, or the message is invalid. + */ + +int process_incoming_push_update(struct context *c, + unsigned int permission_mask, + unsigned int *option_types_found, + struct buffer *buf); + int process_incoming_push_msg(struct context *c, const struct buffer *buffer, bool honor_received_options, diff --git a/src/openvpn/push_util.c b/src/openvpn/push_util.c new file mode 100644 index 0000000..b4d1e8b --- /dev/null +++ b/src/openvpn/push_util.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "push.h" + +int +process_incoming_push_update(struct context *c, + unsigned int permission_mask, + unsigned int *option_types_found, + struct buffer *buf) +{ + int ret = PUSH_MSG_ERROR; + const uint8_t ch = buf_read_u8(buf); + if (ch == ',') + { + if (apply_push_options(c, + &c->options, + buf, + permission_mask, + option_types_found, + c->c2.es, + true)) + { + switch (c->options.push_continuation) + { + case 0: + case 1: + ret = PUSH_MSG_UPDATE; + break; + + case 2: + ret = PUSH_MSG_CONTINUATION; + break; + } + } + } + else if (ch == '\0') + { + ret = PUSH_MSG_UPDATE; + } + + return ret; +} diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 9c6616a..a7658dd 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1993,6 +1993,9 @@ /* support for exit notify via control channel */ iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; + /* support push-updates */ + iv_proto |= IV_PROTO_PUSH_UPDATE; + if (session->opt->pull) { /* support for receiving push_reply before sending diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 000992d..0a43ea1 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -114,6 +114,9 @@ /** Supports the --dns option after all the incompatible changes */ #define IV_PROTO_DNS_OPTION_V2 (1<<11) +/** Supports push-update */ +#define IV_PROTO_PUSH_UPDATE (1<<12) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index b47b495..b24e03c 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -11,7 +11,7 @@ endif test_binaries += crypto_testdriver packet_id_testdriver auth_token_testdriver ncp_testdriver misc_testdriver \ - pkt_testdriver ssl_testdriver user_pass_testdriver + pkt_testdriver ssl_testdriver user_pass_testdriver push_update_msg_testdriver if HAVE_LD_WRAP_SUPPORT if !WIN32 @@ -326,3 +326,21 @@ $(top_srcdir)/src/openvpn/win32-util.c \ $(top_srcdir)/src/openvpn/platform.c \ $(top_srcdir)/src/openvpn/list.c + +push_update_msg_testdriver_CFLAGS = -I$(top_srcdir)/src/openvpn \ + -I$(top_srcdir)/src/compat \ + -I$(top_srcdir)/tests/unit_tests/openvpn \ + @TEST_CFLAGS@ + +push_update_msg_testdriver_LDFLAGS = \ + @TEST_LDFLAGS@ \ + -L$(top_srcdir)/src/openvpn + +push_update_msg_testdriver_SOURCES = test_push_update_msg.c \ + mock_msg.c \ + mock_get_random.c \ + $(top_srcdir)/src/openvpn/buffer.c \ + $(top_srcdir)/src/openvpn/platform.c \ + $(top_srcdir)/src/openvpn/push_util.c \ + $(top_srcdir)/src/openvpn/options_util.c \ + $(top_srcdir)/src/openvpn/otime.c \ No newline at end of file diff --git a/tests/unit_tests/openvpn/test_push_update_msg.c b/tests/unit_tests/openvpn/test_push_update_msg.c new file mode 100644 index 0000000..d47286a --- /dev/null +++ b/tests/unit_tests/openvpn/test_push_update_msg.c @@ -0,0 +1,260 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdarg.h> +#include <setjmp.h> +#include <cmocka.h> +#include "push.h" +#include "options_util.h" + +/* mocks */ + +unsigned int +pull_permission_mask(const struct context *c) +{ + unsigned int flags = + OPT_P_UP + | OPT_P_ROUTE_EXTRAS + | OPT_P_SOCKBUF + | OPT_P_SOCKFLAGS + | OPT_P_SETENV + | OPT_P_SHAPER + | OPT_P_TIMER + | OPT_P_COMP + | OPT_P_PERSIST + | OPT_P_MESSAGES + | OPT_P_EXPLICIT_NOTIFY + | OPT_P_ECHO + | OPT_P_PULL_MODE + | OPT_P_PEER_ID + | OPT_P_NCP + | OPT_P_PUSH_MTU + | OPT_P_ROUTE + | OPT_P_DHCPDNS; + return flags; +} + +bool +apply_push_options(struct context *c, + struct options *options, + struct buffer *buf, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es, + bool is_update) +{ + char line[OPTION_PARM_SIZE]; + + while (buf_parse(buf, ',', line, sizeof(line))) + { + unsigned int push_update_option_flags = 0; + int i = 0; + + if (is_update || options->pull_filter_list) + { + /* skip leading spaces matching the behaviour of parse_line */ + while (isspace(line[i])) + { + i++; + } + + if ((is_update && !check_push_update_option_flags(line, &i, &push_update_option_flags)) + || (options->pull_filter_list && !apply_pull_filter(options, &line[i]))) + { + if (push_update_option_flags & PUSH_OPT_OPTIONAL) + { + continue; /* Ignoring this option */ + } + msg(M_WARN, "Offending option received from server"); + return false; /* Cause push/pull error and stop push processing */ + } + } + /* + * No need to test also the application part here + * (add_option/remove_option/update_option) + */ + } + return true; +} + +int +process_incoming_push_msg(struct context *c, + const struct buffer *buffer, + bool honor_received_options, + unsigned int permission_mask, + unsigned int *option_types_found) +{ + struct buffer buf = *buffer; + + if (buf_string_compare_advance(&buf, "PUSH_REQUEST")) + { + return PUSH_MSG_REQUEST; + } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_reply_cmd)) + { + return PUSH_MSG_REPLY; + } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_update_cmd)) + { + return process_incoming_push_update(c, permission_mask, + option_types_found, &buf); + } + else + { + return PUSH_MSG_ERROR; + } +} + +/* tests */ + +static void +test_incoming_push_message_basic(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,dhcp-option DNS 8.8.8.8, route 0.0.0.0 0.0.0.0 10.10.10.1"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_error1(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATEerr,dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + + +static void +test_incoming_push_message_error2(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE ,dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_1(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, -?dns, route something, ?dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_bad_format(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, -dhcp-option, ?-dns"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_not_updatable_option(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, dev tun"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_mix(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,-dhcp-option, route 10.10.10.0, dhcp-option DNS 1.1.1.1, route 10.11.12.0, dhcp-option DOMAIN corp.local, keepalive 10 60"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_mix2(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,-dhcp-option,dhcp-option DNS 8.8.8.8,redirect-gateway local,route 192.168.1.0 255.255.255.0"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static int +setup(void **state) +{ + struct context *c = calloc(1, sizeof(struct context)); + c->options.pull = true; + c->options.route_nopull = false; + *state = c; + return 0; +} + +static int +teardown(void **state) +{ + struct context *c = *state; + free(c); + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_incoming_push_message_basic, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_error1, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_error2, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_not_updatable_option, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_1, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_bad_format, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_mix, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |
From: cron2 (C. Review) <ge...@op...> - 2025-07-29 10:35:58
|
Attention is currently required from: flichtenheld, mrbff, stipa. cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/808?usp=email ) Change subject: PUSH_UPDATE: Allow OpenVPN in client mode to receive and handle PUSH UPDATE control messages to allow options updating at runtime. ...................................................................... Patch Set 22: Code-Review+2 -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/808?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I6ecd4cb47571cc8c20e46de8595c742aeec6064a Gerrit-Change-Number: 808 Gerrit-PatchSet: 22 Gerrit-Owner: mrbff <ma...@ma...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-Reviewer: stipa <lst...@gm...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Attention: mrbff <ma...@ma...> Gerrit-Attention: stipa <lst...@gm...> Gerrit-Comment-Date: Tue, 29 Jul 2025 10:35:43 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment |
From: Gert D. <ge...@gr...> - 2025-07-29 10:31:58
|
That's an easy one :-) - taking out configure stuff and #ifdefs, always welcome. Tested on "stock FreeBSD 13.5" which has no if_ovpn, and "stock FreeBSD 14.2" which has if_ovpn but not the float stuff. Your patch has been applied to the master branch. commit 796ad2c55951635382e48ea5b71d13bbb83ebfb1 Author: Kristof Provost Date: Tue Jul 29 11:39:07 2025 +0200 dco-freebsd: always enable float notification support Signed-off-by: Kristof Provost <kpr...@ne...> Message-Id: <202...@ne...> URL: https://www.mail-archive.com/ope...@li.../msg32402.html Acked-by: Gert Doering <ge...@gr...> Signed-off-by: Gert Doering <ge...@gr...> -- kind regards, Gert Doering |
From: Gert D. <ge...@gr...> - 2025-07-29 10:14:15
|
Hi, (uh, forgot to send this - push has been done yesterday already) On Mon, Jul 28, 2025 at 01:00:09PM +0200, Gert Doering wrote: > It seems this would also affect feodora-42 on amd64, we just missed on > the "updates that bring in the breaking change" - but now we are prepared ;-) > > Patch has been applied to the master branch. > > commit 035d47e6d80996a4cde8af1b35f9ba40b676c825 > Author: Gert Doering > Date: Mon Jul 28 12:42:29 2025 +0200 Frank has pointed out that this is the sort of maintenance fixes we do want in release/2.6 as well, so here we go... tested via GHA and local fedora42/arm64 VM commit 5c968a361fba7362306fcd977acdff52ccb4c884 (release/2.6) Author: Gert Doering <ge...@gr...> Date: Mon Jul 28 12:42:29 2025 +0200 unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 gert - "If was one thing all people took for granted, was conviction that if you feed honest figures into a computer, honest figures come out. Never doubted it myself till I met a computer with a sense of humor." Robert A. Heinlein, The Moon is a Harsh Mistress Gert Doering - Munich, Germany ge...@gr... |
From: Kristof P. <kpr...@ne...> - 2025-07-29 10:07:15
|
From: Kristof Provost <kp...@Fr...> If the kernel doesn't support it we'll simply never get the notification. In other words, there's no downside to always enabling this, so let's do that. Signed-off-by: Kristof Provost <kpr...@ne...> --- configure.ac | 9 --------- src/openvpn/dco_freebsd.c | 4 ---- 2 files changed, 13 deletions(-) diff --git a/configure.ac b/configure.ac index 50697b8e..66cb79b1 100644 --- a/configure.ac +++ b/configure.ac @@ -848,15 +848,6 @@ if test "$enable_dco" != "no"; then else AC_MSG_ERROR([DCO support can't be enabled]) fi - else - AC_CHECK_DECLS( - [OVPN_NOTIF_FLOAT], - [AC_DEFINE([ENABLE_DCO_FLOAT_FREEBSD], [1], [We have DCO float notifications on FreeBSD])], - , - [[ - #include <net/if_ovpn.h> - ]] - ) fi ;; *-mingw*) diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index 306ecd31..488665fc 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -73,7 +73,6 @@ sockaddr_to_nvlist(const struct sockaddr *sa) return (nvl); } -#ifdef ENABLE_DCO_FLOAT_FREEBSD static bool nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss) { @@ -133,7 +132,6 @@ nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss) return (true); } -#endif /* ifdef ENABLE_DCO_FLOAT_FREEBSD */ int dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, @@ -636,7 +634,6 @@ dco_do_read(dco_context_t *dco) dco->dco_message_type = OVPN_CMD_SWAP_KEYS; break; -#ifdef ENABLE_DCO_FLOAT_FREEBSD case OVPN_NOTIF_FLOAT: { const nvlist_t *address; @@ -655,7 +652,6 @@ dco_do_read(dco_context_t *dco) dco->dco_message_type = OVPN_CMD_FLOAT_PEER; break; } -#endif default: msg(M_WARN, "Unknown kernel notification %d", type); -- 2.50.1 |
From: Kristof P. <kpr...@ne...> - 2025-07-29 09:44:27
|
From: Kristof Provost <kp...@Fr...> To support link-local (IPv6) addresses we must pass the scope to the kernel as well. We should also extract it from the kernel notification for float events. Signed-off-by: Kristof Provost <kpr...@ne...> --- src/openvpn/dco_freebsd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index 8add41af..306ecd31 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -62,6 +62,7 @@ sockaddr_to_nvlist(const struct sockaddr *sa) const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)sa; nvlist_add_binary(nvl, "address", &in6->sin6_addr, sizeof(in6->sin6_addr)); nvlist_add_number(nvl, "port", in6->sin6_port); + nvlist_add_number(nvl, "scopeid", in6->sin6_scope_id); break; } @@ -118,6 +119,11 @@ nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss) assert(len == sizeof(in6->sin6_addr)); memcpy(&in6->sin6_addr, data, sizeof(in6->sin6_addr)); in6->sin6_port = nvlist_get_number(nvl, "port"); + + if (nvlist_exists_number(nvl, "scopeid")) + { + in6->sin6_scope_id = nvlist_get_number(nvl, "scopeid"); + } break; } -- 2.50.1 |
From: cron2 (C. Review) <ge...@op...> - 2025-07-28 14:14:56
|
cron2 has submitted this change. ( http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email ) Change subject: options: Simplify function setenv_foreign_option ...................................................................... options: Simplify function setenv_foreign_option This was relatively complex for the actual usage. Looked at the code because of -Wconversion warnings related to the len argument. So this should also be gone. Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Signed-off-by: Frank Lichtenheld <fr...@li...> Acked-by: Gert Doering <ge...@gr...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32396.html Signed-off-by: Gert Doering <ge...@gr...> --- M src/openvpn/options.c 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 0662b49..d44c102 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1067,41 +1067,32 @@ #ifndef _WIN32 static void -setenv_foreign_option(struct options *o, const char *argv[], int len, struct env_set *es) +setenv_foreign_option(struct options *o, const char *option, const char *value, struct env_set *es) { - if (len > 0) - { - struct gc_arena gc = gc_new(); - struct buffer name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - struct buffer value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - int i; - bool first = true; - bool good = true; + struct gc_arena gc = gc_new(); + struct buffer env_name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + struct buffer env_value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + bool good = true; - good &= buf_printf(&name, "foreign_option_%d", o->foreign_option_index + 1); - ++o->foreign_option_index; - for (i = 0; i < len; ++i) - { - if (argv[i]) - { - if (!first) - { - good &= buf_printf(&value, " "); - } - good &= buf_printf(&value, "%s", argv[i]); - first = false; - } - } - if (good) - { - setenv_str(es, BSTR(&name), BSTR(&value)); - } - else - { - msg(M_WARN, "foreign_option: name/value overflow"); - } - gc_free(&gc); + good &= buf_printf(&env_name, "foreign_option_%d", o->foreign_option_index + 1); + if (value) + { + good &= buf_printf(&env_value, "dhcp-option %s %s", option, value); } + else + { + good &= buf_printf(&env_value, "dhcp-option %s", option); + } + if (good) + { + setenv_str(es, BSTR(&env_name), BSTR(&env_value)); + ++o->foreign_option_index; + } + else + { + msg(M_WARN, "foreign_option: name/value overflow"); + } + gc_free(&gc); } #endif /* ifndef _WIN32 */ @@ -3678,15 +3669,10 @@ else if (o->up_script && !dns_updown_user_set(dns) && !dns_updown_forced(dns)) { /* Set foreign option env vars from --dns config */ - const char *p[] = { "dhcp-option", NULL, NULL }; - size_t p_len = sizeof(p) / sizeof(p[0]); - - p[1] = "DOMAIN"; const struct dns_domain *d = dns->search_domains; while (d) { - p[2] = d->name; - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, "DOMAIN", d->name, es); d = d->next; } @@ -3713,17 +3699,19 @@ { for (int i = 0; i < s->addr_count; ++i) { + const char *option; + const char *value; if (s->addr[i].family == AF_INET) { - p[1] = "DNS"; - p[2] = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); + option = "DNS"; + value = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); } else { - p[1] = "DNS6"; - p[2] = print_in6_addr(s->addr[i].in.a6, 0, &gc); + option = "DNS6"; + value = print_in6_addr(s->addr[i].in.a6, 0, &gc); } - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, option, value, es); } break; } @@ -8388,7 +8376,7 @@ goto err; } #else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); #endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ } #ifdef _WIN32 @@ -8530,7 +8518,7 @@ else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_DHCPDNS); - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); } else if (streq(p[0], "route-method") && p[1] && !p[2]) { -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Gerrit-Change-Number: 1112 Gerrit-PatchSet: 4 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-MessageType: merged |
From: Gert D. <ge...@gr...> - 2025-07-28 14:14:50
|
Stared at code (simple is good ;-) ). Tested with manually connecting to a server that pushes --dns and --dhcp-option <things> (DNS and others), and verifying the output before/after. Same. Your patch has been applied to the master branch. commit 654671a10b8f26ed0041ce434016fecb11438aae Author: Frank Lichtenheld Date: Mon Jul 28 14:56:41 2025 +0200 options: Simplify function setenv_foreign_option Signed-off-by: Frank Lichtenheld <fr...@li...> Acked-by: Gert Doering <ge...@gr...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32396.html Signed-off-by: Gert Doering <ge...@gr...> -- kind regards, Gert Doering |
From: cron2 (C. Review) <ge...@op...> - 2025-07-28 14:14:50
|
cron2 has uploaded a new patch set (#4) to the change originally created by flichtenheld. ( http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email ) The following approvals got outdated and were removed: Code-Review+2 by cron2 Change subject: options: Simplify function setenv_foreign_option ...................................................................... options: Simplify function setenv_foreign_option This was relatively complex for the actual usage. Looked at the code because of -Wconversion warnings related to the len argument. So this should also be gone. Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Signed-off-by: Frank Lichtenheld <fr...@li...> Acked-by: Gert Doering <ge...@gr...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32396.html Signed-off-by: Gert Doering <ge...@gr...> --- M src/openvpn/options.c 1 file changed, 33 insertions(+), 45 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/12/1112/4 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 0662b49..d44c102 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1067,41 +1067,32 @@ #ifndef _WIN32 static void -setenv_foreign_option(struct options *o, const char *argv[], int len, struct env_set *es) +setenv_foreign_option(struct options *o, const char *option, const char *value, struct env_set *es) { - if (len > 0) - { - struct gc_arena gc = gc_new(); - struct buffer name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - struct buffer value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - int i; - bool first = true; - bool good = true; + struct gc_arena gc = gc_new(); + struct buffer env_name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + struct buffer env_value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + bool good = true; - good &= buf_printf(&name, "foreign_option_%d", o->foreign_option_index + 1); - ++o->foreign_option_index; - for (i = 0; i < len; ++i) - { - if (argv[i]) - { - if (!first) - { - good &= buf_printf(&value, " "); - } - good &= buf_printf(&value, "%s", argv[i]); - first = false; - } - } - if (good) - { - setenv_str(es, BSTR(&name), BSTR(&value)); - } - else - { - msg(M_WARN, "foreign_option: name/value overflow"); - } - gc_free(&gc); + good &= buf_printf(&env_name, "foreign_option_%d", o->foreign_option_index + 1); + if (value) + { + good &= buf_printf(&env_value, "dhcp-option %s %s", option, value); } + else + { + good &= buf_printf(&env_value, "dhcp-option %s", option); + } + if (good) + { + setenv_str(es, BSTR(&env_name), BSTR(&env_value)); + ++o->foreign_option_index; + } + else + { + msg(M_WARN, "foreign_option: name/value overflow"); + } + gc_free(&gc); } #endif /* ifndef _WIN32 */ @@ -3678,15 +3669,10 @@ else if (o->up_script && !dns_updown_user_set(dns) && !dns_updown_forced(dns)) { /* Set foreign option env vars from --dns config */ - const char *p[] = { "dhcp-option", NULL, NULL }; - size_t p_len = sizeof(p) / sizeof(p[0]); - - p[1] = "DOMAIN"; const struct dns_domain *d = dns->search_domains; while (d) { - p[2] = d->name; - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, "DOMAIN", d->name, es); d = d->next; } @@ -3713,17 +3699,19 @@ { for (int i = 0; i < s->addr_count; ++i) { + const char *option; + const char *value; if (s->addr[i].family == AF_INET) { - p[1] = "DNS"; - p[2] = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); + option = "DNS"; + value = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); } else { - p[1] = "DNS6"; - p[2] = print_in6_addr(s->addr[i].in.a6, 0, &gc); + option = "DNS6"; + value = print_in6_addr(s->addr[i].in.a6, 0, &gc); } - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, option, value, es); } break; } @@ -8388,7 +8376,7 @@ goto err; } #else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); #endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ } #ifdef _WIN32 @@ -8530,7 +8518,7 @@ else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_DHCPDNS); - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); } else if (streq(p[0], "route-method") && p[1] && !p[2]) { -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Gerrit-Change-Number: 1112 Gerrit-PatchSet: 4 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-MessageType: newpatchset |
From: flichtenheld (C. Review) <ge...@op...> - 2025-07-28 13:53:17
|
Attention is currently required from: plaisthos. Hello plaisthos, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/1104?usp=email to look at the new patch set (#2). Change subject: ssl_common: Make sure ssl flags are treated as unsigned ...................................................................... ssl_common: Make sure ssl flags are treated as unsigned tls_options.ssl_flags is already unsigned, make sure the flags are as well to avoid spurious conversion warnings. Also fix various warning regarding the use of the flags for TLS version handling. Change-Id: I03e5ece7580ca4ebd41a7928ead544df46e8bad1 Signed-off-by: Frank Lichtenheld <fr...@li...> --- M src/openvpn/options.c M src/openvpn/ssl_common.h 2 files changed, 20 insertions(+), 22 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/04/1104/2 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 0662b49..6ad1170 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2722,14 +2722,14 @@ "may accept clients which do not present a certificate"); } - const int tls_version_max = + const unsigned int tls_version_max = (options->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK; - const int tls_version_min = + const unsigned int tls_version_min = (options->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK; - if (tls_version_max > 0 && tls_version_max < tls_version_min) + if (tls_version_max < tls_version_min) { msg(M_USAGE, "--tls-version-min bigger than --tls-version-max"); } @@ -3387,12 +3387,12 @@ options_set_backwards_compatible_options(struct options *o) { /* TLS min version is not set */ - int tls_ver_min = (o->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) - & SSLF_TLS_VERSION_MIN_MASK; + unsigned int tls_ver_min = (o->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) + & SSLF_TLS_VERSION_MIN_MASK; if (tls_ver_min == 0) { - int tls_ver_max = (o->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) - & SSLF_TLS_VERSION_MAX_MASK; + unsigned int tls_ver_max = (o->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) + & SSLF_TLS_VERSION_MAX_MASK; if (need_compatibility_before(o, 20307)) { /* 2.3.6 and earlier have TLS 1.0 only, set minimum to TLS 1.0 */ @@ -9074,9 +9074,8 @@ } else if (streq(p[0], "tls-version-min") && p[1] && !p[3]) { - int ver; VERIFY_PERMISSION(OPT_P_GENERAL); - ver = tls_version_parse(p[1], p[2]); + int ver = tls_version_parse(p[1], p[2]); if (ver == TLS_VER_BAD) { msg(msglevel, "unknown tls-version-min parameter: %s", p[1]); @@ -9093,13 +9092,12 @@ options->ssl_flags &= ~(SSLF_TLS_VERSION_MIN_MASK << SSLF_TLS_VERSION_MIN_SHIFT); - options->ssl_flags |= (ver << SSLF_TLS_VERSION_MIN_SHIFT); + options->ssl_flags |= ((unsigned int)ver << SSLF_TLS_VERSION_MIN_SHIFT); } else if (streq(p[0], "tls-version-max") && p[1] && !p[2]) { - int ver; VERIFY_PERMISSION(OPT_P_GENERAL); - ver = tls_version_parse(p[1], NULL); + int ver = tls_version_parse(p[1], NULL); if (ver == TLS_VER_BAD) { msg(msglevel, "unknown tls-version-max parameter: %s", p[1]); @@ -9107,7 +9105,7 @@ } options->ssl_flags &= ~(SSLF_TLS_VERSION_MAX_MASK << SSLF_TLS_VERSION_MAX_SHIFT); - options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT); + options->ssl_flags |= ((unsigned int)ver << SSLF_TLS_VERSION_MAX_SHIFT); } #ifndef ENABLE_CRYPTO_MBEDTLS else if (streq(p[0], "pkcs12") && p[1] && !p[2]) diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index e9e50da..750891c 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -415,17 +415,17 @@ #endif /* configuration file SSL-related boolean and low-permutation options */ -#define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) -#define SSLF_CLIENT_CERT_OPTIONAL (1<<1) -#define SSLF_USERNAME_AS_COMMON_NAME (1<<2) -#define SSLF_AUTH_USER_PASS_OPTIONAL (1<<3) -#define SSLF_OPT_VERIFY (1<<4) -#define SSLF_CRL_VERIFY_DIR (1<<5) +#define SSLF_CLIENT_CERT_NOT_REQUIRED (1u<<0) +#define SSLF_CLIENT_CERT_OPTIONAL (1u<<1) +#define SSLF_USERNAME_AS_COMMON_NAME (1u<<2) +#define SSLF_AUTH_USER_PASS_OPTIONAL (1u<<3) +#define SSLF_OPT_VERIFY (1u<<4) +#define SSLF_CRL_VERIFY_DIR (1u<<5) #define SSLF_TLS_VERSION_MIN_SHIFT 6 -#define SSLF_TLS_VERSION_MIN_MASK 0xF /* (uses bit positions 6 to 9) */ +#define SSLF_TLS_VERSION_MIN_MASK 0xFu /* (uses bit positions 6 to 9) */ #define SSLF_TLS_VERSION_MAX_SHIFT 10 -#define SSLF_TLS_VERSION_MAX_MASK 0xF /* (uses bit positions 10 to 13) */ -#define SSLF_TLS_DEBUG_ENABLED (1<<14) +#define SSLF_TLS_VERSION_MAX_MASK 0xFu /* (uses bit positions 10 to 13) */ +#define SSLF_TLS_DEBUG_ENABLED (1u<<14) unsigned int ssl_flags; #ifdef ENABLE_MANAGEMENT -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1104?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I03e5ece7580ca4ebd41a7928ead544df46e8bad1 Gerrit-Change-Number: 1104 Gerrit-PatchSet: 2 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-MessageType: newpatchset |
From: Gert D. <ge...@gr...> - 2025-07-28 12:57:01
|
From: Frank Lichtenheld <fr...@li...> This was relatively complex for the actual usage. Looked at the code because of -Wconversion warnings related to the len argument. So this should also be gone. Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Signed-off-by: Frank Lichtenheld <fr...@li...> Acked-by: Gert Doering <ge...@gr...> --- 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/+/1112 This mail reflects revision 2 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering <ge...@gr...> diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 70b5799..8757581 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1067,41 +1067,32 @@ #ifndef _WIN32 static void -setenv_foreign_option(struct options *o, const char *argv[], int len, struct env_set *es) +setenv_foreign_option(struct options *o, const char *option, const char *value, struct env_set *es) { - if (len > 0) - { - struct gc_arena gc = gc_new(); - struct buffer name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - struct buffer value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - int i; - bool first = true; - bool good = true; + struct gc_arena gc = gc_new(); + struct buffer env_name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + struct buffer env_value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + bool good = true; - good &= buf_printf(&name, "foreign_option_%d", o->foreign_option_index + 1); - ++o->foreign_option_index; - for (i = 0; i < len; ++i) - { - if (argv[i]) - { - if (!first) - { - good &= buf_printf(&value, " "); - } - good &= buf_printf(&value, "%s", argv[i]); - first = false; - } - } - if (good) - { - setenv_str(es, BSTR(&name), BSTR(&value)); - } - else - { - msg(M_WARN, "foreign_option: name/value overflow"); - } - gc_free(&gc); + good &= buf_printf(&env_name, "foreign_option_%d", o->foreign_option_index + 1); + if (value) + { + good &= buf_printf(&env_value, "dhcp-option %s %s", option, value); } + else + { + good &= buf_printf(&env_value, "dhcp-option %s", option); + } + if (good) + { + setenv_str(es, BSTR(&env_name), BSTR(&env_value)); + ++o->foreign_option_index; + } + else + { + msg(M_WARN, "foreign_option: name/value overflow"); + } + gc_free(&gc); } #endif /* ifndef _WIN32 */ @@ -3678,15 +3669,10 @@ else if (o->up_script && !dns_updown_user_set(dns) && !dns_updown_forced(dns)) { /* Set foreign option env vars from --dns config */ - const char *p[] = { "dhcp-option", NULL, NULL }; - size_t p_len = sizeof(p) / sizeof(p[0]); - - p[1] = "DOMAIN"; const struct dns_domain *d = dns->search_domains; while (d) { - p[2] = d->name; - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, "DOMAIN", d->name, es); d = d->next; } @@ -3713,17 +3699,19 @@ { for (int i = 0; i < s->addr_count; ++i) { + const char *option; + const char *value; if (s->addr[i].family == AF_INET) { - p[1] = "DNS"; - p[2] = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); + option = "DNS"; + value = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); } else { - p[1] = "DNS6"; - p[2] = print_in6_addr(s->addr[i].in.a6, 0, &gc); + option = "DNS6"; + value = print_in6_addr(s->addr[i].in.a6, 0, &gc); } - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, option, value, es); } break; } @@ -8388,7 +8376,7 @@ goto err; } #else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); #endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ } #ifdef _WIN32 @@ -8530,7 +8518,7 @@ else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_DHCPDNS); - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); } else if (streq(p[0], "route-method") && p[1] && !p[2]) { |
From: cron2 (C. Review) <ge...@op...> - 2025-07-28 12:56:04
|
Attention is currently required from: flichtenheld, plaisthos. cron2 has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email ) Change subject: options: Simplify function setenv_foreign_option ...................................................................... Patch Set 2: Code-Review+2 -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Gerrit-Change-Number: 1112 Gerrit-PatchSet: 2 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Comment-Date: Mon, 28 Jul 2025 12:55:55 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment |
From: flichtenheld (C. Review) <ge...@op...> - 2025-07-28 12:29:34
|
Attention is currently required from: cron2, plaisthos. flichtenheld has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email ) Change subject: options: Simplify function setenv_foreign_option ...................................................................... Patch Set 2: (1 comment) Patchset: PS1: > I'm not convinced we couldn't do something more radical, like, getting rid of the loop and `first` a […] Done -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Gerrit-Change-Number: 1112 Gerrit-PatchSet: 2 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: cron2 <ge...@gr...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Comment-Date: Mon, 28 Jul 2025 12:29:20 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: No Comment-In-Reply-To: cron2 <ge...@gr...> Gerrit-MessageType: comment |
From: flichtenheld (C. Review) <ge...@op...> - 2025-07-28 12:29:07
|
Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email to look at the new patch set (#2). Change subject: options: Simplify function setenv_foreign_option ...................................................................... options: Simplify function setenv_foreign_option This was relatively complex for the actual usage. Looked at the code because of -Wconversion warnings related to the len argument. So this should also be gone. Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Signed-off-by: Frank Lichtenheld <fr...@li...> --- M src/openvpn/options.c 1 file changed, 33 insertions(+), 45 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/12/1112/2 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 70b5799..8757581 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1067,41 +1067,32 @@ #ifndef _WIN32 static void -setenv_foreign_option(struct options *o, const char *argv[], int len, struct env_set *es) +setenv_foreign_option(struct options *o, const char *option, const char *value, struct env_set *es) { - if (len > 0) - { - struct gc_arena gc = gc_new(); - struct buffer name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - struct buffer value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); - int i; - bool first = true; - bool good = true; + struct gc_arena gc = gc_new(); + struct buffer env_name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + struct buffer env_value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + bool good = true; - good &= buf_printf(&name, "foreign_option_%d", o->foreign_option_index + 1); - ++o->foreign_option_index; - for (i = 0; i < len; ++i) - { - if (argv[i]) - { - if (!first) - { - good &= buf_printf(&value, " "); - } - good &= buf_printf(&value, "%s", argv[i]); - first = false; - } - } - if (good) - { - setenv_str(es, BSTR(&name), BSTR(&value)); - } - else - { - msg(M_WARN, "foreign_option: name/value overflow"); - } - gc_free(&gc); + good &= buf_printf(&env_name, "foreign_option_%d", o->foreign_option_index + 1); + if (value) + { + good &= buf_printf(&env_value, "dhcp-option %s %s", option, value); } + else + { + good &= buf_printf(&env_value, "dhcp-option %s", option); + } + if (good) + { + setenv_str(es, BSTR(&env_name), BSTR(&env_value)); + ++o->foreign_option_index; + } + else + { + msg(M_WARN, "foreign_option: name/value overflow"); + } + gc_free(&gc); } #endif /* ifndef _WIN32 */ @@ -3678,15 +3669,10 @@ else if (o->up_script && !dns_updown_user_set(dns) && !dns_updown_forced(dns)) { /* Set foreign option env vars from --dns config */ - const char *p[] = { "dhcp-option", NULL, NULL }; - size_t p_len = sizeof(p) / sizeof(p[0]); - - p[1] = "DOMAIN"; const struct dns_domain *d = dns->search_domains; while (d) { - p[2] = d->name; - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, "DOMAIN", d->name, es); d = d->next; } @@ -3713,17 +3699,19 @@ { for (int i = 0; i < s->addr_count; ++i) { + const char *option; + const char *value; if (s->addr[i].family == AF_INET) { - p[1] = "DNS"; - p[2] = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); + option = "DNS"; + value = print_in_addr_t(s->addr[i].in.a4.s_addr, IA_NET_ORDER, &gc); } else { - p[1] = "DNS6"; - p[2] = print_in6_addr(s->addr[i].in.a6, 0, &gc); + option = "DNS6"; + value = print_in6_addr(s->addr[i].in.a6, 0, &gc); } - setenv_foreign_option(o, (const char **)p, p_len, es); + setenv_foreign_option(o, option, value, es); } break; } @@ -8388,7 +8376,7 @@ goto err; } #else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); #endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ } #ifdef _WIN32 @@ -8530,7 +8518,7 @@ else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_DHCPDNS); - setenv_foreign_option(options, (const char **)p, 3, es); + setenv_foreign_option(options, p[1], p[2], es); } else if (streq(p[0], "route-method") && p[1] && !p[2]) { -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1112?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I7efc77f63734501dfa8a8f5bed17b1a1b4e9e201 Gerrit-Change-Number: 1112 Gerrit-PatchSet: 2 Gerrit-Owner: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: cron2 <ge...@gr...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-MessageType: newpatchset |
From: plaisthos (C. Review) <ge...@op...> - 2025-07-28 11:51:34
|
Attention is currently required from: flichtenheld, plaisthos. Hello flichtenheld, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/1067?usp=email to look at the new patch set (#4). The following approvals got outdated and were removed: Code-Review-1 by flichtenheld Change subject: Check message id/acked ids too when doing sessionid cookie checks ...................................................................... Check message id/acked ids too when doing sessionid cookie checks This fixes that control packets on a floating client can trigger creating a new session in special circumstances: To trigger this circumstance a connection needs to - starts on IP A - successfully floats to IP B by data packet - then has a control packet from IP A before any data packet can trigger the float back to IP A and all of this needs to happen in the 60s time that hmac cookie is valid in the default configuration. In this scenario we would trigger a new connection as the HMAC session id would be valid. This patch adds checking also of the message-id and acked ids to discern packet from the initial three-way handshake where these ids 0 or 1 from any later packet. This will now trigger (at verb 4 or higher) a messaged like: Packet (P_ACK_V1) with invalid or missing SID instead. Also remove a few duplicated free_tls_pre_decrypt_state in test_ssl. Reported-By: Walter Doekes <wal...@wj...> Tested-By: Walter Doekes <wal...@wj...> Change-Id: I6752dcd5aff3e5cea2b439366479e86751a1c403 Signed-off-by: Arne Schwabe <ar...@rf...> --- M src/openvpn/mudp.c M src/openvpn/ssl_pkt.c M src/openvpn/ssl_pkt.h M tests/unit_tests/openvpn/test_pkt.c 4 files changed, 113 insertions(+), 12 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/67/1067/4 diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 93e65e0..9cd667c 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -63,7 +63,6 @@ msg(D_MULTI_DEBUG, "Reset packet from client, sending HMAC based reset challenge"); } - /* Returns true if this packet should create a new session */ static bool do_pre_decrypt_check(struct multi_context *m, @@ -155,7 +154,8 @@ * need to contain the peer id */ struct gc_arena gc = gc_new(); - bool ret = check_session_id_hmac(state, from, hmac, handwindow); + bool pkt_is_ack = (verdict == VERDICT_VALID_ACK_V1); + bool ret = check_session_id_hmac(state, from, hmac, handwindow, pkt_is_ack); const char *peer = print_link_socket_actual(&m->top.c2.from, &gc); uint8_t pkt_firstbyte = *BPTR( &m->top.c2.buf); @@ -171,6 +171,7 @@ msg(D_MULTI_DEBUG, "Valid packet (%s) with HMAC challenge from peer (%s), " "accepting new connection.", packet_opcode_name(op), peer); } + gc_free(&gc); return ret; diff --git a/src/openvpn/ssl_pkt.c b/src/openvpn/ssl_pkt.c index bfd405f..0bbc465 100644 --- a/src/openvpn/ssl_pkt.c +++ b/src/openvpn/ssl_pkt.c @@ -293,6 +293,7 @@ } } + /* * This function is similar to tls_pre_decrypt, except it is called * when we are in server mode and receive an initial incoming @@ -530,7 +531,8 @@ check_session_id_hmac(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from, hmac_ctx_t *hmac, - int handwindow) + int handwindow, + bool pkt_is_ack) { if (!from) { @@ -545,6 +547,36 @@ return false; } + /* Check if the packet ID of the packet or ACKED packet is <= 1 */ + for (int i = 0; i < ack.len; i++) + { + /* This packet ACKs a packet that has a higher packet id than the + * ones expected in the three-way handshake, consider it as invalid + * for the session */ + if (ack.packet_id[i] > 1) + { + return false; + } + } + + if (!pkt_is_ack) + { + packet_id_type message_id; + /* Extract the packet ID from the packet */ + if (!reliable_ack_read_packet_id(&buf, &message_id)) + { + return false; + } + + /* similar check. Anything larger than 1 is not considered part of the + * three-way handshake */ + if (message_id > 1) + { + return false; + } + } + + /* check adjacent timestamps too */ for (int offset = -2; offset <= 1; offset++) { diff --git a/src/openvpn/ssl_pkt.h b/src/openvpn/ssl_pkt.h index 98a39d3..1b6bcc0 100644 --- a/src/openvpn/ssl_pkt.h +++ b/src/openvpn/ssl_pkt.h @@ -180,17 +180,24 @@ /** * Checks if a control packet has a correct HMAC server session id * + * This will also consider packets that have a packet id higher + * than 1 or ack packets higher than 1 to be invalid as they are + * not part of the initial three way handshake of OpenVPN and should + * not create a new connection. + * * @param state session information * @param from link_socket from the client * @param hmac the hmac context to use for the calculation * @param handwindow the quantisation of the current time + * @param pkt_is_ack the packet being checked is a P_ACK_V1 * @return the expected server session id */ bool check_session_id_hmac(struct tls_pre_decrypt_state *state, const struct openvpn_sockaddr *from, hmac_ctx_t *hmac, - int handwindow); + int handwindow, + bool pkt_is_ack); /* * Write a control channel authentication record. diff --git a/tests/unit_tests/openvpn/test_pkt.c b/tests/unit_tests/openvpn/test_pkt.c index ebffabe..f771a10 100644 --- a/tests/unit_tests/openvpn/test_pkt.c +++ b/tests/unit_tests/openvpn/test_pkt.c @@ -170,6 +170,27 @@ 0x85, 0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e }; +/* no tls-auth, P_ACK_V1, acks 0,1, and 2 */ +const uint8_t client_ack_123_none_random_id[] = { + 0x28, + 0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8, + 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, + 0xdd, 0x85, 0xdb, 0x53, 0x56, 0x23, 0xb0, 0x2e +}; + +/* no tls-auth, P_CONTROL_V1, acks 0, msg-id 2 */ +const uint8_t client_control_none_random_id[] = { + 0x20, + 0xae, 0xb9, 0xaf, 0xe1, 0xf0, 0x1d, 0x79, 0xc8, + 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x02 +}; + + struct tls_auth_standalone init_tas_auth(int key_direction) { @@ -290,12 +311,10 @@ assert_int_equal(verdict, VERDICT_VALID_RESET_V2); free_tls_pre_decrypt_state(&state); - free_tls_pre_decrypt_state(&state); /* The pre decrypt function should not modify the buffer, so calling it * again should have the same result */ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); assert_int_equal(verdict, VERDICT_VALID_RESET_V2); - free_tls_pre_decrypt_state(&state); /* and buf memory should be equal */ assert_memory_equal(BPTR(&buf), client_reset_v2_tls_auth, sizeof(client_reset_v2_tls_auth)); @@ -313,7 +332,6 @@ assert_int_equal(verdict, VERDICT_INVALID); free_tls_pre_decrypt_state(&state); - free_tls_pre_decrypt_state(&state); /* Wrong key direction gives a wrong hmac key and should not validate */ free_key_ctx_bi(&tas.tls_wrap.opt.key_ctx_bi); free_tas(&tas); @@ -353,15 +371,12 @@ assert_int_equal(verdict, VERDICT_VALID_RESET_V2); free_tls_pre_decrypt_state(&state); - free_tls_pre_decrypt_state(&state); buf_reset_len(&buf); buf_write(&buf, client_reset_v2_tls_crypt, sizeof(client_reset_v2_none)); verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); assert_int_equal(verdict, VERDICT_VALID_RESET_V2); free_tls_pre_decrypt_state(&state); - free_tls_pre_decrypt_state(&state); - /* This is not a reset packet and should trigger the other response */ buf_reset_len(&buf); buf_write(&buf, client_ack_tls_auth_randomid, sizeof(client_ack_tls_auth_randomid)); @@ -439,7 +454,7 @@ assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1); /* This is a valid packet but containing a random id instead of an HMAC id*/ - bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30); + bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30, false); assert_false(valid); free_tls_pre_decrypt_state(&state); @@ -470,7 +485,7 @@ verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); assert_int_equal(verdict, VERDICT_VALID_ACK_V1); - bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30); + bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30, true); assert_true(valid); free_tls_pre_decrypt_state(&state); @@ -479,6 +494,51 @@ hmac_ctx_free(hmac); } +static void +test_verify_hmac_none_out_of_range_ack(void **ut_state) +{ + hmac_ctx_t *hmac = session_id_hmac_init(); + + struct link_socket_actual from = { 0 }; + from.dest.addr.sa.sa_family = AF_INET; + + struct tls_auth_standalone tas = { 0 }; + struct tls_pre_decrypt_state state = { 0 }; + + struct buffer buf = alloc_buf(1024); + enum first_packet_verdict verdict; + + tas.tls_wrap.mode = TLS_WRAP_NONE; + + buf_reset_len(&buf); + buf_write(&buf, client_ack_123_none_random_id, sizeof(client_ack_123_none_random_id)); + + + verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); + assert_int_equal(verdict, VERDICT_VALID_ACK_V1); + + /* should fail because it acks 2 */ + bool valid = check_session_id_hmac(&state, &from.dest, hmac, 30, true); + assert_false(valid); + free_tls_pre_decrypt_state(&state); + + /* Try test with the control with a too high message id now */ + buf_reset_len(&buf); + buf_write(&buf, client_control_none_random_id, sizeof(client_control_none_random_id)); + + verdict = tls_pre_decrypt_lite(&tas, &state, &from, &buf); + assert_int_equal(verdict, VERDICT_VALID_CONTROL_V1); + + /* should fail because it has message id 2 */ + valid = check_session_id_hmac(&state, &from.dest, hmac, 30, true); + assert_false(valid); + + free_tls_pre_decrypt_state(&state); + free_buf(&buf); + hmac_ctx_cleanup(hmac); + hmac_ctx_free(hmac); +} + static hmac_ctx_t * init_static_hmac(void) { @@ -667,6 +727,7 @@ cmocka_unit_test(test_calc_session_id_hmac_static), cmocka_unit_test(test_verify_hmac_none), cmocka_unit_test(test_verify_hmac_tls_auth), + cmocka_unit_test(test_verify_hmac_none_out_of_range_ack), cmocka_unit_test(test_generate_reset_packet_plain), cmocka_unit_test(test_generate_reset_packet_tls_auth), cmocka_unit_test(test_extract_control_message) -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1067?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I6752dcd5aff3e5cea2b439366479e86751a1c403 Gerrit-Change-Number: 1067 Gerrit-PatchSet: 4 Gerrit-Owner: plaisthos <arn...@rf...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-MessageType: newpatchset |
From: ordex (C. Review) <ge...@op...> - 2025-07-28 11:39:50
|
Attention is currently required from: cron2, flichtenheld, plaisthos. ordex has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/1116?usp=email ) Change subject: dco: drop client prefix after DCO PEER_FLOAT notification ...................................................................... Patch Set 2: (1 comment) Patchset: PS2: > These are 2 different problems: […] After fixing problem 1) we should heck what remains of problem 2, because we execute DCO commands always in the context of a known peer. We can't truly jump from peer X to peer Y. Also when doing a PEER_GET with id=-1 (dump all peers), we should not have any prefix set. If we had one imho it was a leftover from the float (problem 1) -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1116?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I1ad5df0f6785ffe9becd9f83329a9335d1a36f24 Gerrit-Change-Number: 1116 Gerrit-PatchSet: 2 Gerrit-Owner: ordex <an...@ma...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Comment-Date: Mon, 28 Jul 2025 11:39:36 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: No Comment-In-Reply-To: cron2 <ge...@gr...> Comment-In-Reply-To: ordex <an...@ma...> Gerrit-MessageType: comment |
From: ordex (C. Review) <ge...@op...> - 2025-07-28 11:38:04
|
Attention is currently required from: cron2, flichtenheld, plaisthos. ordex has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/1116?usp=email ) Change subject: dco: drop client prefix after DCO PEER_FLOAT notification ...................................................................... Patch Set 2: (1 comment) Patchset: PS2: > Actually it is just fixing one particular symptom, but we can get there in other paths as well - her […] These are 2 different problems: 1) when we float we set an unexpected prefix and we stick to it. 2) when we parse notifications we may use the prefix coming from another instance. This patch is trying to fix problem 1, which is similar but different from problem 2. -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1116?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I1ad5df0f6785ffe9becd9f83329a9335d1a36f24 Gerrit-Change-Number: 1116 Gerrit-PatchSet: 2 Gerrit-Owner: ordex <an...@ma...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Comment-Date: Mon, 28 Jul 2025 11:37:49 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: No Comment-In-Reply-To: cron2 <ge...@gr...> Gerrit-MessageType: comment |
From: cron2 (C. Review) <ge...@op...> - 2025-07-28 11:00:45
|
cron2 has submitted this change. ( http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email ) Change subject: unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 ...................................................................... unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 add <stdint.h> to test_search_and_replace.c to fix build error on fedora 42 / arm64 ("error: uintptr_t undeclared") Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Signed-off-by: Gert Doering <ge...@gr...> Acked-by: Frank Lichtenheld <fr...@li...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32384.html Signed-off-by: Gert Doering <ge...@gr...> --- M tests/unit_tests/plugins/auth-pam/test_search_and_replace.c 1 file changed, 1 insertion(+), 0 deletions(-) diff --git a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c index d40467f..50b241d 100644 --- a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c +++ b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c @@ -2,6 +2,7 @@ #include <unistd.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <setjmp.h> #include <cmocka.h> -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Gerrit-Change-Number: 1118 Gerrit-PatchSet: 2 Gerrit-Owner: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-MessageType: merged |
From: cron2 (C. Review) <ge...@op...> - 2025-07-28 11:00:39
|
Hello flichtenheld, plaisthos, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email to look at the new patch set (#2). The following approvals got outdated and were removed: Code-Review+2 by flichtenheld Change subject: unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 ...................................................................... unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 add <stdint.h> to test_search_and_replace.c to fix build error on fedora 42 / arm64 ("error: uintptr_t undeclared") Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Signed-off-by: Gert Doering <ge...@gr...> Acked-by: Frank Lichtenheld <fr...@li...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32384.html Signed-off-by: Gert Doering <ge...@gr...> --- M tests/unit_tests/plugins/auth-pam/test_search_and_replace.c 1 file changed, 1 insertion(+), 0 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/18/1118/2 diff --git a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c index d40467f..50b241d 100644 --- a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c +++ b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c @@ -2,6 +2,7 @@ #include <unistd.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <setjmp.h> #include <cmocka.h> -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Gerrit-Change-Number: 1118 Gerrit-PatchSet: 2 Gerrit-Owner: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-MessageType: newpatchset |
From: Gert D. <ge...@gr...> - 2025-07-28 11:00:23
|
It seems this would also affect feodora-42 on amd64, we just missed on the "updates that bring in the breaking change" - but now we are prepared ;-) Patch has been applied to the master branch. commit 035d47e6d80996a4cde8af1b35f9ba40b676c825 Author: Gert Doering Date: Mon Jul 28 12:42:29 2025 +0200 unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 Signed-off-by: Gert Doering <ge...@gr...> Acked-by: Frank Lichtenheld <fr...@li...> Message-Id: <202...@gr...> URL: https://www.mail-archive.com/ope...@li.../msg32384.html Signed-off-by: Gert Doering <ge...@gr...> -- kind regards, Gert Doering |
From: mrbff (C. Review) <ge...@op...> - 2025-07-28 10:43:23
|
Attention is currently required from: cron2, flichtenheld, stipa. mrbff has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/808?usp=email ) Change subject: PUSH_UPDATE: Allow OpenVPN in client mode to receive and handle PUSH UPDATE control messages to allow options updating at runtime. ...................................................................... Patch Set 21: (2 comments) File src/openvpn/options.c: http://gerrit.openvpn.net/c/openvpn/+/808/comment/341dde0f_71ee184e : PS21, Line 5524: { > please get rid of this extra `if()` level. […] Done http://gerrit.openvpn.net/c/openvpn/+/808/comment/005048a0_9d87b4c9 : PS21, Line 5532: || (options->pull_filter_list && !apply_pull_filter(options, &line[i]))) > I find this very hard to understand, even if it's a bit more space-efficient than having two `if()` […] Done -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/808?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I6ecd4cb47571cc8c20e46de8595c742aeec6064a Gerrit-Change-Number: 808 Gerrit-PatchSet: 21 Gerrit-Owner: mrbff <ma...@ma...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-Reviewer: stipa <lst...@gm...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Attention: stipa <lst...@gm...> Gerrit-Comment-Date: Mon, 28 Jul 2025 10:43:08 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: No Comment-In-Reply-To: cron2 <ge...@gr...> Gerrit-MessageType: comment |
From: mrbff (C. Review) <ge...@op...> - 2025-07-28 10:43:12
|
Attention is currently required from: cron2, flichtenheld, mrbff, stipa. Hello cron2, flichtenheld, plaisthos, stipa, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/808?usp=email to look at the new patch set (#22). The following approvals got outdated and were removed: Code-Review-1 by cron2 Change subject: PUSH_UPDATE: Allow OpenVPN in client mode to receive and handle PUSH UPDATE control messages to allow options updating at runtime. ...................................................................... PUSH_UPDATE: Allow OpenVPN in client mode to receive and handle PUSH UPDATE control messages to allow options updating at runtime. * Added IV_PROTO_PUSH_UPDATE flag bit to support push-updates. * Added process_incoming_push_update(), in a separate file to create tests more easily. * Modified incoming_push_message(), process_incoming_push_msg(), apply_push_options(), apply_pull_filter() to process also push-update messages. * Added the check_push_update_option_flags() function used in apply_pull_filter() to check options formatting inside push-update messages, if the options are updatables and to check for '?' and '-' flags that may be present in front of the options. The '-' flag is used to indicate that the option in question should be removed, while the '?' indicates that the option is optional and to do not generate errors if the client cannot update that option. For more info you can read the RFC at https://github.com/OpenVPN/openvpn-rfc . * Created some unit tests for the push-update message handling in test_push_update_msg.c. Change-Id: I6ecd4cb47571cc8c20e46de8595c742aeec6064a Signed-off-by: Marco Baffo <ma...@ma...> --- M CMakeLists.txt M src/openvpn/Makefile.am M src/openvpn/forward.c M src/openvpn/init.c M src/openvpn/options.c M src/openvpn/options.h M src/openvpn/options_util.c M src/openvpn/options_util.h M src/openvpn/push.c M src/openvpn/push.h A src/openvpn/push_util.c M src/openvpn/ssl.c M src/openvpn/ssl.h M tests/unit_tests/openvpn/Makefile.am A tests/unit_tests/openvpn/test_push_update_msg.c 15 files changed, 625 insertions(+), 88 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/08/808/22 diff --git a/CMakeLists.txt b/CMakeLists.txt index efb2d2d..3866e21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,6 +534,7 @@ src/openvpn/ps.c src/openvpn/ps.h src/openvpn/push.c + src/openvpn/push_util.c src/openvpn/push.h src/openvpn/pushlist.h src/openvpn/reflect_filter.c @@ -652,6 +653,7 @@ "test_provider" "test_ssl" "test_user_pass" + "test_push_update_msg" ) if (WIN32) @@ -854,6 +856,14 @@ src/openvpn/run_command.c ) + target_sources(test_push_update_msg PRIVATE + tests/unit_tests/openvpn/mock_msg.c + tests/unit_tests/openvpn/mock_get_random.c + src/openvpn/push_util.c + src/openvpn/options_util.c + src/openvpn/otime.c + ) + if (TARGET test_argv) target_link_options(test_argv PRIVATE -Wl,--wrap=parse_line) target_sources(test_argv PRIVATE diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a5d4cdc..1e17c3f 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -117,7 +117,7 @@ proto.c proto.h \ proxy.c proxy.h \ ps.c ps.h \ - push.c push.h \ + push.c push_util.c push.h \ pushlist.h \ reflect_filter.c reflect_filter.h \ reliable.c reliable.h \ diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index dfc6708..475d142 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -2064,7 +2064,7 @@ } /* check for incoming control messages on the control channel like - * push request/reply, or authentication failure and 2FA messages */ + * push request/reply/update, or authentication failure and 2FA messages */ if (tls_test_payload_len(c->c2.tls_multi) > 0) { check_incoming_control_channel(c); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index aac8a6a..ba1dda4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2051,8 +2051,8 @@ /* possibly add routes */ if ((route_order(c->c1.tuntap) == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) { - int status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); + bool status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); *error_flags |= (status ? 0 : ISC_ROUTE_ERRORS); } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 0662b49..2083eae 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -66,6 +66,7 @@ #include <ctype.h> #include "memdbg.h" +#include "options_util.h" const char title_string[] = PACKAGE_STRING @@ -948,24 +949,6 @@ } } -struct pull_filter -{ -#define PUF_TYPE_UNDEF 0 /**< undefined filter type */ -#define PUF_TYPE_ACCEPT 1 /**< filter type to accept a matching option */ -#define PUF_TYPE_IGNORE 2 /**< filter type to ignore a matching option */ -#define PUF_TYPE_REJECT 3 /**< filter type to reject and trigger SIGUSR1 */ - int type; - int size; - char *pattern; - struct pull_filter *next; -}; - -struct pull_filter_list -{ - struct pull_filter *head; - struct pull_filter *tail; -}; - #ifndef ENABLE_SMALL static const char * @@ -5515,60 +5498,14 @@ } } -/** - * Filter an option line by all pull filters. - * - * If a match is found, the line is modified depending on - * the filter type, and returns true. If the filter type is - * reject, SIGUSR1 is triggered and the return value is false. - * In that case the caller must end the push processing. - */ -static bool -apply_pull_filter(const struct options *o, char *line) -{ - struct pull_filter *f; - - if (!o->pull_filter_list) - { - return true; - } - - /* skip leading spaces matching the behaviour of parse_line */ - while (isspace(*line)) - { - line++; - } - - for (f = o->pull_filter_list->head; f; f = f->next) - { - if (f->type == PUF_TYPE_ACCEPT && strncmp(line, f->pattern, f->size) == 0) - { - msg(D_LOW, "Pushed option accepted by filter: '%s'", line); - return true; - } - else if (f->type == PUF_TYPE_IGNORE && strncmp(line, f->pattern, f->size) == 0) - { - msg(D_PUSH, "Pushed option removed by filter: '%s'", line); - *line = '\0'; - return true; - } - else if (f->type == PUF_TYPE_REJECT && strncmp(line, f->pattern, f->size) == 0) - { - msg(M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line); - *line = '\0'; - throw_signal_soft(SIGUSR1, "Offending option received from server"); - return false; - } - } - return true; -} - bool -apply_push_options(struct options *options, +apply_push_options(struct context *c, + struct options *options, struct buffer *buf, unsigned int permission_mask, unsigned int *option_types_found, - struct env_set *es) + struct env_set *es, + bool is_update) { char line[OPTION_PARM_SIZE]; int line_num = 0; @@ -5580,14 +5517,40 @@ char *p[MAX_PARMS+1]; CLEAR(p); ++line_num; - if (!apply_pull_filter(options, line)) + unsigned int push_update_option_flags = 0; + int i = 0; + + /* skip leading spaces matching the behaviour of parse_line */ + while (isspace(line[i])) { + i++; + } + + /* If we are not in a 'PUSH_UPDATE' we just check `apply_pull_filter()` + * otherwise we must call `check_push_update_option_flags()` first + */ + if ((is_update && !check_push_update_option_flags(line, &i, &push_update_option_flags)) + || !apply_pull_filter(options, &line[i])) + { + /* In case we are in a `PUSH_UPDATE` and `check_push_update_option_flags()` + * or `apply_pull_filter()` fail but the option is flagged by `PUSH_OPT_OPTIONAL`, + * instead of restarting, we just ignore the option and we process the next one + */ + if (push_update_option_flags & PUSH_OPT_OPTIONAL) + { + continue; /* Ignoring this option */ + } + throw_signal_soft(SIGUSR1, "Offending option received from server"); return false; /* Cause push/pull error and stop push processing */ } - if (parse_line(line, p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) + + if (parse_line(&line[i], p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) { - add_option(options, p, false, file, line_num, 0, msglevel, - permission_mask, option_types_found, es); + if (!is_update) + { + add_option(options, p, false, file, line_num, 0, msglevel, + permission_mask, option_types_found, es); + } } } return true; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 56e85d7..0544ca9 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -794,6 +794,33 @@ #define MAN_CLIENT_AUTH_ENABLED(opt) (false) #endif +/* + * some PUSH_UPDATE options + */ +#define OPT_P_U_ROUTE (1<<0) +#define OPT_P_U_ROUTE6 (1<<1) +#define OPT_P_U_DNS (1<<2) +#define OPT_P_U_DHCP (1<<3) +#define OPT_P_U_REDIR_GATEWAY (1<<4) + +struct pull_filter +{ +#define PUF_TYPE_UNDEF 0 /**< undefined filter type */ +#define PUF_TYPE_ACCEPT 1 /**< filter type to accept a matching option */ +#define PUF_TYPE_IGNORE 2 /**< filter type to ignore a matching option */ +#define PUF_TYPE_REJECT 3 /**< filter type to reject and trigger SIGUSR1 */ + int type; + int size; + char *pattern; + struct pull_filter *next; +}; + +struct pull_filter_list +{ + struct pull_filter *head; + struct pull_filter *tail; +}; + void parse_argv(struct options *options, const int argc, char *argv[], @@ -862,11 +889,13 @@ void pre_connect_restore(struct options *o, struct gc_arena *gc); -bool apply_push_options(struct options *options, +bool apply_push_options(struct context *c, + struct options *options, struct buffer *buf, unsigned int permission_mask, unsigned int *option_types_found, - struct env_set *es); + struct env_set *es, + bool is_update); void options_detach(struct options *o); diff --git a/src/openvpn/options_util.c b/src/openvpn/options_util.c index 80d0c08..d317c1a 100644 --- a/src/openvpn/options_util.c +++ b/src/openvpn/options_util.c @@ -30,6 +30,8 @@ #include "options_util.h" +#include "push.h" + const char * parse_auth_failed_temp(struct options *o, const char *reason) { @@ -145,3 +147,116 @@ return (int) i; } + +static const char *updatable_options[] = { + "block-ipv6", + "block-outside-dns", + "dhcp-option", + "dns", + "ifconfig", + "ifconfig-ipv6", + "push-continuation", + "redirect-gateway", + "redirect-private", + "route", + "route-gateway", + "route-ipv6", + "route-metric", + "topology", + "tun-mtu", + "keepalive" +}; + +bool +check_push_update_option_flags(char *line, int *i, unsigned int *flags) +{ + *flags = 0; + bool opt_is_updatable = false; + char c = line[*i]; + + /* We check for '?' and '-' and + * if they are present we skip them. + */ + if (c == '-') + { + if (!(line)[*i + 1]) + { + return false; + } + *flags |= PUSH_OPT_TO_REMOVE; + c = (line)[++(*i)]; + } + if (c == '?') + { + if (!(line)[*i + 1] || (line)[*i + 1] == '-') + { + return false; + } + *flags |= PUSH_OPT_OPTIONAL; + c = (line)[++(*i)]; + } + + size_t len = strlen(&line[*i]); + int count = sizeof(updatable_options)/sizeof(char *); + for (int j = 0; j < count; ++j) + { + size_t opt_len = strlen(updatable_options[j]); + if (len < opt_len) + { + continue; + } + if (!strncmp(&line[*i], updatable_options[j], opt_len) + && (!line[*i + opt_len] || line[*i + opt_len] == ' ')) + { + opt_is_updatable = true; + break; + } + } + + if (!opt_is_updatable) + { + if (*flags & PUSH_OPT_OPTIONAL) + { + msg(D_PUSH, "Pushed option is not updatable: '%s'. Ignoring.", line); + } + else + { + msg(M_WARN, "Pushed option is not updatable: '%s'. Restarting.", line); + return false; + } + } + + return true; +} + +bool +apply_pull_filter(const struct options *o, char *line) +{ + if (!o->pull_filter_list) + { + return true; + } + + struct pull_filter *f; + + for (f = o->pull_filter_list->head; f; f = f->next) + { + if (f->type == PUF_TYPE_ACCEPT && strncmp(line, f->pattern, f->size) == 0) + { + msg(D_LOW, "Pushed option accepted by filter: '%s'", line); + return true; + } + else if (f->type == PUF_TYPE_IGNORE && strncmp(line, f->pattern, f->size) == 0) + { + msg(D_PUSH, "Pushed option removed by filter: '%s'", line); + *line = '\0'; + return true; + } + else if (f->type == PUF_TYPE_REJECT && strncmp(line, f->pattern, f->size) == 0) + { + msg(M_WARN, "Pushed option rejected by filter: '%s'.", line); + return false; + } + } + return true; +} diff --git a/src/openvpn/options_util.h b/src/openvpn/options_util.h index 2474e7f..71d51d6 100644 --- a/src/openvpn/options_util.h +++ b/src/openvpn/options_util.h @@ -50,4 +50,47 @@ int atoi_warn(const char *str, int msglevel); +/** + * Filter an option line by all pull filters. + * + * If a match is found, the line is modified depending on + * the filter type, and returns true. If the filter type is + * reject, SIGUSR1 is triggered and the return value is false. + * In that case the caller must end the push processing. + */ +bool +apply_pull_filter(const struct options *o, + char *line); + +/** + * @brief Checks the formatting and validity of options inside push-update messages. + * + * This function is used to validate and process options + * in push-update messages. It performs the following checks: + * - Determines if the options are updatable. + * - Checks for the presence of the `-` flag, which indicates that the option + * should be removed. + * - Checks for the `?` flag, which marks the option as optional and suppresses + * errors if the client cannot update it. + * - Increase the value pointed by 'i' when we encounter the `'-'` and `'?'` flags + * after validating them and updating the appropriate flags in the `flags` variable. + * - `-?option`, `-option`, `?option` are valid formats, `?-option` is not a valid format. + * - If the flags and the option are not consecutive, the option is invalid: + * `- ?option`, `-? option`, `- option` are invalid formats. + * + * @param line A pointer to an option string. This string is the option being validated. + * @param i A pointer to an integer that represents the current index in the `line` string. + * @param flags A pointer where flags will be stored: + * - `PUSH_OPT_TO_REMOVE`: Set if the `-` flag is present. + * - `PUSH_OPT_OPTIONAL`: Set if the `?` flag is present. + * + * @return true if the flags and option combination are valid. + * @return false if: + * - The `-` and `?` flags are not formatted correctly. + * - The `line` parameter is empty or `NULL`. + * - The `?` flag is absent and the option is not updatable. + */ +bool +check_push_update_option_flags(char *line, int *i, unsigned int *flags); + #endif /* ifndef OPTIONS_UTIL_H_ */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index ad8fa3d7..858b821 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -39,8 +39,6 @@ #include "ssl_util.h" #include "options_util.h" -static char push_reply_cmd[] = "PUSH_REPLY"; - /* * Auth username/password * @@ -519,21 +517,31 @@ { msg(D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); } - else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) + else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_UPDATE || status == PUSH_MSG_CONTINUATION) { c->options.push_option_types_found |= option_types_found; /* delay bringing tun/tap up until --push parms received from remote */ - if (status == PUSH_MSG_REPLY) + if (status == PUSH_MSG_REPLY || status == PUSH_MSG_UPDATE) { if (!options_postprocess_pull(&c->options, c->c2.es)) { goto error; } - if (!do_up(c, true, c->options.push_option_types_found)) + if (status == PUSH_MSG_REPLY) { - msg(D_PUSH_ERRORS, "Failed to open tun/tap interface"); - goto error; + if (!do_up(c, true, c->options.push_option_types_found)) + { + msg(D_PUSH_ERRORS, "Failed to open tun/tap interface"); + goto error; + } + } + else + { + if (!option_types_found) + { + msg(M_WARN, "No updatable options found in incoming PUSH_UPDATE message"); + } } } event_timeout_clear(&c->c2.push_request_interval); @@ -1056,11 +1064,13 @@ md_ctx_init(c->c2.pulled_options_state, "SHA256"); c->c2.pulled_options_digest_init_done = true; } - if (apply_push_options(&c->options, + if (apply_push_options(c, + &c->options, buf, permission_mask, option_types_found, - c->c2.es)) + c->c2.es, + false)) { push_update_digest(c->c2.pulled_options_state, &buf_orig, &c->options); @@ -1111,6 +1121,12 @@ return process_incoming_push_reply(c, permission_mask, option_types_found, &buf); } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_update_cmd)) + { + return process_incoming_push_update(c, permission_mask, + option_types_found, &buf); + } else { return PUSH_MSG_ERROR; diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 048b4c4..18dfcd8 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -33,9 +33,42 @@ #define PUSH_MSG_AUTH_FAILURE 4 #define PUSH_MSG_CONTINUATION 5 #define PUSH_MSG_ALREADY_REPLIED 6 +#define PUSH_MSG_UPDATE 7 + +#define push_reply_cmd "PUSH_REPLY" +#define push_update_cmd "PUSH_UPDATE" + +/* Push-update options flags */ +#define PUSH_OPT_TO_REMOVE (1<<0) +#define PUSH_OPT_OPTIONAL (1<<1) int process_incoming_push_request(struct context *c); +/** + * @brief Handles the receiving of a push-update message and applies updates to the specified options. + * + * This function processes a push-update message, validating its content and applying updates + * to the options specified in the message. It also handles split messages if the complete + * message has not yet been received. + * + * @param c The context for the operation. + * @param permission_mask The permission mask specifying which options are allowed to be pulled. + * @param option_types_found A pointer to a variable that will be filled with the types of options + * found in the message. + * @param buf A buffer containing the received message. + * + * @return + * - `PUSH_MSG_UPDATE`: The message was processed successfully, and the updates were applied. + * - `PUSH_MSG_CONTINUATION`: The message is a fragment of a larger message, and the program is + * waiting for the final part. + * - `PUSH_MSG_ERROR`: An error occurred during message processing, or the message is invalid. + */ + +int process_incoming_push_update(struct context *c, + unsigned int permission_mask, + unsigned int *option_types_found, + struct buffer *buf); + int process_incoming_push_msg(struct context *c, const struct buffer *buffer, bool honor_received_options, diff --git a/src/openvpn/push_util.c b/src/openvpn/push_util.c new file mode 100644 index 0000000..b4d1e8b --- /dev/null +++ b/src/openvpn/push_util.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "push.h" + +int +process_incoming_push_update(struct context *c, + unsigned int permission_mask, + unsigned int *option_types_found, + struct buffer *buf) +{ + int ret = PUSH_MSG_ERROR; + const uint8_t ch = buf_read_u8(buf); + if (ch == ',') + { + if (apply_push_options(c, + &c->options, + buf, + permission_mask, + option_types_found, + c->c2.es, + true)) + { + switch (c->options.push_continuation) + { + case 0: + case 1: + ret = PUSH_MSG_UPDATE; + break; + + case 2: + ret = PUSH_MSG_CONTINUATION; + break; + } + } + } + else if (ch == '\0') + { + ret = PUSH_MSG_UPDATE; + } + + return ret; +} diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 9c6616a..a7658dd 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1993,6 +1993,9 @@ /* support for exit notify via control channel */ iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; + /* support push-updates */ + iv_proto |= IV_PROTO_PUSH_UPDATE; + if (session->opt->pull) { /* support for receiving push_reply before sending diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 000992d..0a43ea1 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -114,6 +114,9 @@ /** Supports the --dns option after all the incompatible changes */ #define IV_PROTO_DNS_OPTION_V2 (1<<11) +/** Supports push-update */ +#define IV_PROTO_PUSH_UPDATE (1<<12) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index b47b495..b24e03c 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -11,7 +11,7 @@ endif test_binaries += crypto_testdriver packet_id_testdriver auth_token_testdriver ncp_testdriver misc_testdriver \ - pkt_testdriver ssl_testdriver user_pass_testdriver + pkt_testdriver ssl_testdriver user_pass_testdriver push_update_msg_testdriver if HAVE_LD_WRAP_SUPPORT if !WIN32 @@ -326,3 +326,21 @@ $(top_srcdir)/src/openvpn/win32-util.c \ $(top_srcdir)/src/openvpn/platform.c \ $(top_srcdir)/src/openvpn/list.c + +push_update_msg_testdriver_CFLAGS = -I$(top_srcdir)/src/openvpn \ + -I$(top_srcdir)/src/compat \ + -I$(top_srcdir)/tests/unit_tests/openvpn \ + @TEST_CFLAGS@ + +push_update_msg_testdriver_LDFLAGS = \ + @TEST_LDFLAGS@ \ + -L$(top_srcdir)/src/openvpn + +push_update_msg_testdriver_SOURCES = test_push_update_msg.c \ + mock_msg.c \ + mock_get_random.c \ + $(top_srcdir)/src/openvpn/buffer.c \ + $(top_srcdir)/src/openvpn/platform.c \ + $(top_srcdir)/src/openvpn/push_util.c \ + $(top_srcdir)/src/openvpn/options_util.c \ + $(top_srcdir)/src/openvpn/otime.c \ No newline at end of file diff --git a/tests/unit_tests/openvpn/test_push_update_msg.c b/tests/unit_tests/openvpn/test_push_update_msg.c new file mode 100644 index 0000000..d47286a --- /dev/null +++ b/tests/unit_tests/openvpn/test_push_update_msg.c @@ -0,0 +1,260 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdarg.h> +#include <setjmp.h> +#include <cmocka.h> +#include "push.h" +#include "options_util.h" + +/* mocks */ + +unsigned int +pull_permission_mask(const struct context *c) +{ + unsigned int flags = + OPT_P_UP + | OPT_P_ROUTE_EXTRAS + | OPT_P_SOCKBUF + | OPT_P_SOCKFLAGS + | OPT_P_SETENV + | OPT_P_SHAPER + | OPT_P_TIMER + | OPT_P_COMP + | OPT_P_PERSIST + | OPT_P_MESSAGES + | OPT_P_EXPLICIT_NOTIFY + | OPT_P_ECHO + | OPT_P_PULL_MODE + | OPT_P_PEER_ID + | OPT_P_NCP + | OPT_P_PUSH_MTU + | OPT_P_ROUTE + | OPT_P_DHCPDNS; + return flags; +} + +bool +apply_push_options(struct context *c, + struct options *options, + struct buffer *buf, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es, + bool is_update) +{ + char line[OPTION_PARM_SIZE]; + + while (buf_parse(buf, ',', line, sizeof(line))) + { + unsigned int push_update_option_flags = 0; + int i = 0; + + if (is_update || options->pull_filter_list) + { + /* skip leading spaces matching the behaviour of parse_line */ + while (isspace(line[i])) + { + i++; + } + + if ((is_update && !check_push_update_option_flags(line, &i, &push_update_option_flags)) + || (options->pull_filter_list && !apply_pull_filter(options, &line[i]))) + { + if (push_update_option_flags & PUSH_OPT_OPTIONAL) + { + continue; /* Ignoring this option */ + } + msg(M_WARN, "Offending option received from server"); + return false; /* Cause push/pull error and stop push processing */ + } + } + /* + * No need to test also the application part here + * (add_option/remove_option/update_option) + */ + } + return true; +} + +int +process_incoming_push_msg(struct context *c, + const struct buffer *buffer, + bool honor_received_options, + unsigned int permission_mask, + unsigned int *option_types_found) +{ + struct buffer buf = *buffer; + + if (buf_string_compare_advance(&buf, "PUSH_REQUEST")) + { + return PUSH_MSG_REQUEST; + } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_reply_cmd)) + { + return PUSH_MSG_REPLY; + } + else if (honor_received_options + && buf_string_compare_advance(&buf, push_update_cmd)) + { + return process_incoming_push_update(c, permission_mask, + option_types_found, &buf); + } + else + { + return PUSH_MSG_ERROR; + } +} + +/* tests */ + +static void +test_incoming_push_message_basic(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,dhcp-option DNS 8.8.8.8, route 0.0.0.0 0.0.0.0 10.10.10.1"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_error1(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATEerr,dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + + +static void +test_incoming_push_message_error2(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE ,dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_1(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, -?dns, route something, ?dhcp-option DNS 8.8.8.8"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_bad_format(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, -dhcp-option, ?-dns"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_not_updatable_option(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE, dev tun"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_ERROR); + + free_buf(&buf); +} + +static void +test_incoming_push_message_mix(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,-dhcp-option, route 10.10.10.0, dhcp-option DNS 1.1.1.1, route 10.11.12.0, dhcp-option DOMAIN corp.local, keepalive 10 60"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static void +test_incoming_push_message_mix2(void **state) +{ + struct context *c = *state; + struct buffer buf = alloc_buf(256); + const char *update_msg = "PUSH_UPDATE,-dhcp-option,dhcp-option DNS 8.8.8.8,redirect-gateway local,route 192.168.1.0 255.255.255.0"; + buf_write(&buf, update_msg, strlen(update_msg)); + unsigned int option_types_found = 0; + + assert_int_equal(process_incoming_push_msg(c, &buf, c->options.pull, pull_permission_mask(c), &option_types_found), PUSH_MSG_UPDATE); + + free_buf(&buf); +} + +static int +setup(void **state) +{ + struct context *c = calloc(1, sizeof(struct context)); + c->options.pull = true; + c->options.route_nopull = false; + *state = c; + return 0; +} + +static int +teardown(void **state) +{ + struct context *c = *state; + free(c); + return 0; +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_incoming_push_message_basic, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_error1, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_error2, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_not_updatable_option, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_1, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_bad_format, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_mix, setup, teardown), + cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/808?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I6ecd4cb47571cc8c20e46de8595c742aeec6064a Gerrit-Change-Number: 808 Gerrit-PatchSet: 22 Gerrit-Owner: mrbff <ma...@ma...> Gerrit-Reviewer: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-Reviewer: stipa <lst...@gm...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Attention: flichtenheld <fr...@li...> Gerrit-Attention: mrbff <ma...@ma...> Gerrit-Attention: stipa <lst...@gm...> Gerrit-MessageType: newpatchset |
From: Gert D. <ge...@gr...> - 2025-07-28 10:42:52
|
add <stdint.h> to test_search_and_replace.c to fix build error on fedora 42 / arm64 ("error: uintptr_t undeclared") Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Signed-off-by: Gert Doering <ge...@gr...> Acked-by: Frank Lichtenheld <fr...@li...> --- 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/+/1118 This mail reflects revision 1 of this Change. Acked-by according to Gerrit (reflected above): Frank Lichtenheld <fr...@li...> diff --git a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c index d40467f..50b241d 100644 --- a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c +++ b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c @@ -2,6 +2,7 @@ #include <unistd.h> #include <stdlib.h> #include <stdarg.h> +#include <stdint.h> #include <string.h> #include <setjmp.h> #include <cmocka.h> |
From: flichtenheld (C. Review) <ge...@op...> - 2025-07-28 10:38:43
|
Attention is currently required from: cron2, plaisthos. flichtenheld has posted comments on this change. ( http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email ) Change subject: unit_tests/plugins/auth-pam: fix stdint.h related build error on fedora 42 ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/1118?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I2ab13767b5aa858e024b45be3d161bf6090de763 Gerrit-Change-Number: 1118 Gerrit-PatchSet: 1 Gerrit-Owner: cron2 <ge...@gr...> Gerrit-Reviewer: flichtenheld <fr...@li...> Gerrit-Reviewer: plaisthos <arn...@rf...> Gerrit-CC: openvpn-devel <ope...@li...> Gerrit-Attention: plaisthos <arn...@rf...> Gerrit-Attention: cron2 <ge...@gr...> Gerrit-Comment-Date: Mon, 28 Jul 2025 10:38:32 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment |