]> jfr.im git - solanum.git/blobdiff - ircd/match.c
Correct order of chunking and encoding steps.
[solanum.git] / ircd / match.c
index 165baeabc083c59d90b0033e7127bf8b76d2591f..368ee353834ff48cdd6a98175d26f14b19459dd6 100644 (file)
@@ -22,6 +22,7 @@
 #include "client.h"
 #include "ircd.h"
 #include "match.h"
+#include "s_conf.h"
 #include "s_assert.h"
 
 /*
@@ -104,6 +105,31 @@ int match(const char *mask, const char *name)
        }
 }
 
+/* Reorder runs of [?*] in mask to the form  ``**...??...'' */
+void
+match_arrange_stars(char *mask)
+{
+       char *swap = NULL;
+
+       for (char *p = mask; *p != '\0'; p++)
+       {
+               switch (*p)
+               {
+               case '*':
+                       if (swap == NULL) break;
+                       *swap++ = '*';
+                       *p = '?';
+                       break;
+               case '?':
+                       if (swap == NULL) swap = p;
+                       break;
+               default:
+                       swap = NULL;
+                       break;
+               }
+       }
+}
+
 /** Check a mask against a mask.
  * This test checks using traditional IRC wildcards only: '*' means
  * match zero or more characters of any type; '?' means match exactly
@@ -115,15 +141,23 @@ int match(const char *mask, const char *name)
  * @param[in] name New wildcard-containing mask.
  * @return 1 if \a name is equal to or more specific than \a mask, 0 otherwise.
  */
