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:
William Pitcock 2015-12-12 05:20:51 -06:00
parent 94356462c0
commit b5b4a0e79b
7 changed files with 101 additions and 56 deletions

View file

@ -240,6 +240,7 @@ struct LocalUser
time_t next_away; /* Don't allow next away before... */
time_t last;
uint32_t connid;
/* clients allowed to talk through +g */
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 *z_ctl; /* second ctl for ssl+zlib */
uint32_t zconnid;
uint32_t localflags;
struct ZipStats *zipstats; /* zipstats */
uint16_t cork_count; /* used for corking/uncorking connections */

View file

@ -45,8 +45,8 @@ extern struct Dictionary *nd_dict;
#define U_MAX_BITS 17
#define U_MAX 131072 /* 2^17 */
/* Client fd hash table size, used in hash.c */
#define CLI_FD_MAX 4096
/* Client connid hash table size, used in hash.c */
#define CLI_CONNID_MAX 4096
/* Channel hash table size, hash.c/s_debug.c */
#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 void clear_resv_hash(void);
void add_to_cli_fd_hash(struct Client *client_p);
void del_from_cli_fd_hash(struct Client *client_p);
struct Client *find_cli_fd_hash(int fd);
void add_to_cli_connid_hash(struct Client *client_p);
void del_from_cli_connid_hash(struct Client *client_p);
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 *);

View file

@ -79,6 +79,7 @@ static rb_bh *pclient_heap = NULL;
static rb_bh *user_heap = NULL;
static rb_bh *away_heap = NULL;
static char current_uid[IDLEN];
static int32_t current_connid = 0;
struct Dictionary *nd_dict = NULL;
@ -162,6 +163,17 @@ make_client(struct Client *from)
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);
/* as good a place as any... */
@ -220,9 +232,9 @@ free_local_client(struct Client *client_p)
client_p->localClient->listener = 0;
}
del_from_cli_connid_hash(client_p);
if(client_p->localClient->F != NULL)
{
del_from_cli_fd_hash(client_p);
rb_close(client_p->localClient->F);
}
@ -1911,7 +1923,7 @@ close_connection(struct Client *client_p)
if(!IsIOError(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);
client_p->localClient->F = NULL;
}

View file

@ -40,9 +40,13 @@
#include "s_newconf.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 *channelTable;
@ -666,34 +670,60 @@ clear_resv_hash(void)
}
void
add_to_cli_fd_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)
add_to_zconnid_hash(struct Client *client_p)
{
unsigned int hashv;
hashv = hash_cli_fd(rb_get_fd(client_p->localClient->F));
rb_dlinkFindDestroy(client_p, &clientbyfdTable[hashv]);
hashv = hash_zconnid(client_p->localClient->zconnid);
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 *
find_cli_fd_hash(int fd)
find_cli_connid_hash(int connid)
{
struct Client *target_p;
rb_dlink_node *ptr;
unsigned int hashv;
hashv = hash_cli_fd(fd);
RB_DLINK_FOREACH(ptr, clientbyfdTable[hashv].head)
hashv = hash_cli_connid(connid);
RB_DLINK_FOREACH(ptr, clientbyconnidTable[hashv].head)
{
target_p = ptr->data;
if(rb_get_fd(target_p->localClient->F) == fd)
if(target_p->localClient->connid == connid)
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
@ -770,4 +800,6 @@ hash_stats(struct Client *source_p)
count_hash(source_p, idTable, U_MAX, "ID");
sendto_one_numeric(source_p, RPL_STATSDEBUG, "B :--");
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");
}

View file

@ -464,7 +464,7 @@ close_listeners()
* any client list yet.
*/
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;
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);
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->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));
new_client->localClient->F = F;
add_to_cli_fd_hash(new_client);
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;
@ -577,21 +591,6 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
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
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;
}
if(listener->ssl)
accept_ssld(F, addr, (struct sockaddr *)&lip, listener);
else
add_connection(listener, F, addr, (struct sockaddr *)&lip, NULL);
add_connection(listener, F, addr, (struct sockaddr *)&lip);
}

View file

@ -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->sockhost, server_p->host, sizeof(client_p->sockhost));
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
@ -1263,9 +1263,9 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data)
return;
}
del_from_cli_fd_hash(client_p);
del_from_cli_connid_hash(client_p);
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]));
SetSSL(client_p);

View file

@ -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]);
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)
return;
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))
return;
client_p = find_cli_fd_hash(fd);
client_p = find_cli_connid_hash(fd);
if(client_p != NULL && client_p->localClient != NULL)
{
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]);
len = buf_to_uint32(&ctl_buf->buf[5]);
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)
return;
rb_free(client_p->certfp);
@ -821,11 +821,11 @@ start_zlib_session(void *data)
F[0] = server->localClient->F;
F[1] = xF1;
del_from_cli_fd_hash(server);
del_from_cli_connid_hash(server);
server->localClient->F = xF2;
/* need to redo as what we did before isn't valid now */
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->cli_count++;