Message ID | 20220429170236.48239-3-kprovost@netgate.com |
---|---|
State | Superseded |
Headers | show |
Series | [Openvpn-devel,1/4] Handle (DCO) timeouts in client mode | expand |
On 29 Apr 2022, at 19:02, Kristof Provost wrote: > From: Kristof Provost <kp@FreeBSD.org> > > We must create the peer before we can dco_set_peer or dco_new_key. > On the other hand, we must first process options, because those may > change our peer id and we should create the peer with the correct id. > > Split up do_deferred_options() in do_deferred_options() and > finish_options(). Call any DCO configuration operations (i.e. > dco_set_peer()/dco_new_key()) after we've created the peer (i.e. > dco_new_peer()). > > Signed-off-by: Kristof Provost <kprovost@netgate.com> > --- > src/openvpn/init.c | 112 > +++++++++++++++++++++++++------------------- > src/openvpn/init.h | 2 + > src/openvpn/multi.c | 2 + > 3 files changed, 68 insertions(+), 48 deletions(-) > > diff --git a/src/openvpn/init.c b/src/openvpn/init.c > index 8496e21f..5d53cf7e 100644 > --- a/src/openvpn/init.c > +++ b/src/openvpn/init.c > @@ -2100,26 +2100,26 @@ do_up(struct context *c, bool pulled_options, > unsigned int option_types_found) > } > } > > - if ((c->mode == MODE_POINT_TO_POINT) && c->c2.did_open_tun) > + if (pulled_options) > { > - /* If we are in DCO mode we need to set the new peer > options now */ > - int ret = dco_p2p_add_new_peer(c); > - if (ret < 0) > + if (!do_deferred_options(c, option_types_found)) > { > - msg(D_DCO, "Cannot add peer to DCO: %s", > strerror(-ret)); > + msg(D_PUSH_ERRORS, "ERROR: Failed to apply push > options"); > return false; > } > } > - > - if (pulled_options) > + if (c->mode == MODE_POINT_TO_POINT) > { > - if (!do_deferred_options(c, option_types_found)) > + /* If we are in DCO mode we need to set the new peer > options now */ > + int ret = dco_p2p_add_new_peer(c); > + if (ret < 0) > { > - msg(D_PUSH_ERRORS, "ERROR: Failed to apply push > options"); > + msg(D_DCO, "Cannot add peer to DCO: %s", > strerror(-ret)); > return false; > } > } > - else if (c->mode == MODE_POINT_TO_POINT) > + > + if (!pulled_options && c->mode == MODE_POINT_TO_POINT) > { > if (!do_deferred_p2p_ncp(c)) > { > @@ -2128,6 +2128,13 @@ do_up(struct context *c, bool pulled_options, > unsigned int option_types_found) > } > } > > + > + if (!finish_options(c)) > + { > + msg(D_TLS_ERRORS, "ERROR: Failed to finish option > processing"); > + return false; > + } > + > if (c->c2.did_open_tun) > { > c->c1.pulled_options_digest_save = > c->c2.pulled_options_digest; > @@ -2344,49 +2351,58 @@ do_deferred_options(struct context *c, const > unsigned int found) > { > return false; > } > - struct frame *frame_fragment = NULL; > + } > + > + return true; > +} > + > +bool > +finish_options(struct context *c) > +{ > + if (!c->options.pull || !dco_enabled(&c->options)) > + { > + return true; > + } > + > + struct frame *frame_fragment = NULL; > #ifdef ENABLE_FRAGMENT > - if (c->options.ce.fragment) > - { > - frame_fragment = &c->c2.frame_fragment; > - } > + if (c->options.ce.fragment) > + { > + frame_fragment = &c->c2.frame_fragment; > + } > #endif > > - struct tls_session *session = > &c->c2.tls_multi->session[TM_ACTIVE]; > - if (!tls_session_update_crypto_params(c->c2.tls_multi, > session, > - &c->options, > &c->c2.frame, > - frame_fragment, > - > get_link_socket_info(c))) > - { > - msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto > options"); > - return false; > - } > + struct tls_session *session = > &c->c2.tls_multi->session[TM_ACTIVE]; > + if (!tls_session_update_crypto_params(c->c2.tls_multi, session, > + &c->options, &c->c2.frame, > + frame_fragment, > + get_link_socket_info(c))) > + { > + msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto > options"); > + return false; > + } > > - if (dco_enabled(&c->options)) > - { > - /* Check if the pushed options are compatible with DCO if > we have > - * DCO enabled */ > - if (!check_dco_pull_options(&c->options)) > - { > - msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are > incompatible with " > - "data channel offload. Use --disable-dco to > connect" > - "to this server"); > - return false; > - } > + /* Check if the pushed options are compatible with DCO if we have > + * DCO enabled */ > + if (!check_dco_pull_options(&c->options)) > + { > + msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are > incompatible with " > + "data channel offload. Use --disable-dco to connect" > + "to this server"); > + return false; > + } > > - if (c->options.ping_send_timeout || c->c2.frame.mss_fix) > - { > - int ret = dco_set_peer(&c->c1.tuntap->dco, > - c->c2.tls_multi->peer_id, > - c->options.ping_send_timeout, > - c->options.ping_rec_timeout, > - c->c2.frame.mss_fix); > - if (ret < 0) > - { > - msg(D_DCO, "Cannot set DCO peer: %s", > strerror(-ret)); > - return false; > - } > - } > + if (c->options.ping_send_timeout || c->c2.frame.mss_fix) > + { > + int ret = dco_set_peer(&c->c1.tuntap->dco, > + c->c2.tls_multi->peer_id, > + c->options.ping_send_timeout, > + c->options.ping_rec_timeout, > + c->c2.frame.mss_fix); > + if (ret < 0) > + { > + msg(D_DCO, "Cannot set DCO peer: %s", strerror(-ret)); > + return false; > } > } > return true; > diff --git a/src/openvpn/init.h b/src/openvpn/init.h > index 1c341da3..5cc2a990 100644 > --- a/src/openvpn/init.h > +++ b/src/openvpn/init.h > @@ -97,6 +97,8 @@ void reset_coarse_timers(struct context *c); > > bool do_deferred_options(struct context *c, const unsigned int > found); > > +bool finish_options(struct context *c); > + > void inherit_context_child(struct context *dest, > const struct context *src); > > diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c > index 958712f1..47e1c6cc 100644 > --- a/src/openvpn/multi.c > +++ b/src/openvpn/multi.c > @@ -2452,6 +2452,8 @@ multi_client_connect_late_setup(struct > multi_context *m, > mi->context.c2.tls_multi->multi_state = CAS_FAILED; > } > > + finish_options(&mi->context); > + > /* send push reply if ready */ > if (mi->context.c2.push_request_received) > { > -- This patch isn’t quite right. It works well for DCO, but breaks non-DCO. It fails to call tls_session_update_crypto_params() if DCO is disabled. It needs this on top of it: commit ee846144a46b20b889ab1966246f789f3266c2f9 (HEAD -> tmp_v10) Author: Kristof Provost <kp@FreeBSD.org> Date: Thu May 5 19:36:13 2022 +0200 Fix finish_options() to perform the required work for non-DCO modes We still need to run tls_session_update_crypto_params(), even when DCO is not enabled. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 7083b803..ab59cbd7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2374,7 +2374,7 @@ do_deferred_options(struct context *c, const unsigned int found) bool finish_options(struct context *c) { - if (!c->options.pull || !dco_enabled(&c->options)) + if (!c->options.pull) { return true; } @@ -2399,7 +2399,7 @@ finish_options(struct context *c) /* Check if the pushed options are compatible with DCO if we have * DCO enabled */ - if (!check_dco_pull_options(&c->options)) + if (dco_enabled(&c->options) && !check_dco_pull_options(&c->options)) { msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " "data channel offload. Use --disable-dco to connect" @@ -2407,7 +2407,7 @@ finish_options(struct context *c) return false; } - if (c->options.ping_send_timeout || c->c2.frame.mss_fix) + if (dco_enabled(&c->options) && (c->options.ping_send_timeout || c->c2.frame.mss_fix)) { int ret = dco_set_peer(&c->c1.tuntap->dco, c->c2.tls_multi->peer_id, I’ll post an updated series in due course, but wanted to point this issue out already. Kristof <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"> </head> <body><div style="font-family: sans-serif;"><div class="markdown" style="white-space: normal;"> <p dir="auto">On 29 Apr 2022, at 19:02, Kristof Provost wrote:</p> </div><div class="plaintext" style="white-space: normal;"><blockquote style="margin: 0 0 5px; padding-left: 5px; border-left: 2px solid #136BCE; color: #136BCE;"><p dir="auto">From: Kristof Provost <kp@FreeBSD.org></p> <p dir="auto">We must create the peer before we can dco_set_peer or dco_new_key. <br> On the other hand, we must first process options, because those may <br> change our peer id and we should create the peer with the correct id.</p> <p dir="auto">Split up do_deferred_options() in do_deferred_options() and <br> finish_options(). Call any DCO configuration operations (i.e. <br> dco_set_peer()/dco_new_key()) after we've created the peer (i.e. <br> dco_new_peer()).</p> <p dir="auto">Signed-off-by: Kristof Provost <kprovost@netgate.com> <br> --- <br> src/openvpn/init.c | 112 +++++++++++++++++++++++++------------------- <br> src/openvpn/init.h | 2 + <br> src/openvpn/multi.c | 2 + <br> 3 files changed, 68 insertions(+), 48 deletions(-)</p> <p dir="auto">diff --git a/src/openvpn/init.c b/src/openvpn/init.c <br> index 8496e21f..5d53cf7e 100644 <br> --- a/src/openvpn/init.c <br> +++ b/src/openvpn/init.c <br> @@ -2100,26 +2100,26 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) <br> } <br> }</p> <p dir="auto">- if ((c->mode == MODE_POINT_TO_POINT) && c->c2.did_open_tun) <br> + if (pulled_options) <br> { <br> - /* If we are in DCO mode we need to set the new peer options now */ <br> - int ret = dco_p2p_add_new_peer(c); <br> - if (ret < 0) <br> + if (!do_deferred_options(c, option_types_found)) <br> { <br> - msg(D_DCO, "Cannot add peer to DCO: %s", strerror(-ret)); <br> + msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); <br> return false; <br> } <br> } <br> - <br> - if (pulled_options) <br> + if (c->mode == MODE_POINT_TO_POINT) <br> { <br> - if (!do_deferred_options(c, option_types_found)) <br> + /* If we are in DCO mode we need to set the new peer options now */ <br> + int ret = dco_p2p_add_new_peer(c); <br> + if (ret < 0) <br> { <br> - msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); <br> + msg(D_DCO, "Cannot add peer to DCO: %s", strerror(-ret)); <br> return false; <br> } <br> } <br> - else if (c->mode == MODE_POINT_TO_POINT) <br> + <br> + if (!pulled_options && c->mode == MODE_POINT_TO_POINT) <br> { <br> if (!do_deferred_p2p_ncp(c)) <br> { <br> @@ -2128,6 +2128,13 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) <br> } <br> }</p> <p dir="auto">+ <br> + if (!finish_options(c)) <br> + { <br> + msg(D_TLS_ERRORS, "ERROR: Failed to finish option processing"); <br> + return false; <br> + } <br> + <br> if (c->c2.did_open_tun) <br> { <br> c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; <br> @@ -2344,49 +2351,58 @@ do_deferred_options(struct context *c, const unsigned int found) <br> { <br> return false; <br> } <br> - struct frame *frame_fragment = NULL; <br> + } <br> + <br> + return true; <br> +} <br> + <br> +bool <br> +finish_options(struct context *c) <br> +{ <br> + if (!c->options.pull || !dco_enabled(&c->options)) <br> + { <br> + return true; <br> + } <br> + <br> + struct frame *frame_fragment = NULL; <br> #ifdef ENABLE_FRAGMENT <br> - if (c->options.ce.fragment) <br> - { <br> - frame_fragment = &c->c2.frame_fragment; <br> - } <br> + if (c->options.ce.fragment) <br> + { <br> + frame_fragment = &c->c2.frame_fragment; <br> + } <br> #endif</p> <p dir="auto">- struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; <br> - if (!tls_session_update_crypto_params(c->c2.tls_multi, session, <br> - &c->options, &c->c2.frame, <br> - frame_fragment, <br> - get_link_socket_info(c))) <br> - { <br> - msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); <br> - return false; <br> - } <br> + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; <br> + if (!tls_session_update_crypto_params(c->c2.tls_multi, session, <br> + &c->options, &c->c2.frame, <br> + frame_fragment, <br> + get_link_socket_info(c))) <br> + { <br> + msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); <br> + return false; <br> + }</p> <p dir="auto">- if (dco_enabled(&c->options)) <br> - { <br> - /* Check if the pushed options are compatible with DCO if we have <br> - * DCO enabled */ <br> - if (!check_dco_pull_options(&c->options)) <br> - { <br> - msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " <br> - "data channel offload. Use --disable-dco to connect" <br> - "to this server"); <br> - return false; <br> - } <br> + /* Check if the pushed options are compatible with DCO if we have <br> + * DCO enabled */ <br> + if (!check_dco_pull_options(&c->options)) <br> + { <br> + msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " <br> + "data channel offload. Use --disable-dco to connect" <br> + "to this server"); <br> + return false; <br> + }</p> <p dir="auto">- if (c->options.ping_send_timeout || c->c2.frame.mss_fix) <br> - { <br> - int ret = dco_set_peer(&c->c1.tuntap->dco, <br> - c->c2.tls_multi->peer_id, <br> - c->options.ping_send_timeout, <br> - c->options.ping_rec_timeout, <br> - c->c2.frame.mss_fix); <br> - if (ret < 0) <br> - { <br> - msg(D_DCO, "Cannot set DCO peer: %s", strerror(-ret)); <br> - return false; <br> - } <br> - } <br> + if (c->options.ping_send_timeout || c->c2.frame.mss_fix) <br> + { <br> + int ret = dco_set_peer(&c->c1.tuntap->dco, <br> + c->c2.tls_multi->peer_id, <br> + c->options.ping_send_timeout, <br> + c->options.ping_rec_timeout, <br> + c->c2.frame.mss_fix); <br> + if (ret < 0) <br> + { <br> + msg(D_DCO, "Cannot set DCO peer: %s", strerror(-ret)); <br> + return false; <br> } <br> } <br> return true; <br> diff --git a/src/openvpn/init.h b/src/openvpn/init.h <br> index 1c341da3..5cc2a990 100644 <br> --- a/src/openvpn/init.h <br> +++ b/src/openvpn/init.h <br> @@ -97,6 +97,8 @@ void reset_coarse_timers(struct context *c);</p> <p dir="auto"> bool do_deferred_options(struct context *c, const unsigned int found);</p> <p dir="auto">+bool finish_options(struct context *c); <br> + <br> void inherit_context_child(struct context *dest, <br> const struct context *src);</p> <p dir="auto">diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c <br> index 958712f1..47e1c6cc 100644 <br> --- a/src/openvpn/multi.c <br> +++ b/src/openvpn/multi.c <br> @@ -2452,6 +2452,8 @@ multi_client_connect_late_setup(struct multi_context *m, <br> mi->context.c2.tls_multi->multi_state = CAS_FAILED; <br> }</p> <p dir="auto">+ finish_options(&mi->context); <br> + <br> /* send push reply if ready */ <br> if (mi->context.c2.push_request_received) <br> { <br> -- </p> </blockquote></div> <div class="markdown" style="white-space: normal;"> <p dir="auto">This patch isn’t quite right. It works well for DCO, but breaks non-DCO. It fails to call tls_session_update_crypto_params() if DCO is disabled. It needs this on top of it:</p> <pre style="margin-left: 15px; margin-right: 15px; padding: 5px; border: thin solid gray; overflow-x: auto; max-width: 90vw; background-color: #E4E4E4;"><code>commit ee846144a46b20b889ab1966246f789f3266c2f9 (HEAD -> tmp_v10) Author: Kristof Provost <kp@FreeBSD.org> Date: Thu May 5 19:36:13 2022 +0200 Fix finish_options() to perform the required work for non-DCO modes We still need to run tls_session_update_crypto_params(), even when DCO is not enabled. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 7083b803..ab59cbd7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2374,7 +2374,7 @@ do_deferred_options(struct context *c, const unsigned int found) bool finish_options(struct context *c) { - if (!c->options.pull || !dco_enabled(&c->options)) + if (!c->options.pull) { return true; } @@ -2399,7 +2399,7 @@ finish_options(struct context *c) /* Check if the pushed options are compatible with DCO if we have * DCO enabled */ - if (!check_dco_pull_options(&c->options)) + if (dco_enabled(&c->options) && !check_dco_pull_options(&c->options)) { msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " "data channel offload. Use --disable-dco to connect" @@ -2407,7 +2407,7 @@ finish_options(struct context *c) return false; } - if (c->options.ping_send_timeout || c->c2.frame.mss_fix) + if (dco_enabled(&c->options) && (c->options.ping_send_timeout || c->c2.frame.mss_fix)) { int ret = dco_set_peer(&c->c1.tuntap->dco, c->c2.tls_multi->peer_id, </code></pre> <p dir="auto">I’ll post an updated series in due course, but wanted to point this issue out already.</p> <p dir="auto">Kristof</p> </div></div></body> </html>
diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 8496e21f..5d53cf7e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2100,26 +2100,26 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) } } - if ((c->mode == MODE_POINT_TO_POINT) && c->c2.did_open_tun) + if (pulled_options) { - /* If we are in DCO mode we need to set the new peer options now */ - int ret = dco_p2p_add_new_peer(c); - if (ret < 0) + if (!do_deferred_options(c, option_types_found)) { - msg(D_DCO, "Cannot add peer to DCO: %s", strerror(-ret)); + msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); return false; } } - - if (pulled_options) + if (c->mode == MODE_POINT_TO_POINT) { - if (!do_deferred_options(c, option_types_found)) + /* If we are in DCO mode we need to set the new peer options now */ + int ret = dco_p2p_add_new_peer(c); + if (ret < 0) { - msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); + msg(D_DCO, "Cannot add peer to DCO: %s", strerror(-ret)); return false; } } - else if (c->mode == MODE_POINT_TO_POINT) + + if (!pulled_options && c->mode == MODE_POINT_TO_POINT) { if (!do_deferred_p2p_ncp(c)) { @@ -2128,6 +2128,13 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) } } + + if (!finish_options(c)) + { + msg(D_TLS_ERRORS, "ERROR: Failed to finish option processing"); + return false; + } + if (c->c2.did_open_tun) { c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; @@ -2344,49 +2351,58 @@ do_deferred_options(struct context *c, const unsigned int found) { return false; } - struct frame *frame_fragment = NULL; + } + + return true; +} + +bool +finish_options(struct context *c) +{ + if (!c->options.pull || !dco_enabled(&c->options)) + { + return true; + } + + struct frame *frame_fragment = NULL; #ifdef ENABLE_FRAGMENT - if (c->options.ce.fragment) - { - frame_fragment = &c->c2.frame_fragment; - } + if (c->options.ce.fragment) + { + frame_fragment = &c->c2.frame_fragment; + } #endif - struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; - if (!tls_session_update_crypto_params(c->c2.tls_multi, session, - &c->options, &c->c2.frame, - frame_fragment, - get_link_socket_info(c))) - { - msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); - return false; - } + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + if (!tls_session_update_crypto_params(c->c2.tls_multi, session, + &c->options, &c->c2.frame, + frame_fragment, + get_link_socket_info(c))) + { + msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); + return false; + } - if (dco_enabled(&c->options)) - { - /* Check if the pushed options are compatible with DCO if we have - * DCO enabled */ - if (!check_dco_pull_options(&c->options)) - { - msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " - "data channel offload. Use --disable-dco to connect" - "to this server"); - return false; - } + /* Check if the pushed options are compatible with DCO if we have + * DCO enabled */ + if (!check_dco_pull_options(&c->options)) + { + msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " + "data channel offload. Use --disable-dco to connect" + "to this server"); + return false; + } - if (c->options.ping_send_timeout || c->c2.frame.mss_fix) - { - int ret = dco_set_peer(&c->c1.tuntap->dco, - c->c2.tls_multi->peer_id, - c->options.ping_send_timeout, - c->options.ping_rec_timeout, - c->c2.frame.mss_fix); - if (ret < 0) - { - msg(D_DCO, "Cannot set DCO peer: %s", strerror(-ret)); - return false; - } - } + if (c->options.ping_send_timeout || c->c2.frame.mss_fix) + { + int ret = dco_set_peer(&c->c1.tuntap->dco, + c->c2.tls_multi->peer_id, + c->options.ping_send_timeout, + c->options.ping_rec_timeout, + c->c2.frame.mss_fix); + if (ret < 0) + { + msg(D_DCO, "Cannot set DCO peer: %s", strerror(-ret)); + return false; } } return true; diff --git a/src/openvpn/init.h b/src/openvpn/init.h index 1c341da3..5cc2a990 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -97,6 +97,8 @@ void reset_coarse_timers(struct context *c); bool do_deferred_options(struct context *c, const unsigned int found); +bool finish_options(struct context *c); + void inherit_context_child(struct context *dest, const struct context *src); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 958712f1..47e1c6cc 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2452,6 +2452,8 @@ multi_client_connect_late_setup(struct multi_context *m, mi->context.c2.tls_multi->multi_state = CAS_FAILED; } + finish_options(&mi->context); + /* send push reply if ready */ if (mi->context.c2.push_request_received) {