Add connection rate limiting.

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.
This commit is contained in:
Guus Sliepen 2013-07-11 23:38:38 +02:00
parent 2eba793305
commit 24e3ec863e
6 changed files with 62 additions and 2 deletions

View file

@ -335,6 +335,11 @@ This only has effect when
.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

View 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".
@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.
@ -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.
@cindex StrictSubnets
@item StrictSubnets <yes|no> (no) [experimental]
When this option is enabled tinc will only use Subnet statements which are

View file

@ -133,6 +133,7 @@ extern io_t unix_socket;
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;

View file

@ -711,7 +711,12 @@ static bool setup_myself(void) {
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) {

View file

@ -45,6 +45,7 @@ int maxtimeout = 900;
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;
@ -561,6 +562,47 @@ void handle_new_meta_connection(void *data, int flags) {
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;

View file

@ -1296,6 +1296,7 @@ const var_t variables[] = {
{"KeyExpire", VAR_SERVER},
{"LocalDiscovery", VAR_SERVER},
{"MACExpire", VAR_SERVER},
{"MaxConnectionBurst", VAR_SERVER},
{"MaxOutputBufferSize", VAR_SERVER},
{"MaxTimeout", VAR_SERVER},
{"Mode", VAR_SERVER | VAR_SAFE},