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