1/* $NetBSD: sockaddr.c,v 1.1 2024/02/18 20:57:50 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <stdbool.h> 19#include <stdio.h> 20#if defined(WIN32) || defined(WIN64) 21#include <malloc.h> 22#endif /* if defined(WIN32) || defined(WIN64) */ 23 24#include <isc/buffer.h> 25#include <isc/hash.h> 26#include <isc/netaddr.h> 27#include <isc/print.h> 28#include <isc/region.h> 29#include <isc/sockaddr.h> 30#include <isc/string.h> 31#include <isc/util.h> 32 33bool 34isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 35 return (isc_sockaddr_compare(a, b, 36 ISC_SOCKADDR_CMPADDR | 37 ISC_SOCKADDR_CMPPORT | 38 ISC_SOCKADDR_CMPSCOPE)); 39} 40 41bool 42isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 43 return (isc_sockaddr_compare( 44 a, b, ISC_SOCKADDR_CMPADDR | ISC_SOCKADDR_CMPSCOPE)); 45} 46 47bool 48isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b, 49 unsigned int flags) { 50 REQUIRE(a != NULL && b != NULL); 51 52 if (a->length != b->length) { 53 return (false); 54 } 55 56 /* 57 * We don't just memcmp because the sin_zero field isn't always 58 * zero. 59 */ 60 61 if (a->type.sa.sa_family != b->type.sa.sa_family) { 62 return (false); 63 } 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 { 70 return (false); 71 } 72 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 73 a->type.sin.sin_port != b->type.sin.sin_port) 74 { 75 return (false); 76 } 77 break; 78 case AF_INET6: 79 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && 80 memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr, 81 sizeof(a->type.sin6.sin6_addr)) != 0) 82 { 83 return (false); 84 } 85 /* 86 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return 87 * false if one of the scopes in zero. 88 */ 89 if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 && 90 a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id && 91 ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 || 92 (a->type.sin6.sin6_scope_id != 0 && 93 b->type.sin6.sin6_scope_id != 0))) 94 { 95 return (false); 96 } 97 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 98 a->type.sin6.sin6_port != b->type.sin6.sin6_port) 99 { 100 return (false); 101 } 102 break; 103 default: 104 if (memcmp(&a->type, &b->type, a->length) != 0) { 105 return (false); 106 } 107 } 108 return (true); 109} 110 111bool 112isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b, 113 unsigned int prefixlen) { 114 isc_netaddr_t na, nb; 115 isc_netaddr_fromsockaddr(&na, a); 116 isc_netaddr_fromsockaddr(&nb, b); 117 return (isc_netaddr_eqprefix(&na, &nb, prefixlen)); 118} 119 120isc_result_t 121isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) { 122 isc_result_t result; 123 isc_netaddr_t netaddr; 124 char pbuf[sizeof("65000")]; 125 unsigned int plen; 126 isc_region_t avail; 127 128 REQUIRE(sockaddr != NULL); 129 130 /* 131 * Do the port first, giving us the opportunity to check for 132 * unsupported address families before calling 133 * isc_netaddr_fromsockaddr(). 134 */ 135 switch (sockaddr->type.sa.sa_family) { 136 case AF_INET: 137 snprintf(pbuf, sizeof(pbuf), "%u", 138 ntohs(sockaddr->type.sin.sin_port)); 139 break; 140 case AF_INET6: 141 snprintf(pbuf, sizeof(pbuf), "%u", 142 ntohs(sockaddr->type.sin6.sin6_port)); 143 break; 144#ifdef ISC_PLATFORM_HAVESYSUNH 145 case AF_UNIX: 146 plen = strlen(sockaddr->type.sunix.sun_path); 147 if (plen >= isc_buffer_availablelength(target)) { 148 return (ISC_R_NOSPACE); 149 } 150 151 isc_buffer_putmem( 152 target, 153 (const unsigned char *)sockaddr->type.sunix.sun_path, 154 plen); 155 156 /* 157 * Null terminate after used region. 158 */ 159 isc_buffer_availableregion(target, &avail); 160 INSIST(avail.length >= 1); 161 avail.base[0] = '\0'; 162 163 return (ISC_R_SUCCESS); 164#endif /* ifdef ISC_PLATFORM_HAVESYSUNH */ 165 default: 166 return (ISC_R_FAILURE); 167 } 168 169 plen = strlen(pbuf); 170 INSIST(plen < sizeof(pbuf)); 171 172 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 173 result = isc_netaddr_totext(&netaddr, target); 174 if (result != ISC_R_SUCCESS) { 175 return (result); 176 } 177 178 if (1 + plen + 1 > isc_buffer_availablelength(target)) { 179 return (ISC_R_NOSPACE); 180 } 181 182 isc_buffer_putmem(target, (const unsigned char *)"#", 1); 183 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen); 184 185 /* 186 * Null terminate after used region. 187 */ 188 isc_buffer_availableregion(target, &avail); 189 INSIST(avail.length >= 1); 190 avail.base[0] = '\0'; 191 192 return (ISC_R_SUCCESS); 193} 194 195void 196isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) { 197 isc_result_t result; 198 isc_buffer_t buf; 199 200 if (size == 0U) { 201 return; 202 } 203 204 isc_buffer_init(&buf, array, size); 205 result = isc_sockaddr_totext(sa, &buf); 206 if (result != ISC_R_SUCCESS) { 207 /* 208 * The message is the same as in netaddr.c. 209 */ 210 snprintf(array, size, "<unknown address, family %u>", 211 sa->type.sa.sa_family); 212 array[size - 1] = '\0'; 213 } 214} 215 216unsigned int 217isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) { 218 unsigned int length = 0; 219 const unsigned char *s = NULL; 220 unsigned int h = 0; 221 unsigned int p = 0; 222 const struct in6_addr *in6; 223 224 REQUIRE(sockaddr != NULL); 225 226 switch (sockaddr->type.sa.sa_family) { 227 case AF_INET: 228 s = (const unsigned char *)&sockaddr->type.sin.sin_addr; 229 p = ntohs(sockaddr->type.sin.sin_port); 230 length = sizeof(sockaddr->type.sin.sin_addr.s_addr); 231 break; 232 case AF_INET6: 233 in6 = &sockaddr->type.sin6.sin6_addr; 234 s = (const unsigned char *)in6; 235 if (IN6_IS_ADDR_V4MAPPED(in6)) { 236 s += 12; 237 length = sizeof(sockaddr->type.sin.sin_addr.s_addr); 238 } else { 239 length = sizeof(sockaddr->type.sin6.sin6_addr); 240 } 241 p = ntohs(sockaddr->type.sin6.sin6_port); 242 break; 243 default: 244 UNEXPECTED_ERROR(__FILE__, __LINE__, 245 "unknown address family: %d", 246 (int)sockaddr->type.sa.sa_family); 247 s = (const unsigned char *)&sockaddr->type; 248 length = sockaddr->length; 249 p = 0; 250 } 251 252 uint8_t buf[sizeof(struct sockaddr_storage) + sizeof(p)]; 253 memmove(buf, s, length); 254 if (!address_only) { 255 memmove(buf + length, &p, sizeof(p)); 256 h = isc_hash_function(buf, length + sizeof(p), true); 257 } else { 258 h = isc_hash_function(buf, length, true); 259 } 260 261 return (h); 262} 263 264void 265isc_sockaddr_any(isc_sockaddr_t *sockaddr) { 266 memset(sockaddr, 0, sizeof(*sockaddr)); 267 sockaddr->type.sin.sin_family = AF_INET; 268 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; 269 sockaddr->type.sin.sin_port = 0; 270 sockaddr->length = sizeof(sockaddr->type.sin); 271 ISC_LINK_INIT(sockaddr, link); 272} 273 274void 275isc_sockaddr_any6(isc_sockaddr_t *sockaddr) { 276 memset(sockaddr, 0, sizeof(*sockaddr)); 277 sockaddr->type.sin6.sin6_family = AF_INET6; 278 sockaddr->type.sin6.sin6_addr = in6addr_any; 279 sockaddr->type.sin6.sin6_port = 0; 280 sockaddr->length = sizeof(sockaddr->type.sin6); 281 ISC_LINK_INIT(sockaddr, link); 282} 283 284void 285isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 286 in_port_t port) { 287 memset(sockaddr, 0, sizeof(*sockaddr)); 288 sockaddr->type.sin.sin_family = AF_INET; 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 UNREACHABLE(); 306 } 307} 308 309void 310isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, 311 in_port_t port) { 312 memset(sockaddr, 0, sizeof(*sockaddr)); 313 sockaddr->type.sin6.sin6_family = AF_INET6; 314 sockaddr->type.sin6.sin6_addr = *ina6; 315 sockaddr->type.sin6.sin6_port = htons(port); 316 sockaddr->length = sizeof(sockaddr->type.sin6); 317 ISC_LINK_INIT(sockaddr, link); 318} 319 320void 321isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 322 in_port_t port) { 323 memset(sockaddr, 0, sizeof(*sockaddr)); 324 sockaddr->type.sin6.sin6_family = AF_INET6; 325 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff; 326 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff; 327 memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4); 328 sockaddr->type.sin6.sin6_port = htons(port); 329 sockaddr->length = sizeof(sockaddr->type.sin6); 330 ISC_LINK_INIT(sockaddr, link); 331} 332 333int 334isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { 335 /* 336 * Get the protocol family of 'sockaddr'. 337 */ 338 339#if (AF_INET == PF_INET && AF_INET6 == PF_INET6) 340 /* 341 * Assume that PF_xxx == AF_xxx for all AF and PF. 342 */ 343 return (sockaddr->type.sa.sa_family); 344#else /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 345 switch (sockaddr->type.sa.sa_family) { 346 case AF_INET: 347 return (PF_INET); 348 case AF_INET6: 349 return (PF_INET6); 350 default: 351 FATAL_ERROR(__FILE__, __LINE__, "unknown address family: %d", 352 (int)sockaddr->type.sa.sa_family); 353 } 354#endif /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 355} 356 357void 358isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, 359 in_port_t port) { 360 memset(sockaddr, 0, sizeof(*sockaddr)); 361 sockaddr->type.sin.sin_family = na->family; 362 switch (na->family) { 363 case AF_INET: 364 sockaddr->length = sizeof(sockaddr->type.sin); 365 sockaddr->type.sin.sin_addr = na->type.in; 366 sockaddr->type.sin.sin_port = htons(port); 367 break; 368 case AF_INET6: 369 sockaddr->length = sizeof(sockaddr->type.sin6); 370 memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16); 371 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na); 372 sockaddr->type.sin6.sin6_port = htons(port); 373 break; 374 default: 375 UNREACHABLE(); 376 } 377 ISC_LINK_INIT(sockaddr, link); 378} 379 380void 381isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) { 382 switch (sockaddr->type.sa.sa_family) { 383 case AF_INET: 384 sockaddr->type.sin.sin_port = htons(port); 385 break; 386 case AF_INET6: 387 sockaddr->type.sin6.sin6_port = htons(port); 388 break; 389 default: 390 FATAL_ERROR(__FILE__, __LINE__, "unknown address family: %d", 391 (int)sockaddr->type.sa.sa_family); 392 } 393} 394 395in_port_t 396isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { 397 in_port_t port = 0; 398 399 switch (sockaddr->type.sa.sa_family) { 400 case AF_INET: 401 port = ntohs(sockaddr->type.sin.sin_port); 402 break; 403 case AF_INET6: 404 port = ntohs(sockaddr->type.sin6.sin6_port); 405 break; 406 default: 407 FATAL_ERROR(__FILE__, __LINE__, "unknown address family: %d", 408 (int)sockaddr->type.sa.sa_family); 409 } 410 411 return (port); 412} 413 414bool 415isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { 416 isc_netaddr_t netaddr; 417 418 if (sockaddr->type.sa.sa_family == AF_INET || 419 sockaddr->type.sa.sa_family == AF_INET6) 420 { 421 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 422 return (isc_netaddr_ismulticast(&netaddr)); 423 } 424 return (false); 425} 426 427bool 428isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) { 429 isc_netaddr_t netaddr; 430 431 if (sockaddr->type.sa.sa_family == AF_INET) { 432 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 433 return (isc_netaddr_isexperimental(&netaddr)); 434 } 435 return (false); 436} 437 438bool 439isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { 440 isc_netaddr_t netaddr; 441 442 if (sockaddr->type.sa.sa_family == AF_INET6) { 443 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 444 return (isc_netaddr_issitelocal(&netaddr)); 445 } 446 return (false); 447} 448 449bool 450isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { 451 isc_netaddr_t netaddr; 452 453 if (sockaddr->type.sa.sa_family == AF_INET6) { 454 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 455 return (isc_netaddr_islinklocal(&netaddr)); 456 } 457 return (false); 458} 459 460bool 461isc_sockaddr_isnetzero(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_isnetzero(&netaddr)); 467 } 468 return (false); 469} 470 471isc_result_t 472isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) { 473#ifdef ISC_PLATFORM_HAVESYSUNH 474 if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path)) { 475 return (ISC_R_NOSPACE); 476 } 477 memset(sockaddr, 0, sizeof(*sockaddr)); 478 sockaddr->length = sizeof(sockaddr->type.sunix); 479 sockaddr->type.sunix.sun_family = AF_UNIX; 480 strlcpy(sockaddr->type.sunix.sun_path, path, 481 sizeof(sockaddr->type.sunix.sun_path)); 482 return (ISC_R_SUCCESS); 483#else /* ifdef ISC_PLATFORM_HAVESYSUNH */ 484 UNUSED(sockaddr); 485 UNUSED(path); 486 return (ISC_R_NOTIMPLEMENTED); 487#endif /* ifdef ISC_PLATFORM_HAVESYSUNH */ 488} 489 490isc_result_t 491isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) { 492 unsigned int length = 0; 493 494 switch (sa->sa_family) { 495 case AF_INET: 496 length = sizeof(isa->type.sin); 497 break; 498 case AF_INET6: 499 length = sizeof(isa->type.sin6); 500 break; 501#ifdef ISC_PLATFORM_HAVESYSUNH 502 case AF_UNIX: 503 length = sizeof(isa->type.sunix); 504 break; 505#endif /* ifdef ISC_PLATFORM_HAVESYSUNH */ 506 default: 507 return (ISC_R_NOTIMPLEMENTED); 508 } 509 510 memset(isa, 0, sizeof(isc_sockaddr_t)); 511 memmove(isa, sa, length); 512 isa->length = length; 513 514 return (ISC_R_SUCCESS); 515} 516