Home | History | Annotate | Line # | Download | only in isc
sockaddr.c revision 1.12
      1 /*	$NetBSD: sockaddr.c,v 1.12 2024/09/22 00:14:08 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 
     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 	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 
    190 void
    191 isc_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 
    211 unsigned int
    212 isc_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 
    258 void
    259 isc_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 
    268 void
    269 isc_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 
    278 void
    279 isc_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 
    289 void
    290 isc_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 
    303 void
    304 isc_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 
    314 void
    315 isc_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 
    327 int
    328 isc_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 
    351 void
    352 isc_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 
    374 void
    375 isc_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 
    389 in_port_t
    390 isc_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 
    408 bool
    409 isc_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 
    421 bool
    422 isc_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 
    432 bool
    433 isc_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 
    443 bool
    444 isc_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 
    454 bool
    455 isc_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 
    465 isc_result_t
    466 isc_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 
    478 isc_result_t
    479 isc_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 
    503 bool
    504 isc_sockaddr_disabled(const isc_sockaddr_t *sockaddr) {
    505 	if ((sockaddr->type.sa.sa_family == AF_INET &&
    506 	     isc_net_probeipv4() == ISC_R_DISABLED) ||
    507 	    (sockaddr->type.sa.sa_family == AF_INET6 &&
    508 	     isc_net_probeipv6() == ISC_R_DISABLED))
    509 	{
    510 		return (true);
    511 	}
    512 	return (false);
    513 }
    514