-int mask_match(const char *mask, const char *name)
+int mask_match(const char *mask_, const char *name)
 {
+       static char mask[BUFSIZE];
        const char *m = mask, *n = name;
        const char *m_tmp = mask, *n_tmp = name;
+       size_t len;
        int star_p;
 
-       s_assert(mask != NULL);
+       s_assert(mask_ != NULL);
        s_assert(name != NULL);
 
+       len = rb_strlcpy(mask, mask_, sizeof mask);
+       s_assert(len < sizeof mask);
+       (void) len; /* for NDEBUG */
+
+       match_arrange_stars(mask);
+
        for (;;)
        {
                switch (*m)
@@ -146,6 +180,7 @@ int mask_match(const char *mask, const char *name)
                                  else if (*m == '?')
                                  {
                                          /* changed for mask_match() */
+                                         while (star_p && *n == '*') n++;
                                          if (*n == '*' || !*n)
                                                  goto backtrack;
                                          n++;
@@ -313,7 +348,7 @@ int comp_with_mask(void *addr, void *dest, unsigned int mask)
        if (memcmp(addr, dest, mask / 8) == 0)
        {
                int n = mask / 8;
-               int m = ((-1) << (8 - (mask % 8)));
+               unsigned char m = (0xFF << (8 - (mask % 8)));
                if (mask % 8 == 0 || (((unsigned char *) addr)[n] & m) == (((unsigned char *) dest)[n] & m))
                {
                        return (1);
@@ -332,14 +367,12 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, unsigned i
                iaddr = &((struct sockaddr_in *)(void *)addr)->sin_addr;
                idest = &((struct sockaddr_in *)(void *)dest)->sin_addr;
        }
-#ifdef RB_IPV6
        else
        {
                iaddr = &((struct sockaddr_in6 *)(void *)addr)->sin6_addr;
                idest = &((struct sockaddr_in6 *)(void *)dest)->sin6_addr;
 
        }
-#endif
 
        return (comp_with_mask(iaddr, idest, mask));
 }
@@ -371,7 +404,6 @@ int match_ips(const char *s1, const char *s2)
        if (cidrlen <= 0)
                return 0;
 
-#ifdef RB_IPV6
        if (strchr(mask, ':') && strchr(address, ':'))
        {
                if (cidrlen > 128)
@@ -381,9 +413,7 @@ int match_ips(const char *s1, const char *s2)
                ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
                maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
        }
-       else
-#endif
-       if (!strchr(mask, ':') && !strchr(address, ':'))
+       else if (!strchr(mask, ':') && !strchr(address, ':'))
        {
                if (cidrlen > 32)
                        return 0;
@@ -447,7 +477,6 @@ int match_cidr(const char *s1, const char *s2)
        if (cidrlen <= 0)
                return 0;
 
-#ifdef RB_IPV6
        if (strchr(ip, ':') && strchr(ipmask, ':'))
        {
                if (cidrlen > 128)
@@ -457,9 +486,7 @@ int match_cidr(const char *s1, const char *s2)
                ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
                maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
        }
-       else
-#endif
-       if (!strchr(ip, ':') && !strchr(ipmask, ':'))
+       else if (!strchr(ip, ':') && !strchr(ipmask, ':'))
        {
                if (cidrlen > 32)
                        return 0;
@@ -594,6 +621,82 @@ int ircncmp(const char *s1, const char *s2, int n)
        return (res);
 }
 
+void matchset_for_client(struct Client *who, struct matchset *m)
+{
+       bool hide_ip = IsIPSpoof(who) || (!ConfigChannel.ip_bans_through_vhost && IsDynSpoof(who));
+       unsigned hostn = 0;
+       unsigned ipn = 0;
+
+       struct sockaddr_in ip4;
+
+       sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->host);
+
+       if (!hide_ip)
+       {
+               sprintf(m->ip[ipn++], "%s!%s@%s", who->name, who->username, who->sockhost);
+       }
+
+       if (who->localClient->mangledhost != NULL)
+       {
+               /* if host mangling mode enabled, also check their real host */
+               if (!strcmp(who->host, who->localClient->mangledhost))
+               {
+                       sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->orighost);
+               }
+               /* if host mangling mode not enabled and no other spoof,
+                * also check the mangled form of their host */
+               else if (!IsDynSpoof(who))
+               {
+                       sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
+               }
+       }
+       if (!hide_ip && GET_SS_FAMILY(&who->localClient->ip) == AF_INET6 &&
+                       rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
+       {
+               int n = sprintf(m->ip[ipn], "%s!%s@", who->name, who->username);
+               rb_inet_ntop_sock((struct sockaddr *)&ip4,
+                               m->ip[ipn] + n, sizeof m->ip[ipn] - n);
+               ipn++;
+       }
+
+       for (int i = hostn; i < ARRAY_SIZE(m->host); i++)
+       {
+               m->host[i][0] = '\0';
+       }
+       for (int i = ipn; i < ARRAY_SIZE(m->ip); i++)
+       {
+               m->ip[i][0] = '\0';
+       }
+}
+
+bool client_matches_mask(struct Client *who, const char *mask)
+{
+       static struct matchset ms;
+       matchset_for_client(who, &ms);
+       return matches_mask(&ms, mask);
+}
+
+bool matches_mask(const struct matchset *m, const char *mask)
+{
+       for (int i = 0; i < ARRAY_SIZE(m->host); i++)
+       {
+               if (m->host[i][0] == '\0')
+                       break;
+               if (match(mask, m->host[i]))
+                       return true;
+       }
+       for (int i = 0; i < ARRAY_SIZE(m->ip); i++)
+       {
+               if (m->ip[i][0] == '\0')
+                       break;
+               if (match(mask, m->ip[i]))
+                       return true;
+               if (match_cidr(mask, m->ip[i]))
+                       return true;
+       }
+       return false;
+}
+
 const unsigned char irctolower_tab[] = {
        0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
        0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
@@ -670,7 +773,7 @@ const unsigned char irctoupper_tab[] = {
  * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed
  * for channel names
  */
-const unsigned int CharAttrs[] = {
+unsigned int CharAttrs[] = {
 /* 0  */ CNTRL_C,
 /* 1  */ CNTRL_C | CHAN_C | NONEOS_C,
 /* 2  */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,