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