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