X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fmatch.c;h=5cb91da54b3dea2059ac4df0ba1edf2b7b6b2206;hb=9b1f5beca29ec78141f19a19d689f0f7cc3fe3ac;hp=821c22252db242b1877cb60d646ccd33ce2b6607;hpb=9e97df973e333c18f65f251a213fcf736e52653f;p=ircu2.10.12-pk.git diff --git a/ircd/match.c b/ircd/match.c index 821c222..5cb91da 100644 --- a/ircd/match.c +++ b/ircd/match.c @@ -22,6 +22,10 @@ #include "match.h" #include "ircd_chattr.h" +#include "ircd_string.h" +#include "ircd_snprintf.h" +#include "support.h" + /* * mmatch() * @@ -788,195 +792,72 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen) return 1; /* Auch... something left out ? Fail */ } -/* - * matchcompIP() - * Compiles an IP mask into an in_mask structure - * The given can either be: - * - An usual irc type mask, containing * and or ? - * - An ip number plus a /bitnumber part, that will only consider - * the first "bitnumber" bits of the IP (bitnumber must be in 0-31 range) - * - An ip numer plus a /ip.bit.mask.values that will consider - * only the bits marked as 1 in the ip.bit.mask.values - * In the last two cases both the ip number and the bitmask can specify - * less than 4 bytes, the missing bytes then default to zero, note that - * this is *different* from the way inet_aton() does and that this does - * NOT happen for normal IPmasks (not containing '/') - * If the returned value is zero the produced in_mask might match some IP, - * if it's nonzero it will never match anything (and the imask struct is - * set so that always fails). - * - * The returned structure contains 3 fields whose meaning is the following: - * im.mask = The bits considered significative in the IP - * im.bits = What these bits should look like to have a match - * im.fall = If zero means that the above information used as - * ((IP & im.mask) == im.bits) is enough to tell if the compiled - * mask matches the given IP, nonzero means that it is needed, - * in case they did match, to call also the usual text match - * functions, because the mask wasn't "completely compiled" - * - * They should be used like: - * matchcompIP(&im, mask); - * if ( ((IP & im.mask)!=im.bits)) || (im.fall&&match(mask,inet_ntoa(IP))) ) - * { handle_non_match } else { handle_match }; - * instead of: - * if ( match(mask, inet_ntoa(IP)) ) - * { handle_non_match } else { handle_match }; - * - * Note: This function could be smarter when dealing with complex masks, - * this implementation is quite lazy and understands only very simple - * cases, whatever contains a ? anywhere or contains a '*' that isn't - * part of a trailing '.*' will fallback to text-match, this could be - * avoided for masks like 12?3.5.6 12.*.3.4 1.*.*.2 72?72?72?72 and - * so on that "could" be completely compiled to IP masks. - * If you try to improve this be aware of the fact that ? and * - * could match both dots and digits and we _must_ always reject - * what doesn't match in textform (like leading zeros and so on), - * so it's a LOT more tricky than it might seem. By now most common - * cases are optimized. - */ +#include +#include +#include +#include +#include +#include -int matchcompIP(struct in_mask *imask, const char *mask) +static int ipmask_parse_ipv4(const char *in, struct in_addr *out) { - const char *m = mask; - unsigned int bits = 0; - unsigned int filt = 0; - int unco = 0; - int digits = 0; - int shift = 24; - int tmp = 0; - - do - { - switch (*m) - { - case '\\': - if ((m[1] == '\\') || (m[1] == '*') || (m[1] == '?') - || (m[1] == '\0')) - break; - continue; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digits && !tmp) /* Leading zeros */ - break; - digits++; - tmp *= 10; - tmp += (*m - '0'); /* Can't overflow, INT_MAX > 2559 */ - if (tmp > 255) - break; - continue; - case '\0': - filt = 0xFFFFFFFF; - /* Intentional fallthrough */ - case '.': - if ((!shift) != (!*m)) - break; - /* Intentional fallthrough */ - case '/': - bits |= (tmp << shift); - shift -= 8; - digits = 0; - tmp = 0; - if (*m != '/') - continue; - shift = 24; - do - { - m++; - if (IsDigit(*m)) - { - if (digits && !tmp) /* Leading zeros */ - break; - digits++; - tmp *= 10; - tmp += (*m - '0'); /* Can't overflow, INT_MAX > 2559 */ - if (tmp > 255) - break; - } - else - { - switch (*m) - { - case '.': - case '\0': - if ((!shift) && (*m)) - break; - filt |= (tmp << shift); - shift -= 8; - tmp = 0; - digits = 0; - continue; - default: - break; - } - break; - } - } - while (*m); - if (*m) - break; - if (filt && (!(shift < 16)) && (!(filt & 0xE0FFFFFF))) - filt = 0xFFFFFFFF << (32 - ((filt >> 24))); - bits &= filt; - continue; - case '?': - unco = 1; - /* Intentional fallthrough */ - case '*': - if (digits) - unco = 1; - filt = (0xFFFFFFFF << (shift)) << 8; - while (*++m) - { - if (IsDigit(*m)) - unco = 1; - else - { - switch (*m) - { - case '.': - if (m[1] != '*') - unco = 1; - if (!shift) - break; - shift -= 8; - continue; - case '?': - unco = 1; - case '*': - continue; - default: - break; - } - break; - } - } - if (*m) - break; - continue; - default: - break; - } - - /* If we get here there is some error and this can't ever match */ - filt = 0; - bits = ~0; - unco = 0; - break; /* This time break the loop :) */ + int class; + char ipname[16]; + int ad[4] = { 0 }; + int bits = 0; + + class = sscanf(in, "%d.%d.%d.%d/%d", &ad[0], &ad[1], &ad[2], &ad[3], &bits); + if (class != 5) + bits = class * 8; + ircd_snprintf(0, ipname, sizeof(ipname), "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]); + out->s_addr = inet_addr(ipname); + return bits; +} +int ipmask_parse(const char *in, struct irc_in_addr *mask, unsigned char *bits_ptr) +{ + struct in_addr ipv4; + char *p; + int bits = 0; + + if (check_if_ipmask(in)) { + bits = ipmask_parse_ipv4(in, &ipv4); + mask->in6_16[0] = mask->in6_16[1] = mask->in6_16[2] = 0; + mask->in6_16[3] = mask->in6_16[4] = mask->in6_16[5] = 0; + memcpy(&mask->in6_16[6], &ipv4.s_addr, sizeof(ipv4.s_addr)); + bits += 96; + } else { + if (!(p = strchr(in, '/'))) + bits = 128; + else + *p = 0; + if (!ircd_aton(mask, in)) { + if (p) + *p = '/'; + return 0; + } + if (p) { + bits = atoi(p + 1); + *p = '/'; + } } - while (*m++); - imask->bits.s_addr = htonl(bits); - imask->mask.s_addr = htonl(filt); - imask->fall = unco; - return ((bits & ~filt) ? -1 : 0); + if (bits_ptr) + *bits_ptr = bits; + return 1; +} +int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits) +{ + int k; + + for (k = 0; k < 8; k++) { + if (bits < 16) + return (addr->in6_16[k] & ((unsigned char) (0xffff << (16-bits)))) == mask->in6_16[k]; + if (addr->in6_16[k] != mask->in6_16[k]) + return 0; + if (!(bits -= 16)) + return 1; + } + return -1; }