1 /* $NetBSD: sockaddr.c,v 1.13 2025/01/26 16:25:38 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 <netdb.h> 19 #include <stdbool.h> 20 #include <stdio.h> 21 22 #include <isc/buffer.h> 23 #include <isc/hash.h> 24 #include <isc/netaddr.h> 25 #include <isc/region.h> 26 #include <isc/sockaddr.h> 27 #include <isc/string.h> 28 #include <isc/util.h> 29 30 bool 31 isc_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 38 bool 39 isc_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 44 bool 45 isc_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 108 bool 109 isc_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 117 isc_result_t 118 isc_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 default: 142 return ISC_R_FAILURE; 143 } 144 145 plen = strlen(pbuf); 146 INSIST(plen < sizeof(pbuf)); 147 148 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 149 result = isc_netaddr_totext(&netaddr, target); 150 if (result != ISC_R_SUCCESS) { 151 return result; 152 } 153 154 if (1 + plen + 1 > isc_buffer_availablelength(target)) { 155 return ISC_R_NOSPACE; 156 } 157 158 isc_buffer_putmem(target, (const unsigned char *)"#", 1); 159 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen); 160 161 /* 162 * Null terminate after used region. 163 */ 164 isc_buffer_availableregion(target, &avail); 165 INSIST(avail.length >= 1); 166 avail.base[0] = '\0'; 167 168 return ISC_R_SUCCESS; 169 } 170 171 void 172 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) { 173 isc_result_t result; 174 isc_buffer_t buf; 175 176 if (size == 0U) { 177 return; 178 } 179 180 isc_buffer_init(&buf, array, size); 181 result = isc_sockaddr_totext(sa, &buf); 182 if (result != ISC_R_SUCCESS) { 183 /* 184 * The message is the same as in netaddr.c. 185 */ 186 snprintf(array, size, "<unknown address, family %u>", 187 sa->type.sa.sa_family); 188 array[size - 1] = '\0'; 189 } 190 } 191 192 void 193 isc_sockaddr_hash_ex(isc_hash32_t *hash, const isc_sockaddr_t *sockaddr, 194 bool address_only) { 195 REQUIRE(sockaddr != NULL); 196 197 size_t len = 0; 198 const uint8_t *s = NULL; 199 unsigned int p = 0; 200 const struct in6_addr *in6; 201 202 switch (sockaddr->type.sa.sa_family) { 203 case AF_INET: 204 s = (const uint8_t *)&sockaddr->type.sin.sin_addr; 205 len = sizeof(sockaddr->type.sin.sin_addr.s_addr); 206 if (!address_only) { 207 p = ntohs(sockaddr->type.sin.sin_port); 208 } 209 break; 210 case AF_INET6: 211 in6 = &sockaddr->type.sin6.sin6_addr; 212 s = (const uint8_t *)in6; 213 if (IN6_IS_ADDR_V4MAPPED(in6)) { 214 s += 12; 215 len = sizeof(sockaddr->type.sin.sin_addr.s_addr); 216 } else { 217 len = sizeof(sockaddr->type.sin6.sin6_addr); 218 } 219 if (!address_only) { 220 p = ntohs(sockaddr->type.sin6.sin6_port); 221 } 222 break; 223 default: 224 UNREACHABLE(); 225 } 226 227 isc_hash32_hash(hash, s, len, true); 228 if (!address_only) { 229 isc_hash32_hash(hash, &p, sizeof(p), true); 230 } 231 } 232 233 uint32_t 234 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) { 235 isc_hash32_t hash; 236 237 isc_hash32_init(&hash); 238 239 isc_sockaddr_hash_ex(&hash, sockaddr, address_only); 240 241 return isc_hash32_finalize(&hash); 242 } 243 244 void 245 isc_sockaddr_any(isc_sockaddr_t *sockaddr) { 246 memset(sockaddr, 0, sizeof(*sockaddr)); 247 sockaddr->type.sin.sin_family = AF_INET; 248 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; 249 sockaddr->type.sin.sin_port = 0; 250 sockaddr->length = sizeof(sockaddr->type.sin); 251 ISC_LINK_INIT(sockaddr, link); 252 } 253 254 void 255 isc_sockaddr_any6(isc_sockaddr_t *sockaddr) { 256 memset(sockaddr, 0, sizeof(*sockaddr)); 257 sockaddr->type.sin6.sin6_family = AF_INET6; 258 sockaddr->type.sin6.sin6_addr = in6addr_any; 259 sockaddr->type.sin6.sin6_port = 0; 260 sockaddr->length = sizeof(sockaddr->type.sin6); 261 ISC_LINK_INIT(sockaddr, link); 262 } 263 264 void 265 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 266 in_port_t port) { 267 memset(sockaddr, 0, sizeof(*sockaddr)); 268 sockaddr->type.sin.sin_family = AF_INET; 269 sockaddr->type.sin.sin_addr = *ina; 270 sockaddr->type.sin.sin_port = htons(port); 271 sockaddr->length = sizeof(sockaddr->type.sin); 272 ISC_LINK_INIT(sockaddr, link); 273 } 274 275 void 276 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) { 277 switch (pf) { 278 case AF_INET: 279 isc_sockaddr_any(sockaddr); 280 break; 281 case AF_INET6: 282 isc_sockaddr_any6(sockaddr); 283 break; 284 default: 285 UNREACHABLE(); 286 } 287 } 288 289 void 290 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, 291 in_port_t port) { 292 memset(sockaddr, 0, sizeof(*sockaddr)); 293 sockaddr->type.sin6.sin6_family = AF_INET6; 294 sockaddr->type.sin6.sin6_addr = *ina6; 295 sockaddr->type.sin6.sin6_port = htons(port); 296 sockaddr->length = sizeof(sockaddr->type.sin6); 297 ISC_LINK_INIT(sockaddr, link); 298 } 299 300 void 301 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 302 in_port_t port) { 303 memset(sockaddr, 0, sizeof(*sockaddr)); 304 sockaddr->type.sin6.sin6_family = AF_INET6; 305 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff; 306 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff; 307 memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4); 308 sockaddr->type.sin6.sin6_port = htons(port); 309 sockaddr->length = sizeof(sockaddr->type.sin6); 310 ISC_LINK_INIT(sockaddr, link); 311 } 312 313 int 314 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { 315 /* 316 * Get the protocol family of 'sockaddr'. 317 */ 318 319 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6) 320 /* 321 * Assume that PF_xxx == AF_xxx for all AF and PF. 322 */ 323 return sockaddr->type.sa.sa_family; 324 #else /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 325 switch (sockaddr->type.sa.sa_family) { 326 case AF_INET: 327 return PF_INET; 328 case AF_INET6: 329 return PF_INET6; 330 default: 331 FATAL_ERROR("unknown address family: %d", 332 (int)sockaddr->type.sa.sa_family); 333 } 334 #endif /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */ 335 } 336 337 void 338 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, 339 in_port_t port) { 340 memset(sockaddr, 0, sizeof(*sockaddr)); 341 sockaddr->type.sin.sin_family = na->family; 342 switch (na->family) { 343 case AF_INET: 344 sockaddr->length = sizeof(sockaddr->type.sin); 345 sockaddr->type.sin.sin_addr = na->type.in; 346 sockaddr->type.sin.sin_port = htons(port); 347 break; 348 case AF_INET6: 349 sockaddr->length = sizeof(sockaddr->type.sin6); 350 memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16); 351 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na); 352 sockaddr->type.sin6.sin6_port = htons(port); 353 break; 354 default: 355 UNREACHABLE(); 356 } 357 ISC_LINK_INIT(sockaddr, link); 358 } 359 360 void 361 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) { 362 switch (sockaddr->type.sa.sa_family) { 363 case AF_INET: 364 sockaddr->type.sin.sin_port = htons(port); 365 break; 366 case AF_INET6: 367 sockaddr->type.sin6.sin6_port = htons(port); 368 break; 369 default: 370 FATAL_ERROR("unknown address family: %d", 371 (int)sockaddr->type.sa.sa_family); 372 } 373 } 374 375 in_port_t 376 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { 377 in_port_t port = 0; 378 379 switch (sockaddr->type.sa.sa_family) { 380 case AF_INET: 381 port = ntohs(sockaddr->type.sin.sin_port); 382 break; 383 case AF_INET6: 384 port = ntohs(sockaddr->type.sin6.sin6_port); 385 break; 386 default: 387 FATAL_ERROR("unknown address family: %d", 388 (int)sockaddr->type.sa.sa_family); 389 } 390 391 return port; 392 } 393 394 bool 395 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { 396 isc_netaddr_t netaddr; 397 398 if (sockaddr->type.sa.sa_family == AF_INET || 399 sockaddr->type.sa.sa_family == AF_INET6) 400 { 401 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 402 return isc_netaddr_ismulticast(&netaddr); 403 } 404 return false; 405 } 406 407 bool 408 isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) { 409 isc_netaddr_t netaddr; 410 411 if (sockaddr->type.sa.sa_family == AF_INET) { 412 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 413 return isc_netaddr_isexperimental(&netaddr); 414 } 415 return false; 416 } 417 418 bool 419 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { 420 isc_netaddr_t netaddr; 421 422 if (sockaddr->type.sa.sa_family == AF_INET6) { 423 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 424 return isc_netaddr_issitelocal(&netaddr); 425 } 426 return false; 427 } 428 429 bool 430 isc_sockaddr_islinklocal(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_islinklocal(&netaddr); 436 } 437 return false; 438 } 439 440 bool 441 isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) { 442 isc_netaddr_t netaddr; 443 444 if (sockaddr->type.sa.sa_family == AF_INET) { 445 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 446 return isc_netaddr_isnetzero(&netaddr); 447 } 448 return false; 449 } 450 451 isc_result_t 452 isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) { 453 unsigned int length = 0; 454 455 switch (sa->sa_family) { 456 case AF_INET: 457 length = sizeof(isa->type.sin); 458 break; 459 case AF_INET6: 460 length = sizeof(isa->type.sin6); 461 break; 462 default: 463 return ISC_R_NOTIMPLEMENTED; 464 } 465 466 *isa = (isc_sockaddr_t){ .length = length, 467 .link = ISC_LINK_INITIALIZER }; 468 memmove(isa, sa, length); 469 470 return ISC_R_SUCCESS; 471 } 472 473 bool 474 isc_sockaddr_disabled(const isc_sockaddr_t *sockaddr) { 475 if ((sockaddr->type.sa.sa_family == AF_INET && 476 isc_net_probeipv4() == ISC_R_DISABLED) || 477 (sockaddr->type.sa.sa_family == AF_INET6 && 478 isc_net_probeipv6() == ISC_R_DISABLED)) 479 { 480 return true; 481 } 482 return false; 483 } 484