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 36isc_boolean_t 37isc_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 43isc_boolean_t 44isc_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 49isc_boolean_t 50isc_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 103isc_boolean_t 104isc_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 113isc_result_t 114isc_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 180void 181isc_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 200unsigned int 201isc_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 250void 251isc_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 264void 265isc_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 278void 279isc_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 293void 294isc_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 307void 308isc_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 322void 323isc_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 339int 340isc_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 367void 368isc_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 399void 400isc_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 417in_port_t 418isc_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 439isc_boolean_t 440isc_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 451isc_boolean_t 452isc_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 462isc_boolean_t 463isc_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 473isc_boolean_t 474isc_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 484isc_result_t 485isc_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} 504