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