From 2c089146f08538afd3a83998ba37cbb6dd2c8f6e Mon Sep 17 00:00:00 2001 From: pk910 Date: Tue, 4 Mar 2014 18:19:02 +0100 Subject: [PATCH] [IOMultiplexerV2] added SSL Backend --- src/IOHandler/IOSSLBackend.c | 258 +++++++++++++++++++++++++++++ src/IOHandler/IOSSLBackend.h | 48 ++++++ src/IOHandler/IOSockets.c | 135 ++++++++++----- src/IOHandler/IOSockets.h | 23 +-- src/IOHandler/Makefile.am | 1 + src/IOHandler_test/socket/iotest.c | 15 +- 6 files changed, 422 insertions(+), 58 deletions(-) create mode 100644 src/IOHandler/IOSSLBackend.c create mode 100644 src/IOHandler/IOSSLBackend.h diff --git a/src/IOHandler/IOSSLBackend.c b/src/IOHandler/IOSSLBackend.c new file mode 100644 index 0000000..5fe568e --- /dev/null +++ b/src/IOHandler/IOSSLBackend.c @@ -0,0 +1,258 @@ +/* IOSSLBackend.c - IOMultiplexer + * Copyright (C) 2014 Philipp Kreil (pk910) + * + * 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 3 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 . + */ +#define _IOHandler_internals +#include "IOInternal.h" +#include "IOHandler.h" +#include "IOLog.h" +#include "IOSockets.h" +#include "IOSSLBackend.h" + +#ifdef HAVE_OPENSSL_SSL_H +/* OpenSSL Backend */ + + +void iossl_init() { + SSL_library_init(); + OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ + SSL_load_error_strings(); +} + +static void iossl_error() { + unsigned long e; + while((e = ERR_get_error())) { + iolog_trigger(IOLOG_ERROR, "SSLv23 ERROR %lu: %s", e, ERR_error_string(e, NULL)); + } +} + +// Client +void iossl_connect(struct _IOSocket *iosock) { + struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode)); + sslnode->sslContext = SSL_CTX_new(SSLv23_client_method()); + if(!sslnode->sslContext) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL CTX"); + goto ssl_connect_err; + } + sslnode->sslHandle = SSL_new(sslnode->sslContext); + if(!sslnode->sslHandle) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle"); + goto ssl_connect_err; + } + if(!SSL_set_fd(sslnode->sslHandle, iosock->fd)) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle"); + goto ssl_connect_err; + } + SSL_set_connect_state(sslnode->sslHandle); + iosock->sslnode = sslnode; + iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE; + iossl_client_handshake(iosock); + return; +ssl_connect_err: + free(sslnode); + iosocket_events_callback(iosock, 0, 0); +} + +void iossl_client_handshake(struct _IOSocket *iosock) { + // Perform an SSL handshake. + int ret = SSL_do_handshake(iosock->sslnode->sslHandle); + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE; + switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) { + case SSL_ERROR_NONE: + iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd); + iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED; + iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event + break; + case SSL_ERROR_WANT_READ: + iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd); + break; + case SSL_ERROR_WANT_WRITE: + iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE; + iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd); + break; + default: + iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd); + iosocket_events_callback(iosock, 0, 0); + break; + } +} + + +// Server +void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) { + struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode)); + sslnode->sslContext = SSL_CTX_new(SSLv23_server_method()); + if(!sslnode->sslContext) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not create server SSL CTX"); + goto ssl_listen_err; + } + /* load certificate */ + if(SSL_CTX_use_certificate_file(sslnode->sslContext, certfile, SSL_FILETYPE_PEM) <= 0) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not load server certificate (%s)", certfile); + goto ssl_listen_err; + } + /* load keyfile */ + if(SSL_CTX_use_PrivateKey_file(sslnode->sslContext, keyfile, SSL_FILETYPE_PEM) <= 0) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not load server keyfile (%s)", keyfile); + goto ssl_listen_err; + } + /* check certificate and keyfile */ + if(!SSL_CTX_check_private_key(sslnode->sslContext)) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: server certificate (%s) and keyfile (%s) doesn't match!", certfile, keyfile); + goto ssl_listen_err; + } + iosock->sslnode = sslnode; + iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED; + return; +ssl_listen_err: + free(sslnode); + iosock->sslnode = NULL; + iosocket_events_callback(iosock, 0, 0); +} + +void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock) { + struct IOSSLDescriptor *sslnode = malloc(sizeof(*sslnode)); + sslnode->sslHandle = SSL_new(sslnode->sslContext); + if(!sslnode->sslHandle) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not create client SSL Handle"); + goto ssl_accept_err; + } + if(!SSL_set_fd(sslnode->sslHandle, new_iosock->fd)) { + iossl_error(); + iolog_trigger(IOLOG_ERROR, "SSL: could not set client fd in SSL Handle"); + goto ssl_accept_err; + } + new_iosock->sslnode = sslnode; + new_iosock->socket_flags |= IOSOCKETFLAG_SSL_HANDSHAKE; + return; +ssl_accept_err: + free(sslnode); + iosock->sslnode = NULL; + iosocket_events_callback(new_iosock, 0, 0); +} + +void iossl_server_handshake(struct _IOSocket *iosock) { + // Perform an SSL handshake. + int ret = SSL_accept(iosock->sslnode->sslHandle); + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_WANTWRITE; + switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) { + case SSL_ERROR_NONE: + iolog_trigger(IOLOG_DEBUG, "SSL handshake for fd %d successful", iosock->fd); + iosock->socket_flags |= IOSOCKETFLAG_SSL_ESTABLISHED; + iosocket_events_callback(iosock, 0, 0); //perform IOEVENT_CONNECTED event + break; + case SSL_ERROR_WANT_READ: + iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_READ", iosock->fd); + break; + case SSL_ERROR_WANT_WRITE: + iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE; + iolog_trigger(IOLOG_DEBUG, "SSL_do_handshake for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd); + break; + default: + iolog_trigger(IOLOG_ERROR, "SSL_do_handshake for fd %d failed with ", iosock->fd); + iosocket_events_callback(iosock, 0, 0); + break; + } +} + +void iossl_disconnect(struct _IOSocket *iosock) { + if(!iosock->sslnode) return; + SSL_shutdown(iosock->sslnode->sslHandle); + SSL_free(iosock->sslnode->sslHandle); + SSL_CTX_free(iosock->sslnode->sslContext); + free(iosock->sslnode); + iosock->sslnode = NULL; + iosock->socket_flags &= ~IOSOCKETFLAG_SSLSOCKET; +} + +int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) + return 0; + int ret = SSL_read(iosock->sslnode->sslHandle, buffer, len); + iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS); + switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_WANT_READ: + iosock->socket_flags |= IOSOCKETFLAG_SSL_READHS; + iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_READ", iosock->fd); + errno = EAGAIN; + ret = -1; + break; + case SSL_ERROR_WANT_WRITE: + iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_READHS; + iolog_trigger(IOLOG_DEBUG, "SSL_read for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd); + errno = EAGAIN; + ret = -1; + break; + default: + iolog_trigger(IOLOG_ERROR, "SSL_read for fd %d failed with ", iosock->fd); + ret = -1; + break; + } + return ret; +} + +int iossl_write(struct _IOSocket *iosock, char *buffer, int len) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) != (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_ESTABLISHED)) + return 0; + int ret = SSL_write(iosock->sslnode->sslHandle, buffer, len); + iosock->socket_flags &= ~(IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS); + switch(SSL_get_error(iosock->sslnode->sslHandle, ret)) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_WANT_READ: + iosock->socket_flags |= IOSOCKETFLAG_SSL_WRITEHS; + iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_READ", iosock->fd); + errno = EAGAIN; + ret = -1; + break; + case SSL_ERROR_WANT_WRITE: + iosock->socket_flags |= IOSOCKETFLAG_SSL_WANTWRITE | IOSOCKETFLAG_SSL_WRITEHS; + iolog_trigger(IOLOG_DEBUG, "SSL_write for fd %d returned SSL_ERROR_WANT_WRITE", iosock->fd); + errno = EAGAIN; + ret = -1; + break; + default: + iolog_trigger(IOLOG_ERROR, "SSL_write for fd %d failed with ", iosock->fd); + ret = -1; + break; + } + return ret; +} + +#else +// NULL-backend + +void iossl_init() {}; +void iossl_connect(struct _IOSocket *iosock) {}; +void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {}; +void iossl_client_handshake(struct _IOSocket *iosock) {}; +void iossl_client_accepted(struct _IOSocket *iosock, struct IODescriptor *client_iofd) {}; +void iossl_server_handshake(struct _IOSocket *iosock) {}; +void iossl_disconnect(struct _IOSocket *iosock) {}; +int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { return 0; }; +int iossl_write(struct _IOSocket *iosock, char *buffer, int len) { return 0; }; +#endif diff --git a/src/IOHandler/IOSSLBackend.h b/src/IOHandler/IOSSLBackend.h new file mode 100644 index 0000000..879537e --- /dev/null +++ b/src/IOHandler/IOSSLBackend.h @@ -0,0 +1,48 @@ +/* IOHandler_SSL.h - IOMultiplexer + * Copyright (C) 2014 Philipp Kreil (pk910) + * + * 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 3 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 . + */ +#ifndef _IOSSLBackend_h +#define _IOSSLBackend_h + +struct _IOSocket; + +#ifdef HAVE_OPENSSL_SSL_H +#include +#include +#include + +struct IOSSLDescriptor { + unsigned int flags : 8; + SSL *sslHandle; + SSL_CTX *sslContext; +}; +#else +struct IOSSLDescriptor { + //just unused +}; +#endif + +void iossl_init(); +void iossl_connect(struct _IOSocket *iosock); +void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile); +void iossl_client_handshake(struct _IOSocket *iosock); +void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *new_iosock); +void iossl_server_handshake(struct _IOSocket *iosock); +void iossl_disconnect(struct _IOSocket *iosock); +int iossl_read(struct _IOSocket *iosock, char *buffer, int len); +int iossl_write(struct _IOSocket *iosock, char *buffer, int len); + +#endif diff --git a/src/IOHandler/IOSockets.c b/src/IOHandler/IOSockets.c index 480d1ba..4a7da99 100644 --- a/src/IOHandler/IOSockets.c +++ b/src/IOHandler/IOSockets.c @@ -100,7 +100,8 @@ void _init_sockets() { } #endif - iosockets_init_engine(); + iosockets_init_engine(); + iossl_init(); } @@ -140,6 +141,8 @@ void _free_socket(struct _IOSocket *iosock) { free(iosock->readbuf.buffer); if(iosock->writebuf.buffer) free(iosock->writebuf.buffer); + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) + iossl_disconnect(iosock); free(iosock); } @@ -622,7 +625,8 @@ struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) { if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { new_iosocket->ssl = 1; new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET; - //TODO: SSL Handshake + + iossl_client_accepted(iosock, new_iosock); } iosocket_activate(new_iosock); @@ -717,12 +721,6 @@ struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosock->parent = iodescriptor; iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING; iosock->port = port; - /* - if(ssl) { - iodescriptor->ssl = 1; - iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET; - } - */ switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) { case -1: @@ -748,8 +746,11 @@ struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, co } struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) { - //TODO: SSL - return NULL; + struct IOSocket *iosocket = iosocket_listen_flags(hostname, port, callback, flags); + struct _IOSocket *iosock = iosocket->iosocket; + iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_HANDSHAKE; + iossl_listen(iosock, certfile, keyfile); + return iosocket; } void iosocket_close(struct IOSocket *iosocket) { @@ -777,9 +778,8 @@ void iosocket_close(struct IOSocket *iosocket) { iosocket_try_write(iosock); } //close IOSocket - if(iosock->sslnode) { - //TODO: SSL - } + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) + iossl_disconnect(iosock); if(iosock->fd) close(iosock->fd); _free_socket(iosock); @@ -789,13 +789,13 @@ void iosocket_close(struct IOSocket *iosocket) { } static int iosocket_try_write(struct _IOSocket *iosock) { - if(!iosock->writebuf.bufpos) return 0; + if(!iosock->writebuf.bufpos && !(iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) + return 0; iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd); int res; - if(iosock->sslnode) { - /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */ - // TODO - } else + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) + res = iossl_write(iosock, iosock->writebuf.buffer, iosock->writebuf.bufpos); + else res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0); if(res < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) @@ -846,12 +846,11 @@ void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) { int pos; sendBuf[0] = '\0'; va_start(arg_list, text); - pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list); + pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 1, text, arg_list); va_end(arg_list); - if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2; - sendBuf[pos] = '\n'; - sendBuf[pos+1] = '\0'; - iosocket_send(iosocket, sendBuf, pos+1); + if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 1)) pos = IOSOCKET_PRINTF_LINE_LEN - 1; + sendBuf[pos] = '\0'; + iosocket_send(iosocket, sendBuf, pos); } @@ -871,7 +870,40 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea callback_event.socket = iosocket; if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) { - //TODO: SSL + if(readable || writeable) { + if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) + iossl_server_handshake(iosock); + else + iossl_client_handshake(iosock); + engine->update(iosock); + } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) { + //TODO: SSL init error + } else if((iosock->socket_flags & IOSOCKETFLAG_INCOMING)) { + if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) { + //incoming SSL connection accepted + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE; + callback_event.type = IOSOCKETEVENT_ACCEPT; + callback_event.data.accept_socket = iosock->parent; + } else { + //incoming SSL connection failed, simply drop + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + iolog_trigger(IOLOG_ERROR, "SSL Handshake failed for incoming connection. Dropping fd %d", iosock->fd); + } + } else { + // SSL Backend finished + if((iosock->socket_flags & IOSOCKETFLAG_SSL_ESTABLISHED)) { + iosocket->status = IOSOCKET_CONNECTED; + iosock->socket_flags &= ~IOSOCKETFLAG_SSL_HANDSHAKE; + callback_event.type = IOSOCKETEVENT_CONNECTED; + engine->update(iosock); + + //initialize readbuf + iosocket_increase_buffer(&iosock->readbuf, 1024); + } else { + callback_event.type = IOSOCKETEVENT_NOTCONNECTED; + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + } + } } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) { if(readable) { //new client connected @@ -904,32 +936,43 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea iosock->socket_flags |= IOSOCKETFLAG_DEAD; } } else if(writeable) { //connection established - iosocket->status = IOSOCKET_CONNECTED; - if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { - //TODO: SSL Handshake + iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING; + socket_lookup_clear(iosock); + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { + iolog_trigger(IOLOG_DEBUG, "SSL client socket connected. Stating SSL handshake..."); + iossl_connect(iosock); + engine->update(iosock); return; } + iosocket->status = IOSOCKET_CONNECTED; callback_event.type = IOSOCKETEVENT_CONNECTED; - iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING; - socket_lookup_clear(iosock); engine->update(iosock); //initialize readbuf iosocket_increase_buffer(&iosock->readbuf, 1024); } - } else { - if(readable) { + } else { + int ssl_rehandshake = 0; + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { + if((iosock->socket_flags & IOSOCKETFLAG_SSL_READHS)) + ssl_rehandshake = 1; + else if((iosock->socket_flags & IOSOCKETFLAG_SSL_WRITEHS)) + ssl_rehandshake = 2; + } + if((readable && ssl_rehandshake == 0) || ssl_rehandshake == 1) { int bytes; if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128) iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024); - if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) { - //TODO: SSL read - } else + if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) + bytes = iossl_read(iosock, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos); + else bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0); - if(bytes <= 0) { - if (errno != EAGAIN || errno != EWOULDBLOCK) { + if(bytes <= 0) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_READHS)) { + ssl_rehandshake = 1; + } else if (errno != EAGAIN || errno != EWOULDBLOCK) { iosock->socket_flags |= IOSOCKETFLAG_DEAD; callback_event.type = IOSOCKETEVENT_CLOSED; @@ -989,17 +1032,23 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea callback_event.data.recv_buf = &iosock->readbuf; } } - if(writeable) { + if((writeable && ssl_rehandshake == 0) || ssl_rehandshake == 2) { int bytes; bytes = iosocket_try_write(iosock); - if(bytes < 0) { - iosock->socket_flags |= IOSOCKETFLAG_DEAD; - - callback_event.type = IOSOCKETEVENT_CLOSED; - callback_event.data.errid = errno; + if(bytes < 0) { + if((iosock->socket_flags & (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) == (IOSOCKETFLAG_SSLSOCKET | IOSOCKETFLAG_SSL_WRITEHS)) { + ssl_rehandshake = 1; + } else { + iosock->socket_flags |= IOSOCKETFLAG_DEAD; + + callback_event.type = IOSOCKETEVENT_CLOSED; + callback_event.data.errid = errno; + } } + } + if(ssl_rehandshake) { + engine->update(iosock); } - } if(callback_event.type != IOSOCKETEVENT_IGNORE) iosocket_trigger_event(&callback_event); diff --git a/src/IOHandler/IOSockets.h b/src/IOHandler/IOSockets.h index 6f07160..2d8dd77 100644 --- a/src/IOHandler/IOSockets.h +++ b/src/IOHandler/IOSockets.h @@ -70,12 +70,15 @@ extern struct _IOSocket *iosocket_last; #define IOSOCKETFLAG_PARENT_DNSENGINE 0x0200 #define IOSOCKETFLAG_SSLSOCKET 0x0400 /* use ssl after connecting */ #define IOSOCKETFLAG_SSL_HANDSHAKE 0x0800 /* SSL Handshake in progress */ -#define IOSOCKETFLAG_SSL_WANTWRITE 0x1000 -#define IOSOCKETFLAG_SHUTDOWN 0x2000 /* disconnect pending */ -#define IOSOCKETFLAG_CONNECTING 0x4000 -#define IOSOCKETFLAG_INCOMING 0x8000 /* incoming (accepted) connection */ -#define IOSOCKETFLAG_DEAD 0x10000 -#define IOSOCKETFLAG_RECONNECT_IPV4 0x20000 /* possible fallback to ipv4 connect if ipv6 fails */ +#define IOSOCKETFLAG_SSL_WANTWRITE 0x1000 +#define IOSOCKETFLAG_SSL_READHS 0x2000 /* ssl read rehandshake */ +#define IOSOCKETFLAG_SSL_WRITEHS 0x4000 /* ssl write rehandshake */ +#define IOSOCKETFLAG_SSL_ESTABLISHED 0x8000 +#define IOSOCKETFLAG_SHUTDOWN 0x10000 /* disconnect pending */ +#define IOSOCKETFLAG_CONNECTING 0x20000 +#define IOSOCKETFLAG_INCOMING 0x40000 /* incoming (accepted) connection */ +#define IOSOCKETFLAG_DEAD 0x80000 +#define IOSOCKETFLAG_RECONNECT_IPV4 0x100000 /* possible fallback to ipv4 connect if ipv6 fails */ struct IOSocketDNSLookup { unsigned int bindlookup : 1; @@ -115,8 +118,8 @@ void _init_sockets(); void iosocket_loop(int usec); void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event); void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable); - -#define iosocket_wants_writes(IOSOCK) (IOSOCK->writebuf.bufpos || (IOSOCK->socket_flags & (IOSOCKETFLAG_CONNECTING | IOSOCKETFLAG_SSL_WANTWRITE))) + +#define iosocket_wants_writes(IOSOCK) ((IOSOCK->writebuf.bufpos && !(IOSOCK->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS))) || (IOSOCK->socket_flags & (IOSOCKETFLAG_CONNECTING | IOSOCKETFLAG_SSL_WANTWRITE))) #endif @@ -129,7 +132,8 @@ enum IOSocketStatus { IOSOCKET_CLOSED, /* descriptor is dead (socket waiting for removal or timer) */ IOSOCKET_LISTENING, /* descriptor is waiting for connections (server socket) */ IOSOCKET_CONNECTING, /* descriptor is waiting for connection approval (connecting client socket) */ - IOSOCKET_CONNECTED /* descriptor is connected (connected client socket) */ + IOSOCKET_CONNECTED, /* descriptor is connected (connected client socket) */ + IOSOCKET_SSLHANDSHAKE /* descriptor is waiting for ssl (handshake) */ }; enum IOSocketEventType { @@ -139,7 +143,6 @@ enum IOSocketEventType { IOSOCKETEVENT_NOTCONNECTED, /* client socket could not connect (errid valid) */ IOSOCKETEVENT_CLOSED, /* client socket lost connection (errid valid) */ IOSOCKETEVENT_ACCEPT, /* server socket accepted new connection (accept_socket valid) */ - IOSOCKETEVENT_SSLFAILED, /* failed to initialize SSL session */ IOSOCKETEVENT_DNSFAILED /* failed to lookup DNS information (recv_str contains error message) */ }; diff --git a/src/IOHandler/Makefile.am b/src/IOHandler/Makefile.am index 7cbb02c..ab0142f 100644 --- a/src/IOHandler/Makefile.am +++ b/src/IOHandler/Makefile.am @@ -14,6 +14,7 @@ libiohandler_a_SOURCES = compat/utime.c \ IOGarbageCollector.c \ IOLog.c \ IOSockets.c \ + IOSSLBackend.c \ IOTimer.c noinst_LIBRARIES = libiohandler.a diff --git a/src/IOHandler_test/socket/iotest.c b/src/IOHandler_test/socket/iotest.c index d534ccb..9da8b2b 100644 --- a/src/IOHandler_test/socket/iotest.c +++ b/src/IOHandler_test/socket/iotest.c @@ -30,10 +30,7 @@ int main(int argc, char *argv[]) { iolog_register_callback(io_log); - irc_iofd = iosocket_connect("irc.nextirc.net", 6667, 0, NULL, io_callback); - irc_iofd->parse_delimiter = 1; - irc_iofd->delimiters[0] = '\n'; - irc_iofd->delimiters[1] = '\r'; + irc_iofd = iosocket_connect("test.pk910.de", 443, 1, NULL, io_callback); iohandler_run(); @@ -44,12 +41,20 @@ static IOSOCKET_CALLBACK(io_callback) { switch(event->type) { case IOSOCKETEVENT_CONNECTED: printf("[connect]\n"); + iosocket_printf(event->socket, "GET / HTTP/1.1\r\n"); + iosocket_printf(event->socket, "Host: test.pk910.de\r\n"); + iosocket_printf(event->socket, "\r\n"); break; case IOSOCKETEVENT_CLOSED: printf("[disconnect]\n"); break; case IOSOCKETEVENT_RECV: - printf("[in] %s\n", event->data.recv_str); + { + struct IOSocketBuffer *recv_buf = event->data.recv_buf; + write(1, recv_buf->buffer, recv_buf->bufpos); + recv_buf->bufpos = 0; + printf("\n"); + } break; default: -- 2.20.1