]> git.meshlink.io Git - meshlink/commitdiff
Add connection rate limiting.
authorGuus Sliepen <guus@tinc-vpn.org>
Thu, 11 Jul 2013 21:38:38 +0000 (23:38 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Thu, 11 Jul 2013 21:38:38 +0000 (23:38 +0200)
Tinc now strictly limits incoming connections from the same host to 1 per
second. For incoming connections from multiple hosts short bursts of incoming
connections are allowed (by default 100), but on average also only 1 connection
per second is allowed.

When an incoming connection exceeds the limit, tinc will keep the connection in
a tarpit; the connection will be kept open but it is ignored completely. Only
one connection is in a tarpit at a time to limit the number of useless open
connections.

doc/tinc.conf.5.in
doc/tinc.texi
src/net.h
src/net_setup.c
src/net_socket.c
src/tincctl.c

index 0376328f07714e7791943c40fa84f6264dc09714..69deace9cc618f830be918bb0cb9e2f3a78ee019 100644 (file)
@@ -335,6 +335,11 @@ This only has effect when
 .Va Mode
 is set to
 .Qq switch .
 .Va Mode
 is set to
 .Qq switch .
+.It Va MaxConnectionBurst Li = Ar count Pq 100
+This option controls how many connections tinc accepts in quick succession.
+If there are more connections than the given number in a short time interval,
+tinc will reduce the number of accepted connections to only one per second,
+until the burst has passed.
 .It Va MaxTimeout Li = Ar seconds Pq 900
 This is the maximum delay before trying to reconnect to other tinc daemons.
 .It Va Mode Li = router | switch | hub Pq router
 .It Va MaxTimeout Li = Ar seconds Pq 900
 This is the maximum delay before trying to reconnect to other tinc daemons.
 .It Va Mode Li = router | switch | hub Pq router
index 08021f9ad4051d0b38675b230d4c2a3aa3392e4d..a39e9ae6de2ab1cea4219e912ac36283b0adda63 100644 (file)
@@ -1101,6 +1101,13 @@ impossible to crack a single key.
 This option controls the amount of time MAC addresses are kept before they are removed.
 This only has effect when Mode is set to "switch".
 
 This option controls the amount of time MAC addresses are kept before they are removed.
 This only has effect when Mode is set to "switch".
 
+@cindex MaxConnectionBurst
+@item MaxConnectionBurst = <@var{count}> (100)
+This option controls how many connections tinc accepts in quick succession.
+If there are more connections than the given number in a short time interval,
+tinc will reduce the number of accepted connections to only one per second,
+until the burst has passed.
+
 @cindex Name
 @item Name = <@var{name}> [required]
 This is a symbolic name for this connection.
 @cindex Name
 @item Name = <@var{name}> [required]
 This is a symbolic name for this connection.
@@ -1182,7 +1189,6 @@ reordering. Setting this to zero will disable replay tracking completely and
 pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
 traffic.
 
 pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
 traffic.
 
-
 @cindex StrictSubnets
 @item StrictSubnets <yes|no> (no) [experimental]
 When this option is enabled tinc will only use Subnet statements which are
 @cindex StrictSubnets
 @item StrictSubnets <yes|no> (no) [experimental]
 When this option is enabled tinc will only use Subnet statements which are
index 5f6224e2ccc31a083d189e1c82405d649fd55360..9a97276ca99d62f6c95fce0b2ef25040e7a01756 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -133,6 +133,7 @@ extern io_t unix_socket;
 extern int keylifetime;
 extern int udp_rcvbuf;
 extern int udp_sndbuf;
 extern int keylifetime;
 extern int udp_rcvbuf;
 extern int udp_sndbuf;
+extern int max_connection_burst;
 extern bool do_prune;
 extern char *myport;
 extern int autoconnect;
 extern bool do_prune;
 extern char *myport;
 extern int autoconnect;
index 8ae1e72bbaafd3d90cd1118c2faa3085b36032cb..334ea5d16886df2b97d5efa27abfd9441fd20680 100644 (file)
@@ -711,7 +711,12 @@ static bool setup_myself(void) {
        get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
        strictsubnets |= tunnelserver;
 
        get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
        strictsubnets |= tunnelserver;
 
-
+       if(get_config_int(lookup_config(config_tree, "MaxConnectionBurst"), &max_connection_burst)) {
+               if(max_connection_burst <= 0) {
+                       logger(DEBUG_ALWAYS, LOG_ERR, "MaxConnectionBurst cannot be negative!");
+                       return false;
+               }
+       }
 
        if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
                if(udp_rcvbuf <= 0) {
 
        if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
                if(udp_rcvbuf <= 0) {
index 1b49aeeb4090865dd357cc235e1dffc24fe0de72..ded9224d48dd720bfd11ccb7e9c6f334da0d8060 100644 (file)
@@ -45,6 +45,7 @@ int maxtimeout = 900;
 int seconds_till_retry = 5;
 int udp_rcvbuf = 0;
 int udp_sndbuf = 0;
 int seconds_till_retry = 5;
 int udp_rcvbuf = 0;
 int udp_sndbuf = 0;
+int max_connection_burst = 100;
 
 listen_socket_t listen_socket[MAXSOCKETS];
 int listen_sockets;
 
 listen_socket_t listen_socket[MAXSOCKETS];
 int listen_sockets;
@@ -561,6 +562,47 @@ void handle_new_meta_connection(void *data, int flags) {
 
        sockaddrunmap(&sa);
 
 
        sockaddrunmap(&sa);
 
+       // Check if we get many connections from the same host
+
+       static sockaddr_t prev_sa;
+       static time_t prev_time;
+       static int tarpit = -1;
+
+       if(tarpit >= 0) {
+               closesocket(tarpit);
+               tarpit = -1;
+       }
+
+       if(prev_time == now.tv_sec && !sockaddrcmp_noport(&sa, &prev_sa)) {
+               // if so, keep the connection open but ignore it completely.
+               tarpit = fd;
+               return;
+       }
+
+       memcpy(&prev_sa, &sa, sizeof sa);
+       prev_time = now.tv_sec;
+
+       // Check if we get many connections from different hosts
+
+       static int connection_burst;
+       static int connection_burst_time;
+
+       if(now.tv_sec - connection_burst_time > connection_burst)
+               connection_burst = 0;
+       else
+               connection_burst -= now.tv_sec - connection_burst_time;
+
+       connection_burst_time = now.tv_sec;
+       connection_burst++;
+
+       if(connection_burst >= max_connection_burst) {
+               connection_burst = max_connection_burst;
+               tarpit = fd;
+               return;
+       }
+
+       // Accept the new connection
+
        c = new_connection();
        c->name = xstrdup("<unknown>");
        c->outcipher = myself->connection->outcipher;
        c = new_connection();
        c->name = xstrdup("<unknown>");
        c->outcipher = myself->connection->outcipher;
index 1183dd78c4401874d41a635722f0947bbff7a1b6..b3e10c879a2ade8a35eecab2b3ea47d68cb686d0 100644 (file)
@@ -1296,6 +1296,7 @@ const var_t variables[] = {
        {"KeyExpire", VAR_SERVER},
        {"LocalDiscovery", VAR_SERVER},
        {"MACExpire", VAR_SERVER},
        {"KeyExpire", VAR_SERVER},
        {"LocalDiscovery", VAR_SERVER},
        {"MACExpire", VAR_SERVER},
+       {"MaxConnectionBurst", VAR_SERVER},
        {"MaxOutputBufferSize", VAR_SERVER},
        {"MaxTimeout", VAR_SERVER},
        {"Mode", VAR_SERVER | VAR_SAFE},
        {"MaxOutputBufferSize", VAR_SERVER},
        {"MaxTimeout", VAR_SERVER},
        {"Mode", VAR_SERVER | VAR_SAFE},