Return to sockaddr.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
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: }