1/* 2 * Copyright (C) 2004-2007, 2010-2012 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$ */ 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 if (size == 0U) 186 return; 187 188 isc_buffer_init(&buf, array, size); 189 result = isc_sockaddr_totext(sa, &buf); 190 if (result != ISC_R_SUCCESS) { 191 /* 192 * The message is the same as in netaddr.c. 193 */ 194 snprintf(array, size, 195 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, 196 ISC_MSG_UNKNOWNADDR, 197 "<unknown address, family %u>"), 198 sa->type.sa.sa_family); 199 array[size - 1] = '\0'; 200 } 201} 202 203unsigned int 204isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) { 205 unsigned int length = 0; 206 const unsigned char *s = NULL; 207 unsigned int h = 0; 208 unsigned int g; 209 unsigned int p = 0; 210 const struct in6_addr *in6; 211 212 REQUIRE(sockaddr != NULL); 213 214 switch (sockaddr->type.sa.sa_family) { 215 case AF_INET: 216 s = (const unsigned char *)&sockaddr->type.sin.sin_addr; 217 p = ntohs(sockaddr->type.sin.sin_port); 218 length = sizeof(sockaddr->type.sin.sin_addr.s_addr); 219 break; 220 case AF_INET6: 221 in6 = &sockaddr->type.sin6.sin6_addr; 222 if (IN6_IS_ADDR_V4MAPPED(in6)) { 223 s = (const unsigned char *)&in6[12]; 224 length = sizeof(sockaddr->type.sin.sin_addr.s_addr); 225 } else { 226 s = (const unsigned char *)in6; 227 length = sizeof(sockaddr->type.sin6.sin6_addr); 228 } 229 p = ntohs(sockaddr->type.sin6.sin6_port); 230 break; 231 default: 232 UNEXPECTED_ERROR(__FILE__, __LINE__, 233 isc_msgcat_get(isc_msgcat, 234 ISC_MSGSET_SOCKADDR, 235 ISC_MSG_UNKNOWNFAMILY, 236 "unknown address family: %d"), 237 (int)sockaddr->type.sa.sa_family); 238 s = (const unsigned char *)&sockaddr->type; 239 length = sockaddr->length; 240 p = 0; 241 } 242 243 h = isc_hash_calc(s, length, ISC_TRUE); 244 if (!address_only) { 245 g = isc_hash_calc((const unsigned char *)&p, sizeof(p), 246 ISC_TRUE); 247 h = h ^ g; /* XXX: we should concatenate h and p first */ 248 } 249 250 return (h); 251} 252 253void 254isc_sockaddr_any(isc_sockaddr_t *sockaddr) 255{ 256 memset(sockaddr, 0, sizeof(*sockaddr)); 257 sockaddr->type.sin.sin_family = AF_INET; 258#ifdef ISC_PLATFORM_HAVESALEN 259 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); 260#endif 261 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; 262 sockaddr->type.sin.sin_port = 0; 263 sockaddr->length = sizeof(sockaddr->type.sin); 264 ISC_LINK_INIT(sockaddr, link); 265} 266 267void 268isc_sockaddr_any6(isc_sockaddr_t *sockaddr) 269{ 270 memset(sockaddr, 0, sizeof(*sockaddr)); 271 sockaddr->type.sin6.sin6_family = AF_INET6; 272#ifdef ISC_PLATFORM_HAVESALEN 273 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 274#endif 275 sockaddr->type.sin6.sin6_addr = in6addr_any; 276 sockaddr->type.sin6.sin6_port = 0; 277 sockaddr->length = sizeof(sockaddr->type.sin6); 278 ISC_LINK_INIT(sockaddr, link); 279} 280 281void 282isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 283 in_port_t port) 284{ 285 memset(sockaddr, 0, sizeof(*sockaddr)); 286 sockaddr->type.sin.sin_family = AF_INET; 287#ifdef ISC_PLATFORM_HAVESALEN 288 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); 289#endif 290 sockaddr->type.sin.sin_addr = *ina; 291 sockaddr->type.sin.sin_port = htons(port); 292 sockaddr->length = sizeof(sockaddr->type.sin); 293 ISC_LINK_INIT(sockaddr, link); 294} 295 296void 297isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) { 298 switch (pf) { 299 case AF_INET: 300 isc_sockaddr_any(sockaddr); 301 break; 302 case AF_INET6: 303 isc_sockaddr_any6(sockaddr); 304 break; 305 default: 306 INSIST(0); 307 } 308} 309 310void 311isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, 312 in_port_t port) 313{ 314 memset(sockaddr, 0, sizeof(*sockaddr)); 315 sockaddr->type.sin6.sin6_family = AF_INET6; 316#ifdef ISC_PLATFORM_HAVESALEN 317 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 318#endif 319 sockaddr->type.sin6.sin6_addr = *ina6; 320 sockaddr->type.sin6.sin6_port = htons(port); 321 sockaddr->length = sizeof(sockaddr->type.sin6); 322 ISC_LINK_INIT(sockaddr, link); 323} 324 325void 326isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 327 in_port_t port) 328{ 329 memset(sockaddr, 0, sizeof(*sockaddr)); 330 sockaddr->type.sin6.sin6_family = AF_INET6; 331#ifdef ISC_PLATFORM_HAVESALEN 332 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 333#endif 334 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff; 335 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff; 336 memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4); 337 sockaddr->type.sin6.sin6_port = htons(port); 338 sockaddr->length = sizeof(sockaddr->type.sin6); 339 ISC_LINK_INIT(sockaddr, link); 340} 341 342int 343isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { 344 345 /* 346 * Get the protocol family of 'sockaddr'. 347 */ 348 349#if (AF_INET == PF_INET && AF_INET6 == PF_INET6) 350 /* 351 * Assume that PF_xxx == AF_xxx for all AF and PF. 352 */ 353 return (sockaddr->type.sa.sa_family); 354#else 355 switch (sockaddr->type.sa.sa_family) { 356 case AF_INET: 357 return (PF_INET); 358 case AF_INET6: 359 return (PF_INET6); 360 default: 361 FATAL_ERROR(__FILE__, __LINE__, 362 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, 363 ISC_MSG_UNKNOWNFAMILY, 364 "unknown address family: %d"), 365 (int)sockaddr->type.sa.sa_family); 366 } 367#endif 368} 369 370void 371isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, 372 in_port_t port) 373{ 374 memset(sockaddr, 0, sizeof(*sockaddr)); 375 sockaddr->type.sin.sin_family = na->family; 376 switch (na->family) { 377 case AF_INET: 378 sockaddr->length = sizeof(sockaddr->type.sin); 379#ifdef ISC_PLATFORM_HAVESALEN 380 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); 381#endif 382 sockaddr->type.sin.sin_addr = na->type.in; 383 sockaddr->type.sin.sin_port = htons(port); 384 break; 385 case AF_INET6: 386 sockaddr->length = sizeof(sockaddr->type.sin6); 387#ifdef ISC_PLATFORM_HAVESALEN 388 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 389#endif 390 memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16); 391#ifdef ISC_PLATFORM_HAVESCOPEID 392 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na); 393#endif 394 sockaddr->type.sin6.sin6_port = htons(port); 395 break; 396 default: 397 INSIST(0); 398 } 399 ISC_LINK_INIT(sockaddr, link); 400} 401 402void 403isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) { 404 switch (sockaddr->type.sa.sa_family) { 405 case AF_INET: 406 sockaddr->type.sin.sin_port = htons(port); 407 break; 408 case AF_INET6: 409 sockaddr->type.sin6.sin6_port = htons(port); 410 break; 411 default: 412 FATAL_ERROR(__FILE__, __LINE__, 413 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, 414 ISC_MSG_UNKNOWNFAMILY, 415 "unknown address family: %d"), 416 (int)sockaddr->type.sa.sa_family); 417 } 418} 419 420in_port_t 421isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { 422 in_port_t port = 0; 423 424 switch (sockaddr->type.sa.sa_family) { 425 case AF_INET: 426 port = ntohs(sockaddr->type.sin.sin_port); 427 break; 428 case AF_INET6: 429 port = ntohs(sockaddr->type.sin6.sin6_port); 430 break; 431 default: 432 FATAL_ERROR(__FILE__, __LINE__, 433 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, 434 ISC_MSG_UNKNOWNFAMILY, 435 "unknown address family: %d"), 436 (int)sockaddr->type.sa.sa_family); 437 } 438 439 return (port); 440} 441 442isc_boolean_t 443isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { 444 isc_netaddr_t netaddr; 445 446 if (sockaddr->type.sa.sa_family == AF_INET || 447 sockaddr->type.sa.sa_family == AF_INET6) { 448 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 449 return (isc_netaddr_ismulticast(&netaddr)); 450 } 451 return (ISC_FALSE); 452} 453 454isc_boolean_t 455isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) { 456 isc_netaddr_t netaddr; 457 458 if (sockaddr->type.sa.sa_family == AF_INET) { 459 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 460 return (isc_netaddr_isexperimental(&netaddr)); 461 } 462 return (ISC_FALSE); 463} 464 465isc_boolean_t 466isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { 467 isc_netaddr_t netaddr; 468 469 if (sockaddr->type.sa.sa_family == AF_INET6) { 470 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 471 return (isc_netaddr_issitelocal(&netaddr)); 472 } 473 return (ISC_FALSE); 474} 475 476isc_boolean_t 477isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { 478 isc_netaddr_t netaddr; 479 480 if (sockaddr->type.sa.sa_family == AF_INET6) { 481 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 482 return (isc_netaddr_islinklocal(&netaddr)); 483 } 484 return (ISC_FALSE); 485} 486 487isc_result_t 488isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) { 489#ifdef ISC_PLATFORM_HAVESYSUNH 490 if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path)) 491 return (ISC_R_NOSPACE); 492 memset(sockaddr, 0, sizeof(*sockaddr)); 493 sockaddr->length = sizeof(sockaddr->type.sunix); 494 sockaddr->type.sunix.sun_family = AF_UNIX; 495#ifdef ISC_PLATFORM_HAVESALEN 496 sockaddr->type.sunix.sun_len = 497 (unsigned char)sizeof(sockaddr->type.sunix); 498#endif 499 strcpy(sockaddr->type.sunix.sun_path, path); 500 return (ISC_R_SUCCESS); 501#else 502 UNUSED(sockaddr); 503 UNUSED(path); 504 return (ISC_R_NOTIMPLEMENTED); 505#endif 506} 507