Return to netaddr.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") ! 3: * Copyright (C) 1999-2002 Internet Software Consortium. ! 4: * ! 5: * Permission to use, copy, modify, and/or distribute this software for any ! 6: * purpose with or without fee is hereby granted, provided that the above ! 7: * copyright notice and this permission notice appear in all copies. ! 8: * ! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ! 15: * PERFORMANCE OF THIS SOFTWARE. ! 16: */ ! 17: ! 18: /* $Id: netaddr.c,v 1.38 2007/06/18 23:47:44 tbox Exp $ */ ! 19: ! 20: /*! \file */ ! 21: ! 22: #include <config.h> ! 23: ! 24: #include <stdio.h> ! 25: ! 26: #include <isc/buffer.h> ! 27: #include <isc/msgs.h> ! 28: #include <isc/net.h> ! 29: #include <isc/netaddr.h> ! 30: #include <isc/print.h> ! 31: #include <isc/sockaddr.h> ! 32: #include <isc/string.h> ! 33: #include <isc/util.h> ! 34: ! 35: isc_boolean_t ! 36: isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { ! 37: REQUIRE(a != NULL && b != NULL); ! 38: ! 39: if (a->family != b->family) ! 40: return (ISC_FALSE); ! 41: ! 42: if (a->zone != b->zone) ! 43: return (ISC_FALSE); ! 44: ! 45: switch (a->family) { ! 46: case AF_INET: ! 47: if (a->type.in.s_addr != b->type.in.s_addr) ! 48: return (ISC_FALSE); ! 49: break; ! 50: case AF_INET6: ! 51: if (memcmp(&a->type.in6, &b->type.in6, ! 52: sizeof(a->type.in6)) != 0 || ! 53: a->zone != b->zone) ! 54: return (ISC_FALSE); ! 55: break; ! 56: #ifdef ISC_PLATFORM_HAVESYSUNH ! 57: case AF_UNIX: ! 58: if (strcmp(a->type.un, b->type.un) != 0) ! 59: return (ISC_FALSE); ! 60: break; ! 61: #endif ! 62: default: ! 63: return (ISC_FALSE); ! 64: } ! 65: return (ISC_TRUE); ! 66: } ! 67: ! 68: isc_boolean_t ! 69: isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, ! 70: unsigned int prefixlen) ! 71: { ! 72: const unsigned char *pa, *pb; ! 73: unsigned int ipabytes; /* Length of whole IP address in bytes */ ! 74: unsigned int nbytes; /* Number of significant whole bytes */ ! 75: unsigned int nbits; /* Number of significant leftover bits */ ! 76: ! 77: REQUIRE(a != NULL && b != NULL); ! 78: ! 79: if (a->family != b->family) ! 80: return (ISC_FALSE); ! 81: ! 82: if (a->zone != b->zone && b->zone != 0) ! 83: return (ISC_FALSE); ! 84: ! 85: switch (a->family) { ! 86: case AF_INET: ! 87: pa = (const unsigned char *) &a->type.in; ! 88: pb = (const unsigned char *) &b->type.in; ! 89: ipabytes = 4; ! 90: break; ! 91: case AF_INET6: ! 92: pa = (const unsigned char *) &a->type.in6; ! 93: pb = (const unsigned char *) &b->type.in6; ! 94: ipabytes = 16; ! 95: break; ! 96: default: ! 97: pa = pb = NULL; /* Avoid silly compiler warning. */ ! 98: ipabytes = 0; /* Ditto. */ ! 99: return (ISC_FALSE); ! 100: } ! 101: ! 102: /* ! 103: * Don't crash if we get a pattern like 10.0.0.1/9999999. ! 104: */ ! 105: if (prefixlen > ipabytes * 8) ! 106: prefixlen = ipabytes * 8; ! 107: ! 108: nbytes = prefixlen / 8; ! 109: nbits = prefixlen % 8; ! 110: ! 111: if (nbytes > 0) { ! 112: if (memcmp(pa, pb, nbytes) != 0) ! 113: return (ISC_FALSE); ! 114: } ! 115: if (nbits > 0) { ! 116: unsigned int bytea, byteb, mask; ! 117: INSIST(nbytes < ipabytes); ! 118: INSIST(nbits < 8); ! 119: bytea = pa[nbytes]; ! 120: byteb = pb[nbytes]; ! 121: mask = (0xFF << (8-nbits)) & 0xFF; ! 122: if ((bytea & mask) != (byteb & mask)) ! 123: return (ISC_FALSE); ! 124: } ! 125: return (ISC_TRUE); ! 126: } ! 127: ! 128: isc_result_t ! 129: isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { ! 130: char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; ! 131: char zbuf[sizeof("%4294967295")]; ! 132: unsigned int alen; ! 133: int zlen; ! 134: const char *r; ! 135: const void *type; ! 136: ! 137: REQUIRE(netaddr != NULL); ! 138: ! 139: switch (netaddr->family) { ! 140: case AF_INET: ! 141: type = &netaddr->type.in; ! 142: break; ! 143: case AF_INET6: ! 144: type = &netaddr->type.in6; ! 145: break; ! 146: #ifdef ISC_PLATFORM_HAVESYSUNH ! 147: case AF_UNIX: ! 148: alen = strlen(netaddr->type.un); ! 149: if (alen > isc_buffer_availablelength(target)) ! 150: return (ISC_R_NOSPACE); ! 151: isc_buffer_putmem(target, ! 152: (const unsigned char *)(netaddr->type.un), ! 153: alen); ! 154: return (ISC_R_SUCCESS); ! 155: #endif ! 156: default: ! 157: return (ISC_R_FAILURE); ! 158: } ! 159: r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf)); ! 160: if (r == NULL) ! 161: return (ISC_R_FAILURE); ! 162: ! 163: alen = strlen(abuf); ! 164: INSIST(alen < sizeof(abuf)); ! 165: ! 166: zlen = 0; ! 167: if (netaddr->family == AF_INET6 && netaddr->zone != 0) { ! 168: zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); ! 169: if (zlen < 0) ! 170: return (ISC_R_FAILURE); ! 171: INSIST((unsigned int)zlen < sizeof(zbuf)); ! 172: } ! 173: ! 174: if (alen + zlen > isc_buffer_availablelength(target)) ! 175: return (ISC_R_NOSPACE); ! 176: ! 177: isc_buffer_putmem(target, (unsigned char *)abuf, alen); ! 178: isc_buffer_putmem(target, (unsigned char *)zbuf, zlen); ! 179: ! 180: return (ISC_R_SUCCESS); ! 181: } ! 182: ! 183: void ! 184: isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { ! 185: isc_result_t result; ! 186: isc_buffer_t buf; ! 187: ! 188: isc_buffer_init(&buf, array, size); ! 189: result = isc_netaddr_totext(na, &buf); ! 190: ! 191: /* ! 192: * Null terminate. ! 193: */ ! 194: if (result == ISC_R_SUCCESS) { ! 195: if (isc_buffer_availablelength(&buf) >= 1) ! 196: isc_buffer_putuint8(&buf, 0); ! 197: else ! 198: result = ISC_R_NOSPACE; ! 199: } ! 200: ! 201: if (result != ISC_R_SUCCESS) { ! 202: snprintf(array, size, ! 203: isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, ! 204: ISC_MSG_UNKNOWNADDR, ! 205: "<unknown address, family %u>"), ! 206: na->family); ! 207: array[size - 1] = '\0'; ! 208: } ! 209: } ! 210: ! 211: ! 212: isc_result_t ! 213: isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { ! 214: static const unsigned char zeros[16] = { 0 }; ! 215: unsigned int nbits, nbytes, ipbytes; ! 216: const unsigned char *p; ! 217: ! 218: switch (na->family) { ! 219: case AF_INET: ! 220: p = (const unsigned char *) &na->type.in; ! 221: ipbytes = 4; ! 222: if (prefixlen > 32) ! 223: return (ISC_R_RANGE); ! 224: break; ! 225: case AF_INET6: ! 226: p = (const unsigned char *) &na->type.in6; ! 227: ipbytes = 16; ! 228: if (prefixlen > 128) ! 229: return (ISC_R_RANGE); ! 230: break; ! 231: default: ! 232: ipbytes = 0; ! 233: return (ISC_R_NOTIMPLEMENTED); ! 234: } ! 235: nbytes = prefixlen / 8; ! 236: nbits = prefixlen % 8; ! 237: if (nbits != 0) { ! 238: if ((p[nbytes] & (0xff>>nbits)) != 0U) ! 239: return (ISC_R_FAILURE); ! 240: nbytes++; ! 241: } ! 242: if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) ! 243: return (ISC_R_FAILURE); ! 244: return (ISC_R_SUCCESS); ! 245: } ! 246: ! 247: isc_result_t ! 248: isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { ! 249: unsigned int nbits, nbytes, ipbytes, i; ! 250: const unsigned char *p; ! 251: ! 252: switch (s->family) { ! 253: case AF_INET: ! 254: p = (const unsigned char *) &s->type.in; ! 255: ipbytes = 4; ! 256: break; ! 257: case AF_INET6: ! 258: p = (const unsigned char *) &s->type.in6; ! 259: ipbytes = 16; ! 260: break; ! 261: default: ! 262: ipbytes = 0; ! 263: return (ISC_R_NOTIMPLEMENTED); ! 264: } ! 265: nbytes = nbits = 0; ! 266: for (i = 0; i < ipbytes; i++) { ! 267: if (p[i] != 0xFF) ! 268: break; ! 269: } ! 270: nbytes = i; ! 271: if (i < ipbytes) { ! 272: unsigned int c = p[nbytes]; ! 273: while ((c & 0x80) != 0 && nbits < 8) { ! 274: c <<= 1; nbits++; ! 275: } ! 276: if ((c & 0xFF) != 0) ! 277: return (ISC_R_MASKNONCONTIG); ! 278: i++; ! 279: } ! 280: for (; i < ipbytes; i++) { ! 281: if (p[i] != 0) ! 282: return (ISC_R_MASKNONCONTIG); ! 283: i++; ! 284: } ! 285: *lenp = nbytes * 8 + nbits; ! 286: return (ISC_R_SUCCESS); ! 287: } ! 288: ! 289: void ! 290: isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { ! 291: memset(netaddr, 0, sizeof(*netaddr)); ! 292: netaddr->family = AF_INET; ! 293: netaddr->type.in = *ina; ! 294: } ! 295: ! 296: void ! 297: isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { ! 298: memset(netaddr, 0, sizeof(*netaddr)); ! 299: netaddr->family = AF_INET6; ! 300: netaddr->type.in6 = *ina6; ! 301: } ! 302: ! 303: isc_result_t ! 304: isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { ! 305: #ifdef ISC_PLATFORM_HAVESYSUNH ! 306: if (strlen(path) > sizeof(netaddr->type.un) - 1) ! 307: return (ISC_R_NOSPACE); ! 308: ! 309: memset(netaddr, 0, sizeof(*netaddr)); ! 310: netaddr->family = AF_UNIX; ! 311: strcpy(netaddr->type.un, path); ! 312: netaddr->zone = 0; ! 313: return (ISC_R_SUCCESS); ! 314: #else ! 315: UNUSED(netaddr); ! 316: UNUSED(path); ! 317: return (ISC_R_NOTIMPLEMENTED); ! 318: #endif ! 319: } ! 320: ! 321: ! 322: void ! 323: isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) { ! 324: /* we currently only support AF_INET6. */ ! 325: REQUIRE(netaddr->family == AF_INET6); ! 326: ! 327: netaddr->zone = zone; ! 328: } ! 329: ! 330: isc_uint32_t ! 331: isc_netaddr_getzone(const isc_netaddr_t *netaddr) { ! 332: return (netaddr->zone); ! 333: } ! 334: ! 335: void ! 336: isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { ! 337: int family = s->type.sa.sa_family; ! 338: t->family = family; ! 339: switch (family) { ! 340: case AF_INET: ! 341: t->type.in = s->type.sin.sin_addr; ! 342: t->zone = 0; ! 343: break; ! 344: case AF_INET6: ! 345: memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16); ! 346: #ifdef ISC_PLATFORM_HAVESCOPEID ! 347: t->zone = s->type.sin6.sin6_scope_id; ! 348: #else ! 349: t->zone = 0; ! 350: #endif ! 351: break; ! 352: #ifdef ISC_PLATFORM_HAVESYSUNH ! 353: case AF_UNIX: ! 354: memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); ! 355: t->zone = 0; ! 356: break; ! 357: #endif ! 358: default: ! 359: INSIST(0); ! 360: } ! 361: } ! 362: ! 363: void ! 364: isc_netaddr_any(isc_netaddr_t *netaddr) { ! 365: memset(netaddr, 0, sizeof(*netaddr)); ! 366: netaddr->family = AF_INET; ! 367: netaddr->type.in.s_addr = INADDR_ANY; ! 368: } ! 369: ! 370: void ! 371: isc_netaddr_any6(isc_netaddr_t *netaddr) { ! 372: memset(netaddr, 0, sizeof(*netaddr)); ! 373: netaddr->family = AF_INET6; ! 374: netaddr->type.in6 = in6addr_any; ! 375: } ! 376: ! 377: isc_boolean_t ! 378: isc_netaddr_ismulticast(isc_netaddr_t *na) { ! 379: switch (na->family) { ! 380: case AF_INET: ! 381: return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr))); ! 382: case AF_INET6: ! 383: return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6))); ! 384: default: ! 385: return (ISC_FALSE); /* XXXMLG ? */ ! 386: } ! 387: } ! 388: ! 389: isc_boolean_t ! 390: isc_netaddr_isexperimental(isc_netaddr_t *na) { ! 391: switch (na->family) { ! 392: case AF_INET: ! 393: return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr))); ! 394: default: ! 395: return (ISC_FALSE); /* XXXMLG ? */ ! 396: } ! 397: } ! 398: ! 399: isc_boolean_t ! 400: isc_netaddr_islinklocal(isc_netaddr_t *na) { ! 401: switch (na->family) { ! 402: case AF_INET: ! 403: return (ISC_FALSE); ! 404: case AF_INET6: ! 405: return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6))); ! 406: default: ! 407: return (ISC_FALSE); ! 408: } ! 409: } ! 410: ! 411: isc_boolean_t ! 412: isc_netaddr_issitelocal(isc_netaddr_t *na) { ! 413: switch (na->family) { ! 414: case AF_INET: ! 415: return (ISC_FALSE); ! 416: case AF_INET6: ! 417: return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6))); ! 418: default: ! 419: return (ISC_FALSE); ! 420: } ! 421: } ! 422: ! 423: void ! 424: isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { ! 425: isc_netaddr_t *src; ! 426: ! 427: DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ ! 428: ! 429: REQUIRE(s->family == AF_INET6); ! 430: REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); ! 431: ! 432: memset(t, 0, sizeof(*t)); ! 433: t->family = AF_INET; ! 434: memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4); ! 435: return; ! 436: }