use hash tables to locate proc entries

That would avoid a walk on all connected clients, when a
new UDP session starts.
This commit is contained in:
Nikos Mavrogiannopoulos
2014-10-27 14:52:59 +01:00
parent 81107b80f8
commit 53005a2cfd
7 changed files with 224 additions and 22 deletions

View File

@@ -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)

View File

@@ -35,6 +35,7 @@
#include <tlslib.h>
#include <script-list.h>
#include <ip-lease.h>
#include <proc-search.h>
#include <main-sup-config.h>
#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;
}

View File

@@ -43,6 +43,7 @@
#include <sec-mod.h>
#include <route-add.h>
#include <ip-lease.h>
#include <proc-search.h>
#include <ipc.pb-c.h>
#include <script-list.h>
#include <main-sup-config.h>
@@ -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);
}

View File

@@ -56,6 +56,7 @@
#include <route-add.h>
#include <worker.h>
#include <cookies.h>
#include <proc-search.h>
#include <tun.h>
#include <grp.h>
#include <ip-lease.h>
@@ -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);

View File

@@ -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];

160
src/proc-search.c Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <proc-search.h>
#include <main.h>
#include <common.h>
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);
}

40
src/proc-search.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>
*/
#ifndef PROC_SEARCH_H
# define PROC_SEARCH_H
#include <vpn.h>
#include <string.h>
#include <sys/socket.h>
#include <ccan/hash/hash.h>
#include <main.h>
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