diff --git a/src/Makefile.am b/src/Makefile.am index 69d3185d..1ae8e6f8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ sup-config/file.c sup-config/file.h \ worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \ vasprintf.c vasprintf.h \ + proc-search.c proc-search.h \ str.c str.h gettime.h $(CCAN_SOURCES) $(HTTP_PARSER_SOURCES) \ $(PROTOBUF_SOURCES) diff --git a/src/main-auth.c b/src/main-auth.c index 1389dba7..9a4aad34 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "str.h" @@ -287,6 +288,9 @@ struct cookie_entry_st *old; return -1; } + /* add the links to proc hash */ + proc_table_add(s, proc); + return 0; } diff --git a/src/main-misc.c b/src/main-misc.c index 13cf0b50..fb68cd9c 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -294,6 +295,7 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k) } close_tun(s, proc); + proc_table_del(s, proc); talloc_free(proc); } diff --git a/src/main.c b/src/main.c index b08387ba..30e05826 100644 --- a/src/main.c +++ b/src/main.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -625,6 +626,7 @@ void clear_lists(main_server_st *s) tls_cache_deinit(&s->tls_db); ip_lease_deinit(&s->ip_leases); + proc_table_deinit(s); ctl_handler_deinit(s); cookie_db_deinit(&s->cookies); } @@ -664,7 +666,7 @@ static int forward_udp_to_owner(main_server_st* s, struct listener_st *listener) { int ret, e; struct sockaddr_storage cli_addr; -struct proc_st *ctmp = NULL, *proc_to_send = NULL; +struct proc_st *proc_to_send = NULL; socklen_t cli_addr_size; uint8_t buffer[1024]; char tbuf[64]; @@ -672,7 +674,7 @@ uint8_t *session_id = NULL; int session_id_size = 0; ssize_t buffer_size; int connected = 0; -int match_ip_only = 0, matching_ips; +int match_ip_only = 0; time_t now; /* first receive from the correct client and connect socket */ @@ -723,32 +725,16 @@ time_t now; /* search for the IP and the session ID in all procs */ now = time(0); - matching_ips = 0; - list_for_each(&s->proc_list.head, ctmp, list) { - if (match_ip_only == 0 && session_id_size == ctmp->dtls_session_id_size && - memcmp(session_id, ctmp->dtls_session_id, session_id_size) == 0) { - - proc_to_send = ctmp; - break; - } else if (match_ip_only != 0 && cli_addr_size == ctmp->remote_addr_len && - memcmp(SA_IN_P_GENERIC(&cli_addr, cli_addr_size), - SA_IN_P_GENERIC(&ctmp->remote_addr, ctmp->remote_addr_len), - SA_IN_SIZE(ctmp->remote_addr_len)) == 0) { - matching_ips++; - proc_to_send = ctmp; - } + if (match_ip_only == 0) { + proc_to_send = proc_search_sid(s, session_id, session_id_size); + } else { + proc_to_send = proc_search_ip(s, &cli_addr, cli_addr_size); } if (proc_to_send != 0) { UdpFdMsg msg = UDP_FD_MSG__INIT; - if (matching_ips > 1) { - mslog(s, proc_to_send, LOG_INFO, "cannot associate with a client; more than a single clients from %s", - human_addr((struct sockaddr*)&cli_addr, cli_addr_size, tbuf, sizeof(tbuf))); - goto fail; - } - if (now - proc_to_send->udp_fd_receive_time <= UDP_FD_RESEND_TIME) { mslog(s, proc_to_send, LOG_INFO, "received UDP connection too soon from %s", human_addr((struct sockaddr*)&cli_addr, cli_addr_size, tbuf, sizeof(tbuf))); @@ -921,6 +907,7 @@ int main(int argc, char** argv) tls_cache_init(s, &s->tls_db); cookie_db_init(s, &s->cookies); ip_lease_init(&s->ip_leases); + proc_table_init(s); sigemptyset(&blockset); sigemptyset(&emptyset); diff --git a/src/main.h b/src/main.h index 2a71ddcf..f0907a8a 100644 --- a/src/main.h +++ b/src/main.h @@ -179,6 +179,12 @@ struct cookie_entry_db_st { unsigned total; }; +struct proc_hash_db_st { + struct htable *db_ip; + struct htable *db_sid; + unsigned total; +}; + typedef struct main_server_st { struct cfg_st *config; @@ -193,6 +199,8 @@ typedef struct main_server_st { struct listen_list_st listen_list; struct proc_list_st proc_list; struct script_list_st script_list; + /* maps DTLS session IDs to proc entries */ + struct proc_hash_db_st proc_table; char socket_file[_POSIX_PATH_MAX]; char full_socket_file[_POSIX_PATH_MAX]; diff --git a/src/proc-search.c b/src/proc-search.c new file mode 100644 index 00000000..0c8dc3ee --- /dev/null +++ b/src/proc-search.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2014 Red Hat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include +#include +#include + +struct find_ip_st { + struct sockaddr_storage *sockaddr; + unsigned sockaddr_size; + unsigned found_ips; +}; + +struct find_sid_st { + const uint8_t *sid; + unsigned sid_size; +}; + + +static size_t rehash_ip(const void* _p, void* unused) +{ +const struct proc_st * proc = _p; + + return hash_any( + SA_IN_P_GENERIC(&proc->remote_addr, proc->remote_addr_len), + SA_IN_SIZE(proc->remote_addr_len), 0); +} + +static size_t rehash_sid(const void* _p, void* unused) +{ +const struct proc_st * proc = _p; + + return hash_any(proc->dtls_session_id, proc->dtls_session_id_size, 0); +} + +void proc_table_init(main_server_st *s) +{ + s->proc_table.db_ip = talloc(s, struct htable); + s->proc_table.db_sid = talloc(s, struct htable); + htable_init(s->proc_table.db_ip, rehash_ip, NULL); + htable_init(s->proc_table.db_sid, rehash_sid, NULL); + s->proc_table.total = 0; +} + +void proc_table_deinit(main_server_st *s) +{ + htable_clear(s->proc_table.db_ip); + htable_clear(s->proc_table.db_sid); + talloc_free(s->proc_table.db_sid); + talloc_free(s->proc_table.db_ip); +} + +void proc_table_add(main_server_st *s, struct proc_st *proc) +{ + size_t ip_hash = rehash_ip(proc, NULL); + + if (htable_add(s->proc_table.db_ip, ip_hash, proc) == 0) { + return; + } + + if (htable_add(s->proc_table.db_sid, rehash_sid(proc, NULL), proc) == 0) { + htable_del(s->proc_table.db_ip, ip_hash, proc); + return; + } + + s->proc_table.total++; + + return; +} + +void proc_table_del(main_server_st *s, struct proc_st *proc) +{ + htable_del(s->proc_table.db_ip, rehash_ip(proc, NULL), proc); + htable_del(s->proc_table.db_sid, rehash_sid(proc, NULL), proc); +} + +static bool local_ip_cmp(const void* _c1, void* _c2) +{ +const struct proc_st* c1 = _c1; +struct find_ip_st* c2 = _c2; + + if (c1->remote_addr_len != c2->sockaddr_size) + return 0; + + if (memcmp(SA_IN_P_GENERIC(&c1->remote_addr, c1->remote_addr_len), + SA_IN_P_GENERIC(c2->sockaddr, c2->sockaddr_size), + SA_IN_SIZE(c1->remote_addr_len)) == 0) { + c2->found_ips++; + return 1; + } + + return 0; +} + +struct proc_st *proc_search_ip(struct main_server_st *s, + struct sockaddr_storage *sockaddr, + unsigned sockaddr_size) +{ + struct proc_st *proc; + struct find_ip_st fip; + size_t h; + + fip.sockaddr = sockaddr; + fip.sockaddr_size = sockaddr_size; + fip.found_ips = 0; + + h = hash_any(SA_IN_P_GENERIC(sockaddr, sockaddr_size), + SA_IN_SIZE(sockaddr_size), 0); + proc = htable_get(s->proc_table.db_ip, h, local_ip_cmp, &fip); + + if (fip.found_ips > 1) + return NULL; + return proc; +} + +static bool sid_cmp(const void* _c1, void* _c2) +{ +const struct proc_st* c1 = _c1; +struct find_sid_st* c2 = _c2; + + if (c1->dtls_session_id_size != c2->sid_size) + return 0; + + if (memcmp(c1->dtls_session_id, + c2->sid, + c1->dtls_session_id_size) == 0) { + return 1; + } + + return 0; +} +struct proc_st *proc_search_sid(struct main_server_st *s, + const uint8_t *id, unsigned id_size) +{ + struct find_sid_st fsid; + + fsid.sid = id; + fsid.sid_size = id_size; + + return htable_get(s->proc_table.db_sid, hash_any(id, id_size, 0), sid_cmp, &fsid); +} + diff --git a/src/proc-search.h b/src/proc-search.h new file mode 100644 index 00000000..c8dc8ce9 --- /dev/null +++ b/src/proc-search.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of ocserv. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + */ +#ifndef PROC_SEARCH_H +# define PROC_SEARCH_H + +#include +#include +#include +#include +#include + +struct proc_st *proc_search_ip(struct main_server_st *s, + struct sockaddr_storage *sockaddr, + unsigned sockaddr_size); +struct proc_st *proc_search_sid(struct main_server_st *s, const uint8_t *id, unsigned id_size); + +void proc_table_init(main_server_st *s); +void proc_table_deinit(main_server_st *s); +void proc_table_add(main_server_st *s, struct proc_st *proc); +void proc_table_del(main_server_st *s, struct proc_st *proc); + +#endif