Message ID | 20220518093212.2802495-2-arne@rfc2549.org |
---|---|
State | Superseded |
Headers | show |
Series | Implement exit notifcation via control channel and temporary AUTH_FAIL | expand |
> Arne Schwabe <arne@rfc2549.org> hat am 18.05.2022 11:32 geschrieben: > Current exit notification relies on data channel messages with specific > prefix. Adding these to new data channel modules (DCO) adds uncessary "unnecessary" > complexity for the data for messages that from their idea belong to the > control channel anyway. > > This patch adds announcing support for control channel and sending/receving > it. We use the simple EXIT message for this. [...] > diff --git a/doc/man-sections/client-options.rst b/doc/man-sections/client-options.rst > index 8e0e4f18a..5a906895b 100644 > --- a/doc/man-sections/client-options.rst > +++ b/doc/man-sections/client-options.rst > @@ -220,9 +220,14 @@ configuration. > immediately close its client instance object rather than waiting for a > timeout. > > + If both server and client support sending this message using the control > + channel, the message will be sent as control-channel message. Otherwise > + the message is sent as data-channel message, which will be ignored by > + data-channel offloaded peers. > + > The **n** parameter (default :code:`1` if not present) controls the > maximum number of attempts that the client will try to resend the exit > - notification message. > + notification message if messages are sent in data-channel mode. > > In UDP server mode, send :code:`RESTART` control channel command to > connected clients. The ``n`` parameter (default :code:`1` if not present) > diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h > index 98e2c7664..8219d2b76 100644 > --- a/src/openvpn/crypto.h > +++ b/src/openvpn/crypto.h > @@ -264,6 +264,11 @@ struct crypto_options > /**< Bit-flag indicating that we do not allow clients that do > * not support resending the wrapped client key (WKc) with the > * third packet of the three-way handshake */ > +#define CO_USE_CC_EXIT_NOTIFY (1<<6) > + /**< Bit-flag indicating that explicit exit notifies should be > + * send via the control channel instead of using an OCC message "sent" > + */ > + > unsigned int flags; /**< Bit-flags determining behavior of > * security operation functions. */ > }; [...] > diff --git a/src/openvpn/options.c b/src/openvpn/options.c > index 9ff384d09..7913661c7 100644 > --- a/src/openvpn/options.c > +++ b/src/openvpn/options.c > @@ -8338,6 +8338,20 @@ add_option(struct options *options, > msg(msglevel, "Unknown key-derivation method %s", p[1]); > } > } > + else if (streq(p[0], "protocol-flags") && p[1]) I find it a bit irritating that this patch doesn't add any documentation for this new option. But we have other undocumented options, so I assume this is considered fine for options the user is not supposed to set manually? > + { > + for (size_t j = 1; j < MAX_PARMS && p[j] != NULL; j++) > + { > + if (streq(p[j], "cc-exit")) > + { > + options->data_channel_crypto_flags |= CO_USE_CC_EXIT_NOTIFY; > + } > + else > + { > + msg(msglevel, "Unknown protocol-flags flag: %s", p[j]); > + } > + } > + } > else if (streq(p[0], "prng") && p[1] && !p[3]) > { > msg(M_WARN, "NOTICE: --prng option ignored (SSL library PRNG is used)"); > diff --git a/src/openvpn/push.c b/src/openvpn/push.c > index 70fd1c3ce..51b8bd521 100644 > --- a/src/openvpn/push.c > +++ b/src/openvpn/push.c > @@ -176,6 +176,21 @@ server_pushed_signal(struct context *c, const struct buffer *buffer, const bool > } > } > > +void > +receive_exit_message(struct context *c, const struct buffer *buffer) buffer is not used, so we can probably remove it? > +{ > + dmsg(D_STREAM_ERRORS, "Exit message received by peer"); > + c->sig->signal_received = SIGTERM; > + c->sig->signal_text = "remote-exit"; > +#ifdef ENABLE_MANAGEMENT > + if (management) > + { > + management_notify(management, "info", c->sig->signal_text, "EXIT"); > + } > +#endif > +} > + > + > void > server_pushed_info(struct context *c, const struct buffer *buffer, > const int adv) [...] > diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c > index e06edd216..1fc9c6dca 100644 > --- a/src/openvpn/sig.c > +++ b/src/openvpn/sig.c > @@ -321,20 +321,43 @@ print_status(const struct context *c, struct status_output *so) > gc_free(&gc); > } > > + > +/* Small helper function to determine if we should be sending exit notifcation "should send" (not an error, just a simplification), "notification" > + * via control channel */ > +static inline bool > +cc_exit_notify_enabled(struct context *c) > +{ > + /* Check if we have TLS active at all */ > + if (!c->c2.tls_multi) > + { > + return false; > + } > + > + const struct key_state *ks = get_primary_key(c->c2.tls_multi); > + return (ks->crypto_options.flags & CO_USE_CC_EXIT_NOTIFY); > +} > + > /* > * Handle the triggering and time-wait of explicit > * exit notification. > */ > - > static void > process_explicit_exit_notification_init(struct context *c) > { > msg(M_INFO, "SIGTERM received, sending exit notification to peer"); > event_timeout_init(&c->c2.explicit_exit_notification_interval, 1, 0); > reset_coarse_timers(c); > + > signal_reset(c->sig); > halt_non_edge_triggered_signals(); > c->c2.explicit_exit_notification_time_wait = now; > + > + /* Check if we are in TLS mode and should sent the notify via data "should send", "control" > + * channel */ > + if (cc_exit_notify_enabled(c)) > + { > + send_control_channel_string(c, "EXIT", D_PUSH); > + } > } > > void [...] Regards, -- Frank Lichtenheld
diff --git a/doc/man-sections/client-options.rst b/doc/man-sections/client-options.rst index 8e0e4f18a..5a906895b 100644 --- a/doc/man-sections/client-options.rst +++ b/doc/man-sections/client-options.rst @@ -220,9 +220,14 @@ configuration. immediately close its client instance object rather than waiting for a timeout. + If both server and client support sending this message using the control + channel, the message will be sent as control-channel message. Otherwise + the message is sent as data-channel message, which will be ignored by + data-channel offloaded peers. + The **n** parameter (default :code:`1` if not present) controls the maximum number of attempts that the client will try to resend the exit - notification message. + notification message if messages are sent in data-channel mode. In UDP server mode, send :code:`RESTART` control channel command to connected clients. The ``n`` parameter (default :code:`1` if not present) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 98e2c7664..8219d2b76 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -264,6 +264,11 @@ struct crypto_options /**< Bit-flag indicating that we do not allow clients that do * not support resending the wrapped client key (WKc) with the * third packet of the three-way handshake */ +#define CO_USE_CC_EXIT_NOTIFY (1<<6) + /**< Bit-flag indicating that explicit exit notifies should be + * send via the control channel instead of using an OCC message + */ + unsigned int flags; /**< Bit-flags determining behavior of * security operation functions. */ }; diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 6afe152b4..50d3fd2b2 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -241,6 +241,10 @@ check_incoming_control_channel(struct context *c) { receive_auth_pending(c, &buf); } + else if (buf_string_match_head_str(&buf, "EXIT")) + { + receive_exit_message(c, &buf); + } else { msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf)); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ba2f6d581..e7c99f813 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1777,6 +1777,11 @@ multi_client_set_protocol_options(struct context *c) } #endif + if (proto & IV_PROTO_CC_EXIT_NOTIFY) + { + o->data_channel_crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + /* Select cipher if client supports Negotiable Crypto Parameters */ /* if we have already created our key, we cannot *change* our own diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9ff384d09..7913661c7 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -8338,6 +8338,20 @@ add_option(struct options *options, msg(msglevel, "Unknown key-derivation method %s", p[1]); } } + else if (streq(p[0], "protocol-flags") && p[1]) + { + for (size_t j = 1; j < MAX_PARMS && p[j] != NULL; j++) + { + if (streq(p[j], "cc-exit")) + { + options->data_channel_crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + else + { + msg(msglevel, "Unknown protocol-flags flag: %s", p[j]); + } + } + } else if (streq(p[0], "prng") && p[1] && !p[3]) { msg(M_WARN, "NOTICE: --prng option ignored (SSL library PRNG is used)"); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 70fd1c3ce..51b8bd521 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -176,6 +176,21 @@ server_pushed_signal(struct context *c, const struct buffer *buffer, const bool } } +void +receive_exit_message(struct context *c, const struct buffer *buffer) +{ + dmsg(D_STREAM_ERRORS, "Exit message received by peer"); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "remote-exit"; +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_notify(management, "info", c->sig->signal_text, "EXIT"); + } +#endif +} + + void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv) @@ -604,6 +619,10 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, { push_option_fmt(gc, push_list, M_USAGE, "key-derivation tls-ekm"); } + if (o->data_channel_crypto_flags & CO_USE_CC_EXIT_NOTIFY) + { + push_option_fmt(gc, push_list, M_USAGE, "protocol-flags cc-exit"); + } return true; } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 62fad4a14..33e62120c 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -48,6 +48,8 @@ void receive_auth_failed(struct context *c, const struct buffer *buffer); void server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv); +void receive_exit_message(struct context *c, const struct buffer *buffer); + void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv); diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index e06edd216..1fc9c6dca 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -321,20 +321,43 @@ print_status(const struct context *c, struct status_output *so) gc_free(&gc); } + +/* Small helper function to determine if we should be sending exit notifcation + * via control channel */ +static inline bool +cc_exit_notify_enabled(struct context *c) +{ + /* Check if we have TLS active at all */ + if (!c->c2.tls_multi) + { + return false; + } + + const struct key_state *ks = get_primary_key(c->c2.tls_multi); + return (ks->crypto_options.flags & CO_USE_CC_EXIT_NOTIFY); +} + /* * Handle the triggering and time-wait of explicit * exit notification. */ - static void process_explicit_exit_notification_init(struct context *c) { msg(M_INFO, "SIGTERM received, sending exit notification to peer"); event_timeout_init(&c->c2.explicit_exit_notification_interval, 1, 0); reset_coarse_timers(c); + signal_reset(c->sig); halt_non_edge_triggered_signals(); c->c2.explicit_exit_notification_time_wait = now; + + /* Check if we are in TLS mode and should sent the notify via data + * channel */ + if (cc_exit_notify_enabled(c)) + { + send_control_channel_string(c, "EXIT", D_PUSH); + } } void @@ -351,7 +374,7 @@ process_explicit_exit_notification_timer_wakeup(struct context *c) c->sig->signal_received = SIGTERM; c->sig->signal_text = "exit-with-notification"; } - else + else if (!cc_exit_notify_enabled(c)) { c->c2.occ_op = OCC_EXIT; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 61dea996d..4506b7504 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1940,6 +1940,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for P_DATA_V2 */ int iv_proto = IV_PROTO_DATA_V2; + /* support for exit notify via control channel */ + iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; + /* support for receiving push_reply before sending * push request, also signal that the client wants * to get push-reply messages without without requiring a round diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 0ba86d3e6..1b8b736b9 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -93,6 +93,9 @@ * result. */ #define IV_PROTO_NCP_P2P (1<<5) +/** Support for explicit exit notify via control channel */ +#define IV_PROTO_CC_EXIT_NOTIFY (1<<7) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 5d7e6dd38..4a083e247 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -419,6 +419,11 @@ p2p_ncp_set_options(struct tls_multi *multi, struct tls_session *session) multi->peer_id = 0x76706e; /* 'v' 'p' 'n' */ } + if (iv_proto_peer & IV_PROTO_CC_EXIT_NOTIFY) + { + session->opt->crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + #if defined(HAVE_EXPORT_KEYING_MATERIAL) if (iv_proto_peer & IV_PROTO_TLS_KEY_EXPORT) {