Notify clients about server's exit/restart
PATCH v2 1/1 Notify clients about server's exit/restart
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server broadcasts new OCC_SERVER_EXIT command to all clients and reschedules received signal in 2 secs.
When client receives OCC_SERVER_EXIT, it fires SIGUSR1 and switches to the next server. Next server is defined as same remote with different IP address if remote resolves into multiple addresses or next remote otherwise.
v2:
- take into use explicit-exit-notify on the server side
- OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
- minor code prettifying
--- src/openvpn/multi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- src/openvpn/multi.h | 14 ++++++++++- src/openvpn/occ.c | 8 +++++++ src/openvpn/occ.h | 6 +++++ src/openvpn/options.c | 7 ++---- src/openvpn/options.h | 3 ++- 6 files changed, 93 insertions(+), 11 deletions(-)
src/openvpn/multi.c +62 -4
@@ -396,6 +396,8 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time);event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval,0 ); } + + m->deferred_shutdown_signal.signal_received =0 ; } const char *
@@ -603,6 +605,25 @@ multi_close_instance (struct multi_context *m,perf_pop (); } +void +multi_broadcast_server_exit (struct multi_context *m) +{ +msg (D_LOW ,"multi_broadcast_server_exit" ); + +struct gc_arena gc =gc_new (); +struct buffer buf =alloc_buf_gc (BUF_SIZE (&m->top.c2.frame), &gc); + +buf_init (&buf,FRAME_HEADROOM (&m->top.c2.frame)); +buf_safe (&buf,MAX_RW_SIZE_TUN (&m->top.c2.frame)); +buf_write (&buf, occ_magic,OCC_STRING_SIZE ); + +buf_write_u8 (&buf,OCC_SERVER_EXIT ); + +multi_bcast (m, &buf,NULL ,NULL ); + +gc_free (&gc); +} +/* * Called on shutdown or restart. */
@@ -1952,7 +1973,7 @@ multi_unicast (struct multi_context *m,/* * Broadcast a packet to all clients. */ -static void +void multi_bcast (struct multi_context *m, const struct buffer *buf, const struct multi_instance *sender_instance,
@@ -2571,10 +2592,18 @@ multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags)/* instance marked for wakeup? */ if (m->earliest_wakeup) { -set_prefix (m->earliest_wakeup); - ret =multi_process_post (m, m->earliest_wakeup, mpp_flags); +if (m->earliest_wakeup == (struct multi_instance *)&m->deferred_shutdown_signal) + { +schedule_remove_entry (m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal); +throw_signal (m->deferred_shutdown_signal.signal_received); + } +else + { +set_prefix (m->earliest_wakeup); + ret =multi_process_post (m, m->earliest_wakeup, mpp_flags); +clear_prefix (); + } m->earliest_wakeup =NULL ; -clear_prefix (); }return ret; }
@@ -2699,6 +2728,12 @@ multi_top_free (struct multi_context *m)free_context_buffers (m->top.c2.buffers); } +bool +is_exit_restart (int sig) +{ +return (sig ==SIGUSR1 || sig ==SIGTERM || sig ==SIGHUP || sig ==SIGINT ); +} +/* * Return true if event loop should break, * false if it should continue.
@@ -2714,6 +2749,29 @@ multi_process_signal (struct multi_context *m) m->top.sig->signal_received =0 ;return false; } +else if (proto_is_dgram (m->top.options.ce.proto) && +is_exit_restart (m->top.sig->signal_received) && + (m->deferred_shutdown_signal.signal_received ==0 ) && + m->top.options.ce.explicit_exit_notification) + { +/* broadcast OCC_SERVER_EXIT to clients */ +multi_broadcast_server_exit (m); + +/* schedule signal */ +openvpn_gettimeofday (&m->deferred_shutdown_signal.wakeup,NULL ); +struct timeval tv; + tv.tv_sec =2 ; + tv.tv_usec =0 ; +tv_add (&m->deferred_shutdown_signal.wakeup, &tv); + + m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; + +schedule_add_entry (m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal, + &m->deferred_shutdown_signal.wakeup,compute_wakeup_sigma (&m->deferred_shutdown_signal.wakeup)); + + m->top.sig->signal_received =0 ; +return false; + }return true; }
src/openvpn/multi.h +13 -1
@@ -57,6 +57,13 @@ struct multi_reap }; +struct deferred_signal_schedule_entry +{ +struct schedule_entry se; +int signal_received; +struct timeval wakeup; +}; +/** * Server-mode state structure for one single VPN tunnel. *
@@ -172,6 +179,8 @@ struct multi_context {* Timer object for stale route check */ struct event_timeout stale_routes_check_et; + +struct deferred_signal_schedule_entry deferred_shutdown_signal; };/*
@@ -190,7 +199,6 @@ struct multi_routetime_t last_reference; }; -/**************************************************************************/ /** * Main event loop for OpenVPN in server mode.
@@ -290,6 +298,10 @@ bool multi_process_post (struct multi_context *m, struct multi_instance *mi, conbool multi_process_incoming_link (struct multi_context *m,struct multi_instance *instance,const unsigned int mpp_flags); +void multi_bcast (struct multi_context *m,const struct buffer *buf, +const struct multi_instance *sender_instance, +const struct mroute_addr *sender_addr); +/** * Determine the destination VPN tunnel of a packet received over the * virtual tun/tap network interface and then process it accordingly.
src/openvpn/occ.c +8 -0
@@ -390,6 +390,14 @@ process_received_occ_msg (struct context *c) c->sig->signal_received =SIGTERM ; c->sig->signal_text ="remote-exit" ;break ; + +case OCC_SERVER_EXIT : +msg (D_LOW ,"RECEIVED OCC_SERVER_EXIT" ); + c->sig->signal_received =SIGUSR1 ; + c->sig->signal_text ="remote-server-exit" ; + c->options.no_advance = false; +break ; + } c->c2.buf.len =0 ;/* don't pass packet on */ }
src/openvpn/occ.h +6 -0
@@ -69,6 +69,12 @@*/ #define OCC_EXIT 6 + +/* +* Notifies clients that server is exiting/restarting +*/ +#define OCC_SERVER_EXIT 7 +/* * Used to conduct a load test command sequence * of UDP connection for empirical MTU measurement.
src/openvpn/options.c +2 -5
@@ -496,7 +496,8 @@ static const char usage_message[] =#endif #ifdef ENABLE_OCC "--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" - " server/remote. n = # of retries, default=1.\n" +" server/remote or client. n = # of retries, default=1.\n" + " n is ignored in server mode.\n"#endif #ifdef ENABLE_CRYPTO "\n"
@@ -2022,10 +2023,6 @@ options_postprocess_verify_ce (const struct options *options, const struct connemsg (M_USAGE ,"--connect-freq only works with --mode server --proto udp. Try --max-clients instead." );if (!(dev ==DEV_TYPE_TAP || (dev ==DEV_TYPE_TUN && options->topology ==TOP_SUBNET )) && options->ifconfig_pool_netmask)msg (M_USAGE ,"The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode" ); -#ifdef ENABLE_OCC -if (ce->explicit_exit_notification) -msg (M_USAGE ,"--explicit-exit-notify cannot be used with --mode server" ); -#endif if (options->routes && (options->routes->flags &RG_ENABLE ))msg (M_USAGE ,"--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)" );if (options->route_delay_defined)
src/openvpn/options.h +2 -1
@@ -121,7 +121,8 @@ struct connection_entrybool mssfix_default;/* true if --mssfix was supplied without a parameter */ #ifdef ENABLE_OCC -int explicit_exit_notification;/* Explicitly tell peer when we are exiting via OCC_EXIT message */ +/* Explicitly tell peer when we are exiting via OCC_EXIT (client to server) or OCC_SERVER_EXIT (server to client) message */ +int explicit_exit_notification;#endif # define CE_DISABLED (1<<0)
Signature · 1 line
1.9.1
PATCH v3 1/1 Notify clients about server's exit/restart
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server sends RESTART control channel command to all clients and reschedules received signal in 2 secs.
When client receives RESTART command, it either reconnects to the same server or advances to the new one, depends on parameter comes with RESTART command - behavior is controlled by explicit-exit-notify in the server config.
v3:
- Use control channel "RESTART" command instead of new OCC code to
notify clients
- Configure on the server side (by value of explicit-exit-notify) if
client should reconnect to the same server or advance to the next one
- Fix compilation when OCC is disabled (--enable-small)
- Update man page
v2:
- Take into use explicit-exit-notify on the server side
- OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
- Code prettifying
--- doc/openvpn.8 | 15 ++++++++++-- src/openvpn/multi.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/openvpn/multi.h | 9 +++++++ src/openvpn/options.c | 9 +++---- src/openvpn/push.c | 6 +++++ 5 files changed, 96 insertions(+), 11 deletions(-)
doc/openvpn.8 +13 -2
@@ -3829,8 +3829,19 @@ option will tell the server to immediately close its client instance object rather than waiting for a timeout. The .B n parameter (default=1) controls the maximum number of attempts that the client -will try to resend the exit notification message. OpenVPN will not send any exit -notifications unless this option is enabled. +will try to resend the exit notification message. + +In UDP server mode, send RESTART control channel command to connected clients. The +.B n +parameter (default=1) controls client behavior. With +.B n += 1 client will attempt to reconnect +to the same server, with +.B n += 2 client will advance to the next server. + +OpenVPN will not send any exit +notifications unless this option is enabled. .\"********************************************************* .SS Data Channel Encryption Options: These options are meaningful for both Static & TLS-negotiated key modes
src/openvpn/multi.c +65 -3
93 lines not on this page · raw message
src/openvpn/multi.h +9 -0
@@ -57,6 +57,13 @@ struct multi_reap }; +struct deferred_signal_schedule_entry +{ +struct schedule_entry se; +int signal_received; +struct timeval wakeup; +}; +/** * Server-mode state structure for one single VPN tunnel. *
@@ -172,6 +179,8 @@ struct multi_context {* Timer object for stale route check */ struct event_timeout stale_routes_check_et; + +struct deferred_signal_schedule_entry deferred_shutdown_signal; };/*
src/openvpn/options.c +3 -6
@@ -493,8 +493,9 @@ static const char usage_message[] = " waiting for a response before trying the next server.\n"#endif #ifdef ENABLE_OCC -"--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" - " server/remote. n = # of retries, default=1.\n" +"--explicit-exit-notify [n] : On exit/restart, send exit signal/restart command to\n" +" server/remote or client. In client mode: n = # of retries, default=1.\n" + " In server mode: 1 - reconnect to same server, 2 - advance to next server, default=1.\n"#endif #ifdef ENABLE_CRYPTO "\n"
@@ -2020,10 +2021,6 @@ options_postprocess_verify_ce (const struct options *options, const struct connemsg (M_USAGE ,"--connect-freq only works with --mode server --proto udp. Try --max-clients instead." );if (!(dev ==DEV_TYPE_TAP || (dev ==DEV_TYPE_TUN && options->topology ==TOP_SUBNET )) && options->ifconfig_pool_netmask)msg (M_USAGE ,"The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode" ); -#ifdef ENABLE_OCC -if (ce->explicit_exit_notification) -msg (M_USAGE ,"--explicit-exit-notify cannot be used with --mode server" ); -#endif if (options->routes && (options->routes->flags &RG_ENABLE ))msg (M_USAGE ,"--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)" );if (options->route_delay_defined)
src/openvpn/push.c +6 -0
@@ -105,6 +105,7 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool m =BSTR (&buf);/* preserve cached passwords? */ +/* advance to next server? */ {bool purge = true;
@@ -115,6 +116,11 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool {if (m[i] =='P' ) purge = false; +else if (m[i] =='N' ) + { +/* next server? */ + c->options.no_advance = false; + } } }if (purge)
Signature · 1 line
1.9.1
Am 13.10.15 um 16:45 schrieb Lev Stipakov:
Quoted 8 lines
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server sends RESTART control channel command to all clients and reschedules received signal in 2 secs.
When client receives RESTART command, it either reconnects to the same server or advances to the new one, depends on parameter comes with RESTART command - behavior is controlled by explicit-exit-notify in the server config.
Quoted 9 lines
v3:
- Use control channel "RESTART" command instead of new OCC code to
notify clients
- Configure on the server side (by value of explicit-exit-notify) if
client should reconnect to the same server or advance to the next one
- Fix compilation when OCC is disabled (--enable-small)
- Update man page
This gets an ACK from me. As additional note, we should add a follow up that a server shutting down should not accept new clients. My client reconnects in the 2s shutdown interval.
Arne
Hi,
Quoted 8 lines · Lev Stipakov
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server sends RESTART control channel command to all clients and reschedules received signal in 2 secs.
When client receives RESTART command, it either reconnects to the same server or advances to the new one, depends on parameter comes with RESTART command - behavior is controlled by explicit-exit-notify in the server config.
Quoted 7 lines
v3:
- Use control channel "RESTART" command instead of new OCC code to
notify clients
- Configure on the server side (by value of explicit-exit-notify) if
client should reconnect to the same server or advance to the next one
- Fix compilation when OCC is disabled (--enable-small)
- Update man page
Thanks for this. A few observations...
- it does not apply anymore, due to new code in multi.h (someone committed #ifdef ENABLE_ASYNC_PUSH in the meantime :-) ), so I'd appreciate a rebase
- I'm not totally happy about the #ifdef ENABLE_OCC and the fact that multi_push_restart_schedule_exit() is not #ifdef'ed as well (a smart compiler will optimize it away, as it is static and not called, but I'm not sure whether it is considered good style).
Since the new server side code does not actually *do* OCC any more we are just #ifdef'ing it to access options->ce.explicit_exit_notify because that one is only compiled in #ifdef ENABLE_OCC ... so we're coupling this new functionality to an #ifdef which is not really relevant.
No good suggestion yet, just expressing thoughts...
gert
Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
//www.muc.de/~gert/
Gert Doering - Munich, Germany [email protected]...
fax: +49-89-35655025 [email protected]...Hi,
Quoted 8 lines
Since the new server side code does not actually *do* OCC any more we are just #ifdef'ing it to access
options->ce.explicit_exit_notifybecause that one is only compiled in #ifdefENABLE_OCC... so we're coupling this new functionality to an #ifdef which is not really relevant.No good suggestion yet, just expressing thoughts...
Since connection_entry->explicit_exit_notification is now used also outside of OCC context, I suggest to:
1) Remove #ifdef ENABLE_OCC around it's definition.
2) Fix comment there:
/* Explicitly tell peer when we are exiting via OCC_EXIT or control channel [RESTART] message */
3) Remove (unneeded anymore) #ifdef in multi_process_signal around accessing explicit_exit_notification.
What do you think?
-Lev
PATCH v4 1/1 Notify clients about server's exit/restart
When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server sends RESTART control channel command to all clients and reschedules received signal in 2 secs.
When client receives RESTART command, it either reconnects to the same server or advances to the new one, depends on parameter comes with RESTART command - behavior is controlled by explicit-exit-notify in the server config.
v4:
- Rebase on top of master
- Remove #ifdef ENABLE_OCC around connection_entry->explicit_exit_notification since it is also used outside of OCC context
- Update usage message
v3:
- Use control channel "RESTART" command instead of new OCC code to notify clients
- Configure on the server side (by value of explicit-exit-notify) if client should reconnect to the same server or advance to the next one
- Fix compilation when OCC is disabled (--enable-small)
- Update man page
v2:
- Take into use explicit-exit-notify on the server side
- OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT
- Code prettifying
--- doc/openvpn.8 | 15 ++++++++++-- src/openvpn/multi.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/openvpn/multi.h | 9 +++++++ src/openvpn/options.c | 7 +++--- src/openvpn/options.h | 4 +--- src/openvpn/push.c | 6 +++++ 6 files changed, 95 insertions(+), 12 deletions(-)
doc/openvpn.8 +13 -2
@@ -3886,8 +3886,19 @@ option will tell the server to immediately close its client instance object rather than waiting for a timeout. The .B n parameter (default=1) controls the maximum number of attempts that the client -will try to resend the exit notification message. OpenVPN will not send any exit -notifications unless this option is enabled. +will try to resend the exit notification message. + +In UDP server mode, send RESTART control channel command to connected clients. The +.B n +parameter (default=1) controls client behavior. With +.B n += 1 client will attempt to reconnect +to the same server, with +.B n += 2 client will advance to the next server. + +OpenVPN will not send any exit +notifications unless this option is enabled. .\"********************************************************* .SS Data Channel Encryption Options: These options are meaningful for both Static & TLS-negotiated key modes
src/openvpn/multi.c +63 -3
91 lines not on this page · raw message
src/openvpn/multi.h +9 -0
@@ -57,6 +57,13 @@ struct multi_reap }; +struct deferred_signal_schedule_entry +{ +struct schedule_entry se; +int signal_received; +struct timeval wakeup; +}; +/** * Server-mode state structure for one single VPN tunnel. *
@@ -181,6 +188,8 @@ struct multi_context {/* mapping between inotify watch descriptors and multi_instances */ struct hash *inotify_watchers;#endif + +struct deferred_signal_schedule_entry deferred_shutdown_signal; };/*
src/openvpn/options.c +3 -4
@@ -469,6 +469,9 @@ static const char usage_message[] ="--stale-routes-check n [t] : Remove routes with a last activity timestamp\n" " older than n seconds. Run this check every t\n" " seconds (defaults to n).\n" +"--explicit-exit-notify [n] : In UDP server mode send [RESTART] command on exit/restart to connected\n" +" clients. n = 1 - reconnect to same server,\n" +" 2 - advance to next server, default=1.\n" #if PORT_SHARE"--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n" " sessions to a web server at host:port. dir specifies an\n"
@@ -2020,10 +2023,6 @@ options_postprocess_verify_ce (const struct options *options, const struct connemsg (M_USAGE ,"--connect-freq only works with --mode server --proto udp. Try --max-clients instead." );if (!(dev ==DEV_TYPE_TAP || (dev ==DEV_TYPE_TUN && options->topology ==TOP_SUBNET )) && options->ifconfig_pool_netmask)msg (M_USAGE ,"The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode" ); -#ifdef ENABLE_OCC -if (ce->explicit_exit_notification) -msg (M_USAGE ,"--explicit-exit-notify cannot be used with --mode server" ); -#endif if (options->routes && (options->routes->flags &RG_ENABLE ))msg (M_USAGE ,"--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)" );if (options->route_delay_defined)
src/openvpn/options.h +1 -3
@@ -118,9 +118,7 @@ struct connection_entryint mssfix;/* Upper bound on TCP MSS */ bool mssfix_default;/* true if --mssfix was supplied without a parameter */ -#ifdef ENABLE_OCC -int explicit_exit_notification;/* Explicitly tell peer when we are exiting via OCC_EXIT message */ -#endif +int explicit_exit_notification;/* Explicitly tell peer when we are exiting via OCC_EXIT or [RESTART] message */ # define CE_DISABLED (1<<0)# define CE_MAN_QUERY_PROXY (1<<1)
src/openvpn/push.c +6 -0
@@ -105,6 +105,7 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool m =BSTR (&buf);/* preserve cached passwords? */ +/* advance to next server? */ {bool purge = true;
@@ -115,6 +116,11 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool {if (m[i] =='P' ) purge = false; +else if (m[i] =='N' ) + { +/* next server? */ + c->options.no_advance = false; + } } }if (purge)
Signature · 1 line
1.9.1
ACK, and thanks for your patience and persistance
Since v4 is functionally the same as v3 (just a few #ifdef ENABLE_OCC shuffled around, and different "adjacent" code due to rebasing), I've taken Arne's ACK as valid for v4, too - and add my own for the v3->v4 changes.
Your patch has been applied to the master branch.
Awaiting the client-side patch now :-) (and maybe something to make the server block incoming reconnects while in shut-down phase, see Arne's comment)
commit 8dd9ff8ca062de34bcd16e34847d106ee9b992ff (master)
Author: Lev Stipakov Date: Tue Nov 17 11:33:47 2015 +0200
Notify clients about server's exit/restart
Signed-off-by: Lev Stipakov <[email protected]...>
Acked-by: Arne Schwabe <[email protected]...>
Acked-by: Gert Doering <[email protected]...>
Message-Id: <[email protected]...>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10515
Signed-off-by: Gert Doering <[email protected]...>--
kind regards,
Gert Doering