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
30bool
31isc_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
67bool
68isc_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
129isc_result_t
130isc_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
186void
187isc_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
216isc_result_t
217isc_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
257isc_result_t
258isc_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
300void
301isc_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
307void
308isc_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
314isc_result_t
315isc_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
327void
328isc_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
335uint32_t
336isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
337	return (netaddr->zone);
338}
339
340void
341isc_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
362void
363isc_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
369void
370isc_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
376void
377isc_netaddr_unspec(isc_netaddr_t *netaddr) {
378	memset(netaddr, 0, sizeof(*netaddr));
379	netaddr->family = AF_UNSPEC;
380}
381
382bool
383isc_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
394bool
395isc_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
404bool
405isc_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
416bool
417isc_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
431bool
432isc_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
443void
444isc_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
458bool
459isc_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