match.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*
  2. * match.c
  3. * wildcard matching functions
  4. *
  5. *
  6. * Once this code was working, I added support for % so that I could
  7. * use the same code both in Eggdrop and in my IrcII client.
  8. * Pleased with this, I added the option of a fourth wildcard, ~,
  9. * which matches varying amounts of whitespace (at LEAST one space,
  10. * though, for sanity reasons).
  11. *
  12. * This code would not have been possible without the prior work and
  13. * suggestions of various sourced. Special thanks to Robey for
  14. * all his time/help tracking down bugs and his ever-helpful advice.
  15. *
  16. * 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
  17. *
  18. * Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
  19. * crf@cfox.bchs.uh.edu
  20. *
  21. * I hereby release this code into the public domain
  22. *
  23. */
  24. #include "common.h"
  25. #include "match.h"
  26. #include "misc.h"
  27. #include "rfc1459.h"
  28. #include "socket.h"
  29. #define QUOTE '\\' /* quoting character (overrides wildcards) */
  30. #define WILDS '*' /* matches 0 or more characters (including spaces) */
  31. #define WILDP '%' /* matches 0 or more non-space characters */
  32. #define WILDQ '?' /* matches ecactly one character */
  33. #define WILDT '~' /* matches 1 or more spaces */
  34. #define NOMATCH 0
  35. #define MATCH (match+sofar)
  36. #define PERMATCH (match+saved+sofar)
  37. /* binds matching */
  38. int _wild_match_per(register unsigned char *m, register unsigned char *n)
  39. {
  40. /* null strings should never match */
  41. if ((m == 0) || (n == 0) || (!*n))
  42. return NOMATCH;
  43. unsigned char *ma = m, *lsm = NULL, *lsn = NULL, *lpm = NULL, *lpn = NULL;
  44. int match = 1, saved = 0, space;
  45. register int sofar = 0;
  46. while (*n) {
  47. if (*m == WILDT) { /* Match >=1 space */
  48. space = 0; /* Don't need any spaces */
  49. do {
  50. m++;
  51. space++;
  52. } /* Tally 1 more space ... */
  53. while ((*m == WILDT) || (*m == ' ')); /* for each space or ~ */
  54. sofar += space; /* Each counts as exact */
  55. while (*n == ' ') {
  56. n++;
  57. space--;
  58. } /* Do we have enough? */
  59. if (space <= 0)
  60. continue; /* Had enough spaces! */
  61. }
  62. /* Do the fallback */
  63. else {
  64. switch (*m) {
  65. case 0:
  66. do
  67. m--; /* Search backwards */
  68. while ((m > ma) && (*m == '?')); /* For first non-? char */
  69. if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
  70. return PERMATCH; /* nonquoted * = match */
  71. break;
  72. case WILDP:
  73. while (*(++m) == WILDP); /* Zap redundant %s */
  74. if (*m != WILDS) { /* Don't both if next=* */
  75. if (*n != ' ') { /* WILDS can't match ' ' */
  76. lpm = m;
  77. lpn = n; /* Save '%' fallback spot */
  78. saved += sofar;
  79. sofar = 0; /* And save tally count */
  80. }
  81. continue; /* Done with '%' */
  82. }
  83. /* FALL THROUGH */
  84. case WILDS:
  85. do
  86. m++; /* Zap redundant wilds */
  87. while ((*m == WILDS) || (*m == WILDP));
  88. lsm = m;
  89. lsn = n;
  90. lpm = 0; /* Save '*' fallback spot */
  91. match += (saved + sofar); /* Save tally count */
  92. saved = sofar = 0;
  93. continue; /* Done with '*' */
  94. case WILDQ:
  95. m++;
  96. n++;
  97. continue; /* Match one char */
  98. case QUOTE:
  99. m++; /* Handle quoting */
  100. }
  101. if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching */
  102. m++;
  103. n++;
  104. sofar++;
  105. continue; /* Tally the match */
  106. }
  107. #ifdef WILDT
  108. }
  109. #endif
  110. if (lpm) { /* Try to fallback on '%' */
  111. n = ++lpn;
  112. m = lpm;
  113. sofar = 0; /* Restore position */
  114. if ((*n | 32) == 32)
  115. lpm = 0; /* Can't match 0 or ' ' */
  116. continue; /* Next char, please */
  117. }
  118. if (lsm) { /* Try to fallback on '*' */
  119. n = ++lsn;
  120. m = lsm; /* Restore position */
  121. saved = sofar = 0;
  122. continue; /* Next char, please */
  123. }
  124. return NOMATCH; /* No fallbacks=No match */
  125. }
  126. while ((*m == WILDS) || (*m == WILDP))
  127. m++; /* Zap leftover %s & *s */
  128. return (*m) ? NOMATCH : PERMATCH; /* End of both = match */
  129. }
  130. /* general/host matching */
  131. int _wild_match(register unsigned char *m, register unsigned char *n)
  132. {
  133. unsigned char *ma = m, *na = n;
  134. /* null strings should never match */
  135. if ((ma == 0) || (na == 0) || (!*ma) || (!*na))
  136. return NOMATCH;
  137. unsigned char *lsm = NULL, *lsn = NULL;
  138. int match = 1;
  139. register int sofar = 0;
  140. /* find the end of each string */
  141. while (*(++m));
  142. m--;
  143. while (*(++n));
  144. n--;
  145. while (n >= na) {
  146. /* If the mask runs out of chars before the string, fall back on
  147. * a wildcard or fail. */
  148. if (m < ma) {
  149. if (lsm) {
  150. n = --lsn;
  151. m = lsm;
  152. if (n < na) lsm = 0;
  153. sofar = 0;
  154. }
  155. else return NOMATCH;
  156. }
  157. switch (*m) {
  158. case WILDS: /* Matches anything */
  159. do
  160. m--; /* Zap redundant wilds */
  161. while ((m >= ma) && (*m == WILDS));
  162. lsm = m;
  163. lsn = n;
  164. match += sofar;
  165. sofar = 0; /* Update fallback pos */
  166. if (m < ma) return MATCH;
  167. continue; /* Next char, please */
  168. case WILDQ:
  169. m--;
  170. n--;
  171. continue; /* '?' always matches */
  172. }
  173. if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching char */
  174. m--;
  175. n--;
  176. sofar++; /* Tally the match */
  177. continue; /* Next char, please */
  178. }
  179. if (lsm) { /* To to fallback on '*' */
  180. n = --lsn;
  181. m = lsm;
  182. if (n < na)
  183. lsm = 0; /* Rewind to saved pos */
  184. sofar = 0;
  185. continue; /* Next char, please */
  186. }
  187. return NOMATCH; /* No fallback=No match */
  188. }
  189. while ((m >= ma) && (*m == WILDS))
  190. m--; /* Zap leftover %s & *s */
  191. return (m >= ma) ? NOMATCH : MATCH; /* Start of both = match */
  192. }
  193. static inline int
  194. comp_with_mask(void *addr, void *dest, unsigned int mask)
  195. {
  196. if (memcmp(addr, dest, mask >> 3) == 0)
  197. {
  198. int n = mask >> 3;
  199. int m = ((-1) << (8 - (mask % 8)));
  200. if (mask % 8 == 0 ||
  201. (((unsigned char *) addr)[n] & m) == (((unsigned char *) dest)[n] & m))
  202. return (1);
  203. }
  204. return (0);
  205. }
  206. /* match_cidr()
  207. *
  208. * Input - mask, address
  209. * Ouput - + = Matched 0 = Did not match
  210. */
  211. int
  212. match_cidr(const char *s1, const char *s2)
  213. {
  214. char *len = strrchr(s1, '/');
  215. if(len == NULL)
  216. return 0;
  217. char *ipmask = strrchr(s1, '@');
  218. if(ipmask == NULL)
  219. return 0;
  220. char *ip = strrchr(s2, '@');
  221. if(ip == NULL)
  222. return 0;
  223. char mask[NICKLEN + UHOSTLEN + 6] = "";
  224. strlcpy(mask, s1, sizeof(mask));
  225. ipmask = mask + (ipmask - s1);
  226. char address[NICKLEN + UHOSTLEN + 6] = "";
  227. strlcpy(address, s2, sizeof(address));
  228. ip = address + (ip - s2);
  229. *ipmask++ = '\0';
  230. len = mask + (len - s1);
  231. *len++ = '\0';
  232. if (!str_isdigit(len))
  233. return 0;
  234. int cidrlen = atoi(len);
  235. if(cidrlen <= 0)
  236. return 0;
  237. *ip++ = '\0';
  238. int ret = 0;
  239. #ifdef USE_IPV6
  240. int aftype = 0;
  241. #endif
  242. sockname_t ipaddr, maskaddr;
  243. egg_bzero(&ipaddr, sizeof(ipaddr));
  244. egg_bzero(&maskaddr, sizeof(maskaddr));
  245. if (!strchr(ip, ':') && !strchr(ipmask, ':'))
  246. aftype = ipaddr.family = maskaddr.family = AF_INET;
  247. #ifdef USE_IPV6
  248. else if (strchr(ip, ':') && strchr(ipmask, ':'))
  249. aftype = ipaddr.family = maskaddr.family = AF_INET6;
  250. #endif /* USE_IPV6 */
  251. else
  252. return 0;
  253. #ifdef USE_IPV6
  254. if (aftype == AF_INET6) {
  255. if (cidrlen > 128)
  256. return 0;
  257. inet_pton(aftype, ip, &ipaddr.u.ipv6.sin6_addr);
  258. inet_pton(aftype, ipmask, &maskaddr.u.ipv6.sin6_addr);
  259. if (comp_with_mask(&ipaddr.u.ipv6.sin6_addr.s6_addr, &maskaddr.u.ipv6.sin6_addr.s6_addr, cidrlen) &&
  260. ((ret = wild_match(mask, address))))
  261. return ret;
  262. } else if (aftype == AF_INET) {
  263. #endif /* USE_IPV6 */
  264. if (cidrlen > 32)
  265. return 0;
  266. inet_pton(aftype, ip, &ipaddr.u.ipv4.sin_addr);
  267. inet_pton(aftype, ipmask, &maskaddr.u.ipv4.sin_addr);
  268. if (comp_with_mask(&ipaddr.u.ipv4.sin_addr.s_addr, &maskaddr.u.ipv4.sin_addr.s_addr, cidrlen) &&
  269. ((ret = wild_match(mask, address))))
  270. return ret;
  271. #ifdef USE_IPV6
  272. }
  273. #endif
  274. return 0;
  275. }