Home | History | Annotate | Line # | Download | only in isc
netaddr.c revision 1.1.1.8
      1 /*	$NetBSD: netaddr.c,v 1.1.1.8 2024/02/21 21:54:49 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <inttypes.h>
     19 #include <stdbool.h>
     20 #include <stdio.h>
     21 
     22 #include <isc/buffer.h>
     23 #include <isc/net.h>
     24 #include <isc/netaddr.h>
     25 #include <isc/print.h>
     26 #include <isc/sockaddr.h>
     27 #include <isc/string.h>
     28 #include <isc/util.h>
     29 
     30 bool
     31 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
     32 	REQUIRE(a != NULL && b != NULL);
     33 
     34 	if (a->family != b->family) {
     35 		return (false);
     36 	}
     37 
     38 	if (a->zone != b->zone) {
     39 		return (false);
     40 	}
     41 
     42 	switch (a->family) {
     43 	case AF_INET:
     44 		if (a->type.in.s_addr != b->type.in.s_addr) {
     45 			return (false);
     46 		}
     47 		break;
     48 	case AF_INET6:
     49 		if (memcmp(&a->type.in6, &b->type.in6, sizeof(a->type.in6)) !=
     50 			    0 ||
     51 		    a->zone != b->zone)
     52 		{
     53 			return (false);
     54 		}
     55 		break;
     56 	case AF_UNIX:
     57 		if (strcmp(a->type.un, b->type.un) != 0) {
     58 			return (false);
     59 		}
     60 		break;
     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 	case AF_UNIX:
    148 		alen = strlen(netaddr->type.un);
    149 		if (alen > isc_buffer_availablelength(target)) {
    150 			return (ISC_R_NOSPACE);
    151 		}
    152 		isc_buffer_putmem(target,
    153 				  (const unsigned char *)(netaddr->type.un),
    154 				  alen);
    155 		return (ISC_R_SUCCESS);
    156 	default:
    157 		return (ISC_R_FAILURE);
    158 	}
    159 	r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
    160 	if (r == NULL) {
    161 		return (ISC_R_FAILURE);
    162 	}
    163 
    164 	alen = strlen(abuf);
    165 	INSIST(alen < sizeof(abuf));
    166 
    167 	zlen = 0;
    168 	if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
    169 		zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
    170 		if (zlen < 0) {
    171 			return (ISC_R_FAILURE);
    172 		}
    173 		INSIST((unsigned int)zlen < sizeof(zbuf));
    174 	}
    175 
    176 	if (alen + zlen > isc_buffer_availablelength(target)) {
    177 		return (ISC_R_NOSPACE);
    178 	}
    179 
    180 	isc_buffer_putmem(target, (unsigned char *)abuf, alen);
    181 	isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen);
    182 
    183 	return (ISC_R_SUCCESS);
    184 }
    185 
    186 void
    187 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
    188 	isc_result_t result;
    189 	isc_buffer_t buf;
    190 
    191 	isc_buffer_init(&buf, array, size);
    192 	result = isc_netaddr_totext(na, &buf);
    193 
    194 	if (size == 0) {
    195 		return;
    196 	}
    197 
    198 	/*
    199 	 * Null terminate.
    200 	 */
    201 	if (result == ISC_R_SUCCESS) {
    202 		if (isc_buffer_availablelength(&buf) >= 1) {
    203 			isc_buffer_putuint8(&buf, 0);
    204 		} else {
    205 			result = ISC_R_NOSPACE;
    206 		}
    207 	}
    208 
    209 	if (result != ISC_R_SUCCESS) {
    210 		snprintf(array, size, "<unknown address, family %u>",
    211 			 na->family);
    212 		array[size - 1] = '\0';
    213 	}
    214 }
    215 
    216 isc_result_t
    217 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
    218 	static const unsigned char zeros[16];
    219 	unsigned int nbits, nbytes, ipbytes = 0;
    220 	const unsigned char *p;
    221 
    222 	switch (na->family) {
    223 	case AF_INET:
    224 		p = (const unsigned char *)&na->type.in;
    225 		ipbytes = 4;
    226 		if (prefixlen > 32) {
    227 			return (ISC_R_RANGE);
    228 		}
    229 		break;
    230 	case AF_INET6:
    231 		p = (const unsigned char *)&na->type.in6;
    232 		ipbytes = 16;
    233 		if (prefixlen > 128) {
    234 			return (ISC_R_RANGE);
    235 		}
    236 		break;
    237 	default:
    238 		return (ISC_R_NOTIMPLEMENTED);
    239 	}
    240 	nbytes = prefixlen / 8;
    241 	nbits = prefixlen % 8;
    242 	if (nbits != 0) {
    243 		INSIST(nbytes < ipbytes);
    244 		if ((p[nbytes] & (0xff >> nbits)) != 0U) {
    245 			return (ISC_R_FAILURE);
    246 		}
    247 		nbytes++;
    248 	}
    249 	if (nbytes < ipbytes &&
    250 	    memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
    251 	{
    252 		return (ISC_R_FAILURE);
    253 	}
    254 	return (ISC_R_SUCCESS);
    255 }
    256 
    257 isc_result_t
    258 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
    259 	unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
    260 	const unsigned char *p;
    261 
    262 	switch (s->family) {
    263 	case AF_INET:
    264 		p = (const unsigned char *)&s->type.in;
    265 		ipbytes = 4;
    266 		break;
    267 	case AF_INET6:
    268 		p = (const unsigned char *)&s->type.in6;
    269 		ipbytes = 16;
    270 		break;
    271 	default:
    272 		return (ISC_R_NOTIMPLEMENTED);
    273 	}
    274 	for (i = 0; i < ipbytes; i++) {
    275 		if (p[i] != 0xFF) {
    276 			break;
    277 		}
    278 	}
    279 	nbytes = i;
    280 	if (i < ipbytes) {
    281 		unsigned int c = p[nbytes];
    282 		while ((c & 0x80) != 0 && nbits < 8) {
    283 			c <<= 1;
    284 			nbits++;
    285 		}
    286 		if ((c & 0xFF) != 0) {
    287 			return (ISC_R_MASKNONCONTIG);
    288 		}
    289 		i++;
    290 	}
    291 	for (; i < ipbytes; i++) {
    292 		if (p[i] != 0) {
    293 			return (ISC_R_MASKNONCONTIG);
    294 		}
    295 	}
    296 	*lenp = nbytes * 8 + nbits;
    297 	return (ISC_R_SUCCESS);
    298 }
    299 
    300 void
    301 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
    302 	memset(netaddr, 0, sizeof(*netaddr));
    303 	netaddr->family = AF_INET;
    304 	netaddr->type.in = *ina;
    305 }
    306 
    307 void
    308 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
    309 	memset(netaddr, 0, sizeof(*netaddr));
    310 	netaddr->family = AF_INET6;
    311 	netaddr->type.in6 = *ina6;
    312 }
    313 
    314 isc_result_t
    315 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
    316 	if (strlen(path) > sizeof(netaddr->type.un) - 1) {
    317 		return (ISC_R_NOSPACE);
    318 	}
    319 
    320 	memset(netaddr, 0, sizeof(*netaddr));
    321 	netaddr->family = AF_UNIX;
    322 	strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un));
    323 	netaddr->zone = 0;
    324 	return (ISC_R_SUCCESS);
    325 }
    326 
    327 void
    328 isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) {
    329 	/* we currently only support AF_INET6. */
    330 	REQUIRE(netaddr->family == AF_INET6);
    331 
    332 	netaddr->zone = zone;
    333 }
    334 
    335 uint32_t
    336 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
    337 	return (netaddr->zone);
    338 }
    339 
    340 void
    341 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
    342 	int family = s->type.sa.sa_family;
    343 	t->family = family;
    344 	switch (family) {
    345 	case AF_INET:
    346 		t->type.in = s->type.sin.sin_addr;
    347 		t->zone = 0;
    348 		break;
    349 	case AF_INET6:
    350 		memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
    351 		t->zone = s->type.sin6.sin6_scope_id;
    352 		break;
    353 	case AF_UNIX:
    354 		memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
    355 		t->zone = 0;
    356 		break;
    357 	default:
    358 		UNREACHABLE();
    359 	}
    360 }
    361 
    362 void
    363 isc_netaddr_any(isc_netaddr_t *netaddr) {
    364 	memset(netaddr, 0, sizeof(*netaddr));
    365 	netaddr->family = AF_INET;
    366 	netaddr->type.in.s_addr = INADDR_ANY;
    367 }
    368 
    369 void
    370 isc_netaddr_any6(isc_netaddr_t *netaddr) {
    371 	memset(netaddr, 0, sizeof(*netaddr));
    372 	netaddr->family = AF_INET6;
    373 	netaddr->type.in6 = in6addr_any;
    374 }
    375 
    376 void
    377 isc_netaddr_unspec(isc_netaddr_t *netaddr) {
    378 	memset(netaddr, 0, sizeof(*netaddr));
    379 	netaddr->family = AF_UNSPEC;
    380 }
    381 
    382 bool
    383 isc_netaddr_ismulticast(const isc_netaddr_t *na) {
    384 	switch (na->family) {
    385 	case AF_INET:
    386 		return (ISC_IPADDR_ISMULTICAST(na->type.in.s_addr));
    387 	case AF_INET6:
    388 		return (IN6_IS_ADDR_MULTICAST(&na->type.in6));
    389 	default:
    390 		return (false); /* XXXMLG ? */
    391 	}
    392 }
    393 
    394 bool
    395 isc_netaddr_isexperimental(const isc_netaddr_t *na) {
    396 	switch (na->family) {
    397 	case AF_INET:
    398 		return (ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr));
    399 	default:
    400 		return (false); /* XXXMLG ? */
    401 	}
    402 }
    403 
    404 bool
    405 isc_netaddr_islinklocal(const isc_netaddr_t *na) {
    406 	switch (na->family) {
    407 	case AF_INET:
    408 		return (false);
    409 	case AF_INET6:
    410 		return (IN6_IS_ADDR_LINKLOCAL(&na->type.in6));
    411 	default:
    412 		return (false);
    413 	}
    414 }
    415 
    416 bool
    417 isc_netaddr_issitelocal(const isc_netaddr_t *na) {
    418 	switch (na->family) {
    419 	case AF_INET:
    420 		return (false);
    421 	case AF_INET6:
    422 		return (IN6_IS_ADDR_SITELOCAL(&na->type.in6));
    423 	default:
    424 		return (false);
    425 	}
    426 }
    427 
    428 #define ISC_IPADDR_ISNETZERO(i) \
    429 	(((uint32_t)(i) & ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000))
    430 
    431 bool
    432 isc_netaddr_isnetzero(const isc_netaddr_t *na) {
    433 	switch (na->family) {
    434 	case AF_INET:
    435 		return (ISC_IPADDR_ISNETZERO(na->type.in.s_addr));
    436 	case AF_INET6:
    437 		return (false);
    438 	default:
    439 		return (false);
    440 	}
    441 }
    442 
    443 void
    444 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
    445 	isc_netaddr_t *src;
    446 
    447 	DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */
    448 
    449 	REQUIRE(s->family == AF_INET6);
    450 	REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
    451 
    452 	memset(t, 0, sizeof(*t));
    453 	t->family = AF_INET;
    454 	memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
    455 	return;
    456 }
    457 
    458 bool
    459 isc_netaddr_isloopback(const isc_netaddr_t *na) {
    460 	switch (na->family) {
    461 	case AF_INET:
    462 		return (((ntohl(na->type.in.s_addr) & 0xff000000U) ==
    463 			 0x7f000000U));
    464 	case AF_INET6:
    465 		return (IN6_IS_ADDR_LOOPBACK(&na->type.in6));
    466 	default:
    467 		return (false);
    468 	}
    469 }
    470