]> jfr.im git - solanum.git/blobdiff - ircd/s_serv.c
msgbuf: Fix remote crash vulnerability due to malformed message tag.
[solanum.git] / ircd / s_serv.c
index 6335c5767a66249c34c39e4d142741c435102bce..178622baf9e3c8279dcc73c227cb3782a35750a9 100644 (file)
 #include "capability.h"
 #include "s_assert.h"
 
-#ifndef INADDR_NONE
-#define INADDR_NONE ((unsigned int) 0xffffffff)
-#endif
-
 int MaxConnectionCount = 1;
 int MaxClientCount = 1;
 int refresh_user_links = 0;
@@ -151,6 +147,7 @@ init_builtin_capabs(void)
 
 static CNCB serv_connect_callback;
 static CNCB serv_connect_ssl_callback;
+static SSL_OPEN_CB serv_connect_ssl_open_callback;
 
 /*
  * hunt_server - Do the basic thing in delivering the message (command)
@@ -363,6 +360,8 @@ check_server(const char *name, struct Client *client_p)
 
        RB_DLINK_FOREACH(ptr, server_conf_list.head)
        {
+               struct rb_sockaddr_storage client_addr;
+
                tmp_p = ptr->data;
 
                if(ServerConfIllegal(tmp_p))
@@ -373,10 +372,19 @@ check_server(const char *name, struct Client *client_p)
 
                name_matched = true;
 
-               /* XXX: Fix me for IPv6 */
-               /* XXX sockhost is the IPv4 ip as a string */
-               if(match(tmp_p->host, client_p->host) ||
-                  match(tmp_p->host, client_p->sockhost))
+               if(rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&client_addr) <= 0)
+                       SET_SS_FAMILY(&client_addr, AF_UNSPEC);
+
+               if((tmp_p->connect_host && match(tmp_p->connect_host, client_p->host))
+                       || (GET_SS_FAMILY(&client_addr) == GET_SS_FAMILY(&tmp_p->connect4)
+                               && comp_with_mask_sock((struct sockaddr *)&client_addr,
+                                       (struct sockaddr *)&tmp_p->connect4, 32))
+#ifdef RB_IPV6
+                       || (GET_SS_FAMILY(&client_addr) == GET_SS_FAMILY(&tmp_p->connect6)
+                               && comp_with_mask_sock((struct sockaddr *)&client_addr,
+                                       (struct sockaddr *)&tmp_p->connect6, 128))
+#endif
+                       )
                {
                        host_matched = true;
 
@@ -818,7 +826,7 @@ server_estab(struct Client *client_p)
                           EmptyString(server_p->spasswd) ? "*" : server_p->spasswd, TS_CURRENT, me.id);
 
                /* pass info to new server */
