client: use sequential connection ids for ssld connections in ssld RPC, instead of the file descriptor
this avoids race conditions when a file descriptor is reused and an ssld worker has not acked that the previous connection was closed, which results in the new client being kicked.
This commit is contained in:
parent
94356462c0
commit
b5b4a0e79b
7 changed files with 101 additions and 56 deletions
|
@ -240,6 +240,7 @@ struct LocalUser
|
||||||
|
|
||||||
time_t next_away; /* Don't allow next away before... */
|
time_t next_away; /* Don't allow next away before... */
|
||||||
time_t last;
|
time_t last;
|
||||||
|
uint32_t connid;
|
||||||
|
|
||||||
/* clients allowed to talk through +g */
|
/* clients allowed to talk through +g */
|
||||||
rb_dlink_list allow_list;
|
rb_dlink_list allow_list;
|
||||||
|
@ -278,6 +279,7 @@ struct LocalUser
|
||||||
|
|
||||||
struct _ssl_ctl *ssl_ctl; /* which ssl daemon we're associate with */
|
struct _ssl_ctl *ssl_ctl; /* which ssl daemon we're associate with */
|
||||||
struct _ssl_ctl *z_ctl; /* second ctl for ssl+zlib */
|
struct _ssl_ctl *z_ctl; /* second ctl for ssl+zlib */
|
||||||
|
uint32_t zconnid;
|
||||||
uint32_t localflags;
|
uint32_t localflags;
|
||||||
struct ZipStats *zipstats; /* zipstats */
|
struct ZipStats *zipstats; /* zipstats */
|
||||||
uint16_t cork_count; /* used for corking/uncorking connections */
|
uint16_t cork_count; /* used for corking/uncorking connections */
|
||||||
|
|
|
@ -45,8 +45,8 @@ extern struct Dictionary *nd_dict;
|
||||||
#define U_MAX_BITS 17
|
#define U_MAX_BITS 17
|
||||||
#define U_MAX 131072 /* 2^17 */
|
#define U_MAX 131072 /* 2^17 */
|
||||||
|
|
||||||
/* Client fd hash table size, used in hash.c */
|
/* Client connid hash table size, used in hash.c */
|
||||||
#define CLI_FD_MAX 4096
|
#define CLI_CONNID_MAX 4096
|
||||||
|
|
||||||
/* Channel hash table size, hash.c/s_debug.c */
|
/* Channel hash table size, hash.c/s_debug.c */
|
||||||
#define CH_MAX_BITS 16
|
#define CH_MAX_BITS 16
|
||||||
|
@ -101,9 +101,12 @@ extern void del_from_resv_hash(const char *name, struct ConfItem *aconf);
|
||||||
extern struct ConfItem *hash_find_resv(const char *name);
|
extern struct ConfItem *hash_find_resv(const char *name);
|
||||||
extern void clear_resv_hash(void);
|
extern void clear_resv_hash(void);
|
||||||
|
|
||||||
void add_to_cli_fd_hash(struct Client *client_p);
|
void add_to_cli_connid_hash(struct Client *client_p);
|
||||||
void del_from_cli_fd_hash(struct Client *client_p);
|
void del_from_cli_connid_hash(struct Client *client_p);
|
||||||
struct Client *find_cli_fd_hash(int fd);
|
struct Client *find_cli_connid_hash(int connid);
|
||||||
|
|
||||||
|
void add_to_zconnid_hash(struct Client *client_p);
|
||||||
|
void del_from_zconnid_hash(struct Client *client_p);
|
||||||
|
|
||||||
extern void hash_stats(struct Client *);
|
extern void hash_stats(struct Client *);
|
||||||
|
|
||||||
|
|
16
src/client.c
16
src/client.c
|
@ -79,6 +79,7 @@ static rb_bh *pclient_heap = NULL;
|
||||||
static rb_bh *user_heap = NULL;
|
static rb_bh *user_heap = NULL;
|
||||||
static rb_bh *away_heap = NULL;
|
static rb_bh *away_heap = NULL;
|
||||||
static char current_uid[IDLEN];
|
static char current_uid[IDLEN];
|
||||||
|
static int32_t current_connid = 0;
|
||||||
|
|
||||||
struct Dictionary *nd_dict = NULL;
|
struct Dictionary *nd_dict = NULL;
|
||||||
|
|
||||||
|
@ -162,6 +163,17 @@ make_client(struct Client *from)
|
||||||
|
|
||||||
client_p->localClient->F = NULL;
|
client_p->localClient->F = NULL;
|
||||||
|
|
||||||
|
if(current_connid+1 == 0)
|
||||||
|
current_connid++;
|
||||||
|
|
||||||
|
client_p->localClient->connid = ++current_connid;
|
||||||
|
|
||||||
|
if(current_connid+1 == 0)
|
||||||
|
current_connid++;
|
||||||
|
|
||||||
|
client_p->localClient->zconnid = ++current_connid;
|
||||||
|
add_to_cli_connid_hash(client_p);
|
||||||
|
|
||||||
client_p->preClient = rb_bh_alloc(pclient_heap);
|
client_p->preClient = rb_bh_alloc(pclient_heap);
|
||||||
|
|
||||||
/* as good a place as any... */
|
/* as good a place as any... */
|
||||||
|
@ -220,9 +232,9 @@ free_local_client(struct Client *client_p)
|
||||||
client_p->localClient->listener = 0;
|
client_p->localClient->listener = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
del_from_cli_connid_hash(client_p);
|
||||||
if(client_p->localClient->F != NULL)
|
if(client_p->localClient->F != NULL)
|
||||||
{
|
{
|
||||||
del_from_cli_fd_hash(client_p);
|
|
||||||
rb_close(client_p->localClient->F);
|
rb_close(client_p->localClient->F);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1911,7 +1923,7 @@ close_connection(struct Client *client_p)
|
||||||
if(!IsIOError(client_p))
|
if(!IsIOError(client_p))
|
||||||
send_queued(client_p);
|
send_queued(client_p);
|
||||||
|
|
||||||
del_from_cli_fd_hash(client_p);
|
del_from_cli_connid_hash(client_p);
|
||||||
rb_close(client_p->localClient->F);
|
rb_close(client_p->localClient->F);
|
||||||
client_p->localClient->F = NULL;
|
client_p->localClient->F = NULL;
|
||||||
}
|
}
|
||||||
|
|
66
src/hash.c
66
src/hash.c
|
@ -40,9 +40,13 @@
|
||||||
#include "s_newconf.h"
|
#include "s_newconf.h"
|
||||||
#include "s_assert.h"
|
#include "s_assert.h"
|
||||||
|
|
||||||
#define hash_cli_fd(x) (x % CLI_FD_MAX)
|
#define ZCONNID_MAX 64 /* i doubt we'll have this many ziplinks ;) */
|
||||||
|
|
||||||
static rb_dlink_list clientbyfdTable[U_MAX];
|
#define hash_cli_connid(x) (x % CLI_CONNID_MAX)
|
||||||
|
#define hash_zconnid(x) (x % ZCONNID_MAX)
|
||||||
|
|
||||||
|
static rb_dlink_list clientbyconnidTable[CLI_CONNID_MAX];
|
||||||
|
static rb_dlink_list clientbyzconnidTable[ZCONNID_MAX];
|
||||||
|
|
||||||
rb_dlink_list *clientTable;
|
rb_dlink_list *clientTable;
|
||||||
rb_dlink_list *channelTable;
|
rb_dlink_list *channelTable;
|
||||||
|
@ -666,34 +670,60 @@ clear_resv_hash(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
add_to_cli_fd_hash(struct Client *client_p)
|
add_to_zconnid_hash(struct Client *client_p)
|
||||||
{
|
|
||||||
rb_dlinkAddAlloc(client_p, &clientbyfdTable[hash_cli_fd(rb_get_fd(client_p->localClient->F))]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
del_from_cli_fd_hash(struct Client *client_p)
|
|
||||||
{
|
{
|
||||||
unsigned int hashv;
|
unsigned int hashv;
|
||||||
hashv = hash_cli_fd(rb_get_fd(client_p->localClient->F));
|
hashv = hash_zconnid(client_p->localClient->zconnid);
|
||||||
rb_dlinkFindDestroy(client_p, &clientbyfdTable[hashv]);
|
rb_dlinkAddAlloc(client_p, &clientbyzconnidTable[hashv]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
del_from_zconnid_hash(struct Client *client_p)
|
||||||
|
{
|
||||||
|
unsigned int hashv;
|
||||||
|
hashv = hash_zconnid(client_p->localClient->zconnid);
|
||||||
|
rb_dlinkFindDestroy(client_p, &clientbyzconnidTable[hashv]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
add_to_cli_connid_hash(struct Client *client_p)
|
||||||
|
{
|
||||||
|
unsigned int hashv;
|
||||||
|
hashv = hash_cli_connid(client_p->localClient->connid);
|
||||||
|
rb_dlinkAddAlloc(client_p, &clientbyconnidTable[hashv]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
del_from_cli_connid_hash(struct Client *client_p)
|
||||||
|
{
|
||||||
|
unsigned int hashv;
|
||||||
|
hashv = hash_cli_connid(client_p->localClient->connid);
|
||||||
|
rb_dlinkFindDestroy(client_p, &clientbyconnidTable[hashv]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Client *
|
struct Client *
|
||||||
find_cli_fd_hash(int fd)
|
find_cli_connid_hash(int connid)
|
||||||
{
|
{
|
||||||
struct Client *target_p;
|
struct Client *target_p;
|
||||||
rb_dlink_node *ptr;
|
rb_dlink_node *ptr;
|
||||||
unsigned int hashv;
|
unsigned int hashv;
|
||||||
hashv = hash_cli_fd(fd);
|
hashv = hash_cli_connid(connid);
|
||||||
RB_DLINK_FOREACH(ptr, clientbyfdTable[hashv].head)
|
RB_DLINK_FOREACH(ptr, clientbyconnidTable[hashv].head)
|
||||||
{
|
{
|
||||||
target_p = ptr->data;
|
target_p = ptr->data;
|
||||||
if(rb_get_fd(target_p->localClient->F) == fd)
|
if(target_p->localClient->connid == connid)
|
||||||
return target_p;
|
return target_p;
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
hashv = hash_zconnid(connid);
|
||||||
|
RB_DLINK_FOREACH(ptr, clientbyzconnidTable[hashv].head)
|
||||||
|
{
|
||||||
|
target_p = ptr->data;
|
||||||
|
if(target_p->localClient->zconnid == connid)
|
||||||
|
return target_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -770,4 +800,6 @@ hash_stats(struct Client *source_p)
|
||||||
count_hash(source_p, idTable, U_MAX, "ID");
|
count_hash(source_p, idTable, U_MAX, "ID");
|
||||||
sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
|
sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
|
||||||
count_hash(source_p, hostTable, HOST_MAX, "Hostname");
|
count_hash(source_p, hostTable, HOST_MAX, "Hostname");
|
||||||
|
sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
|
||||||
|
count_hash(source_p, clientbyconnidTable, CLI_CONNID_MAX, "Client by connection id");
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,7 +464,7 @@ close_listeners()
|
||||||
* any client list yet.
|
* any client list yet.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, struct sockaddr *lai, void *ssl_ctl)
|
add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, struct sockaddr *lai)
|
||||||
{
|
{
|
||||||
struct Client *new_client;
|
struct Client *new_client;
|
||||||
s_assert(NULL != listener);
|
s_assert(NULL != listener);
|
||||||
|
@ -475,6 +475,24 @@ add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, str
|
||||||
*/
|
*/
|
||||||
new_client = make_client(NULL);
|
new_client = make_client(NULL);
|
||||||
|
|
||||||
|
if (listener->ssl)
|
||||||
|
{
|
||||||
|
rb_fde_t *xF[2];
|
||||||
|
if(rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &xF[0], &xF[1], "Incoming ssld Connection") == -1)
|
||||||
|
{
|
||||||
|
free_client(new_client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new_client->localClient->ssl_ctl = start_ssld_accept(F, xF[1], new_client->localClient->connid); /* this will close F for us */
|
||||||
|
if(new_client->localClient->ssl_ctl == NULL)
|
||||||
|
{
|
||||||
|
free_client(new_client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
F = xF[0];
|
||||||
|
SetSSL(new_client);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&new_client->localClient->ip, sai, sizeof(struct rb_sockaddr_storage));
|
memcpy(&new_client->localClient->ip, sai, sizeof(struct rb_sockaddr_storage));
|
||||||
memcpy(&new_client->preClient->lip, lai, sizeof(struct rb_sockaddr_storage));
|
memcpy(&new_client->preClient->lip, lai, sizeof(struct rb_sockaddr_storage));
|
||||||
|
|
||||||
|
@ -489,11 +507,7 @@ add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, str
|
||||||
rb_strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
|
rb_strlcpy(new_client->host, new_client->sockhost, sizeof(new_client->host));
|
||||||
|
|
||||||
new_client->localClient->F = F;
|
new_client->localClient->F = F;
|
||||||
add_to_cli_fd_hash(new_client);
|
|
||||||
new_client->localClient->listener = listener;
|
new_client->localClient->listener = listener;
|
||||||
new_client->localClient->ssl_ctl = ssl_ctl;
|
|
||||||
if(ssl_ctl != NULL || rb_fd_ssl(F))
|
|
||||||
SetSSL(new_client);
|
|
||||||
|
|
||||||
++listener->ref_count;
|
++listener->ref_count;
|
||||||
|
|
||||||
|
@ -577,21 +591,6 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
accept_ssld(rb_fde_t *F, struct sockaddr *addr, struct sockaddr *laddr, struct Listener *listener)
|
|
||||||
{
|
|
||||||
ssl_ctl_t *ctl;
|
|
||||||
rb_fde_t *xF[2];
|
|
||||||
if(rb_socketpair(AF_UNIX, SOCK_STREAM, 0, &xF[0], &xF[1], "Incoming ssld Connection") == -1)
|
|
||||||
{
|
|
||||||
ilog_error("creating SSL/TLS socket pairs");
|
|
||||||
rb_close(F);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctl = start_ssld_accept(F, xF[1], rb_get_fd(xF[0])); /* this will close F for us */
|
|
||||||
add_connection(listener, xF[0], addr, laddr, ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
|
accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
|
||||||
{
|
{
|
||||||
|
@ -608,8 +607,5 @@ accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t add
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(listener->ssl)
|
add_connection(listener, F, addr, (struct sockaddr *)&lip);
|
||||||
accept_ssld(F, addr, (struct sockaddr *)&lip, listener);
|
|
||||||
else
|
|
||||||
add_connection(listener, F, addr, (struct sockaddr *)&lip, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1164,7 +1164,7 @@ serv_connect(struct server_conf *server_p, struct Client *by)
|
||||||
rb_strlcpy(client_p->host, server_p->host, sizeof(client_p->host));
|
rb_strlcpy(client_p->host, server_p->host, sizeof(client_p->host));
|
||||||
rb_strlcpy(client_p->sockhost, server_p->host, sizeof(client_p->sockhost));
|
rb_strlcpy(client_p->sockhost, server_p->host, sizeof(client_p->sockhost));
|
||||||
client_p->localClient->F = F;
|
client_p->localClient->F = F;
|
||||||
add_to_cli_fd_hash(client_p);
|
add_to_cli_connid_hash(client_p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the initial server evilness, ripped straight from
|
* Set up the initial server evilness, ripped straight from
|
||||||
|
@ -1263,9 +1263,9 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
del_from_cli_fd_hash(client_p);
|
del_from_cli_connid_hash(client_p);
|
||||||
client_p->localClient->F = xF[0];
|
client_p->localClient->F = xF[0];
|
||||||
add_to_cli_fd_hash(client_p);
|
add_to_cli_connid_hash(client_p);
|
||||||
|
|
||||||
client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], rb_get_fd(xF[0]));
|
client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], rb_get_fd(xF[0]));
|
||||||
SetSSL(client_p);
|
SetSSL(client_p);
|
||||||
|
|
|
@ -365,7 +365,7 @@ ssl_process_dead_fd(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf)
|
||||||
|
|
||||||
fd = buf_to_uint32(&ctl_buf->buf[1]);
|
fd = buf_to_uint32(&ctl_buf->buf[1]);
|
||||||
rb_strlcpy(reason, &ctl_buf->buf[5], sizeof(reason));
|
rb_strlcpy(reason, &ctl_buf->buf[5], sizeof(reason));
|
||||||
client_p = find_cli_fd_hash(fd);
|
client_p = find_cli_connid_hash(fd);
|
||||||
if(client_p == NULL)
|
if(client_p == NULL)
|
||||||
return;
|
return;
|
||||||
if(IsAnyServer(client_p) || IsRegistered(client_p))
|
if(IsAnyServer(client_p) || IsRegistered(client_p))
|
||||||
|
@ -401,7 +401,7 @@ ssl_process_cipher_string(ssl_ctl_t *ctl, ssl_ctl_buf_t *ctl_buf)
|
||||||
if(EmptyString(cstring))
|
if(EmptyString(cstring))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
client_p = find_cli_fd_hash(fd);
|
client_p = find_cli_connid_hash(fd);
|
||||||
if(client_p != NULL && client_p->localClient != NULL)
|
if(client_p != NULL && client_p->localClient != NULL)
|
||||||
{
|
{
|
||||||
rb_free(client_p->localClient->cipher_string);
|
rb_free(client_p->localClient->cipher_string);
|
||||||
|
@ -426,7 +426,7 @@ ssl_process_certfp(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf)
|
||||||
fd = buf_to_uint32(&ctl_buf->buf[1]);
|
fd = buf_to_uint32(&ctl_buf->buf[1]);
|
||||||
len = buf_to_uint32(&ctl_buf->buf[5]);
|
len = buf_to_uint32(&ctl_buf->buf[5]);
|
||||||
certfp = (uint8_t *)&ctl_buf->buf[9];
|
certfp = (uint8_t *)&ctl_buf->buf[9];
|
||||||
client_p = find_cli_fd_hash(fd);
|
client_p = find_cli_connid_hash(fd);
|
||||||
if(client_p == NULL)
|
if(client_p == NULL)
|
||||||
return;
|
return;
|
||||||
rb_free(client_p->certfp);
|
rb_free(client_p->certfp);
|
||||||
|
@ -821,11 +821,11 @@ start_zlib_session(void *data)
|
||||||
|
|
||||||
F[0] = server->localClient->F;
|
F[0] = server->localClient->F;
|
||||||
F[1] = xF1;
|
F[1] = xF1;
|
||||||
del_from_cli_fd_hash(server);
|
del_from_cli_connid_hash(server);
|
||||||
server->localClient->F = xF2;
|
server->localClient->F = xF2;
|
||||||
/* need to redo as what we did before isn't valid now */
|
/* need to redo as what we did before isn't valid now */
|
||||||
uint32_to_buf(&buf[1], rb_get_fd(server->localClient->F));
|
uint32_to_buf(&buf[1], rb_get_fd(server->localClient->F));
|
||||||
add_to_cli_fd_hash(server);
|
add_to_cli_connid_hash(server);
|
||||||
|
|
||||||
server->localClient->z_ctl = which_ssld();
|
server->localClient->z_ctl = which_ssld();
|
||||||
server->localClient->z_ctl->cli_count++;
|
server->localClient->z_ctl->cli_count++;
|
||||||
|
|
Loading…
Reference in a new issue