Annotation of embedaddon/ntp/lib/isc/netaddr.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>