Annotation of embedaddon/ntp/lib/isc/sockaddr.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 1999-2003 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: sockaddr.c,v 1.70 2007/06/19 23:47:17 tbox Exp $ */
! 19:
! 20: /*! \file */
! 21:
! 22: #include <config.h>
! 23:
! 24: #include <stdio.h>
! 25:
! 26: #include <isc/buffer.h>
! 27: #include <isc/hash.h>
! 28: #include <isc/msgs.h>
! 29: #include <isc/netaddr.h>
! 30: #include <isc/print.h>
! 31: #include <isc/region.h>
! 32: #include <isc/sockaddr.h>
! 33: #include <isc/string.h>
! 34: #include <isc/util.h>
! 35:
! 36: isc_boolean_t
! 37: isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
! 38: return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
! 39: ISC_SOCKADDR_CMPPORT|
! 40: ISC_SOCKADDR_CMPSCOPE));
! 41: }
! 42:
! 43: isc_boolean_t
! 44: isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
! 45: return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
! 46: ISC_SOCKADDR_CMPSCOPE));
! 47: }
! 48:
! 49: isc_boolean_t
! 50: isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
! 51: unsigned int flags)
! 52: {
! 53: REQUIRE(a != NULL && b != NULL);
! 54:
! 55: if (a->length != b->length)
! 56: return (ISC_FALSE);
! 57:
! 58: /*
! 59: * We don't just memcmp because the sin_zero field isn't always
! 60: * zero.
! 61: */
! 62:
! 63: if (a->type.sa.sa_family != b->type.sa.sa_family)
! 64: return (ISC_FALSE);
! 65: switch (a->type.sa.sa_family) {
! 66: case AF_INET:
! 67: if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
! 68: memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
! 69: sizeof(a->type.sin.sin_addr)) != 0)
! 70: return (ISC_FALSE);
! 71: if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
! 72: a->type.sin.sin_port != b->type.sin.sin_port)
! 73: return (ISC_FALSE);
! 74: break;
! 75: case AF_INET6:
! 76: if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
! 77: memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
! 78: sizeof(a->type.sin6.sin6_addr)) != 0)
! 79: return (ISC_FALSE);
! 80: #ifdef ISC_PLATFORM_HAVESCOPEID
! 81: /*
! 82: * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
! 83: * ISC_FALSE if one of the scopes in zero.
! 84: */
! 85: if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
! 86: a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
! 87: ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
! 88: (a->type.sin6.sin6_scope_id != 0 &&
! 89: b->type.sin6.sin6_scope_id != 0)))
! 90: return (ISC_FALSE);
! 91: #endif
! 92: if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
! 93: a->type.sin6.sin6_port != b->type.sin6.sin6_port)
! 94: return (ISC_FALSE);
! 95: break;
! 96: default:
! 97: if (memcmp(&a->type, &b->type, a->length) != 0)
! 98: return (ISC_FALSE);
! 99: }
! 100: return (ISC_TRUE);
! 101: }
! 102:
! 103: isc_boolean_t
! 104: isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
! 105: unsigned int prefixlen)
! 106: {
! 107: isc_netaddr_t na, nb;
! 108: isc_netaddr_fromsockaddr(&na, a);
! 109: isc_netaddr_fromsockaddr(&nb, b);
! 110: return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
! 111: }
! 112:
! 113: isc_result_t
! 114: isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
! 115: isc_result_t result;
! 116: isc_netaddr_t netaddr;
! 117: char pbuf[sizeof("65000")];
! 118: unsigned int plen;
! 119: isc_region_t avail;
! 120:
! 121: REQUIRE(sockaddr != NULL);
! 122:
! 123: /*
! 124: * Do the port first, giving us the opportunity to check for
! 125: * unsupported address families before calling
! 126: * isc_netaddr_fromsockaddr().
! 127: */
! 128: switch (sockaddr->type.sa.sa_family) {
! 129: case AF_INET:
! 130: snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
! 131: break;
! 132: case AF_INET6:
! 133: snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
! 134: break;
! 135: #ifdef ISC_PLAFORM_HAVESYSUNH
! 136: case AF_UNIX:
! 137: plen = strlen(sockaddr->type.sunix.sun_path);
! 138: if (plen >= isc_buffer_availablelength(target))
! 139: return (ISC_R_NOSPACE);
! 140:
! 141: isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen);
! 142:
! 143: /*
! 144: * Null terminate after used region.
! 145: */
! 146: isc_buffer_availableregion(target, &avail);
! 147: INSIST(avail.length >= 1);
! 148: avail.base[0] = '\0';
! 149:
! 150: return (ISC_R_SUCCESS);
! 151: #endif
! 152: default:
! 153: return (ISC_R_FAILURE);
! 154: }
! 155:
! 156: plen = strlen(pbuf);
! 157: INSIST(plen < sizeof(pbuf));
! 158:
! 159: isc_netaddr_fromsockaddr(&netaddr, sockaddr);
! 160: result = isc_netaddr_totext(&netaddr, target);
! 161: if (result != ISC_R_SUCCESS)
! 162: return (result);
! 163:
! 164: if (1 + plen + 1 > isc_buffer_availablelength(target))
! 165: return (ISC_R_NOSPACE);
! 166:
! 167: isc_buffer_putmem(target, (const unsigned char *)"#", 1);
! 168: isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
! 169:
! 170: /*
! 171: * Null terminate after used region.
! 172: */
! 173: isc_buffer_availableregion(target, &avail);
! 174: INSIST(avail.length >= 1);
! 175: avail.base[0] = '\0';
! 176:
! 177: return (ISC_R_SUCCESS);
! 178: }
! 179:
! 180: void
! 181: isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
! 182: isc_result_t result;
! 183: isc_buffer_t buf;
! 184:
! 185: isc_buffer_init(&buf, array, size);
! 186: result = isc_sockaddr_totext(sa, &buf);
! 187: if (result != ISC_R_SUCCESS) {
! 188: /*
! 189: * The message is the same as in netaddr.c.
! 190: */
! 191: snprintf(array, size,
! 192: isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
! 193: ISC_MSG_UNKNOWNADDR,
! 194: "<unknown address, family %u>"),
! 195: sa->type.sa.sa_family);
! 196: array[size - 1] = '\0';
! 197: }
! 198: }
! 199:
! 200: unsigned int
! 201: isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
! 202: unsigned int length = 0;
! 203: const unsigned char *s = NULL;
! 204: unsigned int h = 0;
! 205: unsigned int g;
! 206: unsigned int p = 0;
! 207: const struct in6_addr *in6;
! 208:
! 209: REQUIRE(sockaddr != NULL);
! 210:
! 211: switch (sockaddr->type.sa.sa_family) {
! 212: case AF_INET:
! 213: s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
! 214: p = ntohs(sockaddr->type.sin.sin_port);
! 215: length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
! 216: break;
! 217: case AF_INET6:
! 218: in6 = &sockaddr->type.sin6.sin6_addr;
! 219: if (IN6_IS_ADDR_V4MAPPED(in6)) {
! 220: s = (const unsigned char *)&in6[12];
! 221: length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
! 222: } else {
! 223: s = (const unsigned char *)in6;
! 224: length = sizeof(sockaddr->type.sin6.sin6_addr);
! 225: }
! 226: p = ntohs(sockaddr->type.sin6.sin6_port);
! 227: break;
! 228: default:
! 229: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 230: isc_msgcat_get(isc_msgcat,
! 231: ISC_MSGSET_SOCKADDR,
! 232: ISC_MSG_UNKNOWNFAMILY,
! 233: "unknown address family: %d"),
! 234: (int)sockaddr->type.sa.sa_family);
! 235: s = (const unsigned char *)&sockaddr->type;
! 236: length = sockaddr->length;
! 237: p = 0;
! 238: }
! 239:
! 240: h = isc_hash_calc(s, length, ISC_TRUE);
! 241: if (!address_only) {
! 242: g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
! 243: ISC_TRUE);
! 244: h = h ^ g; /* XXX: we should concatenate h and p first */
! 245: }
! 246:
! 247: return (h);
! 248: }
! 249:
! 250: void
! 251: isc_sockaddr_any(isc_sockaddr_t *sockaddr)
! 252: {
! 253: memset(sockaddr, 0, sizeof(*sockaddr));
! 254: sockaddr->type.sin.sin_family = AF_INET;
! 255: #ifdef ISC_PLATFORM_HAVESALEN
! 256: sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
! 257: #endif
! 258: sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
! 259: sockaddr->type.sin.sin_port = 0;
! 260: sockaddr->length = sizeof(sockaddr->type.sin);
! 261: ISC_LINK_INIT(sockaddr, link);
! 262: }
! 263:
! 264: void
! 265: isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
! 266: {
! 267: memset(sockaddr, 0, sizeof(*sockaddr));
! 268: sockaddr->type.sin6.sin6_family = AF_INET6;
! 269: #ifdef ISC_PLATFORM_HAVESALEN
! 270: sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
! 271: #endif
! 272: sockaddr->type.sin6.sin6_addr = in6addr_any;
! 273: sockaddr->type.sin6.sin6_port = 0;
! 274: sockaddr->length = sizeof(sockaddr->type.sin6);
! 275: ISC_LINK_INIT(sockaddr, link);
! 276: }
! 277:
! 278: void
! 279: isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
! 280: in_port_t port)
! 281: {
! 282: memset(sockaddr, 0, sizeof(*sockaddr));
! 283: sockaddr->type.sin.sin_family = AF_INET;
! 284: #ifdef ISC_PLATFORM_HAVESALEN
! 285: sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
! 286: #endif
! 287: sockaddr->type.sin.sin_addr = *ina;
! 288: sockaddr->type.sin.sin_port = htons(port);
! 289: sockaddr->length = sizeof(sockaddr->type.sin);
! 290: ISC_LINK_INIT(sockaddr, link);
! 291: }
! 292:
! 293: void
! 294: isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
! 295: switch (pf) {
! 296: case AF_INET:
! 297: isc_sockaddr_any(sockaddr);
! 298: break;
! 299: case AF_INET6:
! 300: isc_sockaddr_any6(sockaddr);
! 301: break;
! 302: default:
! 303: INSIST(0);
! 304: }
! 305: }
! 306:
! 307: void
! 308: isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
! 309: in_port_t port)
! 310: {
! 311: memset(sockaddr, 0, sizeof(*sockaddr));
! 312: sockaddr->type.sin6.sin6_family = AF_INET6;
! 313: #ifdef ISC_PLATFORM_HAVESALEN
! 314: sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
! 315: #endif
! 316: sockaddr->type.sin6.sin6_addr = *ina6;
! 317: sockaddr->type.sin6.sin6_port = htons(port);
! 318: sockaddr->length = sizeof(sockaddr->type.sin6);
! 319: ISC_LINK_INIT(sockaddr, link);
! 320: }
! 321:
! 322: void
! 323: isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
! 324: in_port_t port)
! 325: {
! 326: memset(sockaddr, 0, sizeof(*sockaddr));
! 327: sockaddr->type.sin6.sin6_family = AF_INET6;
! 328: #ifdef ISC_PLATFORM_HAVESALEN
! 329: sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
! 330: #endif
! 331: sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
! 332: sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
! 333: memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
! 334: sockaddr->type.sin6.sin6_port = htons(port);
! 335: sockaddr->length = sizeof(sockaddr->type.sin6);
! 336: ISC_LINK_INIT(sockaddr, link);
! 337: }
! 338:
! 339: int
! 340: isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
! 341:
! 342: /*
! 343: * Get the protocol family of 'sockaddr'.
! 344: */
! 345:
! 346: #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
! 347: /*
! 348: * Assume that PF_xxx == AF_xxx for all AF and PF.
! 349: */
! 350: return (sockaddr->type.sa.sa_family);
! 351: #else
! 352: switch (sockaddr->type.sa.sa_family) {
! 353: case AF_INET:
! 354: return (PF_INET);
! 355: case AF_INET6:
! 356: return (PF_INET6);
! 357: default:
! 358: FATAL_ERROR(__FILE__, __LINE__,
! 359: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
! 360: ISC_MSG_UNKNOWNFAMILY,
! 361: "unknown address family: %d"),
! 362: (int)sockaddr->type.sa.sa_family);
! 363: }
! 364: #endif
! 365: }
! 366:
! 367: void
! 368: isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
! 369: in_port_t port)
! 370: {
! 371: memset(sockaddr, 0, sizeof(*sockaddr));
! 372: sockaddr->type.sin.sin_family = (short)na->family;
! 373: switch (na->family) {
! 374: case AF_INET:
! 375: sockaddr->length = sizeof(sockaddr->type.sin);
! 376: #ifdef ISC_PLATFORM_HAVESALEN
! 377: sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
! 378: #endif
! 379: sockaddr->type.sin.sin_addr = na->type.in;
! 380: sockaddr->type.sin.sin_port = htons(port);
! 381: break;
! 382: case AF_INET6:
! 383: sockaddr->length = sizeof(sockaddr->type.sin6);
! 384: #ifdef ISC_PLATFORM_HAVESALEN
! 385: sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
! 386: #endif
! 387: memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
! 388: #ifdef ISC_PLATFORM_HAVESCOPEID
! 389: sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
! 390: #endif
! 391: sockaddr->type.sin6.sin6_port = htons(port);
! 392: break;
! 393: default:
! 394: INSIST(0);
! 395: }
! 396: ISC_LINK_INIT(sockaddr, link);
! 397: }
! 398:
! 399: void
! 400: isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
! 401: switch (sockaddr->type.sa.sa_family) {
! 402: case AF_INET:
! 403: sockaddr->type.sin.sin_port = htons(port);
! 404: break;
! 405: case AF_INET6:
! 406: sockaddr->type.sin6.sin6_port = htons(port);
! 407: break;
! 408: default:
! 409: FATAL_ERROR(__FILE__, __LINE__,
! 410: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
! 411: ISC_MSG_UNKNOWNFAMILY,
! 412: "unknown address family: %d"),
! 413: (int)sockaddr->type.sa.sa_family);
! 414: }
! 415: }
! 416:
! 417: in_port_t
! 418: isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
! 419: in_port_t port = 0;
! 420:
! 421: switch (sockaddr->type.sa.sa_family) {
! 422: case AF_INET:
! 423: port = ntohs(sockaddr->type.sin.sin_port);
! 424: break;
! 425: case AF_INET6:
! 426: port = ntohs(sockaddr->type.sin6.sin6_port);
! 427: break;
! 428: default:
! 429: FATAL_ERROR(__FILE__, __LINE__,
! 430: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
! 431: ISC_MSG_UNKNOWNFAMILY,
! 432: "unknown address family: %d"),
! 433: (int)sockaddr->type.sa.sa_family);
! 434: }
! 435:
! 436: return (port);
! 437: }
! 438:
! 439: isc_boolean_t
! 440: isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
! 441: isc_netaddr_t netaddr;
! 442:
! 443: if (sockaddr->type.sa.sa_family == AF_INET ||
! 444: sockaddr->type.sa.sa_family == AF_INET6) {
! 445: isc_netaddr_fromsockaddr(&netaddr, sockaddr);
! 446: return (isc_netaddr_ismulticast(&netaddr));
! 447: }
! 448: return (ISC_FALSE);
! 449: }
! 450:
! 451: isc_boolean_t
! 452: isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
! 453: isc_netaddr_t netaddr;
! 454:
! 455: if (sockaddr->type.sa.sa_family == AF_INET) {
! 456: isc_netaddr_fromsockaddr(&netaddr, sockaddr);
! 457: return (isc_netaddr_isexperimental(&netaddr));
! 458: }
! 459: return (ISC_FALSE);
! 460: }
! 461:
! 462: isc_boolean_t
! 463: isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
! 464: isc_netaddr_t netaddr;
! 465:
! 466: if (sockaddr->type.sa.sa_family == AF_INET6) {
! 467: isc_netaddr_fromsockaddr(&netaddr, sockaddr);
! 468: return (isc_netaddr_issitelocal(&netaddr));
! 469: }
! 470: return (ISC_FALSE);
! 471: }
! 472:
! 473: isc_boolean_t
! 474: isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
! 475: isc_netaddr_t netaddr;
! 476:
! 477: if (sockaddr->type.sa.sa_family == AF_INET6) {
! 478: isc_netaddr_fromsockaddr(&netaddr, sockaddr);
! 479: return (isc_netaddr_islinklocal(&netaddr));
! 480: }
! 481: return (ISC_FALSE);
! 482: }
! 483:
! 484: isc_result_t
! 485: isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
! 486: #ifdef ISC_PLATFORM_HAVESYSUNH
! 487: if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path))
! 488: return (ISC_R_NOSPACE);
! 489: memset(sockaddr, 0, sizeof(*sockaddr));
! 490: sockaddr->length = sizeof(sockaddr->type.sunix);
! 491: sockaddr->type.sunix.sun_family = AF_UNIX;
! 492: #ifdef ISC_PLATFORM_HAVESALEN
! 493: sockaddr->type.sunix.sun_len =
! 494: (unsigned char)sizeof(sockaddr->type.sunix);
! 495: #endif
! 496: strcpy(sockaddr->type.sunix.sun_path, path);
! 497: return (ISC_R_SUCCESS);
! 498: #else
! 499: UNUSED(sockaddr);
! 500: UNUSED(path);
! 501: return (ISC_R_NOTIMPLEMENTED);
! 502: #endif
! 503: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>