X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/4d5a902f0888f36c21597874373bc3fcd8ef9862..a4db1d4784bfda4e2fa7e4f7dd1899c90efe8bd3:/ircd/match.c diff --git a/ircd/match.c b/ircd/match.c index 165baeab..368ee353 100644 --- a/ircd/match.c +++ b/ircd/match.c @@ -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,