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