]> jfr.im git - solanum.git/blobdiff - ircd/listener.c
ircd/listener: return a fatal TLS alert for early rejected TLS clients
[solanum.git] / ircd / listener.c
index 2cd2e8a2e5770dc3e1be09f32cb1612f48a2fbfe..02b6dabdc6809fe77b29c0b7e0f4c48230055406 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
  *  Copyright (C) 1996-2002 Hybrid Development Team
  *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2021 Ariadne Conill
  *
  *  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
@@ -43,7 +44,7 @@
 #include "s_assert.h"
 #include "logger.h"
 
-static struct Listener *ListenerPollList = NULL;
+static rb_dlink_list listener_list = {};
 static int accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data);
 static void accept_callback(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t addrlen, void *data);
 static SSL_OPEN_CB accept_sslcallback;
@@ -57,7 +58,6 @@ make_listener(struct rb_sockaddr_storage *addr)
        listener->F = NULL;
 
        memcpy(&listener->addr, addr, sizeof(listener->addr));
-       listener->next = NULL;
        return listener;
 }
 
@@ -67,25 +67,8 @@ free_listener(struct Listener *listener)
        s_assert(NULL != listener);
        if(listener == NULL)
                return;
-       /*
-        * remove from listener list
-        */
-       if(listener == ListenerPollList)
-               ListenerPollList = listener->next;
-       else
-       {
-               struct Listener *prev = ListenerPollList;
-               for (; prev; prev = prev->next)
-               {
-                       if(listener == prev->next)
-                       {
-                               prev->next = listener->next;
-                               break;
-                       }
-               }
-       }
 
-       /* free */
+       rb_dlinkDelete(&listener->lnode, &listener_list);
        rb_free(listener);
 }
 
