On Fri, Jan 06, 2023 at 03:38:41PM +0100, Arne Schwabe wrote: > This limits the nubmer of packets OpenVPN will respond to. This avoid > OpenVPN server being abused for refelection attacks in a large scale > as we gotten a lot more efficient with the cookie approach in our > initial connection approach. > > The defaults of 100 attempts per 10s should work for most people, > esepcially since completed three way handshakes are not counted. So > the default will throttle connection attempts on server with high packet > loss or that are actually under a DOS. > > The 100 per 10s are similar in size to the old 2.5 and earlier behaviour > where every initial connection attempt would take up a slot of the > max-clients sessions and those would only expire after the TLS timeout. > This roughly translates to 1024 connection attempts in 60s on an > empty server. > [...] > diff --git a/doc/man-sections/server-options.rst > b/doc/man-sections/server-options.rst > index 99263fff3..cbb2c3c92 100644 > --- a/doc/man-sections/server-options.rst > +++ b/doc/man-sections/server-options.rst > @@ -184,6 +184,25 @@ fast hardware. SSL/TLS authentication must be used in > this mode. > For the best protection against DoS attacks in server mode, use > ``--proto udp`` and either ``--tls-auth`` or ``--tls-crypt``.
I think we should add a sentence about the relationship between connect-freq and connect-freq-initial. Because users will wonder. Specifically are there attacks that connect-freq protects against that connect-freq-initial does not? > > +--connect-freq-initial args > + (UDP only) Allow a maximum of ``n`` initial connection packet responses > + per ``sec`` seconds from to clients. Remove "from"? > + > + Valid syntax: > + :: > + > + connect-freq-initial n sec > + > + OpenVPN starting at 2.6 is very efficient in responding to initial > + connection packets. When not limiting the initial responses > + an OpenVPN daemon can be abused in reflection attacks. > + This option is designed to limit the rate OpenVPN will respond to initial > + attacks. > + > + Connection attempts that complete the initial three-way handshake > + will not be counted against the limit. The default is to allow > + 100 initial connection per 10s. > + > --duplicate-cn > Allow multiple clients with the same common name to concurrently > connect. In the absence of this option, OpenVPN will disconnect a client [...] > diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c > index c27c6da5b..4ef2f355b 100644 > --- a/src/openvpn/mudp.c > +++ b/src/openvpn/mudp.c > @@ -82,6 +82,16 @@ do_pre_decrypt_check(struct multi_context *m, > struct openvpn_sockaddr *from = &m->top.c2.from.dest; > int handwindow = m->top.options.handshake_window; > > + if (verdict == VERDICT_VALID_RESET_V3 || verdict == > VERDICT_VALID_RESET_V2) > + { > + /* Check if we are still below our limit for sending out > + * responses */ > + if (!reflect_filter_rate_limit_check(m->initial_rate_limiter)) > + { > + return false; > + } > + } > + > if (verdict == VERDICT_VALID_RESET_V3) > { > /* Extract the packet id to check if it has the special format that > @@ -244,6 +254,10 @@ multi_get_create_instance_udp(struct multi_context *m, > bool *floated) > > if (frequency_limit_event_allowed(m->new_connection_limiter)) > { > + /* a successful three-way handshake only counts against > + * connect-freq but not against connect-req-initial */ "connect-freq-initial" > + > reflect_filter_rate_limit_decrease(m->initial_rate_limiter); > + > mi = multi_create_instance(m, &real); > if (mi) > { > diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c > index 0ba509fa0..1a7f278f7 100644 > --- a/src/openvpn/multi.c > +++ b/src/openvpn/multi.c > @@ -52,6 +52,7 @@ > #include "crypto_backend.h" > #include "ssl_util.h" > #include "dco.h" > +#include "reflect_filter.h" > > /*#define MULTI_DEBUG_EVENT_LOOP*/ > > @@ -368,6 +369,8 @@ multi_init(struct multi_context *m, struct context *t, > bool tcp_mode) > */ > m->new_connection_limiter = frequency_limit_init(t->options.cf_max, > t->options.cf_per); > + m->initial_rate_limiter = > initial_rate_limit_init(t->options.cf_initial_max, > + > t->options.cf_initial_per); > > /* > * Allocate broadcast/multicast buffer list > @@ -729,6 +732,7 @@ multi_uninit(struct multi_context *m) > mbuf_free(m->mbuf); > ifconfig_pool_free(m->ifconfig_pool); > frequency_limit_free(m->new_connection_limiter); > + initial_rate_limit_free(m->initial_rate_limiter); > multi_reap_free(m->reaper); > mroute_helper_free(m->route_helper); > multi_tcp_free(m->mtcp); [...] > diff --git a/src/openvpn/options.c b/src/openvpn/options.c > index ee3783046..e756af948 100644 > --- a/src/openvpn/options.c > +++ b/src/openvpn/options.c > @@ -480,6 +480,7 @@ static const char usage_message[] = > " as well as pushes it to connecting clients.\n" > "--learn-address cmd : Run command cmd to validate client virtual > addresses.\n" > "--connect-freq n s : Allow a maximum of n new connections per s > seconds.\n" > + "--connect-freq-initial n s : Allow a maximum of n replies for initial > connections attempts per s seconds.\n" > "--max-clients n : Allow a maximum of n simultaneously connected > clients.\n" > "--max-routes-per-client n : Allow a maximum of n internal routes per > client.\n" > "--stale-routes-check n [t] : Remove routes with a last activity > timestamp\n" > @@ -864,6 +865,8 @@ init_options(struct options *o, const bool init_gc) > o->n_bcast_buf = 256; > o->tcp_queue_limit = 64; > o->max_clients = 1024; > + o->cf_initial_per = 10; > + o->cf_initial_max = 100; > o->max_routes_per_client = 256; > o->stale_routes_check_interval = 0; > o->ifconfig_pool_persist_refresh_freq = 600; > @@ -1555,6 +1558,8 @@ show_p2mp_parms(const struct options *o) > SHOW_BOOL(duplicate_cn); > SHOW_INT(cf_max); > SHOW_INT(cf_per); > + SHOW_INT(cf_initial_max); > + SHOW_INT(cf_initial_per); > SHOW_INT(max_clients); > SHOW_INT(max_routes_per_client); > SHOW_STR(auth_user_pass_verify_script); > @@ -7452,6 +7457,22 @@ add_option(struct options *options, > options->cf_max = cf_max; > options->cf_per = cf_per; > } > + else if (streq(p[0], "connect-freq-initial") && p[1] && p[2] && !p[3]) > + { > + long cf_max, cf_per; > + > + VERIFY_PERMISSION(OPT_P_GENERAL); > + char *e1, *e2; > + cf_max = strtol(p[1], &e1, 10); > + cf_per = strtol(p[2], &e2, 10); > + if (cf_max < 0 || cf_per < 0 || *e1 != '\0' || *e2 != '\0') > + { > + msg(msglevel, "--connect-freq-initial parameters must be > integers and >= 0"); > + goto err; > + } > + options->cf_initial_max = cf_max; > + options->cf_initial_per = cf_per; > + } > else if (streq(p[0], "max-clients") && p[1] && !p[2]) > { > int max_clients; Regards, -- Frank Lichtenheld _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel