Home | History | Annotate | Line # | Download | only in isc
      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