1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * SPDX-License-Identifier: MPL-2.0
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 /*! \file */
15
16 #include <inttypes.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19
20 #include <isc/buffer.h>
21 #include <isc/net.h>
22 #include <isc/netaddr.h>
23 #include <isc/print.h>
24 #include <isc/sockaddr.h>
25 #include <isc/string.h>
26 #include <isc/util.h>
27
28 bool
isc_netaddr_equal(const isc_netaddr_t * a,const isc_netaddr_t * b)29 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
30 REQUIRE(a != NULL && b != NULL);
31
32 if (a->family != b->family) {
33 return (false);
34 }
35
36 if (a->zone != b->zone) {
37 return (false);
38 }
39
40 switch (a->family) {
41 case AF_INET:
42 if (a->type.in.s_addr != b->type.in.s_addr) {
43 return (false);
44 }
45 break;
46 case AF_INET6:
47 if (memcmp(&a->type.in6, &b->type.in6, sizeof(a->type.in6)) !=
48 0 ||
49 a->zone != b->zone)
50 {
51 return (false);
52 }
53 break;
54 #ifdef ISC_PLATFORM_HAVESYSUNH
55 case AF_UNIX:
56 if (strcmp(a->type.un, b->type.un) != 0) {
57 return (false);
58 }
59 break;
60 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
61 default:
62 return (false);
63 }
64 return (true);
65 }
66
67 bool
isc_netaddr_eqprefix(const isc_netaddr_t * a,const isc_netaddr_t * b,unsigned int prefixlen)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
isc_netaddr_totext(const isc_netaddr_t * netaddr,isc_buffer_t * target)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 #ifdef ISC_PLATFORM_HAVESYSUNH
148 case AF_UNIX:
149 alen = strlen(netaddr->type.un);
150 if (alen > isc_buffer_availablelength(target)) {
151 return (ISC_R_NOSPACE);
152 }
153 isc_buffer_putmem(target,
154 (const unsigned char *)(netaddr->type.un),
155 alen);
156 return (ISC_R_SUCCESS);
157 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
158 default:
159 return (ISC_R_FAILURE);
160 }
161 r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
162 if (r == NULL) {
163 return (ISC_R_FAILURE);
164 }
165
166 alen = strlen(abuf);
167 INSIST(alen < sizeof(abuf));
168
169 zlen = 0;
170 if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
171 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
172 if (zlen < 0) {
173 return (ISC_R_FAILURE);
174 }
175 INSIST((unsigned int)zlen < sizeof(zbuf));
176 }
177
178 if (alen + zlen > isc_buffer_availablelength(target)) {
179 return (ISC_R_NOSPACE);
180 }
181
182 isc_buffer_putmem(target, (unsigned char *)abuf, alen);
183 isc_buffer_putmem(target, (unsigned char *)zbuf, (unsigned int)zlen);
184
185 return (ISC_R_SUCCESS);
186 }
187
188 void
isc_netaddr_format(const isc_netaddr_t * na,char * array,unsigned int size)189 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
190 isc_result_t result;
191 isc_buffer_t buf;
192
193 isc_buffer_init(&buf, array, size);
194 result = isc_netaddr_totext(na, &buf);
195
196 if (size == 0) {
197 return;
198 }
199
200 /*
201 * Null terminate.
202 */
203 if (result == ISC_R_SUCCESS) {
204 if (isc_buffer_availablelength(&buf) >= 1) {
205 isc_buffer_putuint8(&buf, 0);
206 } else {
207 result = ISC_R_NOSPACE;
208 }
209 }
210
211 if (result != ISC_R_SUCCESS) {
212 snprintf(array, size, "<unknown address, family %u>",
213 na->family);
214 array[size - 1] = '\0';
215 }
216 }
217
218 isc_result_t
isc_netaddr_prefixok(const isc_netaddr_t * na,unsigned int prefixlen)219 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
220 static const unsigned char zeros[16];
221 unsigned int nbits, nbytes, ipbytes = 0;
222 const unsigned char *p;
223
224 switch (na->family) {
225 case AF_INET:
226 p = (const unsigned char *)&na->type.in;
227 ipbytes = 4;
228 if (prefixlen > 32) {
229 return (ISC_R_RANGE);
230 }
231 break;
232 case AF_INET6:
233 p = (const unsigned char *)&na->type.in6;
234 ipbytes = 16;
235 if (prefixlen > 128) {
236 return (ISC_R_RANGE);
237 }
238 break;
239 default:
240 return (ISC_R_NOTIMPLEMENTED);
241 }
242 nbytes = prefixlen / 8;
243 nbits = prefixlen % 8;
244 if (nbits != 0) {
245 INSIST(nbytes < ipbytes);
246 if ((p[nbytes] & (0xff >> nbits)) != 0U) {
247 return (ISC_R_FAILURE);
248 }
249 nbytes++;
250 }
251 if (nbytes < ipbytes &&
252 memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) {
253 return (ISC_R_FAILURE);
254 }
255 return (ISC_R_SUCCESS);
256 }
257
258 isc_result_t
isc_netaddr_masktoprefixlen(const isc_netaddr_t * s,unsigned int * lenp)259 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
260 unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
261 const unsigned char *p;
262
263 switch (s->family) {
264 case AF_INET:
265 p = (const unsigned char *)&s->type.in;
266 ipbytes = 4;
267 break;
268 case AF_INET6:
269 p = (const unsigned char *)&s->type.in6;
270 ipbytes = 16;
271 break;
272 default:
273 return (ISC_R_NOTIMPLEMENTED);
274 }
275 for (i = 0; i < ipbytes; i++) {
276 if (p[i] != 0xFF) {
277 break;
278 }
279 }
280 nbytes = i;
281 if (i < ipbytes) {
282 unsigned int c = p[nbytes];
283 while ((c & 0x80) != 0 && nbits < 8) {
284 c <<= 1;
285 nbits++;
286 }
287 if ((c & 0xFF) != 0) {
288 return (ISC_R_MASKNONCONTIG);
289 }
290 i++;
291 }
292 for (; i < ipbytes; i++) {
293 if (p[i] != 0) {
294 return (ISC_R_MASKNONCONTIG);
295 }
296 }
297 *lenp = nbytes * 8 + nbits;
298 return (ISC_R_SUCCESS);
299 }
300
301 void
isc_netaddr_fromin(isc_netaddr_t * netaddr,const struct in_addr * ina)302 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
303 memset(netaddr, 0, sizeof(*netaddr));
304 netaddr->family = AF_INET;
305 netaddr->type.in = *ina;
306 }
307
308 void
isc_netaddr_fromin6(isc_netaddr_t * netaddr,const struct in6_addr * ina6)309 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
310 memset(netaddr, 0, sizeof(*netaddr));
311 netaddr->family = AF_INET6;
312 netaddr->type.in6 = *ina6;
313 }
314
315 isc_result_t
isc_netaddr_frompath(isc_netaddr_t * netaddr,const char * path)316 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
317 #ifdef ISC_PLATFORM_HAVESYSUNH
318 if (strlen(path) > sizeof(netaddr->type.un) - 1) {
319 return (ISC_R_NOSPACE);
320 }
321
322 memset(netaddr, 0, sizeof(*netaddr));
323 netaddr->family = AF_UNIX;
324 strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un));
325 netaddr->zone = 0;
326 return (ISC_R_SUCCESS);
327 #else /* ifdef ISC_PLATFORM_HAVESYSUNH */
328 UNUSED(netaddr);
329 UNUSED(path);
330 return (ISC_R_NOTIMPLEMENTED);
331 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
332 }
333
334 void
isc_netaddr_setzone(isc_netaddr_t * netaddr,uint32_t zone)335 isc_netaddr_setzone(isc_netaddr_t *netaddr, uint32_t zone) {
336 /* we currently only support AF_INET6. */
337 REQUIRE(netaddr->family == AF_INET6);
338
339 netaddr->zone = zone;
340 }
341
342 uint32_t
isc_netaddr_getzone(const isc_netaddr_t * netaddr)343 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
344 return (netaddr->zone);
345 }
346
347 void
isc_netaddr_fromsockaddr(isc_netaddr_t * t,const isc_sockaddr_t * s)348 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
349 int family = s->type.sa.sa_family;
350 t->family = family;
351 switch (family) {
352 case AF_INET:
353 t->type.in = s->type.sin.sin_addr;
354 t->zone = 0;
355 break;
356 case AF_INET6:
357 memmove(&t->type.in6, &s->type.sin6.sin6_addr, 16);
358 t->zone = s->type.sin6.sin6_scope_id;
359 break;
360 #ifdef ISC_PLATFORM_HAVESYSUNH
361 case AF_UNIX:
362 memmove(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
363 t->zone = 0;
364 break;
365 #endif /* ifdef ISC_PLATFORM_HAVESYSUNH */
366 default:
367 INSIST(0);
368 ISC_UNREACHABLE();
369 }
370 }
371
372 void
isc_netaddr_any(isc_netaddr_t * netaddr)373 isc_netaddr_any(isc_netaddr_t *netaddr) {
374 memset(netaddr, 0, sizeof(*netaddr));
375 netaddr->family = AF_INET;
376 netaddr->type.in.s_addr = INADDR_ANY;
377 }
378
379 void
isc_netaddr_any6(isc_netaddr_t * netaddr)380 isc_netaddr_any6(isc_netaddr_t *netaddr) {
381 memset(netaddr, 0, sizeof(*netaddr));
382 netaddr->family = AF_INET6;
383 netaddr->type.in6 = in6addr_any;
384 }
385
386 void
isc_netaddr_unspec(isc_netaddr_t * netaddr)387 isc_netaddr_unspec(isc_netaddr_t *netaddr) {
388 memset(netaddr, 0, sizeof(*netaddr));
389 netaddr->family = AF_UNSPEC;
390 }
391
392 bool
isc_netaddr_ismulticast(const isc_netaddr_t * na)393 isc_netaddr_ismulticast(const isc_netaddr_t *na) {
394 switch (na->family) {
395 case AF_INET:
396 return (ISC_IPADDR_ISMULTICAST(na->type.in.s_addr));
397 case AF_INET6:
398 return (IN6_IS_ADDR_MULTICAST(&na->type.in6));
399 default:
400 return (false); /* XXXMLG ? */
401 }
402 }
403
404 bool
isc_netaddr_isexperimental(const isc_netaddr_t * na)405 isc_netaddr_isexperimental(const isc_netaddr_t *na) {
406 switch (na->family) {
407 case AF_INET:
408 return (ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr));
409 default:
410 return (false); /* XXXMLG ? */
411 }
412 }
413
414 bool
isc_netaddr_islinklocal(const isc_netaddr_t * na)415 isc_netaddr_islinklocal(const isc_netaddr_t *na) {
416 switch (na->family) {
417 case AF_INET:
418 return (false);
419 case AF_INET6:
420 return (IN6_IS_ADDR_LINKLOCAL(&na->type.in6));
421 default:
422 return (false);
423 }
424 }
425
426 bool
isc_netaddr_issitelocal(const isc_netaddr_t * na)427 isc_netaddr_issitelocal(const isc_netaddr_t *na) {
428 switch (na->family) {
429 case AF_INET:
430 return (false);
431 case AF_INET6:
432 return (IN6_IS_ADDR_SITELOCAL(&na->type.in6));
433 default:
434 return (false);
435 }
436 }
437
438 #define ISC_IPADDR_ISNETZERO(i) \
439 (((uint32_t)(i)&ISC__IPADDR(0xff000000)) == ISC__IPADDR(0x00000000))
440
441 bool
isc_netaddr_isnetzero(const isc_netaddr_t * na)442 isc_netaddr_isnetzero(const isc_netaddr_t *na) {
443 switch (na->family) {
444 case AF_INET:
445 return (ISC_IPADDR_ISNETZERO(na->type.in.s_addr));
446 case AF_INET6:
447 return (false);
448 default:
449 return (false);
450 }
451 }
452
453 void
isc_netaddr_fromv4mapped(isc_netaddr_t * t,const isc_netaddr_t * s)454 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
455 isc_netaddr_t *src;
456
457 DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */
458
459 REQUIRE(s->family == AF_INET6);
460 REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
461
462 memset(t, 0, sizeof(*t));
463 t->family = AF_INET;
464 memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
465 return;
466 }
467
468 bool
isc_netaddr_isloopback(const isc_netaddr_t * na)469 isc_netaddr_isloopback(const isc_netaddr_t *na) {
470 switch (na->family) {
471 case AF_INET:
472 return (((ntohl(na->type.in.s_addr) & 0xff000000U) ==
473 0x7f000000U));
474 case AF_INET6:
475 return (IN6_IS_ADDR_LOOPBACK(&na->type.in6));
476 default:
477 return (false);
478 }
479 }
480