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