| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- /*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999 - 2002 Eggheads Development Team
- * Copyright (C) 2002 - 2008 Bryan Drewery
- *
- * 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.
- */
- /*
- * match.c
- * wildcard matching functions
- *
- *
- * Once this code was working, I added support for % so that I could
- * use the same code both in Eggdrop and in my IrcII client.
- * Pleased with this, I added the option of a fourth wildcard, ~,
- * which matches varying amounts of whitespace (at LEAST one space,
- * though, for sanity reasons).
- *
- * This code would not have been possible without the prior work and
- * suggestions of various sourced. Special thanks to Robey for
- * all his time/help tracking down bugs and his ever-helpful advice.
- *
- * 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
- *
- * Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
- * crf@cfox.bchs.uh.edu
- *
- * I hereby release this code into the public domain
- *
- */
- #include "common.h"
- #include "match.h"
- #include "misc.h"
- #include "rfc1459.h"
- #include "socket.h"
- #define QUOTE '\\' /* quoting character (overrides wildcards) */
- #define WILDS '*' /* matches 0 or more characters (including spaces) */
- #define WILDP '%' /* matches 0 or more non-space characters */
- #define WILDQ '?' /* matches ecactly one character */
- #define WILDT '~' /* matches 1 or more spaces */
- #define NOMATCH 0
- #define MATCH (match+sofar)
- #define PERMATCH (match+saved+sofar)
- /* binds matching */
- int _wild_match_per(register unsigned char *m, register unsigned char *n)
- {
- /* null strings should never match */
- if ((m == 0) || (n == 0) || (!*n))
- return NOMATCH;
- unsigned char *ma = m, *lsm = NULL, *lsn = NULL, *lpm = NULL, *lpn = NULL;
- int match = 1, saved = 0, space;
- register int sofar = 0;
- while (*n) {
- if (*m == WILDT) { /* Match >=1 space */
- space = 0; /* Don't need any spaces */
- do {
- m++;
- space++;
- } /* Tally 1 more space ... */
- while ((*m == WILDT) || (*m == ' ')); /* for each space or ~ */
- sofar += space; /* Each counts as exact */
- while (*n == ' ') {
- n++;
- space--;
- } /* Do we have enough? */
- if (space <= 0)
- continue; /* Had enough spaces! */
- }
- /* Do the fallback */
- else {
- switch (*m) {
- case 0:
- do
- m--; /* Search backwards */
- while ((m > ma) && (*m == '?')); /* For first non-? char */
- if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
- return PERMATCH; /* nonquoted * = match */
- break;
- case WILDP:
- while (*(++m) == WILDP)
- ; /* Zap redundant %s */
- if (*m != WILDS) { /* Don't both if next=* */
- if (*n != ' ') { /* WILDS can't match ' ' */
- lpm = m;
- lpn = n; /* Save '%' fallback spot */
- saved += sofar;
- sofar = 0; /* And save tally count */
- }
- continue; /* Done with '%' */
- }
- /* FALL THROUGH */
- case WILDS:
- do
- m++; /* Zap redundant wilds */
- while ((*m == WILDS) || (*m == WILDP));
- lsm = m;
- lsn = n;
- lpm = 0; /* Save '*' fallback spot */
- match += (saved + sofar); /* Save tally count */
- saved = sofar = 0;
- continue; /* Done with '*' */
- case WILDQ:
- m++;
- n++;
- continue; /* Match one char */
- case QUOTE:
- m++; /* Handle quoting */
- }
- if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching */
- m++;
- n++;
- sofar++;
- continue; /* Tally the match */
- }
- #ifdef WILDT
- }
- #endif
- if (lpm) { /* Try to fallback on '%' */
- n = ++lpn;
- m = lpm;
- sofar = 0; /* Restore position */
- if ((*n | 32) == 32)
- lpm = 0; /* Can't match 0 or ' ' */
- continue; /* Next char, please */
- }
- if (lsm) { /* Try to fallback on '*' */
- n = ++lsn;
- m = lsm; /* Restore position */
- saved = sofar = 0;
- continue; /* Next char, please */
- }
- return NOMATCH; /* No fallbacks=No match */
- }
- while ((*m == WILDS) || (*m == WILDP))
- m++; /* Zap leftover %s & *s */
- return (*m) ? NOMATCH : PERMATCH; /* End of both = match */
- }
- /* general/host matching */
- int _wild_match(register unsigned char *m, register unsigned char *n)
- {
- unsigned char *ma = m, *na = n;
- /* null strings should never match */
- if ((ma == 0) || (na == 0) || (!*ma) || (!*na))
- return NOMATCH;
- unsigned char *lsm = NULL, *lsn = NULL;
- int match = 1;
- register int sofar = 0;
- /* find the end of each string */
- while (*(++m))
- ;
- m--;
- while (*(++n))
- ;
- n--;
- while (n >= na) {
- /* If the mask runs out of chars before the string, fall back on
- * a wildcard or fail. */
- if (m < ma) {
- if (lsm) {
- n = --lsn;
- m = lsm;
- if (n < na) lsm = 0;
- sofar = 0;
- }
- else return NOMATCH;
- }
- switch (*m) {
- case WILDS: /* Matches anything */
- do
- m--; /* Zap redundant wilds */
- while ((m >= ma) && (*m == WILDS));
- lsm = m;
- lsn = n;
- match += sofar;
- sofar = 0; /* Update fallback pos */
- if (m < ma) return MATCH;
- continue; /* Next char, please */
- case WILDQ:
- m--;
- n--;
- continue; /* '?' always matches */
- }
- if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching char */
- m--;
- n--;
- sofar++; /* Tally the match */
- continue; /* Next char, please */
- }
- if (lsm) { /* To to fallback on '*' */
- n = --lsn;
- m = lsm;
- if (n < na)
- lsm = 0; /* Rewind to saved pos */
- sofar = 0;
- continue; /* Next char, please */
- }
- return NOMATCH; /* No fallback=No match */
- }
- while ((m >= ma) && (*m == WILDS))
- m--; /* Zap leftover %s & *s */
- return (m >= ma) ? NOMATCH : MATCH; /* Start of both = match */
- }
- static inline int
- comp_with_mask(void *addr, void *dest, unsigned int mask)
- {
- if (memcmp(addr, dest, mask >> 3) == 0)
- {
- int n = mask >> 3;
- int m = ((-1) << (8 - (mask % 8)));
- if (mask % 8 == 0 ||
- (((unsigned char *) addr)[n] & m) == (((unsigned char *) dest)[n] & m))
- return (1);
- }
- return (0);
- }
- /* match_cidr()
- *
- * Input - mask, address
- * Ouput - + = Matched 0 = Did not match
- */
- int
- match_cidr(const char *m, const char *a)
- {
- const char *len_p = strrchr(m, '/');
- if(len_p == NULL)
- return 0;
- const char *ip_mask_p = strrchr(m, '@');
- if(ip_mask_p == NULL)
- return 0;
- const char *ip_p = strrchr(a, '@');
- if(ip_p == NULL)
- return 0;
- char mask[NICKLEN + UHOSTLEN + 6] = "", *ipmask = NULL, *ip = NULL, *len = NULL;
- strlcpy(mask, m, sizeof(mask));
- ipmask = mask + (ip_mask_p - m);
- char address[NICKLEN + UHOSTLEN + 6] = "";
- strlcpy(address, a, sizeof(address));
- ip = address + (ip_p - a);
- *ipmask++ = '\0';
- len = mask + (len_p - m);
- *len++ = '\0';
- if (!str_isdigit(len))
- return 0;
- int cidrlen = atoi(len);
- if(cidrlen <= 0)
- return 0;
- *ip++ = '\0';
- int ret = 0;
- #ifdef USE_IPV6
- int aftype = 0;
- #endif
- sockname_t ipaddr, maskaddr;
- bzero(&ipaddr, sizeof(ipaddr));
- bzero(&maskaddr, sizeof(maskaddr));
- if (!strchr(ip, ':') && !strchr(ipmask, ':'))
- aftype = ipaddr.family = maskaddr.family = AF_INET;
- #ifdef USE_IPV6
- else if (strchr(ip, ':') && strchr(ipmask, ':'))
- aftype = ipaddr.family = maskaddr.family = AF_INET6;
- #endif /* USE_IPV6 */
- else
- return 0;
- #ifdef USE_IPV6
- if (aftype == AF_INET6) {
- if (cidrlen > 128)
- return 0;
- inet_pton(aftype, ip, &ipaddr.u.ipv6.sin6_addr);
- inet_pton(aftype, ipmask, &maskaddr.u.ipv6.sin6_addr);
- if (comp_with_mask(&ipaddr.u.ipv6.sin6_addr.s6_addr, &maskaddr.u.ipv6.sin6_addr.s6_addr, cidrlen) &&
- ((ret = wild_match(mask, address))))
- return ret;
- } else if (aftype == AF_INET) {
- #endif /* USE_IPV6 */
- if (cidrlen > 32)
- return 0;
- inet_pton(aftype, ip, &ipaddr.u.ipv4.sin_addr);
- inet_pton(aftype, ipmask, &maskaddr.u.ipv4.sin_addr);
- if (comp_with_mask(&ipaddr.u.ipv4.sin_addr.s_addr, &maskaddr.u.ipv4.sin_addr.s_addr, cidrlen) &&
- ((ret = wild_match(mask, address))))
- return ret;
- #ifdef USE_IPV6
- }
- #endif
- return 0;
- }
|