X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fircd_string.c;h=ed0349ea45fc20b1d8700cc80c355b82317c0603;hp=e264242fa82ea188f38e2afa37b4816ae50014f2;hb=b7f25dcf93cc44cd9f5b4132c976e72118bcd44f;hpb=ca879068abd3a89b47268d4c734843227db70a1e diff --git a/ircd/ircd_string.c b/ircd/ircd_string.c index e264242..ed0349e 100644 --- a/ircd/ircd_string.c +++ b/ircd/ircd_string.c @@ -28,9 +28,8 @@ #include "ircd_log.h" #include "res.h" -#include +/* #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 expresion 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. @@ -262,7 +186,7 @@ int ircd_strcmp(const char *a, const char *b) else ++rb; } - return (*ra - *rb); + return (ToLower(*ra) - ToLower(*rb)); } /** Case insensitive comparison of the starts of two strings. @@ -285,7 +209,7 @@ int ircd_strncmp(const char *a, const char *b, size_t n) else ++rb; } - return (*ra - *rb); + return (ToLower(*ra) - ToLower(*rb)); } /** Fill a vector of distinct names from a delimited input list. @@ -305,10 +229,10 @@ int unique_name_vector(char* names, char token, char** vector, int size) { int i; int count = 0; - char* start = list; + char* start = names; char* end; - assert(0 != list); + assert(0 != names); assert(0 != vector); assert(0 < size); @@ -359,10 +283,10 @@ int unique_name_vector(char* names, char token, char** vector, int size) int token_vector(char* names, char token, char** vector, int size) { int count = 0; - char* start = list; + char* start = names; char* end; - assert(0 != list); + assert(0 != names); assert(0 != vector); assert(1 < size); @@ -392,16 +316,16 @@ char* host_from_uh(char* buf, const char* userhost, size_t len) { const char* s; - assert(0 != host); + assert(0 != buf); assert(0 != userhost); if ((s = strchr(userhost, '@'))) ++s; else s = userhost; - ircd_strncpy(host, s, n); - host[n] = '\0'; - return host; + ircd_strncpy(buf, s, len); + buf[len] = '\0'; + return buf; } /* @@ -450,22 +374,6 @@ const char* ircd_ntoa(const struct irc_in_addr* in) return ircd_ntoa_r(buf, in); } -/* This doesn't really belong here, but otherwise umkpasswd breaks. */ -/** Check whether an IP address looks like an IPv4 address. - * @param[in] addr Address to check. - * @return Non-zero if the address is a valid IPv4 address, zero if not. - */ -int irc_in_addr_is_ipv4(const struct irc_in_addr *addr) -{ - return addr->in6_16[0] == 0 - && addr->in6_16[1] == 0 - && addr->in6_16[2] == 0 - && addr->in6_16[3] == 0 - && addr->in6_16[4] == 0 - && (addr->in6_16[5] == 0 || addr->in6_16[5] == 0xffff) - && addr->in6_16[6] != 0; -} - /** Convert an IP address to printable ASCII form. * @param[out] buf Output buffer to write to. * @param[in] in Address to format. @@ -536,8 +444,6 @@ const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in) if (ii < 7) APPEND(':'); } - if (max_zeros + max_start == 8) - APPEND(':'); #undef APPEND /* Nul terminate and return number of characters used. */ @@ -549,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 @@ -562,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; @@ -607,80 +543,119 @@ ircd_aton(struct irc_in_addr *ip, const char *input) * This is pretty straightforward; the only trick is borrowed * from Paul Vixie (BIND): when it sees a "::" continue as if * it were a single ":", but note where it happened, and fill - * with zeros afterwards. + * with zeros afterward. */ if (input[pos] == ':') { if ((input[pos+1] != ':') || (input[pos+2] == ':')) return 0; colon = 0; 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(input + pos, &ip4); - if (!len || (ii > 6)) - return 0; - ip->in6_16[ii++] = htons(ntohl(ip4) >> 16); - ip->in6_16[ii++] = htons(ntohl(ip4) & 65535); - pos += len; - break; - } - default: { - unsigned int jj; - if (colon >= 8) - return 0; - /* Shift stuff after "::" up and fill middle with zeros. */ - ip->in6_16[ii++] = htons(part); - 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 */ }