@@ -122,10 +105,12 @@ get_listener_name(const struct Listener *listener)
 void
 show_ports(struct Client *source_p)
 {
-       struct Listener *listener = 0;
+       rb_dlink_node *n;
 
-       for (listener = ListenerPollList; listener; listener = listener->next)
+       RB_DLINK_FOREACH(n, listener_list.head)
        {
+               struct Listener *listener = n->data;
+
                sendto_one_numeric(source_p, RPL_STATSPLINE,
                           form_str(RPL_STATSPLINE), 'P',
                           get_listener_port(listener),
@@ -185,7 +170,7 @@ inetport(struct Listener *listener)
        }
 
        if (F == NULL) {
-               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
                                "Cannot open socket for listener on %s port %d",
                                listener->sctp ? "SCTP" : "TCP",
                                get_listener_port(listener));
@@ -203,7 +188,7 @@ inetport(struct Listener *listener)
 
        if (ret) {
                errstr = strerror(rb_get_sockerr(F));
-               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
                                "Cannot bind for listener on %s port %d: %s",
                                listener->sctp ? "SCTP" : "TCP",
                                get_listener_port(listener), errstr);
@@ -217,7 +202,7 @@ inetport(struct Listener *listener)
        if(rb_listen(F, SOMAXCONN, listener->defer_accept))
        {
                errstr = strerror(rb_get_sockerr(F));
-               sendto_realops_snomask(SNO_GENERAL, L_ALL,
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
                                "Cannot listen() for listener on %s port %d: %s",
                                listener->sctp ? "SCTP" : "TCP",
                                get_listener_port(listener), errstr);
@@ -237,10 +222,12 @@ inetport(struct Listener *listener)
 static struct Listener *
 find_listener(struct rb_sockaddr_storage *addr, int sctp)
 {
-       struct Listener *listener = NULL;
+       rb_dlink_node *n;
        struct Listener *last_closed = NULL;
 
-       for (listener = ListenerPollList; listener; listener = listener->next) {
+       RB_DLINK_FOREACH(n, listener_list.head) {
+               struct Listener *listener = n->data;
+
                if (listener->sctp != sctp)
                        continue;
 
@@ -353,8 +340,7 @@ add_tcp_listener(int port, const char *vhost_ip, int family, int ssl, int defer_
                        return;
        } else {
                listener = make_listener(vaddr);
-               listener->next = ListenerPollList;
-               ListenerPollList = listener;
+               rb_dlinkAdd(listener, &listener->lnode, &listener_list);
        }
 
        listener->F = NULL;
@@ -424,8 +410,7 @@ add_sctp_listener(int port, const char *vhost_ip1, const char *vhost_ip2, int ss
                        return;
        } else {
                listener = make_listener(vaddr);
-               listener->next = ListenerPollList;
-               ListenerPollList = listener;
+               rb_dlinkAdd(listener, &listener->lnode, &listener_list);
        }
 
        listener->F = NULL;
@@ -468,18 +453,21 @@ close_listener(struct Listener *listener)
  * close_listeners - close and free all listeners that are not being used
  */
 void
-close_listeners()
+close_listeners(void)
 {
-       struct Listener *listener;
-       struct Listener *listener_next = 0;
+       rb_dlink_node *n, *tn;
+
        /*
         * close all 'extra' listening ports we have
         */
-       for (listener = ListenerPollList; listener; listener = listener_next)
+       RB_DLINK_FOREACH_SAFE(n, tn, listener_list.head)
        {
-               listener_next = listener->next;
+               struct Listener *listener = n->data;
+
                close_listener(listener);
        }
+
+       rb_close_pending_fds();
 }
 
 /*
@@ -541,6 +529,14 @@ add_connection(struct Listener *listener, rb_fde_t *F, struct sockaddr *sai, str
                SetSSL(new_client);
                SetSecure(new_client);
        }
+       else
+       {
+               struct ConfItem *aconf;
+               aconf = find_conf_by_address(NULL, NULL, NULL, sai, CONF_SECURE | 1, sai->sa_family, NULL, NULL);
+
+               if (aconf != NULL)
+                       SetSecure(new_client);
+       }
 
        if (listener->wsock)
        {
@@ -576,8 +572,6 @@ accept_sslcallback(struct Client *client_p, int status)
        return 0; /* use default handler if status != RB_OK */
 }
 
-static const char *toofast = "ERROR :Reconnecting too fast, throttled.\r\n";
-
 static int
 accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, void *data)
 {
@@ -587,6 +581,19 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
        static time_t last_oper_notice = 0;
        int len;
 
+       static const char *allinuse = "ERROR :All connections in use\r\n";
+       static const char *toofast = "ERROR :Reconnecting too fast, throttled.\r\n";
+
+       static const unsigned char ssldeniederrcode[] = {
+               // SSLv3.0 Fatal Alert: Access Denied
+               0x15, 0x03, 0x00, 0x00, 0x02, 0x02, 0x31
+       };
+
+       static const unsigned char sslinternalerrcode[] = {
+               // SSLv3.0 Fatal Alert: Internal Error
+               0x15, 0x03, 0x00, 0x00, 0x02, 0x02, 0x50
+       };
+
        if(listener->ssl && (!ircd_ssl_ok || !get_ssld_count()))
        {
                rb_close(F);
@@ -601,13 +608,17 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
                 */
                if((last_oper_notice + 20) <= rb_current_time())
                {
-                       sendto_realops_snomask(SNO_GENERAL, L_ALL,
+                       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
                                             "All connections in use. (%s)",
                                             get_listener_name(listener));
                        last_oper_notice = rb_current_time();
                }
 
-               rb_write(F, "ERROR :All connections in use\r\n", 31);
+               if(listener->ssl)
+                       rb_write(F, sslinternalerrcode, sizeof(sslinternalerrcode));
+               else
+                       rb_write(F, allinuse, strlen(allinuse));
+
                rb_close(F);
                return 0;
        }
@@ -622,7 +633,11 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
        {
                ServerStats.is_ref++;
 
-               if(ConfigFileEntry.dline_with_reason)
+               if(listener->ssl)
+               {
+                       rb_write(F, ssldeniederrcode, sizeof(ssldeniederrcode));
+               }
+               else if(ConfigFileEntry.dline_with_reason)
                {
                        len = snprintf(buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", get_user_ban_reason(aconf));
                        if (len >= (int)(sizeof(buf)-1))
@@ -631,16 +646,19 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
                                buf[sizeof(buf) - 2] = '\n';
                                buf[sizeof(buf) - 1] = '\0';
                        }
+                       rb_write(F, buf, strlen(buf));
                }
                else
+               {
                        strcpy(buf, "ERROR :You have been D-lined.\r\n");
+                       rb_write(F, buf, strlen(buf));
+               }
 
-               rb_write(F, buf, strlen(buf));
                rb_close(F);
                return 0;
        }
 
-       if(check_reject(F, addr)) {
+       if(check_reject(F, addr, listener->ssl)) {
                /* Reject the connection without closing the socket
                 * because it is now on the delay_exit list. */
                return 0;
@@ -648,7 +666,11 @@ accept_precallback(rb_fde_t *F, struct sockaddr *addr, rb_socklen_t addrlen, voi
 
        if(throttle_add(addr))
        {
-               rb_write(F, toofast, strlen(toofast));
+               if(listener->ssl)
+                       rb_write(F, ssldeniederrcode, sizeof(ssldeniederrcode));
+               else
+                       rb_write(F, toofast, strlen(toofast));
+
                rb_close(F);
                return 0;
        }