From 27c71a75eeeeda3e2b99fde3820fab4bd980f611 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Mon, 3 Aug 2009 16:20:32 +0200 Subject: [PATCH] Hook in the new connection work, also implemented some missing bits and pieces of SSL. SSL seems to work at some basic level, and is largely untested. --- src/core/hub.c | 32 +++++++++- src/core/netevent.c | 128 +++++++++------------------------------ src/core/user.c | 21 ++++--- src/core/user.h | 1 + src/network/connection.c | 47 +++++++++++--- src/network/connection.h | 9 +-- src/network/network.c | 2 +- src/uhub.h | 1 + 8 files changed, 116 insertions(+), 125 deletions(-) diff --git a/src/core/hub.c b/src/core/hub.c index 6c93db3..f457bc5 100644 --- a/src/core/hub.c +++ b/src/core/hub.c @@ -508,11 +508,39 @@ struct hub_info* hub_start_service(struct hub_config* config) net_close(server_tcp); return 0; } - + +#ifdef SSL_SUPPORT + if (config->tls_enable) + { + hub->ssl_method = SSLv23_method(); /* TLSv1_method() */ + hub->ssl_ctx = SSL_CTX_new(hub->ssl_method); + + /* Disable SSLv2 */ + SSL_CTX_set_options(hub->ssl_ctx, SSL_OP_NO_SSLv2); + + if (SSL_CTX_use_certificate_file(hub->ssl_ctx, config->tls_certificate, SSL_FILETYPE_PEM) < 0) + { + LOG_ERROR("SSL_CTX_use_certificate_file: %s", ERR_error_string(ERR_get_error(), NULL)); + } + + if (SSL_CTX_use_PrivateKey_file(hub->ssl_ctx, config->tls_private_key, SSL_FILETYPE_PEM) < 0) + { + LOG_ERROR("SSL_CTX_use_PrivateKey_file: %s", ERR_error_string(ERR_get_error(), NULL)); + } + + if (SSL_CTX_check_private_key(hub->ssl_ctx) != 1) + { + LOG_FATAL("SSL_CTX_check_private_key: Private key does not match the certificate public key: %s", ERR_error_string(ERR_get_error(), NULL)); + return 0; + } + LOG_INFO("Enabling TLS, using certificate: %s, private key: %s", config->tls_certificate, config->tls_private_key); + } +#endif + hub->fd_tcp = server_tcp; hub->config = config; hub->users = NULL; - + if (uman_init(hub) == -1) { hub_free(hub); diff --git a/src/core/netevent.c b/src/core/netevent.c index a85d6a4..bc9184e 100644 --- a/src/core/netevent.c +++ b/src/core/netevent.c @@ -55,81 +55,28 @@ void debug_sendq_recv(struct hub_user* user, int received, int max, const char* int net_user_send(void* ptr, const void* buf, size_t len) { struct hub_user* user = (struct hub_user*) ptr; - int ret = net_send(user->net.connection.sd, buf, len, UHUB_SEND_SIGNAL); + int ret = net_con_send(&user->net.connection, buf, len); #ifdef DEBUG_SENDQ debug_sendq_send(user, ret, len); #endif if (ret > 0) - { - user_reset_last_write(user); - } - else if (ret == -1 && (net_error() == EWOULDBLOCK || net_error() == EINTR)) - { + return ret; + if (ret == 0) return -2; - } else - { - // user->close_flag = quit_socket_error; - return 0; - } - return ret; + return -1; } -#if 0 -int net_user_send_ssl(void* ptr, const void* buf, size_t len) -{ - struct hub_user* user = (struct hub_user*) ptr; - int ret = SSL_write(user->net.ssl, buf, (int) len); -#ifdef DEBUG_SENDQ - debug_sendq_send(user, ret, len); -#endif - if (ret > 0) - { - user_reset_last_write(user); - } - else if (ret == -1 && net_error() == EWOULDBLOCK) - { - return -2; - } - else - { - // user->close_flag = quit_socket_error; - return 0; - } - return ret; -} -#endif - int net_user_recv(void* ptr, void* buf, size_t len) { struct hub_user* user = (struct hub_user*) ptr; - int ret = net_recv(user->net.connection.sd, buf, len, 0); - if (ret > 0) - { - user_reset_last_read(user); - } + int ret = net_con_recv(&user->net.connection, buf, len); #ifdef DEBUG_SENDQ debug_sendq_recv(user, ret, len, buf); #endif return ret; } -#if 0 -int net_user_recv_ssl(void* ptr, void* buf, size_t len) -{ - struct hub_user* user = (struct hub_user*) ptr; - int ret = SSL_read(user->net.ssl, buf, len); - if (ret > 0) - { - user_reset_last_read(user); - } -#ifdef DEBUG_SENDQ - debug_sendq_recv(user, ret, len, buf); -#endif - return ret; -} -#endif - int handle_net_read(struct hub_user* user) { static char buf[MAX_RECV_BUF]; @@ -140,16 +87,16 @@ int handle_net_read(struct hub_user* user) if (size > 0) buf_size += size; - if (size == -1) + if (size < 0) { - if (net_error() == EWOULDBLOCK || net_error() == EINTR) - return 0; - - return quit_socket_error; + if (size == -1) + return quit_disconnected; + else + return quit_socket_error; } else if (size == 0) { - return quit_disconnected; + return 0; } else { @@ -211,16 +158,19 @@ int handle_net_read(struct hub_user* user) int handle_net_write(struct hub_user* user) { + int ret = 0; while (hub_sendq_get_bytes(user->net.send_queue)) { - int ret = hub_sendq_send(user->net.send_queue, net_user_send, user); - if (ret == -2) - break; - + ret = hub_sendq_send(user->net.send_queue, net_user_send, user); if (ret <= 0) - return quit_socket_error; + break; } + if (ret == -1) + return quit_disconnected; + if (ret < 0) + return quit_socket_error; + if (hub_sendq_get_bytes(user->net.send_queue)) { user_net_io_want_write(user); @@ -270,39 +220,13 @@ void net_event(int fd, short ev, void *arg) } } - -static void prepare_user_net(struct hub_info* hub, struct hub_user* user) -{ - int fd = user->net.connection.sd; - -#ifdef SET_SENDBUG - size_t sendbuf = 0; - size_t recvbuf = 0; - - if (net_get_recvbuf_size(fd, &recvbuf) != -1) - { - if (recvbuf > MAX_RECV_BUF || !recvbuf) recvbuf = MAX_RECV_BUF; - net_set_recvbuf_size(fd, recvbuf); - } - - if (net_get_sendbuf_size(fd, &sendbuf) != -1) - { - if (sendbuf > MAX_SEND_BUF || !sendbuf) sendbuf = MAX_SEND_BUF; - net_set_sendbuf_size(fd, sendbuf); - } -#endif - - net_set_nonblocking(fd, 1); - net_set_nosigpipe(fd, 1); -} - void net_on_accept(int server_fd, short ev, void *arg) { struct hub_info* hub = (struct hub_info*) arg; struct hub_user* user = 0; struct ip_addr_encap ipaddr; const char* addr; - + for (;;) { int fd = net_accept(server_fd, &ipaddr); @@ -318,12 +242,12 @@ void net_on_accept(int server_fd, short ev, void *arg) break; } } - + addr = ip_convert_to_string(&ipaddr); /* FIXME: Should have a plugin log this */ LOG_TRACE("Got connection from %s", addr); - + /* FIXME: A plugin should perform this check: is IP banned? */ if (acl_is_ip_banned(hub->acl, addr)) { @@ -331,7 +255,7 @@ void net_on_accept(int server_fd, short ev, void *arg) net_close(fd); continue; } - + user = user_create(hub, fd); if (!user) { @@ -339,11 +263,13 @@ void net_on_accept(int server_fd, short ev, void *arg) net_close(fd); break; } - + /* Store IP address in user object */ memcpy(&user->net.ipaddr, &ipaddr, sizeof(ipaddr)); - prepare_user_net(hub, user); +#ifdef SSL_SUPPORT + net_con_ssl_accept(&user->net.connection); +#endif } } diff --git a/src/core/user.c b/src/core/user.c index 706659d..ea47e96 100644 --- a/src/core/user.c +++ b/src/core/user.c @@ -140,33 +140,36 @@ static int convert_support_fourcc(int fourcc) #endif case FOURCC('B','A','S','E'): return feature_base; - + case FOURCC('A','U','T','0'): return feature_auto; - + case FOURCC('U','C','M','0'): case FOURCC('U','C','M','D'): return feature_ucmd; - + case FOURCC('Z','L','I','F'): return feature_zlif; - + case FOURCC('B','B','S','0'): return feature_bbs; - + case FOURCC('T','I','G','R'): return feature_tiger; - + case FOURCC('B','L','O','M'): case FOURCC('B','L','O','0'): return feature_bloom; - + case FOURCC('P','I','N','G'): return feature_ping; - + case FOURCC('L','I','N','K'): return feature_link; - + + case FOURCC('A','D','C','S'): + return feature_adcs; + default: LOG_DEBUG("Unknown extension: %x", fourcc); return 0; diff --git a/src/core/user.h b/src/core/user.h index d1693e0..5187bc8 100644 --- a/src/core/user.h +++ b/src/core/user.h @@ -44,6 +44,7 @@ enum user_flags feature_bloom = 0x00000040, /** BLO0: Bloom filter (not supported) */ feature_ping = 0x00000080, /** PING: Hub pinger information extension */ feature_link = 0x00000100, /** LINK: Hub link (not supported) */ + feature_adcs = 0x00000200, /** ADCS: ADC over TLS/SSL */ flag_ignore = 0x01000000, /** Ignore further reads */ flag_maxbuf = 0x02000000, /** Hit max buf read, ignore msg */ flag_choke = 0x04000000, /** Choked: Cannot send, waiting for write event */ diff --git a/src/network/connection.c b/src/network/connection.c index 1205809..e41aecc 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -48,15 +48,18 @@ static void net_con_event(int fd, short ev, void *arg) } else { + LOG_DEBUG("net_con_event: ev=%d, con=%p", ev, con); if (ev & (EV_READ | EV_WRITE)) { if (net_con_flag_get(con, NET_WANT_SSL_ACCEPT)) { - net_con_ssl_accept(con); + if (net_con_ssl_accept(con) < 0) + net_event(fd, EV_READ, con->ptr); } else if (net_con_flag_get(con, NET_WANT_SSL_CONNECT)) { - net_con_ssl_connect(con); + if (net_con_ssl_connect(con) < 0) + net_event(fd, EV_READ, con->ptr); } else if (ev == EV_READ && net_con_flag_get(con, NET_WANT_SSL_READ)) { @@ -81,22 +84,31 @@ static void net_con_event(int fd, short ev, void *arg) void net_con_initialize(struct net_connection* con, int sd, const void* ptr, int events) { + LOG_DEBUG("net_con_initialize: sd=%d, ptr=%p", sd, ptr); con->sd = sd; con->ptr = (void*) ptr; con->last_send = time(0); con->last_recv = con->last_send; -#ifdef SSL_SUPPORT - con->ssl = NULL; - con->write_len = 0; -#endif - if (events & EV_READ) net_con_flag_set(con, NET_WANT_READ); if (events & EV_WRITE) net_con_flag_set(con, NET_WANT_WRITE); event_set(&con->event, con->sd, events | EV_PERSIST, net_con_event, con); event_base_set(g_hub->evbase, &con->event); event_add(&con->event, 0); + + net_set_nonblocking(sd, 1); + net_set_nosigpipe(sd, 1); + +#ifdef SSL_SUPPORT + con->ssl = NULL; + con->write_len = 0; + + con->ssl = SSL_new(g_hub->ssl_ctx); + LOG_DEBUG("SSL_new"); + SSL_set_fd(con->ssl, con->sd); + LOG_DEBUG("SSL_set_fd"); +#endif } void net_con_update(struct net_connection* con, int events) @@ -128,36 +140,47 @@ static int handle_openssl_error(struct net_connection* con, int ret) switch (error) { case SSL_ERROR_ZERO_RETURN: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_ZERO_RETURN", ret, error); return ret; case SSL_ERROR_WANT_READ: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_READ", ret, error); net_con_update(con, EV_READ); net_con_flag_set(con, NET_WANT_SSL_READ); return 0; case SSL_ERROR_WANT_WRITE: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_WRITE", ret, error); net_con_update(con, EV_READ | EV_WRITE); net_con_flag_set(con, NET_WANT_SSL_WRITE); return 0; case SSL_ERROR_WANT_CONNECT: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_CONNECT", ret, error); net_con_update(con, EV_READ | EV_WRITE); net_con_flag_set(con, NET_WANT_SSL_CONNECT); return 0; case SSL_ERROR_WANT_ACCEPT: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_ACCEPT", ret, error); net_con_update(con, EV_READ | EV_WRITE); net_con_flag_set(con, NET_WANT_SSL_ACCEPT); return 0; case SSL_ERROR_WANT_X509_LOOKUP: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_WANT_X509_LOOKUP", ret, error); return 0; case SSL_ERROR_SYSCALL: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SYSCALL", ret, error); /* if ret == 0, connection closed, if ret == -1, check with errno */ - return -1; + if (ret == 0) + return -1; + else + return -net_error(); case SSL_ERROR_SSL: + LOG_DEBUG("SSL_get_error: ret=%d, error=%d: SSL_ERROR_SSL", ret, error); /* internal openssl error */ return -1; } @@ -174,6 +197,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) { #endif int ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL); + LOG_DEBUG("net_send: ret=%d", ret); if (ret > 0) { con->last_send = time(0); @@ -192,6 +216,7 @@ ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) else { int ret = SSL_write(con->ssl, buf, len); + LOG_DEBUG("net_send: ret=%d", ret); if (ret > 0) { con->last_send = time(0); @@ -215,6 +240,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) { #endif int ret = net_recv(con->sd, buf, len, 0); + LOG_DEBUG("net_send: ret=%d", ret); if (ret > 0) { con->last_recv = time(0); @@ -233,6 +259,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) else { int ret = SSL_read(con->ssl, buf, len); + LOG_DEBUG("net_send: ret=%d", ret); if (ret > 0) { con->last_recv = time(0); @@ -250,10 +277,13 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) #ifdef SSL_SUPPORT ssize_t net_con_ssl_accept(struct net_connection* con) { + net_con_flag_set(con, NET_WANT_SSL_ACCEPT); ssize_t ret = SSL_accept(con->ssl); + LOG_DEBUG("SSL_accept() ret=%d", ret); if (ret > 0) { net_con_flag_unset(con, NET_WANT_SSL_ACCEPT); + net_con_flag_unset(con, NET_WANT_SSL_READ); } else { @@ -264,6 +294,7 @@ ssize_t net_con_ssl_accept(struct net_connection* con) ssize_t net_con_ssl_connect(struct net_connection* con) { + net_con_flag_set(con, NET_WANT_SSL_CONNECT); ssize_t ret = SSL_connect(con->ssl); if (ret > 0) { diff --git a/src/network/connection.h b/src/network/connection.h index 4365dad..a13229a 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -32,6 +32,7 @@ struct net_connection time_t last_send; /** Timestamp for last send() */ #ifdef SSL_SUPPORT SSL* ssl; /** SSL handle */ + SSL_CTX* ctx; /** FIXME: Should have a global one instead */ size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ #endif /* SSL_SUPPORT */ }; @@ -44,8 +45,8 @@ extern void net_con_close(struct net_connection* con); * Send data * * @return returns the number of bytes sent. - * 0 if no data is sent, and this function should be called again - * -1 if an error occured, and the socket should be considered dead or closed. + * 0 if no data is sent, and this function should be called again (EWOULDBLOCK/EINTR) + * <0 if an error occured, the negative number contains the error code. */ extern ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len); @@ -53,8 +54,8 @@ extern ssize_t net_con_send(struct net_connection* con, const void* buf, size_t * Receive data * * @return returns the number of bytes sent. - * 0 if no data is sent, and this function should be called again - * -1 if an error occured, and the socket should be considered dead or closed. + * 0 if no data is sent, and this function should be called again (EWOULDBLOCK/EINTR) + * <0 if an error occured, the negative number contains the error code. */ extern ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len); diff --git a/src/network/network.c b/src/network/network.c index 90955b4..c0677ef 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -50,8 +50,8 @@ int net_initialize() #ifdef SSL_SUPPORT LOG_TRACE("Initializing OpenSSL..."); - SSL_load_error_strings(); SSL_library_init(); + SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif /* SSL_SUPPORT */ diff --git a/src/uhub.h b/src/uhub.h index 3fa1445..e9a9062 100644 --- a/src/uhub.h +++ b/src/uhub.h @@ -91,6 +91,7 @@ #ifdef SSL_SUPPORT #include +#include #endif #include "../version.h"