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