xref: /netbsd-src/external/mpl/bind/dist/lib/isc/netaddr.c (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /*	$NetBSD: netaddr.c,v 1.9 2024/02/21 22:52:28 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