X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fircd_string.c;h=ed0349ea45fc20b1d8700cc80c355b82317c0603;hp=9ff635b6bc45c60ecaa14b354d7fcfcf2da4aab6;hb=b7f25dcf93cc44cd9f5b4132c976e72118bcd44f;hpb=a8aaf2a7fbfbff14f3d8cd869fcca8b9c9c459cf diff --git a/ircd/ircd_string.c b/ircd/ircd_string.c index 9ff635b..ed0349e 100644 --- a/ircd/ircd_string.c +++ b/ircd/ircd_string.c @@ -30,7 +30,6 @@ /* #include -- Now using assert in ircd_log.h */ #include -#include #include #include @@ -39,68 +38,6 @@ */ #include "chattr.tab.c" - -/* - * Disallow a hostname label to contain anything but a [-a-zA-Z0-9]. - * It may not start or end on a '.'. - * A label may not end on a '-', the maximum length of a label is - * 63 characters. - * On top of that (which seems to be the RFC) we demand that the - * top domain does not contain any digits. - */ -/** Regular expression to match a hostname. - * Matches zero or more alphanumeric labels followed by '.' and a - * final label that may only contain alphabetic characters. - */ -static const char* hostExpr = "^([-0-9A-Za-z]*[0-9A-Za-z]\\.)+[A-Za-z]+$"; -/** Compiled regex to match a hostname. Built from #hostExpr. */ -static regex_t hostRegex; - -/** Regular expression to match an IP address. */ -static const char* addrExpr = - "^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){1,3}" - "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$"; -/** Compiled regex to match an IP address. Built from #addrExpr. */ -static regex_t addrRegex; - -/** Initialize the string matching code. */ -int init_string(void) -{ - /* - * initialize matching expressions - * XXX - expressions MUST be correct, don't change expressions - * without testing them. Might be a good idea to exit if these fail, - * important code depends on them. - * TODO: use regerror for an error message - */ - if (regcomp(&hostRegex, hostExpr, REG_EXTENDED | REG_NOSUB)) - return 0; - - if (regcomp(&addrRegex, addrExpr, REG_EXTENDED | REG_NOSUB)) - return 0; - return 1; -} - -/** Check whether \a str looks like a hostname. - * @param[in] str String that might be a hostname. - * @return Non-zero if it conforms to the rules, zero if not. - */ -int string_is_hostname(const char* str) -{ - assert(0 != str); - return (strlen(str) <= HOSTLEN && 0 == regexec(&hostRegex, str, 0, 0, 0)); -} - -/** Check whether \a str looks like an IP address. - * @param[in] str String that might be an address. - * @return Non-zero if it conforms to the rules, zero if not. - */ -int string_is_address(const char* str) -{ - assert(0 != str); - return (0 == regexec(&addrRegex, str, 0, 0, 0)); -} - /** Check whether \a str contains wildcard characters. * @param[in] str String that might contain wildcards. * @return Non-zero if \a str contains naked (non-escaped) wildcards, @@ -219,6 +156,8 @@ char* ircd_strncpy(char* s1, const char* s2, size_t n) while (s < endp && (*s++ = *s2++)) ; + if (s == endp) + *s = '\0'; return s1; } @@ -232,21 +171,6 @@ NTL_HDR_strCasediff { NTL_SRC_strCasediff } * Other functions visible externally */ -/** Find common character attributes for the start of a string. - * @param[in] s Input string to scan. - * @param[in] n Maximum number of bytes to check. - * @return Bitmask of all character attributes shared by the start of \a s. - */ -int strnChattr(const char *s, const size_t n) -{ - const char *rs = s; - unsigned int x = ~0; - int r = n; - while (*rs && r--) - x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN]; - return x; -} - /** Case insensitive string comparison. * @param[in] a First string to compare. * @param[in] b Second string to compare. @@ -531,12 +455,13 @@ const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in) /** Attempt to parse an IPv4 address into a network-endian form. * @param[in] input Input string. * @param[out] output Network-endian representation of the address. + * @param[out] pbits Number of bits found in pbits. * @return Number of characters used from \a input, or 0 if the parse failed. */ static unsigned int -ircd_aton_ip4(const char *input, unsigned int *output) +ircd_aton_ip4(const char *input, unsigned int *output, unsigned char *pbits) { - unsigned int dots = 0, pos = 0, part = 0, ip = 0; + unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits; /* Intentionally no support for bizarre IPv4 formats (plain * integers, octal or hex components) -- only vanilla dotted @@ -544,33 +469,62 @@ ircd_aton_ip4(const char *input, unsigned int *output) */ if (input[0] == '.') return 0; - while (1) { - if (IsDigit(input[pos])) { - part = part * 10 + input[pos++] - '0'; - if (part > 255) - return 0; - if ((dots == 3) && !IsDigit(input[pos])) { - *output = htonl(ip | part); - return pos; - } - } else if (input[pos] == '.') { - if (input[++pos] == '.') + bits = 32; + while (1) switch (input[pos]) { + case '\0': + if (dots < 3) + return 0; + out: + ip |= part << (24 - 8 * dots); + *output = htonl(ip); + if (pbits) + *pbits = bits; + return pos; + case '.': + if (++dots > 3) + return 0; + if (input[++pos] == '.') + return 0; + ip |= part << (32 - 8 * dots); + part = 0; + if (input[pos] == '*') { + while (input[++pos] == '*' || input[pos] == '.') ; + if (input[pos] != '\0') return 0; - ip |= part << (24 - 8 * dots++); - part = 0; - } else + if (pbits) + *pbits = dots * 8; + *output = htonl(ip); + return pos; + } + break; + case '/': + if (!pbits || !IsDigit(input[pos + 1])) + return 0; + for (bits = 0; IsDigit(input[++pos]); ) + bits = bits * 10 + input[pos] - '0'; + if (bits > 32) + return 0; + goto out; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + part = part * 10 + input[pos++] - '0'; + if (part > 255) return 0; + break; + default: + return 0; } } /** Parse a numeric IPv4 or IPv6 address into an irc_in_addr. - * @param[out] ip Receives parsed IP address. * @param[in] input Input buffer. + * @param[out] ip Receives parsed IP address. + * @param[out] pbits If non-NULL, receives number of bits specified in address mask. * @return Number of characters used from \a input, or 0 if the * address was unparseable or malformed. */ int -ircd_aton(struct irc_in_addr *ip, const char *input) +ipmask_parse(const char *input, struct irc_in_addr *ip, unsigned char *pbits) { char *colon; char *dot; @@ -598,80 +552,110 @@ ircd_aton(struct irc_in_addr *ip, const char *input) pos += 2; part_start = input + pos; } - while (ii < 8) { + while (ii < 8) switch (input[pos]) { unsigned char chval; - - switch (input[pos]) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - chval = input[pos] - '0'; - use_chval: - part = (part << 4) | chval; - if (part > 0xffff) - return 0; - pos++; - break; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - chval = input[pos] - 'A' + 10; - goto use_chval; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - chval = input[pos] - 'a' + 10; - goto use_chval; - case ':': - part_start = input + ++pos; - if (input[pos] == '.') + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + chval = input[pos] - '0'; + use_chval: + part = (part << 4) | chval; + if (part > 0xffff) + return 0; + pos++; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + chval = input[pos] - 'A' + 10; + goto use_chval; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + chval = input[pos] - 'a' + 10; + goto use_chval; + case ':': + part_start = input + ++pos; + if (input[pos] == '.') + return 0; + ip->in6_16[ii++] = htons(part); + part = 0; + if (input[pos] == ':') { + if (colon < 8) return 0; - ip->in6_16[ii++] = htons(part); - part = 0; - if (input[pos] == ':') { - if (colon < 8) + if (ii == 8) return 0; - colon = ii; - pos++; - } - break; - case '.': { - uint32_t ip4; - unsigned int len; - len = ircd_aton_ip4(part_start, &ip4); - if (!len || (ii > 6)) - return 0; - ip->in6_16[ii++] = htons(ntohl(ip4) >> 16); - ip->in6_16[ii++] = htons(ntohl(ip4) & 65535); - if (colon < 8) { - unsigned int jj; - /* Shift stuff after "::" up and fill middle with zeros. */ - for (jj = 0; jj < ii - colon; jj++) - ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1]; - for (jj = 0; jj < 8 - ii; jj++) - ip->in6_16[colon + jj] = 0; - } - return part_start - input + len; - } - default: { - ip->in6_16[ii++] = htons(part); - if (colon < 8) { - unsigned int jj; - /* Shift stuff after "::" up and fill middle with zeros. */ - for (jj = 0; jj < ii - colon; jj++) - ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1]; - for (jj = 0; jj < 8 - ii; jj++) - ip->in6_16[colon + jj] = 0; - } - return pos; - } + colon = ii; + pos++; } + break; + case '.': { + uint32_t ip4; + unsigned int len; + len = ircd_aton_ip4(part_start, &ip4, pbits); + if (!len || (ii > 6)) + return 0; + ip->in6_16[ii++] = htons(ntohl(ip4) >> 16); + ip->in6_16[ii++] = htons(ntohl(ip4) & 65535); + if (pbits) + *pbits += 96; + pos = part_start + len - input; + goto finish; + } + case '/': + if (!pbits || !IsDigit(input[pos + 1])) + return 0; + ip->in6_16[ii++] = htons(part); + for (part = 0; IsDigit(input[++pos]); ) + part = part * 10 + input[pos] - '0'; + if (part > 128) + return 0; + *pbits = part; + goto finish; + case '*': + while (input[++pos] == '*' || input[pos] == ':') ; + if (input[pos] != '\0' || colon < 8) + return 0; + if (part && ii < 8) + ip->in6_16[ii++] = htons(part); + if (pbits) + *pbits = ii * 16; + return pos; + case '\0': + ip->in6_16[ii++] = htons(part); + if (colon == 8 && ii < 8) + return 0; + if (pbits) + *pbits = 128; + goto finish; + default: + return 0; + } + if (input[pos] != '\0') + return 0; + finish: + if (colon < 8) { + unsigned int jj; + /* Shift stuff after "::" up and fill middle with zeros. */ + for (jj = 0; jj < ii - colon; jj++) + ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1]; + for (jj = 0; jj < 8 - ii; jj++) + ip->in6_16[colon + jj] = 0; } return pos; - } else if (dot) { + } else if (dot || strchr(input, '/')) { unsigned int addr; - int len = ircd_aton_ip4(input, &addr); + int len = ircd_aton_ip4(input, &addr, pbits); if (len) { ip->in6_16[5] = htons(65535); ip->in6_16[6] = htons(ntohl(addr) >> 16); ip->in6_16[7] = htons(ntohl(addr) & 65535); - return len; + if (pbits) + *pbits += 96; } - } - return 0; /* parse failed */ + return len; + } else if (input[0] == '*') { + unsigned int pos = 0; + while (input[++pos] == '*') ; + if (input[pos] != '\0') + return 0; + if (pbits) + *pbits = 0; + return pos; + } else return 0; /* parse failed */ }