summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2010-10-01 21:01:49 -0400
committerAdam <Adam@anope.org>2010-10-01 21:01:49 -0400
commitd44f7971b129aa7ba80999f16f17b8c7499686e1 (patch)
treea86d08c3e641ed6b499b53b3bbb74e2a7f5b0dfb /modules
parent70056dd4689eeab4f7a9b31a921e0d7e40d5ed0d (diff)
Rewrote some of the socket code to allow m_ssl to be a service.
This allows modules (xmlrpc) to create and accept SSL connections. Also fixed unloading m_mysql at certain times and made the threading engine always work correctly on Windows.
Diffstat (limited to 'modules')
-rw-r--r--modules/extra/db_mysql.cpp2
-rw-r--r--modules/extra/m_mysql.cpp8
-rw-r--r--modules/extra/m_ssl.cpp246
-rw-r--r--modules/extra/ssl.h9
-rw-r--r--modules/socketengines/m_socketengine_epoll.cpp8
-rw-r--r--modules/socketengines/m_socketengine_select.cpp26
6 files changed, 223 insertions, 76 deletions
diff --git a/modules/extra/db_mysql.cpp b/modules/extra/db_mysql.cpp
index b15ce4de4..274f653b2 100644
--- a/modules/extra/db_mysql.cpp
+++ b/modules/extra/db_mysql.cpp
@@ -352,7 +352,7 @@ class DBMySQL : public Module
return SQL ? SQL->Escape(query) : query;
}
- DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), interface(this), SQL(this, "mysql/main")
+ DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), interface(this), SQL("mysql/main")
{
me = this;
diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp
index f641aa655..de855cead 100644
--- a/modules/extra/m_mysql.cpp
+++ b/modules/extra/m_mysql.cpp
@@ -186,6 +186,7 @@ class ModuleSQL : public Module
DThread->SetExitState();
DThread->Wakeup();
DThread->Join();
+ delete DThread;
delete SQLPipe;
}
@@ -234,6 +235,7 @@ class ModuleSQL : public Module
{
MySQLService *ss = new MySQLService(this, connname, database, server, user, password, port);
this->MySQLServices.insert(std::make_pair(connname, ss));
+ ModuleManager::RegisterService(ss);
Log(LOG_NORMAL, "mysql") << "MySQL: Sucessfully connected to server " << connname << " (" << server << ")";
}
@@ -284,13 +286,13 @@ MySQLService::~MySQLService()
for (unsigned i = me->QueryRequests.size(); i > 0; --i)
{
- QueryRequest &r = me->QueryRequests[i];
+ QueryRequest &r = me->QueryRequests[i - 1];
if (r.service == this)
{
if (r.interface)
r.interface->OnError(SQLResult("", "SQL Interface is going away"));
- me->QueryRequests.erase(me->QueryRequests.begin() + i);
+ me->QueryRequests.erase(me->QueryRequests.begin() + i - 1);
}
}
this->Lock.Unlock();
@@ -373,7 +375,7 @@ void DispatcherThread::Run()
r.service->Lock.Unlock();
this->Lock();
- if (me->QueryRequests.front().query == r.query)
+ if (!me->QueryRequests.empty() && me->QueryRequests.front().query == r.query)
{
if (r.interface)
me->FinishedRequests.push_back(QueryResult(r.interface, sresult));
diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl.cpp
index 5e081c193..9fefb942a 100644
--- a/modules/extra/m_ssl.cpp
+++ b/modules/extra/m_ssl.cpp
@@ -1,6 +1,7 @@
/* RequiredLibraries: ssl,crypt */
#include "module.h"
+#include "ssl.h"
#define OPENSSL_NO_SHA512
#include <openssl/bio.h>
@@ -12,74 +13,98 @@
#define CERTFILE "anope.cert"
#define KEYFILE "anope.key"
-static SSL_CTX *ctx;
+static SSL_CTX *server_ctx, *client_ctx;
-class SSLSocket : public ClientSocket
+class MySSLService : public SSLService
{
- private:
- SSL *sslsock;
-
- int RecvInternal(char *buf, size_t sz) const
- {
- return SSL_read(sslsock, buf, sz);
- }
-
- int SendInternal(const Anope::string &buf) const
- {
- return SSL_write(sslsock, buf.c_str(), buf.length());
- }
public:
- SSLSocket(const Anope::string &nTargetHost, int nPort, const Anope::string &nBindHost = "", bool nIPv6 = false) : ClientSocket(nTargetHost, nPort, nBindHost, nIPv6)
- {
- this->SetBlocking();
+ MySSLService(Module *o, const Anope::string &n);
- sslsock = SSL_new(ctx);
+ /** Initialize a socket to use SSL
+ * @param s The socket
+ */
+ void Init(Socket *s);
+};
- if (!sslsock)
- throw CoreException("Unable to initialize SSL socket");
+class SSLSocketIO : public SocketIO
+{
+ public:
+ /* The SSL socket for this socket */
+ SSL *sslsock;
- SSL_set_connect_state(sslsock);
- SSL_set_fd(sslsock, Sock);
- SSL_connect(sslsock);
+ /** Constructor
+ */
+ SSLSocketIO();
- UplinkSock = this;
+ /** Really receive something from the buffer
+ * @param s The socket
+ * @param buf The buf to read to
+ * @param sz How much to read
+ * @return Number of bytes received
+ */
+ int Recv(Socket *s, char *buf, size_t sz) const;
- this->SetNonBlocking();
- }
+ /** Really write something to the socket
+ * @param s The socket
+ * @param buf What to write
+ * @return Number of bytes written
+ */
+ int Send(Socket *s, const Anope::string &buf) const;
- ~SSLSocket()
- {
- SSL_shutdown(sslsock);
- SSL_free(sslsock);
+ /** Accept a connection from a socket
+ * @param s The socket
+ */
+ void Accept(ListenSocket *s);
- UplinkSock = NULL;
- }
+ /** Connect the socket
+ * @param s THe socket
+ * @param target IP to connect to
+ * @param port to connect to
+ * @param bindip IP to bind to, if any
+ */
+ void Connect(ConnectionSocket *s, const Anope::string &target, int port, const Anope::string &bindip = "");
- bool Read(const Anope::string &buf)
- {
- process(buf);
- return true;
- }
+ /** Called when the socket is destructing
+ */
+ void Destroy();
};
+class SSLModule;
+static SSLModule *me;
class SSLModule : public Module
{
+ static int AlwaysAccept(int, X509_STORE_CTX *)
+ {
+ return 1;
+ }
+
public:
- SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator)
+ MySSLService service;
+
+ SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator), service(this, "ssl")
{
+ me = this;
+
+ this->SetAuthor("Anope");
+ this->SetType(SUPPORTED);
+ this->SetPermanent(true);
+
+ SSL_library_init();
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
- ctx = SSL_CTX_new(SSLv23_client_method());
+ client_ctx = SSL_CTX_new(SSLv23_client_method());
+ server_ctx = SSL_CTX_new(SSLv23_server_method());
- if (!ctx)
+ if (!client_ctx || !server_ctx)
throw ModuleException("Error initializing SSL CTX");
if (IsFile(CERTFILE))
{
- if (!SSL_CTX_use_certificate_file(ctx, CERTFILE, SSL_FILETYPE_PEM))
+ if (!SSL_CTX_use_certificate_file(client_ctx, CERTFILE, SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_file(server_ctx, CERTFILE, SSL_FILETYPE_PEM))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading certificate");
}
}
@@ -88,9 +113,10 @@ class SSLModule : public Module
if (IsFile(KEYFILE))
{
- if (!SSL_CTX_use_PrivateKey_file(ctx, KEYFILE, SSL_FILETYPE_PEM))
+ if (!SSL_CTX_use_PrivateKey_file(client_ctx, KEYFILE, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, KEYFILE, SSL_FILETYPE_PEM))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading private key");
}
}
@@ -98,26 +124,29 @@ class SSLModule : public Module
{
if (IsFile(CERTFILE))
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
throw ModuleException("Error loading private key - file not found");
}
else
Log() << "m_ssl: No private key found";
}
- this->SetAuthor("Anope");
- this->SetType(SUPPORTED);
- this->SetPermanent(true);
+ SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
- SSL_CTX_set_options(ctx, SSL_OP_TLS_ROLLBACK_BUG | SSL_OP_ALL);
+ SSL_CTX_set_verify(client_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
+ SSL_CTX_set_verify(server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, SSLModule::AlwaysAccept);
+
+ ModuleManager::RegisterService(&this->service);
ModuleManager::Attach(I_OnPreServerConnect, this);
}
~SSLModule()
{
- SSL_CTX_free(ctx);
+ SSL_CTX_free(client_ctx);
+ SSL_CTX_free(server_ctx);
}
EventReturn OnPreServerConnect(Uplink *u, int Number)
@@ -128,19 +157,126 @@ class SSLModule : public Module
{
try
{
- new SSLSocket(u->host, u->port, Config->LocalHost, u->ipv6);
- Log() << "Connected to Server " << Number << " (" << u->host << ":" << u->port << ")";
+ new UplinkSocket(uplink_server->ipv6);
+ this->service.Init(UplinkSock);
+ UplinkSock->Connect(uplink_server->host, uplink_server->port, Config->LocalHost);
+
+ Log() << "Connected to server " << Number << " (" << u->host << ":" << u->port << ") with SSL";
+ return EVENT_ALLOW;
}
catch (const SocketException &ex)
{
- Log() << "Unable to connect with SSL to server" << Number << " (" << u->host << ":" << u->port << "), " << ex.GetReason();
+ Log() << "Unable to connect with SSL to server " << Number << " (" << u->host << ":" << u->port << "), " << ex.GetReason();
}
- return EVENT_ALLOW;
+ return EVENT_STOP;
}
return EVENT_CONTINUE;
}
};
+MySSLService::MySSLService(Module *o, const Anope::string &n) : SSLService(o, n)
+{
+}
+
+void MySSLService::Init(Socket *s)
+{
+ if (s->IO != &normalSocketIO)
+ throw CoreException("Socket initializing SSL twice");
+
+ s->IO = new SSLSocketIO();
+}
+
+SSLSocketIO::SSLSocketIO()
+{
+ this->sslsock = NULL;
+}
+
+int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz) const
+{
+ size_t i = SSL_read(this->sslsock, buf, sz);
+ TotalRead += i;
+ return i;
+}
+
+int SSLSocketIO::Send(Socket *s, const Anope::string &buf) const
+{
+ size_t i = SSL_write(this->sslsock, buf.c_str(), buf.length());
+ TotalWritten += i;
+ return i;
+}
+
+void SSLSocketIO::Accept(ListenSocket *s)
+{
+ sockaddrs conaddr;
+
+ socklen_t size = conaddr.size();
+ int newsock = accept(s->GetFD(), &conaddr.sa, &size);
+
+#ifndef INVALID_SOCKET
+# define INVALID_SOCKET -1
+#endif
+ if (newsock <= 0 || newsock == INVALID_SOCKET)
+ throw SocketException("Unable to accept SSL socket: " + Anope::LastError());
+
+ ClientSocket *newsocket = s->OnAccept(newsock, conaddr);
+ me->service.Init(newsocket);
+ SSLSocketIO *IO = debug_cast<SSLSocketIO *>(newsocket->IO);
+
+ IO->sslsock = SSL_new(server_ctx);
+ if (!IO->sslsock)
+ throw SocketException("Unable to initialize SSL socket");
+
+ SSL_set_accept_state(IO->sslsock);
+
+ if (!SSL_set_fd(IO->sslsock, newsock))
+ throw SocketException("Unable to set SSL fd");
+
+ int ret = SSL_accept(IO->sslsock);
+ if (ret <= 0)
+ {
+ int error = SSL_get_error(IO->sslsock, ret);
+
+ if (ret != -1 || (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_READ))
+ throw SocketException("Unable to accept new SSL connection: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
+ }
+}
+
+void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &TargetHost, int Port, const Anope::string &BindHost)
+{
+ if (s->IO == &normalSocketIO)
+ throw SocketException("Attempting to connect uninitialized socket with SQL");
+
+ normalSocketIO.Connect(s, TargetHost, Port, BindHost);
+
+ SSLSocketIO *IO = debug_cast<SSLSocketIO *>(s->IO);
+
+ IO->sslsock = SSL_new(client_ctx);
+ if (!IO->sslsock)
+ throw SocketException("Unable to initialize SSL socket");
+
+ if (!SSL_set_fd(IO->sslsock, s->GetFD()))
+ throw SocketException("Unable to set SSL fd");
+
+ int ret = SSL_connect(IO->sslsock);
+
+ if (ret <= 0)
+ {
+ int error = SSL_get_error(IO->sslsock, ret);
+
+ if (ret != -1 || (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_READ))
+ throw SocketException("Unable to connect to server: " + Anope::string(ERR_error_string(ERR_get_error(), NULL)));
+ }
+}
+
+void SSLSocketIO::Destroy()
+{
+ if (this->sslsock)
+ {
+ SSL_shutdown(this->sslsock);
+ SSL_free(this->sslsock);
+ }
+}
+
MODULE_INIT(SSLModule)
diff --git a/modules/extra/ssl.h b/modules/extra/ssl.h
new file mode 100644
index 000000000..e25251379
--- /dev/null
+++ b/modules/extra/ssl.h
@@ -0,0 +1,9 @@
+
+class SSLService : public Service
+{
+ public:
+ SSLService(Module *o, const Anope::string &n) : Service(o, n) { }
+
+ virtual void Init(Socket *s) = 0;
+};
+
diff --git a/modules/socketengines/m_socketengine_epoll.cpp b/modules/socketengines/m_socketengine_epoll.cpp
index 7b8dbdde5..713c1f0ff 100644
--- a/modules/socketengines/m_socketengine_epoll.cpp
+++ b/modules/socketengines/m_socketengine_epoll.cpp
@@ -48,7 +48,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1)
{
@@ -67,7 +67,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_DEL, ev.data.fd, &ev) == -1)
{
@@ -90,7 +90,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN | EPOLLOUT;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as writable in socketengine epoll: " << Anope::LastError();
@@ -108,7 +108,7 @@ class SocketEngineEPoll : public SocketEngineBase
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
- ev.data.fd = s->GetSock();
+ ev.data.fd = s->GetFD();
if (epoll_ctl(EngineHandle, EPOLL_CTL_MOD, ev.data.fd, &ev) == -1)
Log() << "Unable to mark fd " << ev.data.fd << " as unwritable in socketengine epoll: " << Anope::LastError();
diff --git a/modules/socketengines/m_socketengine_select.cpp b/modules/socketengines/m_socketengine_select.cpp
index 733547167..b1c1c065f 100644
--- a/modules/socketengines/m_socketengine_select.cpp
+++ b/modules/socketengines/m_socketengine_select.cpp
@@ -26,26 +26,26 @@ class SocketEngineSelect : public SocketEngineBase
void AddSocket(Socket *s)
{
- if (s->GetSock() > MaxFD)
- MaxFD = s->GetSock();
- FD_SET(s->GetSock(), &ReadFDs);
- Sockets.insert(std::make_pair(s->GetSock(), s));
+ if (s->GetFD() > MaxFD)
+ MaxFD = s->GetFD();
+ FD_SET(s->GetFD(), &ReadFDs);
+ Sockets.insert(std::make_pair(s->GetFD(), s));
}
void DelSocket(Socket *s)
{
- if (s->GetSock() == MaxFD)
+ if (s->GetFD() == MaxFD)
--MaxFD;
- FD_CLR(s->GetSock(), &ReadFDs);
- FD_CLR(s->GetSock(), &WriteFDs);
- Sockets.erase(s->GetSock());
+ FD_CLR(s->GetFD(), &ReadFDs);
+ FD_CLR(s->GetFD(), &WriteFDs);
+ Sockets.erase(s->GetFD());
}
void MarkWritable(Socket *s)
{
if (s->HasFlag(SF_WRITABLE))
return;
- FD_SET(s->GetSock(), &WriteFDs);
+ FD_SET(s->GetFD(), &WriteFDs);
s->SetFlag(SF_WRITABLE);
}
@@ -53,7 +53,7 @@ class SocketEngineSelect : public SocketEngineBase
{
if (!s->HasFlag(SF_WRITABLE))
return;
- FD_CLR(s->GetSock(), &WriteFDs);
+ FD_CLR(s->GetFD(), &WriteFDs);
s->UnsetFlag(SF_WRITABLE);
}
@@ -79,15 +79,15 @@ class SocketEngineSelect : public SocketEngineBase
if (s->HasFlag(SF_DEAD))
continue;
- if (FD_ISSET(s->GetSock(), &efdset))
+ if (FD_ISSET(s->GetFD(), &efdset))
{
s->ProcessError();
s->SetFlag(SF_DEAD);
continue;
}
- if (FD_ISSET(s->GetSock(), &rfdset) && !s->ProcessRead())
+ if (FD_ISSET(s->GetFD(), &rfdset) && !s->ProcessRead())
s->SetFlag(SF_DEAD);
- if (FD_ISSET(s->GetSock(), &wfdset) && !s->ProcessWrite())
+ if (FD_ISSET(s->GetFD(), &wfdset) && !s->ProcessWrite())
s->SetFlag(SF_DEAD);
}