-               send_capabilities(client_p, default_server_capabs
+               send_capabilities(client_p, default_server_capabs | CAP_MASK
                                  | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
                                  | (ServerConfTb(server_p) ? CAP_TB : 0));
 
@@ -1010,7 +1018,8 @@ int
 serv_connect(struct server_conf *server_p, struct Client *by)
 {
        struct Client *client_p;
-       struct rb_sockaddr_storage myipnum;
+       struct rb_sockaddr_storage sa_connect;
+       struct rb_sockaddr_storage sa_bind;
        char note[HOSTLEN + 10];
        rb_fde_t *F;
 
@@ -1018,8 +1027,42 @@ serv_connect(struct server_conf *server_p, struct Client *by)
        if(server_p == NULL)
                return 0;
 
+       SET_SS_FAMILY(&sa_connect, AF_UNSPEC);
+       SET_SS_FAMILY(&sa_bind, AF_UNSPEC);
+
+#ifdef RB_IPV6
+       if(server_p->aftype != AF_UNSPEC
+               && GET_SS_FAMILY(&server_p->connect4) == AF_INET
+               && GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
+       {
+               if(rand() % 2 == 0)
+               {
+                       sa_connect = server_p->connect4;
+                       sa_bind = server_p->bind4;
+               }
+               else
+               {
+                       sa_connect = server_p->connect6;
+                       sa_bind = server_p->bind6;
+               }
+       }
+       else if(server_p->aftype == AF_INET || GET_SS_FAMILY(&server_p->connect4) == AF_INET)
+#endif
+       {
+               sa_connect = server_p->connect4;
+               sa_bind = server_p->bind4;
+       }
+#ifdef RB_IPV6
+       else if(server_p->aftype == AF_INET6 || GET_SS_FAMILY(&server_p->connect6) == AF_INET6)
+       {
+               sa_connect = server_p->connect6;
+               sa_bind = server_p->bind6;
+       }
+#endif
+
        /* log */
-       rb_inet_ntop_sock((struct sockaddr *)&server_p->my_ipnum, buf, sizeof(buf));
+       buf[0] = 0;
+       rb_inet_ntop_sock((struct sockaddr *)&sa_connect, buf, sizeof(buf));
        ilog(L_SERVER, "Connect to *[%s] @%s", server_p->name, buf);
 
        /*
@@ -1037,7 +1080,12 @@ serv_connect(struct server_conf *server_p, struct Client *by)
        }
 
        /* create a socket for the server connection */
-       if((F = rb_socket(GET_SS_FAMILY(&server_p->my_ipnum), SOCK_STREAM, 0, NULL)) == NULL)
+       if(GET_SS_FAMILY(&sa_connect) == AF_UNSPEC)
+       {
+               ilog_error("unspecified socket address family");
+               return 0;
+       }
+       else if((F = rb_socket(GET_SS_FAMILY(&sa_connect), SOCK_STREAM, 0, NULL)) == NULL)
        {
                ilog_error("opening a stream socket");
                return 0;
@@ -1052,11 +1100,14 @@ serv_connect(struct server_conf *server_p, struct Client *by)
 
        /* Copy in the server, hostname, fd */
        rb_strlcpy(client_p->name, server_p->name, sizeof(client_p->name));
-       rb_strlcpy(client_p->host, server_p->host, sizeof(client_p->host));
+       if(server_p->connect_host)
+               rb_strlcpy(client_p->host, server_p->connect_host, sizeof(client_p->host));
+       else
+               rb_strlcpy(client_p->host, buf, sizeof(client_p->host));
        rb_strlcpy(client_p->sockhost, buf, sizeof(client_p->sockhost));
        client_p->localClient->F = F;
        /* shove the port number into the sockaddr */
-       SET_SS_PORT(&server_p->my_ipnum, htons(server_p->port));
+       SET_SS_PORT(&sa_connect, htons(server_p->port));
 
        /*
         * Set up the initial server evilness, ripped straight from
@@ -1084,65 +1135,28 @@ serv_connect(struct server_conf *server_p, struct Client *by)
         */
        make_server(client_p);
        if(by && IsClient(by))
-               strcpy(client_p->serv->by, by->name);
+               rb_strlcpy(client_p->serv->by, by->name, sizeof(client_p->serv->by));
        else
                strcpy(client_p->serv->by, "AutoConn.");
 
        SetConnecting(client_p);
        rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
 
-       if(ServerConfVhosted(server_p))
+       if(GET_SS_FAMILY(&sa_bind) == AF_UNSPEC)
        {
-               memcpy(&myipnum, &server_p->my_ipnum, sizeof(myipnum));
-               SET_SS_FAMILY(&myipnum, GET_SS_FAMILY(&server_p->my_ipnum));
-               SET_SS_PORT(&myipnum, 0);
-
-       }
-       else if(GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET && ServerInfo.specific_ipv4_vhost)
-       {
-               memcpy(&myipnum, &ServerInfo.ip, sizeof(myipnum));
-               SET_SS_FAMILY(&myipnum, AF_INET);
-               SET_SS_PORT(&myipnum, 0);
-               SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in));
-       }
-
+               if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind4))
+                       sa_bind = ServerInfo.bind4;
 #ifdef RB_IPV6
-       else if((GET_SS_FAMILY(&server_p->my_ipnum) == AF_INET6) && ServerInfo.specific_ipv6_vhost)
-       {
-               memcpy(&myipnum, &ServerInfo.ip6, sizeof(myipnum));
-               SET_SS_FAMILY(&myipnum, AF_INET6);
-               SET_SS_PORT(&myipnum, 0);
-               SET_SS_LEN(&myipnum, sizeof(struct sockaddr_in6));
-       }
+               if(GET_SS_FAMILY(&sa_connect) == GET_SS_FAMILY(&ServerInfo.bind6))
+                       sa_bind = ServerInfo.bind6;
 #endif
