match.c 9.4 KB

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