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