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:
parent
2eba793305
commit
24e3ec863e
6 changed files with 62 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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},
|
||||
|
|
Loading…
Reference in a new issue