From 4fbb736202a4f74ead96bf181712d4ae2e16c7ef Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Sun, 24 Apr 2016 11:48:35 +0100 Subject: [PATCH] ssld: add a callback when the connection is opened This allows us to wait until we have the fingerprint information before continuing with a server connect process. --- include/client.h | 2 ++ ircd/s_serv.c | 5 ++-- ircd/sslproc.c | 58 +++++++++++++++++++++++++++++++++++++++----- modules/m_starttls.c | 2 ++ ssld/ssld.c | 12 +++++++++ 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/include/client.h b/include/client.h index cfc55cee..a23f444b 100644 --- a/include/client.h +++ b/include/client.h @@ -275,6 +275,8 @@ struct LocalUser struct _ssl_ctl *ssl_ctl; /* which ssl daemon we're associate with */ struct _ssl_ctl *z_ctl; /* second ctl for ssl+zlib */ struct ws_ctl *ws_ctl; /* ctl for wsockd */ + CNCB *ssl_callback; /* ssl connection is now open */ + void *ssl_data; /* data for callback */ uint32_t localflags; struct ZipStats *zipstats; /* zipstats */ uint16_t cork_count; /* used for corking/uncorking connections */ diff --git a/ircd/s_serv.c b/ircd/s_serv.c index 6335c576..ac1737dd 100644 --- a/ircd/s_serv.c +++ b/ircd/s_serv.c @@ -1166,6 +1166,8 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data) } client_p->localClient->F = xF[0]; + client_p->localClient->ssl_callback = serv_connect_callback; + client_p->localClient->ssl_data = data; client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], connid_get(client_p)); if(!client_p->localClient->ssl_ctl) @@ -1174,7 +1176,6 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data) return; } SetSSL(client_p); - serv_connect_callback(client_p->localClient->F, RB_OK, client_p); } /* @@ -1218,7 +1219,7 @@ serv_connect_callback(rb_fde_t *F, int status, void *data) /* COMM_ERR_TIMEOUT wont have an errno associated with it, * the others will.. --fl */ - if(status == RB_ERR_TIMEOUT) + if(status == RB_ERR_TIMEOUT || status == RB_ERROR_SSL) { sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL, "Error connecting to %s[%s]: %s", diff --git a/ircd/sslproc.c b/ircd/sslproc.c index 5472fbb0..5abd92b1 100644 --- a/ircd/sslproc.c +++ b/ircd/sslproc.c @@ -387,6 +387,32 @@ ssl_process_zipstats(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) zips->out_ratio = 0; } +static void +ssl_process_open_fd(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) +{ + struct Client *client_p; + uint32_t fd; + + if(ctl_buf->buflen < 5) + return; /* bogus message..drop it.. XXX should warn here */ + + fd = buf_to_uint32(&ctl_buf->buf[1]); + client_p = find_cli_connid_hash(fd); + if(client_p == NULL || client_p->localClient == NULL) + return; + + if(client_p->localClient->ssl_callback) + { + CNCB *hdl = client_p->localClient->ssl_callback; + void *data = client_p->localClient->ssl_data; + + client_p->localClient->ssl_callback = NULL; + client_p->localClient->ssl_data = NULL; + + hdl(client_p->localClient->F, RB_OK, data); + } +} + static void ssl_process_dead_fd(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) { @@ -400,8 +426,30 @@ 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_connid_hash(fd); - if(client_p == NULL) + if(client_p == NULL || client_p->localClient == NULL) return; + + if(IsAnyServer(client_p)) + { + sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL, "ssld error for %s: %s", client_p->name, reason); + ilog(L_SERVER, "ssld error for %s: %s", log_client_name(client_p, SHOW_IP), reason); + } + + /* if there is still a pending callback, call it now */ + if(client_p->localClient->ssl_callback) + { + CNCB *hdl = client_p->localClient->ssl_callback; + void *data = client_p->localClient->ssl_data; + + client_p->localClient->ssl_callback = NULL; + client_p->localClient->ssl_data = NULL; + + hdl(client_p->localClient->F, RB_ERROR_SSL, data); + + /* the callback should have exited the client */ + return; + } + if(IsAnyServer(client_p) || IsRegistered(client_p)) { /* read any last moment ERROR, QUIT or the like -- jilles */ @@ -410,11 +458,6 @@ ssl_process_dead_fd(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) if (IsAnyDead(client_p)) return; } - if(IsAnyServer(client_p)) - { - sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL, "ssld error for %s: %s", client_p->name, reason); - ilog(L_SERVER, "ssld error for %s: %s", log_client_name(client_p, SHOW_IP), reason); - } exit_client(client_p, client_p, &me, reason); } @@ -490,6 +533,9 @@ ssl_process_cmd_recv(ssl_ctl_t * ctl) case 'N': ircd_ssl_ok = false; /* ssld says it can't do ssl/tls */ break; + case 'O': + ssl_process_open_fd(ctl, ctl_buf); + break; case 'D': ssl_process_dead_fd(ctl, ctl_buf); break; diff --git a/modules/m_starttls.c b/modules/m_starttls.c index 62b7feb6..b70d03bd 100644 --- a/modules/m_starttls.c +++ b/modules/m_starttls.c @@ -95,6 +95,8 @@ mr_starttls(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sou sendto_one_numeric(client_p, RPL_STARTTLS, form_str(RPL_STARTTLS)); send_queued(client_p); + /* TODO: set localClient->ssl_callback and handle success/failure */ + ctl = start_ssld_accept(client_p->localClient->F, F[1], connid_get(client_p)); if (ctl != NULL) { diff --git a/ssld/ssld.c b/ssld/ssld.c index cb74d2de..a8243a2d 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -699,6 +699,16 @@ ssl_send_certfp(conn_t *conn) mod_cmd_write_queue(conn->ctl, buf, 9 + len); } +static void +ssl_send_open(conn_t *conn) +{ + uint8_t buf[5]; + + buf[0] = 'O'; + uint32_to_buf(&buf[1], conn->id); + mod_cmd_write_queue(conn->ctl, buf, 5); +} + static void ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) { @@ -708,6 +718,7 @@ ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen { ssl_send_cipher(conn); ssl_send_certfp(conn); + ssl_send_open(conn); conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); return; @@ -726,6 +737,7 @@ ssl_process_connect_cb(rb_fde_t *F, int status, void *data) { ssl_send_cipher(conn); ssl_send_certfp(conn); + ssl_send_open(conn); conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); }