Configurable ReplayWindow size, zero disables

This commit is contained in:
Brandon L Black 2010-11-13 12:05:50 -06:00 committed by Guus Sliepen
parent 8dfe1b374e
commit 23acc19bc0
7 changed files with 43 additions and 18 deletions

View file

@ -344,6 +344,16 @@ specified in the configuration file.
When this option is used the priority of the tincd process will be adjusted.
Increasing the priority may help to reduce latency and packet loss on the VPN.
.It Va ReplayWindow Li = Ar bytes Pq 16
This is the size of the replay tracking window for each remote node, in bytes.
The window is a bitfield which tracks 1 packet per bit, so for example
the default setting of 16 will track up to 128 packets in the window. In high
bandwidth scenarios, setting this to a higher value can reduce packet loss from
the interaction of replay tracking with underlying real packet loss and/or
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.
.It Va StrictSubnets Li = yes | no Po no Pc Bq experimental
When this option is enabled tinc will only use Subnet statements which are
present in the host config files in the local

View file

@ -106,6 +106,7 @@ extern list_t *outgoing_list;
extern int maxoutbufsize;
extern int seconds_till_retry;
extern int addressfamily;
extern unsigned replaywin;
extern listen_socket_t listen_socket[MAXSOCKETS];
extern int listen_sockets;

View file

@ -60,6 +60,8 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
static void send_udppacket(node_t *, vpn_packet_t *);
unsigned replaywin = 16;
#define MAX_SEQNO 1073741824
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
@ -293,25 +295,27 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
inpkt->len -= sizeof(inpkt->seqno);
inpkt->seqno = ntohl(inpkt->seqno);
if(inpkt->seqno != n->received_seqno + 1) {
if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) {
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, sizeof(n->late));
} else if (inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= sizeof(n->late) * 8 && inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8) || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) {
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
return;
if(replaywin) {
if(inpkt->seqno != n->received_seqno + 1) {
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
} else if (inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
return;
}
} else {
for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
} else {
for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
n->late[(i / 8) % sizeof(n->late)] |= 1 << i % 8;
}
}
n->late[(inpkt->seqno / 8) % sizeof(n->late)] &= ~(1 << inpkt->seqno % 8);
n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
}
if(inpkt->seqno > n->received_seqno)
n->received_seqno = inpkt->seqno;

View file

@ -276,6 +276,7 @@ bool setup_myself(void) {
struct addrinfo *ai, *aip, hint = {0};
bool choice;
int i, err;
int replaywin_int;
myself = new_node();
myself->connection = new_connection();
@ -419,6 +420,14 @@ bool setup_myself(void) {
}
}
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
if(replaywin_int < 0) {
logger(LOG_ERR, "ReplayWindow cannot be negative!");
return false;
}
replaywin = (unsigned)replaywin_int;
}
if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
if(!strcasecmp(afname, "IPv4"))
addressfamily = AF_INET;

View file

@ -54,6 +54,7 @@ void exit_nodes(void) {
node_t *new_node(void) {
node_t *n = xmalloc_and_zero(sizeof(*n));
if(replaywin) n->late = xmalloc_and_zero(replaywin);
n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree();
EVP_CIPHER_CTX_init(&n->inctx);

View file

@ -77,7 +77,7 @@ typedef struct node_t {
uint32_t sent_seqno; /* Sequence number last sent to this node */
uint32_t received_seqno; /* Sequence number last received from this node */
unsigned char late[16]; /* Bitfield marking late packets */
unsigned char* late; /* Bitfield marking late packets */
length_t mtu; /* Maximum size of packets to send to this node */
length_t minmtu; /* Probed minimum MTU */

View file

@ -163,7 +163,7 @@ bool send_ans_key(node_t *to) {
// Reset sequence number and late packet window
mykeyused = true;
to->received_seqno = 0;
memset(to->late, 0, sizeof(to->late));
if(replaywin) memset(to->late, 0, replaywin);
// Convert to hexadecimal and send
char key[2 * to->inkeylength + 1];