summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--acconfig.h3
-rw-r--r--configure.in73
-rw-r--r--src/core/Makefile.am1
-rw-r--r--src/core/chat-commands.c10
-rw-r--r--src/core/network-openssl.c291
-rw-r--r--src/core/network.h2
-rw-r--r--src/core/server-connect-rec.h1
-rw-r--r--src/core/server-setup-rec.h1
-rw-r--r--src/core/servers-reconnect.c2
-rw-r--r--src/core/servers-setup.c4
-rw-r--r--src/core/servers.c7
-rw-r--r--src/core/session.c2
-rw-r--r--src/fe-common/core/fe-server.c5
-rw-r--r--src/fe-common/irc/fe-events-numeric.c2
14 files changed, 392 insertions, 12 deletions
diff --git a/acconfig.h b/acconfig.h
index 33f02000..e87197fb 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -36,3 +36,6 @@
#undef HAVE_GETTEXT
#undef HAVE_LC_MESSAGES
#undef HAVE_STPCPY
+
+/* SSL */
+#undef HAVE_OPENSSL
diff --git a/configure.in b/configure.in
index a778c4bf..d612bf04 100644
--- a/configure.in
+++ b/configure.in
@@ -112,7 +112,7 @@ if test "x$prefix" != "xNONE"; then
fi
AC_ARG_WITH(tests,
-[ --with-glib2 Use GLIB 2.0 instead of 1.2],
+[ --with-glib2 Use GLIB 2.0 instead of 1.2],
if test x$withval = xyes; then
want_glib2=yes
else
@@ -126,7 +126,7 @@ AC_ARG_WITH(tests,
AC_ARG_WITH(perl-staticlib,
[ --with-perl-staticlib Specify that we want to link perl libraries
- statically in irssi, default is no],
+ statically in irssi, default is no],
if test x$withval = xyes; then
want_staticperllib=yes
else
@@ -141,7 +141,7 @@ AC_ARG_WITH(perl-staticlib,
AC_ARG_WITH(perl-lib,
[ --with-perl-lib=[site|vendor|DIR] Specify where to install the
- Perl libraries for irssi, default is site],
+ Perl libraries for irssi, default is site],
if test "x$withval" = xyes; then
want_perl=yes
elif test "x$withval" = xno; then
@@ -170,8 +170,8 @@ AC_ARG_WITH(perl-lib,
AC_ARG_WITH(perl,
[ --with-perl[=yes|no|module] Build with Perl support - also specifies
- if it should be built into main irssi binary
- (static, default) or as module],
+ if it should be built into main irssi binary
+ (static, default) or as module],
if test x$withval = xyes; then
want_perl=static
elif test x$withval = xstatic; then
@@ -197,6 +197,62 @@ AC_ARG_ENABLE(ipv6,
want_ipv6=no)
dnl **
+dnl ** SSL Library checks (OpenSSL)
+dnl **
+
+AC_ARG_ENABLE(ssl,
+ [ --disable-ssl Turn on Secure Sockets Layer support [default=yes]],,
+ enable_ssl=yes)
+
+AC_ARG_WITH(openssl-includes,
+ [ --with-openssl-includes Specify location of OpenSSL header files],
+ [openssl_inc_prefix=-I$withval])
+
+AC_ARG_WITH(openssl-libs,
+ [ --with-openssl-libs Specify location of OpenSSL libs],
+ [openssl_prefix=$withval],
+ [openssl_prefix=/usr/lib])
+
+if test "x$enable_ssl" = xyes; then
+ ###
+ ### Check for OpenSSL
+ ###
+ save_CFLAGS=$CFLAGS;
+ CFLAGS="-lcrypto";
+
+ enable_openssl="no";
+ OPENSSL_LDFLAGS="";
+ AC_CHECK_LIB(ssl, SSL_read,
+ AC_CHECK_LIB(crypto, X509_new,
+ AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h,
+ [
+ enable_openssl="yes";
+ OPENSSL_LDFLAGS="-lssl -lcrypto"
+ ],
+ AC_ERROR([Cannot find OpenSSL includes !])),
+ AC_ERROR([Cannot find libCrypto !])),
+ AC_ERROR([Cannot find libSSL !]))
+ CFLAGS=$save_CFLAGS
+
+ if test "x$enable_openssl" = xyes; then
+ AC_DEFINE(HAVE_OPENSSL)
+ OPENSSL_LIBS="-L$openssl_prefix $OPENSSL_LDFLAGS"
+ OPENSSL_CFLAGS="$openssl_inc_prefix"
+ else
+ OPENSSL_LIBS=
+ OPENSSL_CFLAGS=
+ fi
+
+ AC_SUBST(OPENSSL_CFLAGS)
+ AC_SUBST(OPENSSL_LIBS)
+ LIBS="$LIBS $OPENSSL_LIBS"
+ CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
+else
+ enable_openssl="no"
+fi
+
+
+dnl **
dnl ** just some generic stuff...
dnl **
@@ -830,7 +886,6 @@ fi
echo "Building text frontend ..... : $text"
echo "Building irssi bot ......... : $want_irssibot"
echo "Building irssi proxy ....... : $want_irssiproxy"
-echo "Building with IPv6 support . : $want_ipv6"
if test "x$have_gmodule" = "xyes"; then
echo "Building with module support : yes"
else
@@ -877,8 +932,12 @@ if test "x$want_perl" != "xno"; then
echo " Anyway, installing perl to this directory should work just as well."
fi
fi
-
echo "Install prefix ............. : $prefix"
echo
+
+echo "Building with IPv6 support . : $want_ipv6"
+echo "Building with SSL support .. : ${enable_openssl}"
+
+echo
echo "If there was any problems, read the INSTALL file."
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index f543f361..beee1098 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -30,6 +30,7 @@ libcore_a_SOURCES = \
net-nonblock.c \
net-sendbuffer.c \
network.c \
+ network-openssl.c \
nicklist.c \
nickmatch-cache.c \
pidwait.c \
diff --git a/src/core/chat-commands.c b/src/core/chat-commands.c
index 4bc931dc..aff0d8b7 100644
--- a/src/core/chat-commands.c
+++ b/src/core/chat-commands.c
@@ -88,12 +88,16 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
else if (g_hash_table_lookup(optlist, "4") != NULL)
conn->family = AF_INET;
+ if(g_hash_table_lookup(optlist, "ssl") != NULL)
+ conn->use_ssl = TRUE;
+
if (g_hash_table_lookup(optlist, "!") != NULL)
conn->no_autojoin_channels = TRUE;
if (g_hash_table_lookup(optlist, "noproxy") != NULL)
g_free_and_null(conn->proxy);
+
*rawlog_file = g_strdup(g_hash_table_lookup(optlist, "rawlog"));
host = g_hash_table_lookup(optlist, "host");
@@ -108,7 +112,7 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
return conn;
}
-/* SYNTAX: CONNECT [-4 | -6] [-ircnet <ircnet>] [-host <hostname>]
+/* SYNTAX: CONNECT [-4 | -6] [-ssl] [-ircnet <ircnet>] [-host <hostname>]
<address>|<chatnet> [<port> [<password> [<nick>]]] */
static void cmd_connect(const char *data)
{
@@ -209,7 +213,7 @@ static void sig_default_command_server(const char *data, SERVER_REC *server,
signal_emit("command server connect", 3, data, server, item);
}
-/* SYNTAX: SERVER [-4 | -6] [-ircnet <ircnet>] [-host <hostname>]
+/* SYNTAX: SERVER [-4 | -6] [-ssl] [-ircnet <ircnet>] [-host <hostname>]
[+]<address>|<chatnet> [<port> [<password> [<nick>]]] */
static void cmd_server_connect(const char *data, SERVER_REC *server)
{
@@ -439,7 +443,7 @@ void chat_commands_init(void)
signal_add("default command server", (SIGNAL_FUNC) sig_default_command_server);
- command_set_options("connect", "4 6 !! +host noproxy -rawlog");
+ command_set_options("connect", "4 6 !! ssl +host noproxy -rawlog");
command_set_options("join", "invite");
command_set_options("msg", "channel nick");
}
diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c
new file mode 100644
index 00000000..7a4e974d
--- /dev/null
+++ b/src/core/network-openssl.c
@@ -0,0 +1,291 @@
+/*
+ network-ssl.c : SSL support
+
+ Copyright (C) 2002 vjt
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "network.h"
+
+#ifdef HAVE_OPENSSL
+
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+/* ssl read */
+GIOError irssi_ssl_read(GIOChannel *, gchar *, guint, guint *);
+/* ssl write */
+GIOError irssi_ssl_write(GIOChannel *, gchar *, guint, guint*);
+/* ssl seek */
+GIOError irssi_ssl_seek(GIOChannel *, gint, GSeekType);
+/* ssl close */
+void irssi_ssl_close(GIOChannel *);
+/* ssl create watch */
+guint irssi_ssl_create_watch(GIOChannel *, gint, GIOCondition, GIOFunc, gpointer, GDestroyNotify);
+/* ssl free */
+void irssi_ssl_free(GIOChannel *);
+
+/* ssl i/o channel object */
+typedef struct
+{
+ GIOChannel pad;
+ gint fd;
+ GIOChannel *giochan;
+ SSL *ssl;
+ X509 *cert;
+} GIOSSLChannel;
+
+/* ssl function pointers */
+GIOFuncs irssi_ssl_channel_funcs =
+{
+ irssi_ssl_read,
+ irssi_ssl_write,
+ irssi_ssl_seek,
+ irssi_ssl_close,
+ irssi_ssl_create_watch,
+ irssi_ssl_free
+};
+
+SSL_CTX *ssl_ctx = NULL;
+
+#ifdef G_CAN_INLINE
+G_INLINE_FUNC
+#endif
+gint ssl_errno(gint e)
+{
+ switch(e)
+ {
+ case EINVAL:
+ return G_IO_ERROR_INVAL;
+ case EINTR:
+ case EAGAIN:
+ return G_IO_ERROR_AGAIN;
+ default:
+ return G_IO_ERROR_INVAL;
+ }
+ /*UNREACH*/
+ return -1;
+}
+
+gboolean irssi_ssl_cert_step(GIOSSLChannel *chan)
+{
+ gint err;
+ switch(err = SSL_do_handshake(chan->ssl))
+ {
+ case 1:
+ if(!(chan->cert = SSL_get_peer_certificate(chan->ssl)))
+ {
+ g_warning("SSL server supplied no certificate");
+ return G_IO_ERROR_INVAL;
+ }
+ return G_IO_ERROR_NONE;
+ default:
+ if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
+ return G_IO_ERROR_AGAIN;
+ return ssl_errno(errno);
+ }
+ /*UNREACH*/
+ return -1;
+}
+
+GIOError irssi_ssl_read(GIOChannel *handle, gchar *buf, guint len, guint *ret)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ gint err;
+
+ if(chan->cert == NULL)
+ {
+ gint cert_err = irssi_ssl_cert_step(chan);
+ if(cert_err != G_IO_ERROR_NONE)
+ return cert_err;
+ }
+
+ err = SSL_read(chan->ssl, buf, len);
+ if(err < 0)
+ {
+ *ret = 0;
+ if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
+ return G_IO_ERROR_AGAIN;
+ return ssl_errno(errno);
+ }
+ else
+ {
+ *ret = err;
+ return G_IO_ERROR_NONE;
+ }
+ /*UNREACH*/
+ return -1;
+}
+
+GIOError irssi_ssl_write(GIOChannel *handle, gchar *buf, guint len, guint *ret)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ gint err;
+
+ if(chan->cert == NULL)
+ {
+ gint cert_err = irssi_ssl_cert_step(chan);
+ if(cert_err != G_IO_ERROR_NONE)
+ return cert_err;
+ }
+
+
+ err = SSL_write(chan->ssl, (const char *)buf, len);
+ if(err < 0)
+ {
+ *ret = 0;
+ if(SSL_get_error(chan->ssl, err) == SSL_ERROR_WANT_READ)
+ return G_IO_ERROR_AGAIN;
+ return ssl_errno(errno);
+ }
+ else
+ {
+ *ret = err;
+ return G_IO_ERROR_NONE;
+ }
+ /*UNREACH*/
+ return -1;
+}
+
+GIOError irssi_ssl_seek(GIOChannel *handle, gint offset, GSeekType type)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ GIOError e;
+ e = g_io_channel_seek(chan->giochan, offset, type);
+ return (e == G_IO_ERROR_NONE) ? G_IO_ERROR_NONE : G_IO_ERROR_INVAL;
+}
+
+void irssi_ssl_close(GIOChannel *handle)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ g_io_channel_close(chan->giochan);
+}
+
+guint irssi_ssl_create_watch(GIOChannel *handle, gint priority, GIOCondition cond,
+ GIOFunc func, gpointer data, GDestroyNotify notify)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ return chan->giochan->funcs->io_add_watch(handle, priority, cond, func, data, notify);
+}
+
+void irssi_ssl_free(GIOChannel *handle)
+{
+ GIOSSLChannel *chan = (GIOSSLChannel *)handle;
+ g_io_channel_unref(chan->giochan);
+ SSL_free(chan->ssl);
+ g_free(chan);
+}
+
+gboolean irssi_ssl_init(void)
+{
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ if(!ssl_ctx)
+ {
+ g_error("Initialization of the SSL library failed");
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle)
+{
+ GIOSSLChannel *chan;
+ GIOChannel *gchan;
+ int err, fd;
+ SSL *ssl;
+ X509 *cert = NULL;
+
+ g_return_val_if_fail(handle != NULL, NULL);
+
+ if(!ssl_ctx && !irssi_ssl_init())
+ return NULL;
+
+ if(!(fd = g_io_channel_unix_get_fd(handle)))
+ return NULL;
+
+ if(!(ssl = SSL_new(ssl_ctx)))
+ {
+ g_warning("Failed to allocate SSL structure");
+ return NULL;
+ }
+
+ if(!(err = SSL_set_fd(ssl, fd)))
+ {
+ g_warning("Failed to associate socket to SSL stream");
+ return NULL;
+ }
+
+ if((err = SSL_connect(ssl)) <= 0)
+ {
+ switch(err = SSL_get_error(ssl, err))
+ {
+ case SSL_ERROR_SYSCALL:
+ if(errno == EINTR || errno == EAGAIN)
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ break;
+ default:
+ return NULL;
+ }
+ }
+ else if(!(cert = SSL_get_peer_certificate(ssl)))
+ {
+ g_warning("SSL server supplied no certificate");
+ return NULL;
+ }
+ else
+ X509_free(cert);
+
+ chan = g_new0(GIOSSLChannel, 1);
+ chan->fd = fd;
+ chan->giochan = handle;
+ chan->ssl = ssl;
+ chan->cert = cert;
+ g_io_channel_ref(handle);
+
+ gchan = (GIOChannel *)chan;
+ gchan->funcs = &irssi_ssl_channel_funcs;
+ g_io_channel_init(gchan);
+
+ return gchan;
+}
+
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
+{
+ GIOChannel *gret = net_connect_ip(ip, port, my_ip);
+ gret = irssi_ssl_get_iochannel(gret);
+ return gret;
+}
+
+#else /* HAVE_OPENSSL */
+
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip)
+{
+ g_warning("Connection failed: SSL support not enabled in this build.");
+ errno = ENOSYS;
+ return NULL;
+}
+
+#endif /* ! HAVE_OPENSSL */
diff --git a/src/core/network.h b/src/core/network.h
index 646bc05e..c6b08f9f 100644
--- a/src/core/network.h
+++ b/src/core/network.h
@@ -44,6 +44,8 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
/* Connect to socket */
GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
+/* Connect to socket with ip address and SSL*/
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip);
/* Connect to socket with ip address */
GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
/* Connect to named UNIX socket */
diff --git a/src/core/server-connect-rec.h b/src/core/server-connect-rec.h
index 3613759e..ce1e48a4 100644
--- a/src/core/server-connect-rec.h
+++ b/src/core/server-connect-rec.h
@@ -29,5 +29,6 @@ GIOChannel *connect_handle; /* connect using this handle */
unsigned int reconnection:1; /* we're trying to reconnect */
unsigned int no_autojoin_channels:1; /* don't autojoin any channels */
unsigned int unix_socket:1; /* Connect using named unix socket */
+unsigned int use_ssl:1; /* this connection uses SSL */
char *channels;
char *away_reason;
diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h
index f94ec9ae..d04fa1fe 100644
--- a/src/core/server-setup-rec.h
+++ b/src/core/server-setup-rec.h
@@ -18,5 +18,6 @@ unsigned int no_proxy:1;
unsigned int last_failed:1; /* if last connection attempt failed */
unsigned int banned:1; /* if we're banned from this server */
unsigned int dns_error:1; /* DNS said the host doesn't exist */
+unsigned int use_ssl:1; /* this connection uses SSL */
GHashTable *module_data;
diff --git a/src/core/servers-reconnect.c b/src/core/servers-reconnect.c
index 93067b2b..eee3e843 100644
--- a/src/core/servers-reconnect.c
+++ b/src/core/servers-reconnect.c
@@ -164,6 +164,8 @@ server_connect_copy_skeleton(SERVER_CONNECT_REC *src, int connect_info)
dest->away_reason = g_strdup(src->away_reason);
dest->no_autojoin_channels = src->no_autojoin_channels;
+ dest->use_ssl = src->use_ssl;
+
return dest;
}
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c
index d16f93a7..8ccfcc27 100644
--- a/src/core/servers-setup.c
+++ b/src/core/servers-setup.c
@@ -108,6 +108,8 @@ void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
if (sserver->password != NULL && conn->password == NULL)
conn->password = g_strdup(sserver->password);
+ conn->use_ssl = sserver->use_ssl;
+
signal_emit("server setup fill reconn", 2, conn, sserver);
}
@@ -391,6 +393,7 @@ static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
(g_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
rec->address = g_strdup(server);
rec->password = g_strdup(config_node_get_str(node, "password", NULL));
+ rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE);
rec->port = port;
rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
@@ -420,6 +423,7 @@ static void server_setup_save(SERVER_SETUP_REC *rec)
iconfig_node_set_int(node, "port", rec->port);
iconfig_node_set_str(node, "password", rec->password);
+ iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
iconfig_node_set_str(node, "own_host", rec->own_host);
iconfig_node_set_str(node, "family",
diff --git a/src/core/servers.c b/src/core/servers.c
index f26481d5..6bd843af 100644
--- a/src/core/servers.c
+++ b/src/core/servers.c
@@ -178,13 +178,18 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
server->connrec->own_ip4);
port = server->connrec->proxy != NULL ?
server->connrec->proxy_port : server->connrec->port;
- handle = net_connect_ip(ip, port, own_ip);
+ handle = server->connrec->use_ssl ?
+ net_connect_ip_ssl(ip, port, own_ip) :
+ net_connect_ip(ip, port, own_ip);
} else {
handle = net_connect_unix(unix_socket);
}
if (handle == NULL) {
/* failed */
+ if (server->connrec->use_ssl && errno == ENOSYS)
+ server->no_reconnect = TRUE;
+
server->connection_lost = TRUE;
server_connect_failed(server, g_strerror(errno));
} else {
diff --git a/src/core/session.c b/src/core/session.c
index 0f3d089c..004cd4f7 100644
--- a/src/core/session.c
+++ b/src/core/session.c
@@ -182,6 +182,8 @@ static void session_save_server(SERVER_REC *server, CONFIG_REC *config,
config_node_set_str(config, node, "password", server->connrec->password);
config_node_set_str(config, node, "nick", server->nick);
+ config_node_set_bool(config, node, "use_ssl", server->connrec->use_ssl);
+
handle = g_io_channel_unix_get_fd(net_sendbuffer_handle(server->handle));
config_node_set_int(config, node, "handle", handle);
diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c
index db068f3b..06f46777 100644
--- a/src/fe-common/core/fe-server.c
+++ b/src/fe-common/core/fe-server.c
@@ -144,6 +144,9 @@ static void cmd_server_add(const char *data)
else if (g_hash_table_lookup(optlist, "4"))
rec->family = AF_INET;
+ if (g_hash_table_lookup(optlist, "ssl"))
+ rec->use_ssl = TRUE;
+
if (g_hash_table_lookup(optlist, "auto")) rec->autoconnect = TRUE;
if (g_hash_table_lookup(optlist, "noauto")) rec->autoconnect = FALSE;
if (g_hash_table_lookup(optlist, "proxy")) rec->no_proxy = FALSE;
@@ -327,7 +330,7 @@ void fe_server_init(void)
command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect);
command_bind("server add", NULL, (SIGNAL_FUNC) cmd_server_add);
command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove);
- command_set_options("server add", "4 6 auto noauto proxy noproxy -host -port");
+ command_set_options("server add", "4 6 ssl auto noauto proxy noproxy -host -port");
signal_add("server looking", (SIGNAL_FUNC) sig_server_looking);
signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting);
diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c
index 742b4100..a7977c03 100644
--- a/src/fe-common/irc/fe-events-numeric.c
+++ b/src/fe-common/irc/fe-events-numeric.c
@@ -917,6 +917,7 @@ void fe_events_numeric_init(void)
signal_add("event 378", (SIGNAL_FUNC) event_whois_realhost);
signal_add("event 377", (SIGNAL_FUNC) event_whois_usermode);
signal_add("event 320", (SIGNAL_FUNC) event_whois_special);
+ signal_add("event 275", (SIGNAL_FUNC) event_whois_special);
signal_add("event 314", (SIGNAL_FUNC) event_whowas);
signal_add("event 317", (SIGNAL_FUNC) event_whois_idle);
signal_add("event 318", (SIGNAL_FUNC) event_end_of_whois);
@@ -1002,6 +1003,7 @@ void fe_events_numeric_deinit(void)
signal_remove("event 378", (SIGNAL_FUNC) event_whois_realhost);
signal_remove("event 377", (SIGNAL_FUNC) event_whois_usermode);
signal_remove("event 320", (SIGNAL_FUNC) event_whois_special);
+ signal_remove("event 275", (SIGNAL_FUNC) event_whois_special);
signal_remove("event 314", (SIGNAL_FUNC) event_whowas);
signal_remove("event 317", (SIGNAL_FUNC) event_whois_idle);
signal_remove("event 318", (SIGNAL_FUNC) event_end_of_whois);