Exponentially backoff on repeated connect retries
PATCH 1/1 Exponentially backoff on repeated connect retries
- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause.
The base value of restart pause is set using --connect-retry (5 seconds by default). If it is set to zero no slow-down will happen.
--- src/openvpn/init.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
src/openvpn/init.c +12 -0
@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {
@@ -1977,6 +1978,17 @@ socket_restart_pause (struct context *c) sec =10 ;#endif +/* Slow down reconnection after 5 retries per remote */ + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -5 ; +if (backoff >0 ) + sec <<=min_int (backoff,10 ); + +if (backoff >10 && sec >0 ) + { +register_signal (c,SIGHUP ,"Too many restarts" ); +return ; + } +if (c->persist.restart_sleep_seconds >0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds;else if (c->persist.restart_sleep_seconds ==-1 )
Signature · 1 line
1.7.10.4
Am 02.07.16 um 05:32 schrieb Selva Nair:
Quoted 31 lines
- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause.The base value of restart pause is set using --connect-retry (5 seconds by default). If it is set to zero no slow-down will happen.
Signed-off-by Selva Nair <[email protected]...>--- src/openvpn/init.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)src/openvpn/init.c +1
-0@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {@@ -1977,6 +1978,17 @@ socket_restart_pause (struct context *c) sec =10 ;#endif
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1990
Quoted 10 lines
src/openvpn/init.c +10
-0+/* Slow down reconnection after 5 retries per remote */ + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -5 ; +if (backoff >0 ) + sec <<=min_int (backoff,10 ); + +if (backoff >10 && sec >0 ) + { +register_signal (c,SIGHUP ,"Too many restarts" ); +return ; + }
And why sighup? Shouldn't just limiting sec be enought. SIGHUP has many side effects. I don't think we should trigger these for connection time.
With default setting this results in a SIGHUP after some hours and also the last intervals with 5120s are too big for default settings. I would aim for something lower like five or ten minutes.
Arne
Quoted 8 lines
And why sighup? Shouldn't just limiting sec be enought. SIGHUP has many side effects. I don't think we should trigger these for connection time.
With default setting this results in a SIGHUP after some hours and also the last intervals with 5120s are too big for default settings. I would aim for something lower like five or ten minutes.
I think a bit about that and I think a good way to specify exponential back is something like
connect-retry 5 1800, which would mean "scale back up to 1800s" and maybe default that option to connect-retry 5 300. That also allows specifying larger connect-retry values without backoff. E.g. connect-retry 60 60
Arne
Quoted 8 lines · Arne Schwabe
Quoted 7 lines
And why sighup? Shouldn't just limiting sec be enought. SIGHUP has many side effects. I don't think we should trigger these for connection time.
With default setting this results in a SIGHUP after some hours and also the last intervals with 5120s are too big for default settings. I would aim for something lower like five or ten minutes.
Quoted 7 lines
I think a bit about that and I think a good way to specify exponential back is something like
connect-retry 5 1800, which would mean "scale back up to 1800s" and maybe default that option to connect-retry 5 300. That also allows specifying larger connect-retry values without backoff. E.g. connect-retry 60 60
Good idea.
Agreed, triggering SIGHUP is not ideal. The only reason for it was to reset the counters so that the backoff time doesn't get stuck at the highest value for ever. If we reduce the max backoff interval that's less of a concern.
One motivation for this patch is to avoid logs filling up. For a client stuck in a restart loop with verb=3 and 5 minutes max pause, the logs grow by about 1 M per day -- may be not too bad.
Selva
Am 02.07.16 um 18:56 schrieb Selva Nair:
Quoted 28 lines
Quoted 7 lines · On Sat, Jul 2, 2016 at 11:32 AM, Arne Schwabe <[email protected]...…
And why sighup? Shouldn't just limiting sec be enought. SIGHUP has many side effects. I don't think we should trigger these for connection time.
With default setting this results in a SIGHUP after some hours and also the last intervals with 5120s are too big for default settings. I would aim for something lower like five or ten minutes.
I think a bit about that and I think a good way to specify exponential back is something like
connect-retry 5 1800, which would mean "scale back up to 1800s" and maybe default that option to connect-retry 5 300. That also allows specifying larger connect-retry values without backoff. E.g. connect-retry 60 60
Good idea.
Agreed, triggering SIGHUP is not ideal. The only reason for it was to reset the counters so that the backoff time doesn't get stuck at the highest value for ever. If we reduce the max backoff interval that's less of a concern.
Quoted 5 lines
One motivation for this patch is to avoid logs filling up. For a client stuck in a restart loop with verb=3 and 5 minutes max pause, the logs grow by about 1 M per day -- may be not too bad.
Selva
Do you want to propose a new patch or should I do it. I would propose still a exponential backoff but starting a 2s. so we get 2s 4s 8s ... or as default conect-retry 2 256. It would then just stay at the 256s interval until a sucessful connection is established. That simplifies the logic and gives predictable (from a user perspective) results.
Iirc the logic of connect-retry was changed by me in master so changing the logic again should not be a problem.
Quoted 19 lines · Arne Schwabe
Quoted 13 lines
connect-retry 5 1800, which would mean "scale back up to 1800s" and maybe default that option to connect-retry 5 300. That also allows specifying larger connect-retry values without backoff. E.g. connect-retry 60 60
Good idea.
Agreed, triggering SIGHUP is not ideal. The only reason for it was to reset the counters so that the backoff time doesn't get stuck at the highest value for ever. If we reduce the max backoff interval that's less of a concern.
Quoted 5 lines
One motivation for this patch is to avoid logs filling up. For a client stuck in a restart loop with verb=3 and 5 minutes max pause, the logs grow by about 1 M per day -- may be not too bad.
Selva
Quoted 8 lines
Do you want to propose a new patch or should I do it. I would propose still a exponential backoff but starting a 2s. so we get 2s 4s 8s ... or as default conect-retry 2 256. It would then just stay at the 256s interval until a sucessful connection is established. That simplifies the logic and gives predictable (from a user perspective) results.
Iirc the logic of connect-retry was changed by me in master so changing the logic again should not be a problem
Just sent off v2 before checking for new mails... If you want to change the default wait time to 2s, it can be easily done in an independent patch. Was there a reason fro changing it from 2s in 2.3 to the current 5s in the first place?
In any case my v2 would use 5, 5, 5, 5, 5, 10, 20,... ,160 and then jump to 300 instead of 320 and stay there which is pretty ok in my opinion. As the user can now specify any combination of the base wait interval and the max value, the last interval before capping will have an odd value in general -- we can avoid it for the default values but it will only stay so until someone changes the default again one day.. In case it matters, the intervals are still predictable although it doesn't have to be in a true backoff logic.
Selva
PATCH v2 1/1 Exponentially back off on repeated connect retries
In reply to Selva Nair- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause. (removed in v2 of the patch)
The base value of restart pause is set using --connect-retry (5 seconds by default).
v2 changes (based on suggestions from Arne Schwabe <[email protected]...>)
- Do not throw SIGHUP.
- Add an optional argument to "--connect-retry n [m]" where 'm' specifies the max value of restart pause interval (default 300 sec).
E.g., "--connect-retry 5 1800" will cause the restart pause to scale up starting at 5 until it exceeds 1800 seconds at which point it gets capped at 1800.
- If n == m no slow down will occur.
- While at it, fix typos and clarify the description of connect-retry-max in the man page and Changes.rst
--- Changes.rst | 8 ++++++-- doc/openvpn.8 | 19 ++++++++++++------- src/openvpn/init.c | 8 ++++++++ src/openvpn/options.c | 13 ++++++++++--- src/openvpn/options.h | 1 + 5 files changed, 37 insertions(+), 12 deletions(-)
Changes.rst +6 -2
@@ -75,8 +75,8 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment -- connect-retry now specifies the maximum number of unsucessfully - trying all remote/connection entries before exiting. +- connect-retry-max now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting. - sndbuf and recvbuf default now to OS default instead of 64k
@@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections will now behave like regular connection entries and generate a USR1 on failure. +- --connect-retry gets a optional third argument that specifies the maximum + time in seconds to wait between reconnection attempts when an exponential + backoff is triggered due to repeated retries. Default = 300 seconds. + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS
doc/openvpn.8 +12 -7
@@ -462,22 +462,27 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect\-retry n +.B \-\-connect\-retry n [max] Wait .B n -seconds between connection attempts (default=5). +seconds between connection attempts (default=5). Repeated reconnection +attempts are slowed down after 5 retries per remote by doubling the wait +time after each unsuccessful attempt. The optional argument +.B max +specifies the maximum value of wait time in seconds at which it gets +capped (default=300). .\"********************************************************* .TP .B \-\-connect\-retry\-max n .B n -specifies the number of times all +specifies the number of times each .B \-\-remote -respectively +or .B <connection> -statements are tried. Specifiying +entry is tried. Specifying .B n -as one would try each entry exactly once. A sucessful connection -resets the counter. (default=umlimited). +as one would try each entry exactly once. A successful connection +resets the counter. (default=unlimited). .\"********************************************************* .TP .B \-\-show\-proxy\-settings
src/openvpn/init.c +8 -0
@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {
@@ -1977,6 +1978,13 @@ socket_restart_pause (struct context *c) sec =10 ;#endif +/* Slow down reconnection after 5 retries per remote */ + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -4 ; +if (backoff >0 && sec <1 <<16 ) + sec =max_int (sec,1 ) <<min_int (backoff,15 ); +if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; +if (c->persist.restart_sleep_seconds >0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds;else if (c->persist.restart_sleep_seconds ==-1 )
src/openvpn/options.c +10 -3
@@ -123,8 +123,10 @@ static const char usage_message[] =" p = udp (default), tcp-server, or tcp-client\n" "--proto-force p : only consider protocol p in list of connection profiles.\n" " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" -"--connect-retry n : For --proto tcp-client, number of seconds to wait\n" -" between connection retries (default=%d).\n" +"--connect-retry n [m] : For client, number of seconds to wait between\n" +" connection retries (default=%d). On repeated retries\n" +" the wait time is exponentially increased to a maximum of m\n" +" (default=%d).\n" "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" "--http-proxy s p [up] [auth] : Connect to remote host\n" " through an HTTP proxy at address s and port p.\n"
@@ -770,6 +772,7 @@ init_options (struct options *o, const bool init_gc) o->ce.af =AF_UNSPEC ; o->ce.bind_ipv6_only = false; o->ce.connect_retry_seconds =5 ; + o->ce.connect_retry_seconds_max =300 ; o->ce.connect_timeout =120 ; o->connect_retry_max =0 ; o->ce.local_port = o->ce.remote_port =OPENVPN_PORT ;
@@ -3479,6 +3482,7 @@ usage (void) fprintf (fp, usage_message, title_string, o.ce.connect_retry_seconds, + o.ce.connect_retry_seconds_max, o.ce.local_port, o.ce.remote_port, TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, o.verbosity,
@@ -4724,10 +4728,13 @@ add_option (struct options *options,if (p[1 ]) options->ip_remote_hint=p[1 ]; } -else if (streq (p[0 ],"connect-retry" ) && p[1 ] && !p[2 ]) +else if (streq (p[0 ],"connect-retry" ) && p[1 ] && !p[3 ]) {VERIFY_PERMISSION (OPT_P_GENERAL |OPT_P_CONNECTION ); options->ce.connect_retry_seconds =positive_atoi (p[1 ]); +if (p[2 ]) + options->ce.connect_retry_seconds_max = +max_int (positive_atoi (p[2 ]), options->ce.connect_retry_seconds); }else if ((streq (p[0 ],"connect-timeout" ) ||streq (p[0 ],"server-poll-timeout" )) && p[1 ] && !p[2 ])
src/openvpn/options.h +1 -0
@@ -96,6 +96,7 @@ struct connection_entrybool bind_ipv6_only;bool bind_local;int connect_retry_seconds; +int connect_retry_seconds_max;int connect_timeout;struct http_proxy_options *http_proxy_options;const char *socks_proxy_server;
Signature · 1 line
1.7.10.4
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Am 03.07.16 um 01:34 schrieb Selva Nair:
Quoted 37 lines
- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause. (removed in v2 of the patch)The base value of restart pause is set using --connect-retry (5 seconds by default).
v2 changes (based on suggestions from Arne Schwabe <[email protected]...>)
- Do not throw SIGHUP.
- Add an optional argument to "--connect-retry n [m]" where 'm' specifies the max value of restart pause interval (default 300 sec).
E.g., "--connect-retry 5 1800" will cause the restart pause to scale up starting at 5 until it exceeds 1800 seconds at which point it gets capped at 1800.
- If n == m no slow down will occur.
- While at it, fix typos and clarify the description of connect-retry-max in the man page andChanges.rstSigned-off-by Selva Nair <[email protected]...>--- Changes.rst | 8 ++++++-- doc/openvpn.8 | 19 ++++++++++++------- src/openvpn/init.c | 8 ++++++++ src/openvpn/options.c | 13 ++++++++++--- src/openvpn/options.h | 1 + 5 files changed, 37 insertions(+), 12 deletions(-)Changes.rst +0
-0
Changes.rst User-visible Changes · line 80
Quoted 8 lines
Changes.rst +2
-2@@ -75,8 +75,8 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment -- connect-retry now specifies the maximum number of unsucessfully - trying all remote/connection entries before exiting. +- connect-retry-max now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting.
Ooops, my bad.
Changes.rst User-visible Changes · line 125
Quoted 9 lines
Changes.rst +3
-0- sndbuf and recvbuf default now to OS default instead of 64k@@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections will now behave like regular connection entries and generate a USR1 on failure. +- --connect-retry gets a optional third argument that specifies the maximum + time in seconds to wait between reconnection attempts when an exponential + backoff is triggered due to repeated retries. Default = 300 seconds.
Shouldn't that be 2nd argument?
Quoted 56 lines
Changes.rst +1
-0+ Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLSdoc/openvpn.8 +12
-7@@ -462,22 +462,27 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect\-retry n +.B \-\-connect\-retry n [max] Wait .B n -seconds between connection attempts (default=5). +seconds between connection attempts (default=5). Repeated reconnection +attempts are slowed down after 5 retries per remote by doubling the wait +time after each unsuccessful attempt. The optional argument +.B max +specifies the maximum value of wait time in seconds at which it gets +capped (default=300). .\"********************************************************* .TP .B \-\-connect\-retry\-max n .B n -specifies the number of times all +specifies the number of times each .B \-\-remote -respectively +or .B <connection> -statements are tried. Specifiying +entry is tried. Specifying .B n -as one would try each entry exactly once. A sucessful connection -resets the counter. (default=umlimited). +as one would try each entry exactly once. A successful connection +resets the counter. (default=unlimited). .\"********************************************************* .TP .B \-\-show\-proxy\-settingssrc/openvpn/init.c +1
-0@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1981
Quoted 4 lines
src/openvpn/init.c +1
-0@@ -1977,6 +1978,13 @@ socket_restart_pause (struct context *c) sec =10 ;#endif +/* Slow down reconnection after 5 retries per remote */
I still do not like this arbitary 5 times and then the exponential backoff starts. I would prefer a start with a small time and do a consistent backoff. But since tcp does the thing with syn packets (at least on my mac), I can agree to this behaviour too.
Btw. if we introduce this backoff mechansim I think it is safe to lower the connect-retry small time from 5 to 1 since the potential for looping very fast through the connection entries is not there anymore.
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1983
Quoted 2 lines
src/openvpn/init.c +2
-0+ backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -4 ; +if (backoff >0 && sec <1 <<16 )
the 1<<16 seems a bit random here. Could you at least add a comment of why? I don't see any valid reason here since sec is limited between 1 and connect_retry_seconds_max by the next two lines anyway.
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1984
Quoted 1 line
src/openvpn/init.c +1
-0+ sec =max_int (sec,1 ) <<min_int (backoff,15 );
The 15 here is the same. Both lines seem to only make sense with 16 bit integers.
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1986
Quoted 2 lines
src/openvpn/init.c +2
-0+if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max;
Oh, my suggestion made the max time time configurable per connection entry. We should address that in a seperate patch. I think connect-retry as a whole can be made a non connection config entry. (connect-retry traditionally was the time between tcp connects for a tcp connection which looped on its own before the dual stack patch if anyone wonders why it was connection specific).
Other than that, the patch gets an ACK from me.
Arne
P.S.: If you do a third patch, you might rename sec to something more aptly named.
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Hi,
Quoted 6 lines · Arne Schwabe
- sndbuf and recvbuf default now to OS default instead of 64k
Review User-visible Changes · line 120
Quoted 3 lines
(quoted diff) +0
-0@@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxyconnections
Review User-visible Changes · line 121
Quoted 1 line
(quoted diff) +0
-0will now behave like regular connection entries and generate a USR1
Quoted 8 lines
on failure.
Review User-visible Changes · line 122
Quoted 2 lines
(quoted diff) +1
-0+- --connect-retry gets a optional third argument that specifies themaximum
Review User-visible Changes · line 123
Quoted 1 line
(quoted diff) +1
-0+ time in seconds to wait between reconnection attempts when anexponential
Changes.rst User-visible Changes · line 125
Quoted 1 line
Changes.rst +1
-0+ backoff is triggered due to repeated retries. Default = 300 seconds.Shouldn't that be 2nd argument?
Ugh... should be 2nd. Will do a v3..
Quoted 10 lines
+ backoff = (
c->options.unsuccessful_attempts/c->options.connection_list->len) - 4;src/openvpn/init.c socket_restart_pause (struct context *c) · line 1983
Quoted 1 line
src/openvpn/init.c +1
-0+if (backoff >0 && sec <1 <<16 )the 1<<16 seems a bit random here. Could you at least add a comment of why? I don't see any valid reason here since sec is limited between 1 and
connect_retry_seconds_maxby the next two lines anyway.src/openvpn/init.c socket_restart_pause (struct context *c) · line 1984
Quoted 1 line
src/openvpn/init.c +1
-0+ sec =max_int (sec,1 ) <<min_int (backoff,15 );The 15 here is the same. Both lines seem to only make sense with 16 bit integers.
Something like this is needed to protect against overflow of the 32 bit int (signed int in this case). Think of the user specifying sec = 2^17. Any shift by more than 14 will make sec = 0. A more sophisticated logic that counts the bits in sec before shifting is possible, but this looked simple.. Now that a v3 is needed, will change to an explicit check on overflow.
Quoted 8 lines
+ if (sec >
c->options.ce.connect_retry_seconds_max)src/openvpn/init.c socket_restart_pause (struct context *c) · line 1986
Quoted 1 line
src/openvpn/init.c +1
-0+ sec = c->options.ce.connect_retry_seconds_max;Oh, my suggestion made the max time time configurable per connection entry. We should address that in a seperate patch. I think connect-retry as a whole can be made a non connection config entry. (connect-retry traditionally was the time between tcp connects for a tcp connection which looped on its own before the dual stack patch if anyone wonders why it was connection specific).
It can still be specified as a common number outside connection entries, so leaving it as a connection-specific number looks fine to me.
Selva
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Am 04.07.16 um 17:43 schrieb Selva Nair:
Quoted 7 lines
Something like this is needed to protect against overflow of the 32 bit int (signed int in this case). Think of the user specifying sec = 2^17. Any shift by more than 14 will make sec = 0. A more sophisticated logic that counts the bits in sec before shifting is possible, but this looked simple.. Now that a v3 is needed, will change to an explicit check on overflow.
That do that check in options.c and complain there. :)
Arne
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Quoted 11 lines · Arne Schwabe
Quoted 7 lines
Something like this is needed to protect against overflow of the 32 bit int (signed int in this case). Think of the user specifying sec = 2^17. Any shift by more than 14 will make sec = 0. A more sophisticated logic that counts the bits in sec before shifting is possible, but this looked simple.. Now that a v3 is needed, will change to an explicit check on overflow.
That do that check in
options.cand complain there. :)
Yes, we could limit n and m in "--connect-retry n [m]" to < 2^16 and then limit the shift to 15 in init.c. But that adds dependency between two statements in widely different locations. What I propose is to leave options.c as is and change the exponential scaling code in init.c to
if (backoff > 0)
{
sec = max_int (sec, 1) << min_int (backoff, 31); /* left shifting int
by 32 or more is ill-defined */
if (sec == 0) /* overflow */
sec = INT_MAX;}
No more confusing numbers like 16 and 15.
Quoted 9 lines
+ /* Slow down reconnection after 5 retries per remote */
Quoted 1 line
+ backoff = (
c->options.unsuccessful_attempts/
c->options.connection_list->len) - 4;src/openvpn/init.c socket_restart_pause (struct context *c)
Quoted 6 lines
src/openvpn/init.c +5
-0+if (backoff >0 && sec <1 <<16 ) + sec =max_int (sec,1 ) <<min_int (backoff,15 ); +if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; + if (c->persist.restart_sleep_seconds > 0 &&
Quoted 7 lines
c->persist.restart_sleep_seconds> sec)Quoted 3 lines
sec = c->persist.restart_sleep_seconds;else if (
c->persist.restart_sleep_seconds== -1)I think this also needs an excempt for
TCP_SERVERcase. I think moving theTCP_SERVERif below the exponential logic will work. Otherwise connecting just 10 times is an effect dos for a tcp server.
I am not sure I follow. Are you referring to the possibility that the sec = 1 for TCP_SERVER may get set to zero after 5 retries if "--connect-retry 0 0" is used? The server only listens for connections so this should not happen, would it?.
Or do you have tcp-client in mind? In case of tcp-client, before this patch, "--connect-retry 0" will hammer the server with repeated retries. That will be avoided as max sec defaults to 300 sec, unless the user specifies "--connect-retry 0 0". Shall we require that the second arg to connect-retry should be greater than some minimum, say, at least 10 sec?
Selva
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Quoted 7 lines
Or do you have tcp-client in mind? In case of tcp-client, before this patch, "--connect-retry 0" will hammer the server with repeated retries. That will be avoided as max sec defaults to 300 sec, unless the user specifies "--connect-retry 0 0". Shall we require that the second arg to connect-retry should be greater than some minimum, say, at least 10 sec?
No, the TCP-SERVER line there is for p2p mode but with tcp-server. In p2p mode with p2p the code will also execute that socket-restart code after the other side will disconnect.
Arne
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Quoted 10 lines · Arne Schwabe
Quoted 6 lines
Or do you have tcp-client in mind? In case of tcp-client, before this patch, "--connect-retry 0" will hammer the server with repeated retries. That will be avoided as max sec defaults to 300 sec, unless the user specifies "--connect-retry 0 0". Shall we require that the second arg to connect-retry should be greater than some minimum, say, at least 10 sec?
No, the TCP-SERVER line there is for p2p mode but with tcp-server. In p2p mode with p2p the code will also execute that socket-restart code after the other side will disconnect.
In the p2p case the tcp server will just do a SIGUSR1 restart and wait for the client, isn't it -- at least that's what my tests showed on Linux. With "--connect-retry 0", the pause time for tcp-server before restart will be "1, 1, 1, 1, 1, 2, 4, 8 .." seconds until it reaches the max value. If I move the "if for TCP_SERVER" to below the exponential backoff, the server restart pause interval will stay fixed at 1 sec with no backoff. Is that what is preferred? Or am I missing something?
The only issue I see is that the interval for tcp-server will get reset to 0 after 5 retries if "--connect-retry 0 0" is used. This is a general issue that is even worse for the tcp-client which will repeatedly try to reconnect with no pause. Both situations may be fixed by requiring the max interval to be > 0 as I mentioned in my previous email.
Selva
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
Hi,
Quoted 15 lines · Selva Nair
Quoted 10 lines · Arne Schwabe
Quoted 6 lines
Or do you have tcp-client in mind? In case of tcp-client, before this patch, "--connect-retry 0" will hammer the server with repeated retries. That will be avoided as max sec defaults to 300 sec, unless the user specifies "--connect-retry 0 0". Shall we require that the second arg to connect-retry should be greater than some minimum, say, at least 10 sec?
No, the TCP-SERVER line there is for p2p mode but with tcp-server. In p2p mode with p2p the code will also execute that socket-restart code after the other side will disconnect.
Quoted 8 lines
In the p2p case the tcp server will just do a SIGUSR1 restart and wait for the client, isn't it -- at least that's what my tests showed on Linux. With "--connect-retry 0", the pause time for tcp-server before restart will be "1, 1, 1, 1, 1, 2, 4, 8 .." seconds until it reaches the max value. If I move the "if for
TCP_SERVER" to below the exponential backoff, the server restart pause interval will stay fixed at 1 sec with no backoff. Is that what is preferred? Or am I missing something?
Please ignore that. I think I finally got the DOS attack on p2p tcp-server you alluded to. Will move TCP_SERVER case to after the backoff logic in version 3.
Selva
Re: [Openvpn-devel] [PATCH v2] Exponentially back off on repeated connect retries
In reply to Selva NairAm 03.07.16 um 01:34 schrieb Selva Nair:
Quoted 114 lines
- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause. (removed in v2 of the patch)The base value of restart pause is set using --connect-retry (5 seconds by default).
v2 changes (based on suggestions from Arne Schwabe <[email protected]...>)
- Do not throw SIGHUP.
- Add an optional argument to "--connect-retry n [m]" where 'm' specifies the max value of restart pause interval (default 300 sec).
E.g., "--connect-retry 5 1800" will cause the restart pause to scale up starting at 5 until it exceeds 1800 seconds at which point it gets capped at 1800.
- If n == m no slow down will occur.
- While at it, fix typos and clarify the description of connect-retry-max in the man page andChanges.rstSigned-off-by Selva Nair <[email protected]...>--- Changes.rst | 8 ++++++-- doc/openvpn.8 | 19 ++++++++++++------- src/openvpn/init.c | 8 ++++++++ src/openvpn/options.c | 13 ++++++++++--- src/openvpn/options.h | 1 + 5 files changed, 37 insertions(+), 12 deletions(-)Changes.rst +6
-2@@ -75,8 +75,8 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment -- connect-retry now specifies the maximum number of unsucessfully - trying all remote/connection entries before exiting. +- connect-retry-max now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting. - sndbuf and recvbuf default now to OS default instead of 64k@@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections will now behave like regular connection entries and generate a USR1 on failure. +- --connect-retry gets a optional third argument that specifies the maximum + time in seconds to wait between reconnection attempts when an exponential + backoff is triggered due to repeated retries. Default = 300 seconds. + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLSdoc/openvpn.8 +12
-7@@ -462,22 +462,27 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect\-retry n +.B \-\-connect\-retry n [max] Wait .B n -seconds between connection attempts (default=5). +seconds between connection attempts (default=5). Repeated reconnection +attempts are slowed down after 5 retries per remote by doubling the wait +time after each unsuccessful attempt. The optional argument +.B max +specifies the maximum value of wait time in seconds at which it gets +capped (default=300). .\"********************************************************* .TP .B \-\-connect\-retry\-max n .B n -specifies the number of times all +specifies the number of times each .B \-\-remote -respectively +or .B <connection> -statements are tried. Specifiying +entry is tried. Specifying .B n -as one would try each entry exactly once. A sucessful connection -resets the counter. (default=umlimited). +as one would try each entry exactly once. A successful connection +resets the counter. (default=unlimited). .\"********************************************************* .TP .B \-\-show\-proxy\-settingssrc/openvpn/init.c +1
-0@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {@@ -1977,6 +1978,13 @@ socket_restart_pause (struct context *c) sec =10 ;#endif
src/openvpn/init.c socket_restart_pause (struct context *c) · line 1990
Quoted 10 lines
src/openvpn/init.c +7
-0+/* Slow down reconnection after 5 retries per remote */ + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -4 ; +if (backoff >0 && sec <1 <<16 ) + sec =max_int (sec,1 ) <<min_int (backoff,15 ); +if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; +if (c->persist.restart_sleep_seconds >0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds;else if (c->persist.restart_sleep_seconds ==-1 )
I think this also needs an excempt for TCP_SERVER case. I think moving the TCP_SERVER if below the exponential logic will work. Otherwise connecting just 10 times is an effect dos for a tcp server.
Arne
PATCH 1/1 Exponentially back off on repeated connect retries
In reply to Selva Nair- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
- Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause. (removed in v2 of the patch)
The base value of restart pause is set using --connect-retry (5 seconds by default).
v2 changes (based on suggestions from Arne Schwabe <[email protected]...>)
- Do not throw SIGHUP.
- Add an optional argument to "--connect-retry n [m]" where 'm' specifies the max value of restart pause interval (default 300 sec).
E.g., "--connect-retry 5 1800" will cause the restart pause to scale up starting at 5 until it exceeds 1800 seconds at which point it gets capped at 1800.
- If n == m no slow down will occur.
- While at it, fix typos and clarify the description of connect-retry-max in the man page and Changes.rst
v3 changes (on further feedback from [email protected]...):
- Limiting the base value of retry wait interval to 16 bits moved to options.c
- Apply backoff only in the udp and tcp-client modes. Backing off on tcp-server could be exploited by a client in p2p-mode to maliciously slow it down (thanks to Arne Schwabe for pointing this out.
- Fix typo in Changes.rst: "third argument" -> "second argument"
--- Changes.rst | 8 ++++++-- doc/openvpn.8 | 19 ++++++++++++------- src/openvpn/init.c | 15 +++++++++++++++ src/openvpn/options.c | 24 +++++++++++++++++++++--- src/openvpn/options.h | 1 + 5 files changed, 55 insertions(+), 12 deletions(-)
Changes.rst +6 -2
@@ -75,8 +75,8 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment -- connect-retry now specifies the maximum number of unsucessfully - trying all remote/connection entries before exiting. +- connect-retry-max now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting. - sndbuf and recvbuf default now to OS default instead of 64k
@@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections will now behave like regular connection entries and generate a USR1 on failure. +- --connect-retry gets an optional second argument that specifies the maximum + time in seconds to wait between reconnection attempts when an exponential + backoff is triggered due to repeated retries. Default = 300 seconds. + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS
doc/openvpn.8 +12 -7
@@ -462,22 +462,27 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect\-retry n +.B \-\-connect\-retry n [max] Wait .B n -seconds between connection attempts (default=5). +seconds between connection attempts (default=5). Repeated reconnection +attempts are slowed down after 5 retries per remote by doubling the wait +time after each unsuccessful attempt. The optional argument +.B max +specifies the maximum value of wait time in seconds at which it gets +capped (default=300). .\"********************************************************* .TP .B \-\-connect\-retry\-max n .B n -specifies the number of times all +specifies the number of times each .B \-\-remote -respectively +or .B <connection> -statements are tried. Specifiying +entry is tried. Specifying .B n -as one would try each entry exactly once. A sucessful connection -resets the counter. (default=umlimited). +as one would try each entry exactly once. A successful connection +resets the counter. (default=unlimited). .\"********************************************************* .TP .B \-\-show\-proxy\-settings
src/openvpn/init.c +15 -0
@@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) {int sec =2 ; +int backoff =0 ;switch (c->options.ce.proto) {
@@ -1977,6 +1978,20 @@ socket_restart_pause (struct context *c) sec =10 ;#endif +/* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */ +if (c->options.ce.proto !=PROTO_TCP_SERVER ) + { + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) -4 ; +if (backoff >0 ) + { +/* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ + sec =max_int (sec,1 ) <<min_int (backoff,15 ); + } + +if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; + } +if (c->persist.restart_sleep_seconds >0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds;else if (c->persist.restart_sleep_seconds ==-1 )
src/openvpn/options.c +21 -3
@@ -123,8 +123,10 @@ static const char usage_message[] =" p = udp (default), tcp-server, or tcp-client\n" "--proto-force p : only consider protocol p in list of connection profiles.\n" " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" -"--connect-retry n : For --proto tcp-client, number of seconds to wait\n" -" between connection retries (default=%d).\n" +"--connect-retry n [m] : For client, number of seconds to wait between\n" +" connection retries (default=%d). On repeated retries\n" +" the wait time is exponentially increased to a maximum of m\n" +" (default=%d).\n" "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" "--http-proxy s p [up] [auth] : Connect to remote host\n" " through an HTTP proxy at address s and port p.\n"
@@ -770,6 +772,7 @@ init_options (struct options *o, const bool init_gc) o->ce.af =AF_UNSPEC ; o->ce.bind_ipv6_only = false; o->ce.connect_retry_seconds =5 ; + o->ce.connect_retry_seconds_max =300 ; o->ce.connect_timeout =120 ; o->connect_retry_max =0 ; o->ce.local_port = o->ce.remote_port =OPENVPN_PORT ;
@@ -3479,6 +3482,7 @@ usage (void) fprintf (fp, usage_message, title_string, o.ce.connect_retry_seconds, + o.ce.connect_retry_seconds_max, o.ce.local_port, o.ce.remote_port, TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, o.verbosity,
@@ -4724,10 +4728,24 @@ add_option (struct options *options,if (p[1 ]) options->ip_remote_hint=p[1 ]; } -else if (streq (p[0 ],"connect-retry" ) && p[1 ] && !p[2 ]) +else if (streq (p[0 ],"connect-retry" ) && p[1 ] && !p[3 ]) {VERIFY_PERMISSION (OPT_P_GENERAL |OPT_P_CONNECTION ); options->ce.connect_retry_seconds =positive_atoi (p[1 ]); +/* +* Limit the base value of retry wait interval to 16 bits to avoid +* overflow when scaled up for exponential backoff +*/ +if (options->ce.connect_retry_seconds >0xFFFF ) + { + options->ce.connect_retry_seconds =0xFFFF ; +msg (M_WARN ,"connect retry wait interval truncated to %d" , + options->ce.connect_retry_seconds); + } + +if (p[2 ]) + options->ce.connect_retry_seconds_max = +max_int (positive_atoi (p[2 ]), options->ce.connect_retry_seconds); }else if ((streq (p[0 ],"connect-timeout" ) ||streq (p[0 ],"server-poll-timeout" )) && p[1 ] && !p[2 ])
src/openvpn/options.h +1 -0
@@ -96,6 +96,7 @@ struct connection_entrybool bind_ipv6_only;bool bind_local;int connect_retry_seconds; +int connect_retry_seconds_max;int connect_timeout;struct http_proxy_options *http_proxy_options;const char *socks_proxy_server;
Signature · 1 line
1.7.10.4
Re: [Openvpn-devel] [PATCH] Exponentially back off on repeated connect retries
Am 05.07.16 um 17:32 schrieb Selva Nair:
Quoted 4 lines
- When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote.
ACK from me. (Although I still would prefer a lower number like 3)
Arne
[Openvpn-devel] [PATCH applied] Re: Exponentially back off on repeated connect retries
In reply to Selva NairAnother ACK from me, looks good (and works :) )...
Mon Jul 11 16:30:28 2016 us=977593 Restart pause, 2 second(s) Mon Jul 11 16:30:32 2016 us=937071 Restart pause, 2 second(s) Mon Jul 11 16:30:36 2016 us=957047 Restart pause, 2 second(s) Mon Jul 11 16:30:40 2016 us=907049 Restart pause, 2 second(s) Mon Jul 11 16:30:44 2016 us=867052 Restart pause, 4 second(s) Mon Jul 11 16:30:50 2016 us=677019 Restart pause, 8 second(s) Mon Jul 11 16:31:00 2016 us=497045 Restart pause, 16 second(s) Mon Jul 11 16:31:18 2016 us=517110 Restart pause, 32 second(s) Mon Jul 11 16:31:52 2016 us=367066 Restart pause, 64 second(s) Mon Jul 11 16:32:58 2016 us=337024 Restart pause, 128 second(s) Mon Jul 11 16:35:08 2016 us=227030 Restart pause, 140 second(s) Mon Jul 11 16:37:30 2016 us=137063 Restart pause, 140 second(s)
(--connect-retry 2 140)
Thanks :)
Your patch has been applied to the master branch.
commit 5d429efd9720109b9c9f1265f5d351a75a401942
Author: Selva Nair Date: Tue Jul 5 11:32:50 2016 -0400
Exponentially back off on repeated connect retries
Signed-off-by: Selva Nair <[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/12050
Signed-off-by: Gert Doering <[email protected]...>--
kind regards,
Gert Doering