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