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
|
.Va Mode
|
||||||
is set to
|
is set to
|
||||||
.Qq switch .
|
.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
|
.It Va MaxTimeout Li = Ar seconds Pq 900
|
||||||
This is the maximum delay before trying to reconnect to other tinc daemons.
|
This is the maximum delay before trying to reconnect to other tinc daemons.
|
||||||
.It Va Mode Li = router | switch | hub Pq router
|
.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 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 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
|
@cindex Name
|
||||||
@item Name = <@var{name}> [required]
|
@item Name = <@var{name}> [required]
|
||||||
This is a symbolic name for this connection.
|
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
|
pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
|
||||||
traffic.
|
traffic.
|
||||||
|
|
||||||
|
|
||||||
@cindex StrictSubnets
|
@cindex StrictSubnets
|
||||||
@item StrictSubnets <yes|no> (no) [experimental]
|
@item StrictSubnets <yes|no> (no) [experimental]
|
||||||
When this option is enabled tinc will only use Subnet statements which are
|
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 keylifetime;
|
||||||
extern int udp_rcvbuf;
|
extern int udp_rcvbuf;
|
||||||
extern int udp_sndbuf;
|
extern int udp_sndbuf;
|
||||||
|
extern int max_connection_burst;
|
||||||
extern bool do_prune;
|
extern bool do_prune;
|
||||||
extern char *myport;
|
extern char *myport;
|
||||||
extern int autoconnect;
|
extern int autoconnect;
|
||||||
|
|
|
@ -711,7 +711,12 @@ static bool setup_myself(void) {
|
||||||
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
|
get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
|
||||||
strictsubnets |= 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(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
|
||||||
if(udp_rcvbuf <= 0) {
|
if(udp_rcvbuf <= 0) {
|
||||||
|
|
|
@ -45,6 +45,7 @@ int maxtimeout = 900;
|
||||||
int seconds_till_retry = 5;
|
int seconds_till_retry = 5;
|
||||||
int udp_rcvbuf = 0;
|
int udp_rcvbuf = 0;
|
||||||
int udp_sndbuf = 0;
|
int udp_sndbuf = 0;
|
||||||
|
int max_connection_burst = 100;
|
||||||
|
|
||||||
listen_socket_t listen_socket[MAXSOCKETS];
|
listen_socket_t listen_socket[MAXSOCKETS];
|
||||||
int listen_sockets;
|
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 = new_connection();
|
||||||
c->name = xstrdup("<unknown>");
|
c->name = xstrdup("<unknown>");
|
||||||
c->outcipher = myself->connection->outcipher;
|
c->outcipher = myself->connection->outcipher;
|
||||||
|
|
|
@ -1296,6 +1296,7 @@ const var_t variables[] = {
|
||||||
{"KeyExpire", VAR_SERVER},
|
{"KeyExpire", VAR_SERVER},
|
||||||
{"LocalDiscovery", VAR_SERVER},
|
{"LocalDiscovery", VAR_SERVER},
|
||||||
{"MACExpire", VAR_SERVER},
|
{"MACExpire", VAR_SERVER},
|
||||||
|
{"MaxConnectionBurst", VAR_SERVER},
|
||||||
{"MaxOutputBufferSize", VAR_SERVER},
|
{"MaxOutputBufferSize", VAR_SERVER},
|
||||||
{"MaxTimeout", VAR_SERVER},
|
{"MaxTimeout", VAR_SERVER},
|
||||||
{"Mode", VAR_SERVER | VAR_SAFE},
|
{"Mode", VAR_SERVER | VAR_SAFE},
|
||||||
|
|
Loading…
Reference in a new issue