From 25318ec24bb6cf20408d1db093f2b4b2ebdf85bf Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 5 Oct 2012 14:19:54 +0000 Subject: [PATCH] - Port the SSL code over to the evented I/O subsystem. --- include/h.h | 1 + include/ssl.h | 4 +- src/s_bsd.c | 77 ++++++++++++++++++++++++------------- src/socket.c | 26 ++++++++++++- src/ssl.c | 102 +++++++++++++------------------------------------- 5 files changed, 102 insertions(+), 108 deletions(-) diff --git a/include/h.h b/include/h.h index 9cbc85e65..f664428c5 100644 --- a/include/h.h +++ b/include/h.h @@ -808,3 +808,4 @@ extern aPendingNet *find_pending_net_by_numeric_butone(int numeric, aClient *exe extern aClient *find_pending_net_duplicates(aClient *cptr, aClient **srv, int *numeric); extern aClient *find_non_pending_net_duplicates(aClient *cptr); extern void finish_auth(aClient *acptr); +extern void read_packet(int fd, int revents, void *data); diff --git a/include/ssl.h b/include/ssl.h index 558b47fc4..da6989933 100644 --- a/include/ssl.h +++ b/include/ssl.h @@ -6,10 +6,8 @@ extern SSL_METHOD *meth; extern void init_ssl(); extern int ssl_handshake(aClient *); /* Handshake the accpeted con.*/ extern int ssl_client_handshake(aClient *, ConfigItem_link *); /* and the initiated con.*/ -extern int ircd_SSL_read(aClient *acptr, void *buf, int sz); -extern int ircd_SSL_write(aClient *acptr, const void *buf, int sz); extern int ircd_SSL_accept(aClient *acptr, int fd); extern int ircd_SSL_connect(aClient *acptr); extern int SSL_smart_shutdown(SSL *ssl); -extern int ircd_SSL_client_handshake(aClient *acptr); +extern void ircd_SSL_client_handshake(int, int, void *); extern void SSL_set_nonblocking(SSL *s); diff --git a/src/s_bsd.c b/src/s_bsd.c index 8f83afc66..f5fa274fb 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -90,8 +90,6 @@ static int pollfd_count = 0; static int pollfd_to_client[MAXCONNECTIONS]; /* use get_client_by_pollfd() for grabbing, don't grab from array directly ! */ #endif -static void read_packet(int fd, int revents, void *data); - #ifdef INET6 static unsigned char minus_one[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -1528,6 +1526,7 @@ struct hostent *he; doauth: start_auth(acptr); + fd_setselect(acptr->fd, FD_SELECT_READ, read_packet, acptr); } void proceed_normal_client_handshake(aClient *acptr, struct hostent *he) @@ -1541,12 +1540,6 @@ void proceed_normal_client_handshake(aClient *acptr, struct hostent *he) finish_auth(acptr); } -void finish_auth(aClient *acptr) -{ - SetAccess(acptr); - fd_setselect(acptr->fd, FD_SELECT_READ, read_packet, acptr); -} - /* ** read_packet ** @@ -1624,7 +1617,7 @@ static void parse_client_queued(aClient *cptr) } } -static void read_packet(int fd, int revents, void *data) +void read_packet(int fd, int revents, void *data) { aClient *cptr = data; int length = 0; @@ -1636,16 +1629,48 @@ static void read_packet(int fd, int revents, void *data) while (1) { #ifdef USE_SSL - if (cptr->flags & FLAGS_SSL) - length = ircd_SSL_read(cptr, readbuf, sizeof(readbuf)); + if (IsSSL(cptr) && cptr->ssl != NULL) + { + fd_setselect(fd, FD_SELECT_READ, read_packet, cptr); + fd_setselect(fd, FD_SELECT_WRITE, NULL, cptr); + + length = SSL_read(cptr->ssl, readbuf, sizeof(readbuf)); + + if (length < 0) + { + int err = SSL_get_error(cptr->ssl, length); + ircd_log(LOG_ERROR, "error %d", err); + + switch (err) + { + case SSL_ERROR_WANT_WRITE: + fd_setselect(fd, FD_SELECT_READ, NULL, cptr); + fd_setselect(fd, FD_SELECT_WRITE, read_packet, cptr); + break; + case SSL_ERROR_WANT_READ: + SET_ERRNO(P_EWOULDBLOCK); + break; + case SSL_ERROR_SYSCALL: + break; + case SSL_ERROR_SSL: + if (ERRNO == P_EAGAIN) + break; + default: + length = 0; + SET_ERRNO(0); + break; + } + } + } else #endif length = recv(cptr->fd, readbuf, sizeof(readbuf), 0); - if (length < 0 && ERRNO == P_EWOULDBLOCK) - return; - if (length == 0) + if (length <= 0) { + if (length < 0 && (ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN || ERRNO == P_EINTR)) + return; + exit_client(cptr, cptr, cptr, "Read error"); return; } @@ -1662,10 +1687,12 @@ static void read_packet(int fd, int revents, void *data) return; } + ircd_log(LOG_ERROR, "dbuf_put - length %d, ERRNO %d", length, ERRNO); dbuf_put(&cptr->recvQ, readbuf, length); /* parse some of what we have (inducing fakelag, etc) */ - parse_client_queued(cptr); + if (!(DoingDNS(cptr) || DoingAuth(cptr))) + parse_client_queued(cptr); /* excess flood check */ if (IsPerson(cptr) && DBufLength(&cptr->recvQ) > get_recvq(cptr)) @@ -1686,6 +1713,13 @@ static void read_packet(int fd, int revents, void *data) } } +/* When auth is finished, go back and parse all prior input. */ +void finish_auth(aClient *acptr) +{ + SetAccess(acptr); + parse_client_queued(acptr); +} + /* * Check all connections for new connections and input data that is to be * processed. Also check for connections with data queued and whether we can @@ -1884,15 +1918,6 @@ int read_message(time_t delay, fdlist *listp) ** ...room for writing, empty some queue then... */ ClearBlocked(cptr); - if (IsConnecting(cptr)) { -#ifdef USE_SSL - if ((cptr->serv) && (cptr->serv->conf->options & CONNECT_SSL)) - { - Debug((DEBUG_DEBUG, "ircd_SSL_client_handshake(%s)", cptr->name)); - write_err = ircd_SSL_client_handshake(cptr); - } -#endif - } if (!write_err) { if (DoList(cptr) && IsSendable(cptr)) @@ -1948,7 +1973,7 @@ deadsocket: else if (IsSSLConnectHandshake(cptr)) { Debug((DEBUG_ERROR, "ssl: completed_connection", cptr->name)); - completed_connection(cptr); + completed_connection(cptr->fd, FD_SELECT_READ, cptr); } else if (IsSSLStartTLSHandshake(cptr)) { SetUnknown(cptr); @@ -2143,7 +2168,7 @@ int connect_server(ConfigItem_link *aconf, aClient *by, struct hostent *hp) add_client_to_list(cptr); nextping = TStime(); -#if 0 // ifdef USE_SSL +#ifdef USE_SSL if (IsSSL(cptr) && (aconf->options & CONNECT_SSL)) fd_setselect(cptr->fd, FD_SELECT_READ, ircd_SSL_client_handshake, cptr); else diff --git a/src/socket.c b/src/socket.c index 35e5adc44..87384c002 100644 --- a/src/socket.c +++ b/src/socket.c @@ -85,8 +85,30 @@ int deliver_it(aClient *cptr, char *str, int len) } #ifdef USE_SSL - if (cptr->flags & FLAGS_SSL) - retval = ircd_SSL_write(cptr, str, len); + if (IsSSL(cptr) && cptr->ssl != NULL) + { + retval = SSL_write(cptr->ssl, str, len); + + if (retval < 0) + { + switch (SSL_get_error(cptr->ssl, retval)) + { + case SSL_ERROR_WANT_READ: + /* retry later */ + return 0; + case SSL_ERROR_WANT_WRITE: + SET_ERRNO(P_EWOULDBLOCK); + break; + case SSL_ERROR_SYSCALL: + break; + case SSL_ERROR_SSL: + if (ERRNO == P_EAGAIN) + break; + default: + return 0; + } + } + } else #endif retval = send(cptr->fd, str, len, 0); diff --git a/src/ssl.c b/src/ssl.c index 61e7d26c5..cca514914 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -448,78 +448,15 @@ char *ssl_get_cipher(SSL *ssl) return (buf); } -int ircd_SSL_read(aClient *acptr, void *buf, int sz) +void ircd_SSL_client_handshake(int fd, int revents, void *data) { - int len, ssl_err, ssl_errno; - len = SSL_read((SSL *)acptr->ssl, buf, sz); - if (len <= 0) - { - switch(ssl_err = SSL_get_error((SSL *)acptr->ssl, len)) { - case SSL_ERROR_SYSCALL: - if (ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN || - ERRNO == P_EINTR) { - case SSL_ERROR_WANT_READ: - SET_ERRNO(P_EWOULDBLOCK); - Debug((DEBUG_ERROR, "ircd_SSL_read: returning EWOULDBLOCK and 0 for %s - %s", acptr->name, - ssl_err == SSL_ERROR_WANT_READ ? "SSL_ERROR_WANT_READ" : "SSL_ERROR_SYSCALL" - )); - return -1; - } - case SSL_ERROR_SSL: - if(ERRNO == EAGAIN) - return -1; - default: - ssl_errno = ERRNO; - Debug((DEBUG_ERROR, "ircd_SSL_read: returning fatal_ssl_error for %s", - acptr->name)); - return fatal_ssl_error(ssl_err, SAFE_SSL_READ, ssl_errno, acptr); - } - } - Debug((DEBUG_ERROR, "ircd_SSL_read for %s (%p, %i): success", acptr->name, buf, sz)); - return len; -} -int ircd_SSL_write(aClient *acptr, const void *buf, int sz) -{ - int len, ssl_err, ssl_errno; + aClient *acptr = data; - len = SSL_write((SSL *)acptr->ssl, buf, sz); - if (len <= 0) - { - switch(ssl_err = SSL_get_error((SSL *)acptr->ssl, len)) { - case SSL_ERROR_SYSCALL: - if (ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN || - ERRNO == P_EINTR) - { - SET_ERRNO(P_EWOULDBLOCK); - return -1; - } - return -1; - case SSL_ERROR_WANT_WRITE: - SET_ERRNO(P_EWOULDBLOCK); - return -1; - case SSL_ERROR_WANT_READ: - SET_ERRNO(P_EWOULDBLOCK); /* is this correct? next write will block if not read, so sounds right... */ - return -1; - case SSL_ERROR_SSL: - if(ERRNO == EAGAIN) - return -1; - default: - ssl_errno = ERRNO; - Debug((DEBUG_ERROR, "ircd_SSL_write: returning fatal_ssl_error for %s", acptr->name)); - return fatal_ssl_error(ssl_err, SAFE_SSL_WRITE, ssl_errno, acptr); - } - } - Debug((DEBUG_ERROR, "ircd_SSL_write for %s (%p, %i): success", acptr->name, buf, sz)); - return len; -} - -int ircd_SSL_client_handshake(aClient *acptr) -{ acptr->ssl = SSL_new(ctx_client); if (!acptr->ssl) { sendto_realops("Failed to SSL_new(ctx_client)"); - return FALSE; + return; } SSL_set_fd(acptr->ssl, acptr->fd); SSL_set_connect_state(acptr->ssl); @@ -550,22 +487,26 @@ int ircd_SSL_client_handshake(aClient *acptr) acptr->flags |= FLAGS_SSL; switch (ircd_SSL_connect(acptr)) { - case -1: - return -1; + case -1: case 0: Debug((DEBUG_DEBUG, "SetSSLConnectHandshake(%s)", get_client_name(acptr, TRUE))); SetSSLConnectHandshake(acptr); - return 0; - case 1: + return; + case 1: Debug((DEBUG_DEBUG, "SSL_init_finished should finish this job (%s)", get_client_name(acptr, TRUE))); - /* SSL_init_finished in s_bsd will finish the job */ - return 1; + return; default: - return -1; + return; } } +static void ircd_SSL_accept_retry(int fd, int revents, void *data) +{ + aClient *acptr = data; + ircd_SSL_accept(acptr, fd); +} + int ircd_SSL_accept(aClient *acptr, int fd) { int ssl_err; @@ -575,11 +516,15 @@ int ircd_SSL_accept(aClient *acptr, int fd) { case SSL_ERROR_SYSCALL: if (ERRNO == P_EINTR || ERRNO == P_EWOULDBLOCK || ERRNO == P_EAGAIN) - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - Debug((DEBUG_DEBUG, "ircd_SSL_accept(%s), - %s", get_client_name(acptr, TRUE), ssl_error_str(ssl_err, ERRNO))); - /* handshake will be completed later . . */ return 1; + case SSL_ERROR_WANT_READ: + fd_setselect(fd, FD_SELECT_READ, ircd_SSL_accept_retry, acptr); + fd_setselect(fd, FD_SELECT_WRITE, NULL, acptr); + return 1; + case SSL_ERROR_WANT_WRITE: + fd_setselect(fd, FD_SELECT_READ, NULL, acptr); + fd_setselect(fd, FD_SELECT_WRITE, ircd_SSL_accept_retry, acptr); + return 1; default: return fatal_ssl_error(ssl_err, SAFE_SSL_ACCEPT, ERRNO, acptr); @@ -587,6 +532,9 @@ int ircd_SSL_accept(aClient *acptr, int fd) { /* NOTREACHED */ return -1; } + + start_of_normal_client_handshake(acptr); + return 1; }