X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/b98ba21fbcc7390e8dae10e8eb5f8a63b7bfead5..78546f2b0f59b5c8fede1ce5535972716eb17041:/lib/irc_ipv6.c diff --git a/lib/irc_ipv6.c b/lib/irc_ipv6.c index 122c420e..ba6817e1 100644 --- a/lib/irc_ipv6.c +++ b/lib/irc_ipv6.c @@ -3,46 +3,13 @@ #include #include #include +#include #include #include "irc_ipv6.h" +#include #warning This source file is probably GPLed, it needs relicensing. -/* - * this new faster inet_ntoa was ripped from: - * From: Thomas Helvey - */ -/** Array of text strings for dotted quads. */ -static const char* IpQuadTab[] = -{ - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", - "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", - "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", - "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", - "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", - "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", - "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", - "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", - "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", - "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", - "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", - "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", - "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", - "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", - "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", - "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", - "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", - "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", - "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", - "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", - "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", - "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", - "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", - "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", - "250", "251", "252", "253", "254", "255" -}; - /** Convert an IP address to printable ASCII form. * This is generally deprecated in favor of ircd_ntoa_r(). * @param[in] in Address to convert. @@ -65,28 +32,12 @@ const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in) assert(in != NULL); if (irc_in_addr_is_ipv4(in)) { - unsigned int pos, len; unsigned char *pch; pch = (unsigned char*)&in->in6_16[6]; - len = strlen(IpQuadTab[*pch]); - memcpy(buf, IpQuadTab[*pch++], len); - pos = len; - buf[pos++] = '.'; - len = strlen(IpQuadTab[*pch]); - memcpy(buf+pos, IpQuadTab[*pch++], len); - pos += len; - buf[pos++] = '.'; - len = strlen(IpQuadTab[*pch]); - memcpy(buf+pos, IpQuadTab[*pch++], len); - pos += len; - buf[pos++] = '.'; - len = strlen(IpQuadTab[*pch]); - memcpy(buf+pos, IpQuadTab[*pch++], len); - buf[pos + len] = '\0'; + sprintf(buf,"%d.%d.%d.%d",pch[0],pch[1],pch[2],pch[3]); return buf; } else { - static const char hexdigits[] = "0123456789abcdef"; unsigned int pos, part, max_start, max_zeros, curr_zeros, ii; /* Find longest run of zeros. */ @@ -114,13 +65,7 @@ const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in) continue; } part = ntohs(in->in6_16[ii]); - if (part >= 0x1000) - APPEND(hexdigits[part >> 12]); - if (part >= 0x100) - APPEND(hexdigits[(part >> 8) & 15]); - if (part >= 0x10) - APPEND(hexdigits[(part >> 4) & 15]); - APPEND(hexdigits[part & 15]); + pos+=sprintf(buf+pos,"%x",part); if (ii < 7) APPEND(':'); } @@ -132,6 +77,48 @@ const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in) } } +/** Convert a CIDR mask to printable ASCII form. + * This is generally deprecated in favor of ircd_ntoa_masked_r(). + * @param[in] in Address to convert. + * @param[in] bits Mask bits. + * @return Pointer to a static buffer containing the readable form. + */ +const char* ircd_ntoa_masked(const struct irc_in_addr* in, unsigned char bits) +{ + static char buf[CIDRLEN]; + return ircd_ntoa_masked_r(buf, in, bits); +} + +/** Convert a CIDR mask to printable ASCII form. + * @param[out] buf Output buffer to write to. + * @param[in] in Address to format. + * @param[in] bits Mask bits. + * @return Pointer to the output buffer \a buf. + */ +const char* ircd_ntoa_masked_r(char* buf, const struct irc_in_addr* in, unsigned char bits) +{ + char inname[SOCKIPLEN]; + struct irc_in_addr intemp; + int i; + + for(i=0;i<8;i++) { + int curbits = bits - i * 16; + + if (curbits<0) + curbits = 0; + else if (curbits>16) + curbits = 16; + + uint16_t mask = 0xffff & ~((1 << (16 - curbits)) - 1); + intemp.in6_16[i] = htons(ntohs(in->in6_16[i]) & mask); + } + + ircd_ntoa_r(inname, &intemp); + sprintf(buf, "%s/%u", inname, irc_bitlen(in, bits)); + + return buf; +} + /** 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. @@ -161,12 +148,14 @@ ircd_aton_ip4(const char *input, unsigned int *output, unsigned char *pbits) *pbits = bits; return pos; case '.': + if (++dots > 3) + return 0; if (input[++pos] == '.') return 0; - ip |= part << (24 - 8 * dots++); + ip |= part << (32 - 8 * dots); part = 0; if (input[pos] == '*') { - while (input[++pos] == '*') ; + while (input[++pos] == '*' || input[pos] == '.') ; if (input[pos] != '\0') return 0; if (pbits) @@ -284,7 +273,7 @@ ipmask_parse(const char *input, struct irc_in_addr *ip, unsigned char *pbits) *pbits = part; goto finish; case '*': - while (input[++pos] == '*') ; + while (input[++pos] == '*' || input[pos] == ':') ; if (input[pos] != '\0' || colon < 8) return 0; if (pbits) @@ -300,6 +289,8 @@ ipmask_parse(const char *input, struct irc_in_addr *ip, unsigned char *pbits) default: return 0; } + if (input[pos] != '\0') + return 0; finish: if (colon < 8) { unsigned int jj; @@ -466,7 +457,6 @@ const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int c if (curr_zeros > max_zeros) { max_start = ii - curr_zeros; max_zeros = curr_zeros; - curr_zeros = 0; } /* Print the rest of the address */ for (ii = zero; ii < 8; ) { @@ -517,3 +507,48 @@ void base64toip(const char* input, struct irc_in_addr* addr) } } +/** Test whether an address matches the most significant bits of a mask. + * @param[in] addr Address to test. + * @param[in] mask Address to test against. + * @param[in] bits Number of bits to test. + * @return 0 on mismatch, 1 if bits < 128 and all bits match; -1 if + * bits == 128 and all bits match. + */ +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 !(htons(addr->in6_16[k] ^ mask->in6_16[k]) >> (16-bits)); + if (addr->in6_16[k] != mask->in6_16[k]) + return 0; + if (!(bits -= 16)) + return 1; + } + return -1; +} + +/** Convert IP addresses to canonical form for comparison. 6to4 and Teredo addresses + * are converted to IPv4 addresses. All other addresses are left alone. + * @param[out] out Receives canonical format for address. + * @param[in] in IP address to canonicalize. + */ +void ip_canonicalize_tunnel(struct irc_in_addr *out, const struct irc_in_addr *in) +{ + if (in->in6_16[0] == htons(0x2002)) { /* 6to4 */ + out->in6_16[0] = out->in6_16[1] = out->in6_16[2] = 0; + out->in6_16[3] = out->in6_16[4] = 0; + out->in6_16[5] = 0xffff; + out->in6_16[6] = in->in6_16[1]; + out->in6_16[7] = in->in6_16[2]; + } else if(in->in6_16[0] == htons(0x2001) && in->in6_16[1] == 0) { /* Teredo */ + out->in6_16[0] = out->in6_16[1] = out->in6_16[2] = 0; + out->in6_16[3] = out->in6_16[4] = 0; + out->in6_16[5] = 0xffff; + out->in6_16[6] = ~(in->in6_16[6]); + out->in6_16[7] = ~(in->in6_16[7]); + } else + memcpy(out, in, sizeof(*out)); +} +