From: Kirill Isakov Date: Fri, 27 May 2022 12:07:04 +0000 (+0600) Subject: Don't tarpit localhost connections X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=ce4d55b72fd4290d4710f10e755f6dd9ed039d88 Don't tarpit localhost connections --- diff --git a/src/net_socket.c b/src/net_socket.c index 5d72471b..92dcbedb 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -689,32 +689,12 @@ remove: list_delete(&outgoing_list, outgoing); } -/* - accept a new tcp connect and create a - new connection -*/ -void handle_new_meta_connection(void *data, int flags) { - (void)flags; - listen_socket_t *l = data; - connection_t *c; - sockaddr_t sa; - int fd; - socklen_t len = sizeof(sa); - - fd = accept(l->tcp.fd, &sa.sa, &len); - - if(fd < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); - return; - } - - sockaddrunmap(&sa); - +static bool check_tarpit(const sockaddr_t *sa, int fd) { // Check if we get many connections from the same host static sockaddr_t prev_sa; - if(!sockaddrcmp_noport(&sa, &prev_sa)) { + if(!sockaddrcmp_noport(sa, &prev_sa)) { static time_t samehost_burst; static time_t samehost_burst_time; @@ -729,7 +709,7 @@ void handle_new_meta_connection(void *data, int flags) { if(samehost_burst > max_connection_burst) { tarpit(fd); - return; + return true; } } @@ -752,6 +732,34 @@ void handle_new_meta_connection(void *data, int flags) { if(connection_burst >= max_connection_burst) { connection_burst = max_connection_burst; tarpit(fd); + return true; + } + + return false; +} + +/* + accept a new tcp connect and create a + new connection +*/ +void handle_new_meta_connection(void *data, int flags) { + (void)flags; + listen_socket_t *l = data; + connection_t *c; + sockaddr_t sa; + int fd; + socklen_t len = sizeof(sa); + + fd = accept(l->tcp.fd, &sa.sa, &len); + + if(fd < 0) { + logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); + return; + } + + sockaddrunmap(&sa); + + if(!is_local_connection(&sa) && check_tarpit(&sa, fd)) { return; } diff --git a/src/netutl.c b/src/netutl.c index 0c19f5bb..6654f977 100644 --- a/src/netutl.c +++ b/src/netutl.c @@ -301,6 +301,23 @@ void sockaddr_setport(sockaddr_t *sa, const char *port) { } } +bool is_local_connection(const sockaddr_t *sa) { + switch(sa->sa.sa_family) { + case AF_INET: + // 127.0.0.0/8 + return ntohl(sa->in.sin_addr.s_addr) >> 24 == 127; + + case AF_INET6: + return IN6_IS_ADDR_LOOPBACK(&sa->in6.sin6_addr); + + case AF_UNIX: + return true; + + default: + return false; + } +} + uint16_t get_bound_port(int sockfd) { sockaddr_t sa; socklen_t salen = sizeof(sa); diff --git a/src/netutl.h b/src/netutl.h index 32181229..e8de4bbe 100644 --- a/src/netutl.h +++ b/src/netutl.h @@ -38,5 +38,6 @@ extern void sockaddrfree(sockaddr_t *sa); extern void sockaddrcpy(sockaddr_t *dest, const sockaddr_t *src); extern void sockaddr_setport(sockaddr_t *sa, const char *port); extern uint16_t get_bound_port(int sockfd); +extern bool is_local_connection(const sockaddr_t *sa); #endif diff --git a/test/unit/test_netutl.c b/test/unit/test_netutl.c index a3486fcd..32bb6283 100644 --- a/test/unit/test_netutl.c +++ b/test/unit/test_netutl.c @@ -19,10 +19,60 @@ static void test_service_to_port_valid(void **state) { assert_int_equal(1234, service_to_port("1234")); } +static void test_is_local_connection_ipv4(void **state) { + (void)state; + + sockaddr_t sa; + + assert_true(inet_pton(AF_INET, "127.0.0.0", &sa.in.sin_addr)); + sa.sa.sa_family = AF_INET; + assert_true(is_local_connection(&sa)); + + assert_true(inet_pton(AF_INET, "127.42.13.5", &sa.in.sin_addr)); + sa.sa.sa_family = AF_INET; + assert_true(is_local_connection(&sa)); + + assert_true(inet_pton(AF_INET, "127.255.255.255", &sa.in.sin_addr)); + sa.sa.sa_family = AF_INET; + assert_true(is_local_connection(&sa)); + + assert_true(inet_pton(AF_INET, "128.0.0.1", &sa.in.sin_addr)); + sa.sa.sa_family = AF_INET; + assert_false(is_local_connection(&sa)); +} + +static void test_is_local_connection_ipv6(void **state) { + (void)state; + + sockaddr_t sa; + + assert_true(inet_pton(AF_INET6, "::1", &sa.in6.sin6_addr)); + sa.sa.sa_family = AF_INET6; + assert_true(is_local_connection(&sa)); + + assert_true(inet_pton(AF_INET6, "::1:1", &sa.in6.sin6_addr)); + sa.sa.sa_family = AF_INET6; + assert_false(is_local_connection(&sa)); + + assert_true(inet_pton(AF_INET6, "fe80::", &sa.in6.sin6_addr)); + sa.sa.sa_family = AF_INET6; + assert_false(is_local_connection(&sa)); +} + +static void test_is_local_connection_unix(void **state) { + (void)state; + + sockaddr_t sa = {.sa.sa_family = AF_UNIX}; + assert_true(is_local_connection(&sa)); +} + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_service_to_port_invalid), cmocka_unit_test(test_service_to_port_valid), + cmocka_unit_test(test_is_local_connection_ipv4), + cmocka_unit_test(test_is_local_connection_ipv6), + cmocka_unit_test(test_is_local_connection_unix), }; return cmocka_run_group_tests(tests, NULL, NULL); }