--- a/src/connection.h +++ b/src/connection.h @@ -42,7 +42,8 @@ unsigned int decryptin:1; /* 1 if we have to decrypt incoming traffic */ unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */ unsigned int proxy_passed:1; /* 1 if we are connecting via a proxy and we have finished talking with it */ - unsigned int unused:22; + unsigned int tarpit:1; /* 1 if the connection should be added to the tarpit */ + unsigned int unused:21; } connection_status_t; #include "edge.h" --- a/src/net.c +++ b/src/net.c @@ -158,6 +158,22 @@ return max; } +/* Put a misbehaving connection in the tarpit */ +void tarpit(int fd) { + static int pits[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + static int next_pit = 0; + + if(pits[next_pit] != -1) { + closesocket(pits[next_pit]); + } + + pits[next_pit++] = fd; + + if(next_pit >= sizeof pits / sizeof pits[0]) { + next_pit = 0; + } +} + /* Terminate a connection: - Close the socket @@ -178,8 +194,13 @@ if(c->node) c->node->connection = NULL; - if(c->socket) - closesocket(c->socket); + if(c->socket) { + if(c->status.tarpit) { + tarpit(c->socket); + } else { + closesocket(c->socket); + } + } if(c->edge) { if(!c->node) { @@ -266,6 +287,7 @@ closesocket(c->socket); do_outgoing_connection(c); } else { + c->status.tarpit = true; terminate_connection(c, false); } } @@ -345,6 +367,7 @@ if(FD_ISSET(c->socket, readset)) { if(!receive_meta(c)) { + c->status.tarpit = true; terminate_connection(c, c->status.active); continue; } --- a/src/net.h +++ b/src/net.h @@ -150,6 +150,7 @@ extern bool read_rsa_public_key(struct connection_t *); extern void send_mtu_probe(struct node_t *); extern void load_all_subnets(void); +extern void tarpit(int fd); #ifndef HAVE_MINGW #define closesocket(s) close(s) --- a/src/net_socket.c +++ b/src/net_socket.c @@ -552,6 +552,9 @@ new connection */ bool handle_new_meta_connection(int sock) { + static const int max_accept_burst = 10; + static int last_accept_burst; + static int last_accept_time; connection_t *c; sockaddr_t sa; int fd; @@ -564,6 +567,22 @@ return false; } + if(last_accept_time == now) { + last_accept_burst++; + + if(last_accept_burst >= max_accept_burst) { + if(last_accept_burst == max_accept_burst) { + ifdebug(CONNECTIONS) logger(LOG_WARNING, "Throttling incoming connections"); + } + + tarpit(fd); + return false; + } + } else { + last_accept_burst = 0; + last_accept_time = now; + } + sockaddrunmap(&sa); c = new_connection(); @@ -585,7 +604,6 @@ connection_add(c); c->allow_request = ID; - send_id(c); return true; } --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -59,7 +59,7 @@ /* Check if identity is a valid name */ - if(!check_id(name)) { + if(!check_id(name) || !strcmp(name, myself->name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name, c->hostname, "invalid name"); return false; @@ -91,6 +91,11 @@ if(!c->config_tree) init_configuration(&c->config_tree); c->allow_request = ACK; + + if(!c->outgoing) { + send_id(c); + } + return send_ack(c); } @@ -110,6 +115,10 @@ c->allow_request = METAKEY; + if(!c->outgoing) { + send_id(c); + } + return send_metakey(c); } @@ -292,7 +301,8 @@ c->inbudget = byte_budget(c->incipher); c->status.decryptin = true; } else { - c->incipher = NULL; + logger(LOG_ERR, "%s (%s) uses null cipher!", c->name, c->hostname); + return false; } c->inmaclength = maclength; @@ -310,7 +320,8 @@ return false; } } else { - c->indigest = NULL; + logger(LOG_ERR, "%s (%s) uses null digest!", c->name, c->hostname); + return false; } c->incompression = compression; @@ -384,7 +395,11 @@ /* Rest is done by send_chal_reply() */ - return send_chal_reply(c); + if(c->outgoing) { + return send_chal_reply(c); + } else { + return true; + } } bool send_chal_reply(connection_t *c) { @@ -482,6 +497,10 @@ c->allow_request = ACK; + if(!c->outgoing) { + send_chal_reply(c); + } + return send_ack(c); } --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -70,7 +70,7 @@ /* Check if names are valid */ - if(!check_id(from_name) || !check_id(to_name)) { + if(!check_id(from_name) || !check_id(to_name) || !strcmp(from_name, to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "invalid name"); return false; @@ -192,7 +192,7 @@ /* Check if names are valid */ - if(!check_id(from_name) || !check_id(to_name)) { + if(!check_id(from_name) || !check_id(to_name) || !strcmp(from_name, to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, c->hostname, "invalid name"); return false; --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -274,6 +274,11 @@ return true; } } else { + if(from->outkeylength != 1) { + logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname); + return true; + } + from->outcipher = NULL; }