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