+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
#include <string>
#include <vector>
#include "hashcomp.h"
#include "inspircd.h"
-#include "ssl_cert.h"
+#include "transport.h"
/* $ModDesc: Provides SSL support for clients */
/* $CompileFlags: `libgnutls-config --cflags` */
-/* $LinkerFlags: `libgnutls-config --libs` `perl ../gnutls_rpath.pl` */
-
+/* $LinkerFlags: `perl extra/gnutls_rpath.pl` */
+/* $ModDep: transport.h */
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
culllist = new CullList(ServerInstance);
+
+ ServerInstance->PublishInterface("InspSocketHook", this);
// Not rehashable...because I cba to reduce all the sizes of existing buffers.
inbufsize = ServerInstance->Config->NetBufferSize;
if(((Conf->ReadValue("bind", "type", i) == "") || (Conf->ReadValue("bind", "type", i) == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls"))
{
// Get the port we're meant to be listening on with SSL
- unsigned int port = Conf->ReadInteger("bind", "port", i, true);
- if (ServerInstance->Config->AddIOHook(port, this))
+ std::string port = Conf->ReadValue("bind", "port", i);
+ irc::portparser portrange(port, false);
+ long portno = -1;
+ while ((portno = portrange.GetToken()))
{
- // We keep a record of which ports we're listening on with SSL
- listenports.push_back(port);
-
- ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", port);
- }
- else
- {
- ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", port);
+ if (ServerInstance->Config->AddIOHook(portno, this))
+ {
+ listenports.push_back(portno);
+ ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno);
+ }
+ else
+ {
+ ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
+ }
}
}
}
void Implements(char* List)
{
- List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
- List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
+ List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
+ List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
}
+ virtual char* OnRequest(Request* request)
+ {
+ ISHRequest* ISR = (ISHRequest*)request;
+ if (strcmp("IS_NAME", request->GetId()) == 0)
+ {
+ return "gnutls";
+ }
+ else if (strcmp("IS_HOOK", request->GetId()) == 0)
+ {
+ char* ret = "OK";
+ try
+ {
+ ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+ }
+ catch (ModuleException &e)
+ {
+ return NULL;
+ }
+ return ret;
+ }
+ else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
+ {
+ return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+ }
+ else if (strcmp("IS_HSDONE", request->GetId()) == 0)
+ {
+ issl_session* session = &sessions[ISR->Sock->GetFd()];
+ return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK";
+ }
+ else if (strcmp("IS_ATTACH", request->GetId()) == 0)
+ {
+ issl_session* session = &sessions[ISR->Sock->GetFd()];
+ if (session)
+ {
+ VerifyCertificate(session, (InspSocket*)ISR->Sock);
+ return "OK";
+ }
+ }
+ return NULL;
+ }
+
+
virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
{
issl_session* session = &sessions[fd];
Handshake(session);
}
+ virtual void OnRawSocketConnect(int fd)
+ {
+ issl_session* session = &sessions[fd];
+
+ session->fd = fd;
+ session->inbuf = new char[inbufsize];
+ session->inbufoffset = 0;
+
+ gnutls_init(&session->sess, GNUTLS_SERVER);
+
+ gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
+ gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
+ gnutls_dh_set_prime_bits(session->sess, dh_bits);
+
+ gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
+
+ Handshake(session);
+ }
+
virtual void OnRawSocketClose(int fd)
{
ServerInstance->Log(DEBUG, "OnRawSocketClose: %d", fd);
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
- {
+ {
+ if (!count)
+ return 0;
+
issl_session* session = &sessions[fd];
const char* sendbuffer = buffer;
// Bugfix, only send this numeric for *our* SSL users
if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports)))
{
- ServerInstance->SendWhoisLine(source, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
+ ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
}
}
session->status = ISSL_NONE;
}
- void VerifyCertificate(issl_session* session, userrec* user)
+ void VerifyCertificate(issl_session* session, Extensible* user)
{
unsigned int status;
const gnutls_datum_t* cert_list;
else
{
certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size)));
- user->WriteServ("NOTICE %s :*** Your SSL Certificate fingerprint is: %s", user->nick, irc::hex(digest, digest_size).c_str());
}
/* Beware here we do not check for errors.