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