Home | History | Annotate | Line # | Download | only in isc
netaddr.c revision 1.6
      1 /*	$NetBSD: netaddr.c,v 1.6 2021/02/19 16:42:19 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 https://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 <inttypes.h>
     17 #include <stdbool.h>
     18 #include <stdio.h>
     19 
     20 #include <isc/buffer.h>
     21 #include <isc/net.h>
     22 #include <isc/netaddr.h>
     23 #include <isc/print.h>
     24 #include <isc/sockaddr.h>
     25 #include <isc/string.h>
     26 #include <isc/util.h>
     27 
     28 bool
     29 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
     30 	REQUIRE(a != NULL && b != NULL);
     31 
     32 	if (a->family != b->family) {
     33 		return (false);
     34 	}
     35 
     36 	if (a->zone != b->zone) {
     37 		return (false);
     38 	}
     39 
     40 	switch (a->family) {
     41 	case AF_INET:
     42 		if (a->type.in.s_addr != b->type.in.s_addr) {
     43 			return (false);
     44 		}
     45 		break;
     46 	case AF_INET6:
     47 		if (memcmp(&a->type.in6, &b->type.in6, sizeof(a->type.in6)) !=
     48 			    0 ||
     49 		    a->zone != b->zone)
     50 		{
     51 			return (false);
     52 		}
     53 		break;
     54 #ifdef ISC_PLATFORM_HAVESYSUNH
     55 	case AF_UNIX:
     56 		if (strcmp(a->type.un, b->type.un) != 0) {
     57 			return (false);
     58 		}
     59 		break;
     60 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
     61 	default:
     62 		return (false);
     63 	}
     64 	return (true);
     65 }
     66 
     67 bool
     68 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
     69 		     unsigned int prefixlen) {
     70 	const unsigned char *pa = NULL, *pb = NULL;
     71 	unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
     72 	unsigned int nbytes;	   /* Number of significant whole bytes */
     73 	unsigned int nbits;	   /* Number of significant leftover bits */
     74 
     75 	REQUIRE(a != NULL && b != NULL);
     76 
     77 	if (a->family != b->family) {
     78 		return (false);
     79 	}
     80 
     81 	if (a->zone != b->zone && b->zone != 0) {
     82 		return (false);
     83 	}
     84 
     85 	switch (a->family) {
     86 	case AF_INET:
     87 		pa = (const unsigned char *)&a->type.in;
     88 		pb = (const unsigned char *)&b->type.in;
     89 		ipabytes = 4;
     90 		break;
     91 	case AF_INET6:
     92 		pa = (const unsigned char *)&a->type.in6;
     93 		pb = (const unsigned char *)&b->type.in6;
     94 		ipabytes = 16;
     95 		break;
     96 	default:
     97 		return (false);
     98 	}
     99 
    100 	/*
    101 	 * Don't crash if we get a pattern like 10.0.0.1/9999999.
    102 	 */
    103 	if (prefixlen > ipabytes * 8) {
    104 		prefixlen = ipabytes * 8;
    105 	}
    106 
    107 	nbytes = prefixlen / 8;
    108 	nbits = prefixlen % 8;
    109 
    110 	if (nbytes > 0) {
    111 		if (memcmp(pa, pb, nbytes) != 0) {
    112 			return (false);
    113 		}
    114 	}
    115 	if (nbits > 0) {
    116 		unsigned int bytea, byteb, mask;
    117 		INSIST(nbytes < ipabytes);
    118 		INSIST(nbits < 8);
    119 		bytea = pa[nbytes];
    120 		byteb = pb[nbytes];
    121 		mask = (0xFF << (8 - nbits)) & 0xFF;
    122 		if ((bytea & mask) != (byteb & mask)) {
    123 			return (false);
    124 		}
    125 	}
    126 	return (true);
    127 }
    128 
    129 isc_result_t
    130 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
    131 	char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
    132 	char zbuf[sizeof("%4294967295")];
    133 	unsigned int alen;
    134 	int zlen;
    135 	const char *r;
    136 	const void *type;
    137 
    138 	REQUIRE(netaddr != NULL);
    139 
    140 	switch (netaddr->family) {
    141 	case AF_INET:
    142 		type = &netaddr->type.in;
    143 		break;
    144 	case AF_INET6:
    145 		type = &netaddr->type.in6;
    146 		break;
    147 #ifdef ISC_PLATFORM_HAVESYSUNH
    148 	case AF_UNIX:
    149 		alen = strlen(netaddr->type.un);
    150 		if (alen > isc_buffer_availablelength(target)) {
    151 			return (ISC_R_NOSPACE);
    152 		}
    153 		isc_buffer_putmem(target,
    154 				  (const unsigned char *)(netaddr->type.un),
    155 				  alen);
    156 		return (ISC_R_SUCCESS);
    157 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
    158 	default:
    159 		return (ISC_R_FAILURE);
    160 	}
    161 	r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
    162 	if (r == NULL) {
    163 		return (ISC_R_FAILURE);
    164 	}
    165 
    166 	alen = strlen(abuf);
    167 	INSIST(alen < sizeof(abuf));
    168 
    169 	zlen = 0;
    170 	if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
    171 		zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
    172 		if (zlen < 0) {
    173 			return (ISC_R_FAILURE);
    174 		}
    175 		INSIST((unsigned int)zlen < sizeof(zbuf));
    176 	}
    177 
    178 	if (alen + zlen > isc_buffer_availablelength(target)) {
    179 		return (ISC_R_NOSPACE);
    180 	}
    181 
    182 	isc_buffer_putmem(target, (unsigned char *)abuf, alen);
    183 	isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen);
    184 
    185 	return (ISC_R_SUCCESS);
    186 }
    187 
    188 void
    189 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
    190 	isc_result_t result;
    191 	isc_buffer_t buf;
    192 
    193 	isc_buffer_init(&buf, array, size);
    194 	result = isc_netaddr_totext(na, &buf);
    195 
    196 	if (size == 0) {
    197 		return;
    198 	}
    199 
    200 	/*
    201 	 * Null terminate.
    202 	 */
    203 	if (result == ISC_R_SUCCESS) {
    204 		if (isc_buffer_availablelength(&buf) >= 1) {
    205 			isc_buffer_putuint8(&buf, 0);
    206 		} else {
    207 			result = ISC_R_NOSPACE;
    208 		}
    209 	}
    210 
    211 	if (result != ISC_R_SUCCESS) {
    212 		snprintf(array, size, "<unknown address, family %u>",
    213 			 na->family);
    214 		array[size - 1] = '\0';
    215 	}
    216 }
    217 
    218 isc_result_t
    219 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
    220 	static const unsigned char zeros[16];
    221 	unsigned int nbits, nbytes, ipbytes = 0;
    222 	const unsigned char *p;
    223 
    224 	switch (na->family) {
    225 	case AF_INET:
    226 		p = (const unsigned char *)&na->type.in;
    227 		ipbytes = 4;
    228 		if (prefixlen > 32) {
    229 			return (ISC_R_RANGE);
    230 		}
    231 		break;
    232 	case AF_INET6:
    233 		p = (const unsigned char *)&na->type.in6;
    234 		ipbytes = 16;
    235 		if (prefixlen > 128) {
    236 			return (ISC_R_RANGE);
    237 		}
    238 		break;
    239 	default:
    240 		return (ISC_R_NOTIMPLEMENTED);
    241 	}
    242 	nbytes = prefixlen / 8;
    243 	nbits = prefixlen % 8;
    244 	if (nbits != 0) {
    245 		INSIST(nbytes < ipbytes);
    246 		if ((p[nbytes] & (0xff >> nbits)) != 0U) {
    247 			return (ISC_R_FAILURE);
    248 		}
    249 		nbytes++;
    250 	}
    251 	if (nbytes < ipbytes &&
    252 	    memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) {
    253 		return (ISC_R_FAILURE);
    254 	}
    255 	return (ISC_R_SUCCESS);
    256 }
    257 
    258 isc_result_t
    259 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
    260 	unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
    261 	const unsigned char *p;
    262 
    263 	switch (s->family) {
    264 	case AF_INET:
    265 		p = (const unsigned char *)&s->type.in;
    266 		ipbytes = 4;
    267 		break;
    268 	case AF_INET6:
    269 		p = (const unsigned char *)&s->type.in6;
    270 		ipbytes = 16;
    271 		break;
    272 	default:
    273 		return (ISC_R_NOTIMPLEMENTED);
    274 	}
    275 	for (i = 0; i < ipbytes; i++) {
    276 		if (p[i] != 0xFF) {
    277 			break;
    278 		}
    279 	}
    280 	nbytes = i;
    281 	if (i < ipbytes) {
    282 		unsigned int c = p[nbytes];
    283 		while ((c & 0x80) != 0 && nbits < 8) {
    284 			c <<= 1;
    285 			nbits++;
    286 		}
    287 		if ((c & 0xFF) != 0) {
    288 			return (ISC_R_MASKNONCONTIG);
    289 		}
    290 		i++;
    291 	}
    292 	for (; i < ipbytes; i++) {
    293 		if (p[i] != 0) {
    294 			return (ISC_R_MASKNONCONTIG);
    295 		}
    296 	}
    297 	*lenp = nbytes * 8 + nbits;
    298 	return (ISC_R_SUCCESS);
    299 }
    300 
    301 void
    302 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
    303 	memset(netaddr, 0, sizeof(*netaddr));
    304 	netaddr->family = AF_INET;
    305 	netaddr->type.in = *ina;
    306 }
    307 
    308 void
    309 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
    310 	memset(netaddr, 0, sizeof(*netaddr));
    311 	netaddr->family = AF_INET6;
    312 	netaddr->type.in6 = *ina6;
    313 }
    314 
    315 isc_result_t
    316 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
    317 #ifdef ISC_PLATFORM_HAVESYSUNH
    318 	if (strlen(path) > sizeof(netaddr->type.un) - 1) {
    319 		return (ISC_R_NOSPACE);
    320 	}
    321 
    322 	memset(netaddr, 0, sizeof(*netaddr));
    323 	netaddr->family = AF_UNIX;
    324 	strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un));
    325 	netaddr->zone = 0;
    326 	return (ISC_R_SUCCESS);
    327 #else  /* ifdef ISC_PLATFORM_HAVESYSUNH */
    328 	UNUSED(netaddr);
    329 	UNUSED(path);
    330 	return (ISC_R_NOTIMPLEMENTED);
    331 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
    332 }
    333 
    334 void
    335 isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) {
    336 	/* we currently only support AF_INET6. */
    337 	REQUIRE(netaddr->family == AF_INET6);
    338 
    339 	netaddr->zone = zone;
    340 }
    341 
    342 uint32_t
    343 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
    344 	return (netaddr->zone);
    345 }
    346 
    347 void
    348 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
    349 	int family = s->type.sa.sa_family;
    350 	t->family = family;
    351 	switch (family) {
    352 	case AF_INET:
    353 		t->type.in = s->type.sin.sin_addr;
    354 		t->zone = 0;
    355 		break;
    356 	case AF_INET6:
    357 		memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
    358 		t->zone = s->type.sin6.sin6_scope_id;
    359 		break;
    360 #ifdef ISC_PLATFORM_HAVESYSUNH
    361 	case AF_UNIX:
    362 		memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
    363 		t->zone = 0;
    364 		break;
    365 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
    366 	default:
    367 		INSIST(0);
    368 		ISC_UNREACHABLE();
    369 	}
    370 }
    371 
    372 void
    373 isc_netaddr_any(isc_netaddr_t *netaddr) {
    374 	memset(netaddr, 0, sizeof(*netaddr));
    375 	netaddr->family = AF_INET;
    376 	netaddr->type.in.s_addr = INADDR_ANY;
    377 }
    378 
    379 void
    380 isc_netaddr_any6(isc_netaddr_t *netaddr) {
    381 	memset(netaddr, 0, sizeof(*netaddr));
    382 	netaddr->family = AF_INET6;
    383 	netaddr->type.in6 = in6addr_any;
    384 }
    385 
    386 void
    387 isc_netaddr_unspec(isc_netaddr_t *netaddr) {
    388 	memset(netaddr, 0, sizeof(*netaddr));
    389 	netaddr->family = AF_UNSPEC;
    390 }
    391 
    392 bool
    393 isc_netaddr_ismulticast(const isc_netaddr_t *na) {
    394 	switch (na->family) {
    395 	case AF_INET:
    396 		return (ISC_IPADDR_ISMULTICAST(na->type.in.s_addr));
    397 	case AF_INET6:
    398 		return (IN6_IS_ADDR_MULTICAST(&na->type.in6));
    399 	default:
    400 		return (false); /* XXXMLG ? */
    401 	}
    402 }
    403 
    404 bool
    405 isc_netaddr_isexperimental(const isc_netaddr_t *na) {
    406 	switch (na->family) {
    407 	case AF_INET:
    408 		return (ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr));
    409 	default:
    410 		return (false); /* XXXMLG ? */
    411 	}
    412 }
    413 
    414 bool
    415 isc_netaddr_islinklocal(const isc_netaddr_t *na) {
    416 	switch (na->family) {
    417 	case AF_INET:
    418 		return (false);
    419 	case AF_INET6:
    420 		return (IN6_IS_ADDR_LINKLOCAL(&na->type.in6));
    421 	default:
    422 		return (false);
    423 	}
    424 }
    425 
    426 bool
    427 isc_netaddr_issitelocal(const isc_netaddr_t *na) {
    428 	switch (na->family) {
    429 	case AF_INET:
    430 		return (false);
    431 	case AF_INET6:
    432 		return (IN6_IS_ADDR_SITELOCAL(&na->type.in6));
    433 	default:
    434 		return (false);
    435 	}
    436 }
    437 
    438 #define ISC_IPADDR_ISNETZERO(i) \
    439 	(((uint32_t)(i)&ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000))
    440 
    441 bool
    442 isc_netaddr_isnetzero(const isc_netaddr_t *na) {
    443 	switch (na->family) {
    444 	case AF_INET:
    445 		return (ISC_IPADDR_ISNETZERO(na->type.in.s_addr));
    446 	case AF_INET6:
    447 		return (false);
    448 	default:
    449 		return (false);
    450 	}
    451 }
    452 
    453 void
    454 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
    455 	isc_netaddr_t *src;
    456 
    457 	DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */
    458 
    459 	REQUIRE(s->family == AF_INET6);
    460 	REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
    461 
    462 	memset(t, 0, sizeof(*t));
    463 	t->family = AF_INET;
    464 	memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
    465 	return;
    466 }
    467 
    468 bool
    469 isc_netaddr_isloopback(const isc_netaddr_t *na) {
    470 	switch (na->family) {
    471 	case AF_INET:
    472 		return (((ntohl(na->type.in.s_addr) & 0xff000000U) ==
    473 			 0x7f000000U));
    474 	case AF_INET6:
    475 		return (IN6_IS_ADDR_LOOPBACK(&na->type.in6));
    476 	default:
    477 		return (false);
    478 	}
    479 }
    480