From 003f6906aeb911cce26ee25b48a818d0d1c4aea5 Mon Sep 17 00:00:00 2001 From: pk910 Date: Tue, 6 Dec 2011 15:01:55 +0100 Subject: [PATCH] added OpenSSL handler --- Makefile.am | 1 + configure.ac | 9 ++++++ src/ClientSocket.c | 54 +++++++++++++++++++++++++---------- src/ClientSocket.h | 3 ++ src/bot_DummyServ.c | 3 +- src/bot_NeonHelp.c | 3 +- src/bot_NeonServ.c | 3 +- src/bot_NeonSpam.c | 3 +- src/main.c | 2 ++ src/main.h | 1 + src/ssl.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ src/ssl.h | 44 +++++++++++++++++++++++++++++ 12 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 src/ssl.c create mode 100644 src/ssl.h diff --git a/Makefile.am b/Makefile.am index ad6549a..876da82 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ neonserv_SOURCES = src/version.c \ src/ChanNode.c \ src/IRCParser.c \ src/ClientSocket.c \ + src/ssl.c \ src/UserNode.c \ src/ChanUser.c \ src/ModeNode.c \ diff --git a/configure.ac b/configure.ac index becfda3..95d0bdd 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,15 @@ AC_ARG_WITH([winsock], [WINSOCK_LIBS='']) AC_SUBST([WINSOCK_LIBS]) +AC_CHECK_LIB(ssl, SSL_read, [ + AC_CHECK_LIB(crypto, X509_new, [ + AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h openssl/rand.h, [ + LIBS="$LIBS -lssl -lcrypto" + AC_DEFINE([HAVE_SSL], 1, [Define if you are using SSL]) + ]) + ]) +]) + # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h windows.h winsock2.h]) diff --git a/src/ClientSocket.c b/src/ClientSocket.c index a46a4bf..6b32b17 100644 --- a/src/ClientSocket.c +++ b/src/ClientSocket.c @@ -21,6 +21,7 @@ #include "IRCQueue.h" #include "WHOHandler.h" #include "HandleInfoHandler.h" +#include "ssl.h" struct socket_list { struct ClientSocket *data; @@ -110,6 +111,12 @@ int connect_socket(struct ClientSocket *client) { client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT; client->connection_time = time(0); + + if(client->flags & SOCKET_FLAG_SSL) { + ssl_connect(client); + } + + //send the IRC Headers char sendBuf[512]; int len; @@ -163,6 +170,10 @@ int connect_socket(struct ClientSocket *client) { client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT; client->connection_time = time(0); + if(client->flags & SOCKET_FLAG_SSL) { + ssl_connect(client); + } + //send the IRC Headers char sendBuf[512]; int len; @@ -185,6 +196,8 @@ int close_socket(struct ClientSocket *client) { if(client == NULL) return 0; if((client->flags & SOCKET_FLAG_CONNECTED)) close(client->sock); + if(client->flags & SOCKET_FLAG_SSL) + ssl_disconnect(client); struct ClientSocket *sock, *last_sock = NULL; for (sock = sockets->data; sock; sock = sock->next) { if(sock == client) { @@ -210,11 +223,13 @@ int close_socket(struct ClientSocket *client) { int write_socket_force(struct ClientSocket *client, char* msg, int len) { printf("[send %d] %s", len, msg); - #ifdef WIN32 - send(client->sock, msg, len, 0); - #else - write(client->sock, msg, len); - #endif + if(!(client->flags & SOCKET_FLAG_SSL) || ssl_write(client, msg, len) == -2) { + #ifdef WIN32 + send(client->sock, msg, len, 0); + #else + write(client->sock, msg, len); + #endif + } client->traffic_out += len; return 1; } @@ -248,11 +263,13 @@ void socket_loop(int timeout_seconds) { for (sock = sockets->data; sock; sock = sock->next) { if((sock->flags & SOCKET_FLAG_CONNECTED) && FD_ISSET(sock->sock, &fds)) { if(sock->bufferpos != 0) { - #ifdef WIN32 - bytes = recv(sock->sock, buffer, sizeof(buffer), 0); - #else - bytes = read(sock->sock, buffer, sizeof(buffer)); - #endif + if(!(sock->flags & SOCKET_FLAG_SSL) || (bytes = ssl_read(sock, buffer, sizeof(buffer))) == -2) { + #ifdef WIN32 + bytes = recv(sock->sock, buffer, sizeof(buffer), 0); + #else + bytes = read(sock->sock, buffer, sizeof(buffer)); + #endif + } if(bytes > 0) { for(i = 0; i < bytes; i++) { if(sock->bufferpos + i == BUF_SIZ*2) break; //buffer overflow @@ -261,11 +278,13 @@ void socket_loop(int timeout_seconds) { sock->bufferpos += i; } } else { - #ifdef WIN32 - bytes = recv(sock->sock, sock->buffer, sizeof(sock->buffer), 0); - #else - bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer)); - #endif + if(!(sock->flags & SOCKET_FLAG_SSL) || (bytes = ssl_read(sock, buffer, sizeof(buffer))) == -2) { + #ifdef WIN32 + bytes = recv(sock->sock, sock->buffer, sizeof(sock->buffer), 0); + #else + bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer)); + #endif + } if(bytes > 0) sock->bufferpos = bytes; } @@ -275,6 +294,9 @@ void socket_loop(int timeout_seconds) { bot_disconnect(sock); if(sock->queue) queue_destroy(sock); + close(sock->sock); + if(sock->flags & SOCKET_FLAG_SSL) + ssl_disconnect(sock); } else { sock->traffic_in += bytes; int used = parse_lines(sock, sock->buffer, sock->bufferpos); @@ -330,6 +352,8 @@ void free_sockets() { next = client->next; if((client->flags & SOCKET_FLAG_CONNECTED)) close(client->sock); + if(client->flags & SOCKET_FLAG_SSL) + ssl_disconnect(client); if(client->queue) queue_destroy(client); free(client->host); diff --git a/src/ClientSocket.h b/src/ClientSocket.h index 39d7bb0..1ef009c 100644 --- a/src/ClientSocket.h +++ b/src/ClientSocket.h @@ -25,11 +25,13 @@ #define SOCKET_FLAG_PREFERRED 0x08 /* prefered bot to send datas to the IRC World (NOTICE's WHO's etc pp) */ #define SOCKET_FLAG_USE_QUEUE 0x10 #define SOCKET_FLAG_RECONNECT 0x20 +#define SOCKET_FLAG_SSL 0x40 #define BUF_SIZ 512 struct UserNode; struct trigger_cache; +struct SSLConnection; struct ClientSocket { int sock; @@ -46,6 +48,7 @@ struct ClientSocket { unsigned long traffic_in; unsigned long traffic_out; time_t connection_time; + struct SSLConnection *sslconn; struct BotQueue *queue; diff --git a/src/bot_DummyServ.c b/src/bot_DummyServ.c index 9bbdcfe..2635098 100644 --- a/src/bot_DummyServ.c +++ b/src/bot_DummyServ.c @@ -69,13 +69,14 @@ static void start_bots() { MYSQL_RES *res, *res2; MYSQL_ROW row; - printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); res = mysql_use(); while ((row = mysql_fetch_row(res)) != NULL) { client = create_socket(row[3], atoi(row[4]), row[5], row[0], row[1], row[2]); client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); diff --git a/src/bot_NeonHelp.c b/src/bot_NeonHelp.c index 8c358d8..65df0fe 100644 --- a/src/bot_NeonHelp.c +++ b/src/bot_NeonHelp.c @@ -64,13 +64,14 @@ static void start_bots() { MYSQL_RES *res, *res2; MYSQL_ROW row; - printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); res = mysql_use(); while ((row = mysql_fetch_row(res)) != NULL) { client = create_socket(row[3], atoi(row[4]), row[5], row[0], row[1], row[2]); client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); diff --git a/src/bot_NeonServ.c b/src/bot_NeonServ.c index 3f9fc6e..6bedff9 100644 --- a/src/bot_NeonServ.c +++ b/src/bot_NeonServ.c @@ -409,13 +409,14 @@ static void start_bots() { MYSQL_RES *res, *res2; MYSQL_ROW row; - printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); res = mysql_use(); while ((row = mysql_fetch_row(res)) != NULL) { client = create_socket(row[3], atoi(row[4]), row[5], row[0], row[1], row[2]); client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); diff --git a/src/bot_NeonSpam.c b/src/bot_NeonSpam.c index 056a82e..0431f4a 100644 --- a/src/bot_NeonSpam.c +++ b/src/bot_NeonSpam.c @@ -147,13 +147,14 @@ static void start_bots() { MYSQL_RES *res, *res2; MYSQL_ROW row; - printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); res = mysql_use(); while ((row = mysql_fetch_row(res)) != NULL) { client = create_socket(row[3], atoi(row[4]), row[5], row[0], row[1], row[2]); client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); client->botid = BOTID; client->clientid = atoi(row[7]); connect_socket(client); diff --git a/src/main.c b/src/main.c index 6698c5c..1728d00 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,7 @@ #include "DBHelper.h" #include "commands.h" #include "ConfigParser.h" +#include "ssl.h" time_t start_time; static int running; @@ -114,6 +115,7 @@ main: queue_init(); init_lang(); + ssl_init(); init_parser(); init_UserNode(); init_ChanNode(); diff --git a/src/main.h b/src/main.h index 2e62793..b4cf00f 100644 --- a/src/main.h +++ b/src/main.h @@ -16,6 +16,7 @@ */ #ifndef _main_h #define _main_h +#include "../config.h" #define NEONSERV_VERSION "5.2" #define VERSION_PATCHLEVEL 414 diff --git a/src/ssl.c b/src/ssl.c new file mode 100644 index 0000000..0c16548 --- /dev/null +++ b/src/ssl.c @@ -0,0 +1,69 @@ +/* ssl.c - NeonServ v5.2 + * Copyright (C) 2011 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 . + */ + +#include "ssl.h" +#include "ClientSocket.h" + +void ssl_init() { +#ifdef HAVE_SSL + SSL_library_init(); +#endif +} + +void ssl_connect(struct ClientSocket *client) { +#ifdef HAVE_SSL + client->sslconn = NULL; + if(!(client->flags & SOCKET_FLAG_CONNECTED)) return; + struct SSLConnection *sslconn = malloc(sizeof(*sslconn)); + sslconn->sslContext = SSL_CTX_new(SSLv23_client_method()); + if(!sslconn->sslContext) goto ssl_connect_err; + sslconn->sslHandle = SSL_new(sslconn->sslContext); + if(!sslconn->sslHandle) goto ssl_connect_err; + if(!SSL_set_fd(sslconn->sslHandle, client->sock)) goto ssl_connect_err; + if(SSL_connect(sslconn->sslHandle) != 1) goto ssl_connect_err; + client->sslconn = sslconn; +ssl_connect_err: + free(sslconn); +#endif +} + +void ssl_disconnect(struct ClientSocket *client) { +#ifdef HAVE_SSL + if(!client->sslconn) return; + SSL_shutdown(client->sslconn->sslHandle); + SSL_free(client->sslconn->sslHandle); + SSL_CTX_free(client->sslconn->sslContext); + free(client->sslconn); + client->sslconn = NULL; +#endif +} + +int ssl_read(struct ClientSocket *client, char *buffer, int len) { +#ifdef HAVE_SSL + if(!client->sslconn) return -2; + return SSL_read(client->sslconn->sslHandle, buffer, len); +#endif + return -2; +} + +int ssl_write(struct ClientSocket *client, char *buffer, int len) { +#ifdef HAVE_SSL + if(!client->sslconn) return -2; + return SSL_write(client->sslconn->sslHandle, buffer, len); +#endif + return -2; +} \ No newline at end of file diff --git a/src/ssl.h b/src/ssl.h new file mode 100644 index 0000000..d28937b --- /dev/null +++ b/src/ssl.h @@ -0,0 +1,44 @@ +/* ssl.h - NeonServ v5.2 + * Copyright (C) 2011 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 _ssl_h +#define _ssl_h + +#include "main.h" + +struct ClientSocket; + +#ifdef HAVE_SSL +#include +#include + +struct SSLConnection { + SSL *sslHandle; + SSL_CTX *sslContext; +}; +#else +struct SSLConnection { + //just unused +}; +#endif + +void ssl_init(); +void ssl_connect(struct ClientSocket *client); +void ssl_disconnect(struct ClientSocket *client); +int ssl_read(struct ClientSocket *client, char *buffer, int len); +int ssl_write(struct ClientSocket *client, char *buffer, int len); + +#endif \ No newline at end of file -- 2.20.1