-       else
-       {
-               if(ServerConfSSL(server_p))
-               {
-                       rb_connect_tcp(client_p->localClient->F,
-                                      (struct sockaddr *)&server_p->my_ipnum, NULL, 0,
-                                      serv_connect_ssl_callback, client_p,
-                                      ConfigFileEntry.connect_timeout);
-               }
-               else
-                       rb_connect_tcp(client_p->localClient->F,
-                                      (struct sockaddr *)&server_p->my_ipnum, NULL, 0,
-                                      serv_connect_callback, client_p,
-                                      ConfigFileEntry.connect_timeout);
-
-               return 1;
        }
-       if(ServerConfSSL(server_p))
-               rb_connect_tcp(client_p->localClient->F, (struct sockaddr *)&server_p->my_ipnum,
-                              (struct sockaddr *)&myipnum,
-                              GET_SS_LEN(&myipnum), serv_connect_ssl_callback, client_p,
-                              ConfigFileEntry.connect_timeout);
-       else
-               rb_connect_tcp(client_p->localClient->F, (struct sockaddr *)&server_p->my_ipnum,
-                              (struct sockaddr *)&myipnum,
-                              GET_SS_LEN(&myipnum), serv_connect_callback, client_p,
-                              ConfigFileEntry.connect_timeout);
 
+       rb_connect_tcp(client_p->localClient->F,
+               (struct sockaddr *)&sa_connect,
+               GET_SS_FAMILY(&sa_bind) == AF_UNSPEC ? NULL : (struct sockaddr *)&sa_bind,
+               ServerConfSSL(server_p) ? serv_connect_ssl_callback : serv_connect_callback,
+               client_p, ConfigFileEntry.connect_timeout);
        return 1;
 }
 
@@ -1166,6 +1180,7 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data)
 
        }
        client_p->localClient->F = xF[0];
+       client_p->localClient->ssl_callback = serv_connect_ssl_open_callback;
 
        client_p->localClient->ssl_ctl = start_ssld_connect(F, xF[1], connid_get(client_p));
        if(!client_p->localClient->ssl_ctl)
@@ -1174,7 +1189,13 @@ serv_connect_ssl_callback(rb_fde_t *F, int status, void *data)
                return;
        }
        SetSSL(client_p);
-       serv_connect_callback(client_p->localClient->F, RB_OK, client_p);
+}
+
+static int
+serv_connect_ssl_open_callback(struct Client *client_p, int status)
+{
+       serv_connect_callback(client_p->localClient->F, status, client_p);
+       return 1; /* suppress default exit_client handler for status != RB_OK */
 }
 
 /*
@@ -1218,7 +1239,7 @@ serv_connect_callback(rb_fde_t *F, int status, void *data)
                /* COMM_ERR_TIMEOUT wont have an errno associated with it,
                 * the others will.. --fl
                 */
-               if(status == RB_ERR_TIMEOUT)
+               if(status == RB_ERR_TIMEOUT || status == RB_ERROR_SSL)
                {
                        sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
                                        "Error connecting to %s[%s]: %s",
@@ -1256,6 +1277,18 @@ serv_connect_callback(rb_fde_t *F, int status, void *data)
                return;
        }
 
+       if(server_p->certfp && (!client_p->certfp || rb_strcasecmp(server_p->certfp, client_p->certfp) != 0))
+       {
+               sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL,
+                    "Connection to %s has invalid certificate fingerprint %s",
+                    client_p->name, client_p->certfp);
+               ilog(L_SERVER, "Access denied, invalid certificate fingerprint %s from %s",
+                    client_p->certfp, log_client_name(client_p, SHOW_IP));
+
+               exit_client(client_p, client_p, &me, "Invalid fingerprint.");
+               return;
+       }
+
        /* Next, send the initial handshake */
        SetHandshake(client_p);
 
@@ -1264,7 +1297,7 @@ serv_connect_callback(rb_fde_t *F, int status, void *data)
                   EmptyString(server_p->spasswd) ? "*" : server_p->spasswd, TS_CURRENT, me.id);
 
        /* pass my info to the new server */
-       send_capabilities(client_p, default_server_capabs
+       send_capabilities(client_p, default_server_capabs | CAP_MASK
                          | (ServerConfCompressed(server_p) ? CAP_ZIP_SUPPORTED : 0)
                          | (ServerConfTb(server_p) ? CAP_TB : 0));