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