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