]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/isc/netaddr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / isc / netaddr.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2010-2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <stdio.h>
25
26 #include <isc/buffer.h>
27 #include <isc/msgs.h>
28 #include <isc/net.h>
29 #include <isc/netaddr.h>
30 #include <isc/print.h>
31 #include <isc/sockaddr.h>
32 #include <isc/string.h>
33 #include <isc/util.h>
34
35 isc_boolean_t
36 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
37         REQUIRE(a != NULL && b != NULL);
38
39         if (a->family != b->family)
40                 return (ISC_FALSE);
41
42         if (a->zone != b->zone)
43                 return (ISC_FALSE);
44
45         switch (a->family) {
46         case AF_INET:
47                 if (a->type.in.s_addr != b->type.in.s_addr)
48                         return (ISC_FALSE);
49                 break;
50         case AF_INET6:
51                 if (memcmp(&a->type.in6, &b->type.in6,
52                            sizeof(a->type.in6)) != 0 ||
53                     a->zone != b->zone)
54                         return (ISC_FALSE);
55                 break;
56 #ifdef ISC_PLATFORM_HAVESYSUNH
57         case AF_UNIX:
58                 if (strcmp(a->type.un, b->type.un) != 0)
59                         return (ISC_FALSE);
60                 break;
61 #endif
62         default:
63                 return (ISC_FALSE);
64         }
65         return (ISC_TRUE);
66 }
67
68 isc_boolean_t
69 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
70                      unsigned int prefixlen)
71 {
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 (ISC_FALSE);
81
82         if (a->zone != b->zone && b->zone != 0)
83                 return (ISC_FALSE);
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 (ISC_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         nbytes = prefixlen / 8;
107         nbits = prefixlen % 8;
108
109         if (nbytes > 0) {
110                 if (memcmp(pa, pb, nbytes) != 0)
111                         return (ISC_FALSE);
112         }
113         if (nbits > 0) {
114                 unsigned int bytea, byteb, mask;
115                 INSIST(nbytes < ipabytes);
116                 INSIST(nbits < 8);
117                 bytea = pa[nbytes];
118                 byteb = pb[nbytes];
119                 mask = (0xFF << (8-nbits)) & 0xFF;
120                 if ((bytea & mask) != (byteb & mask))
121                         return (ISC_FALSE);
122         }
123         return (ISC_TRUE);
124 }
125
126 isc_result_t
127 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
128         char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
129         char zbuf[sizeof("%4294967295")];
130         unsigned int alen;
131         int zlen;
132         const char *r;
133         const void *type;
134
135         REQUIRE(netaddr != NULL);
136
137         switch (netaddr->family) {
138         case AF_INET:
139                 type = &netaddr->type.in;
140                 break;
141         case AF_INET6:
142                 type = &netaddr->type.in6;
143                 break;
144 #ifdef ISC_PLATFORM_HAVESYSUNH
145         case AF_UNIX:
146                 alen = strlen(netaddr->type.un);
147                 if (alen > isc_buffer_availablelength(target))
148                         return (ISC_R_NOSPACE);
149                 isc_buffer_putmem(target,
150                                   (const unsigned char *)(netaddr->type.un),
151                                   alen);
152                 return (ISC_R_SUCCESS);
153 #endif
154         default:
155                 return (ISC_R_FAILURE);
156         }
157         r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
158         if (r == NULL)
159                 return (ISC_R_FAILURE);
160
161         alen = strlen(abuf);
162         INSIST(alen < sizeof(abuf));
163
164         zlen = 0;
165         if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
166                 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
167                 if (zlen < 0)
168                         return (ISC_R_FAILURE);
169                 INSIST((unsigned int)zlen < sizeof(zbuf));
170         }
171
172         if (alen + zlen > isc_buffer_availablelength(target))
173                 return (ISC_R_NOSPACE);
174
175         isc_buffer_putmem(target, (unsigned char *)abuf, alen);
176         isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
177
178         return (ISC_R_SUCCESS);
179 }
180
181 void
182 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
183         isc_result_t result;
184         isc_buffer_t buf;
185
186         isc_buffer_init(&buf, array, size);
187         result = isc_netaddr_totext(na, &buf);
188
189         if (size == 0)
190                 return;
191
192         /*
193          * Null terminate.
194          */
195         if (result == ISC_R_SUCCESS) {
196                 if (isc_buffer_availablelength(&buf) >= 1)
197                         isc_buffer_putuint8(&buf, 0);
198                 else
199                         result = ISC_R_NOSPACE;
200         }
201
202         if (result != ISC_R_SUCCESS) {
203                 snprintf(array, size,
204                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
205                                         ISC_MSG_UNKNOWNADDR,
206                                         "<unknown address, family %u>"),
207                          na->family);
208                 array[size - 1] = '\0';
209         }
210 }
211
212
213 isc_result_t
214 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
215         static const unsigned char zeros[16];
216         unsigned int nbits, nbytes, ipbytes = 0;
217         const unsigned char *p;
218
219         switch (na->family) {
220         case AF_INET:
221                 p = (const unsigned char *) &na->type.in;
222                 ipbytes = 4;
223                 if (prefixlen > 32)
224                         return (ISC_R_RANGE);
225                 break;
226         case AF_INET6:
227                 p = (const unsigned char *) &na->type.in6;
228                 ipbytes = 16;
229                 if (prefixlen > 128)
230                         return (ISC_R_RANGE);
231                 break;
232         default:
233                 return (ISC_R_NOTIMPLEMENTED);
234         }
235         nbytes = prefixlen / 8;
236         nbits = prefixlen % 8;
237         if (nbits != 0) {
238                 if ((p[nbytes] & (0xff>>nbits)) != 0U)
239                         return (ISC_R_FAILURE);
240                 nbytes++;
241         }
242         if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
243                 return (ISC_R_FAILURE);
244         return (ISC_R_SUCCESS);
245 }
246
247 isc_result_t
248 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
249         unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
250         const unsigned char *p;
251
252         switch (s->family) {
253         case AF_INET:
254                 p = (const unsigned char *) &s->type.in;
255                 ipbytes = 4;
256                 break;
257         case AF_INET6:
258                 p = (const unsigned char *) &s->type.in6;
259                 ipbytes = 16;
260                 break;
261         default:
262                 return (ISC_R_NOTIMPLEMENTED);
263         }
264         for (i = 0; i < ipbytes; i++) {
265                 if (p[i] != 0xFF)
266                         break;
267         }
268         nbytes = i;
269         if (i < ipbytes) {
270                 unsigned int c = p[nbytes];
271                 while ((c & 0x80) != 0 && nbits < 8) {
272                         c <<= 1; nbits++;
273                 }
274                 if ((c & 0xFF) != 0)
275                         return (ISC_R_MASKNONCONTIG);
276                 i++;
277         }
278         for (; i < ipbytes; i++) {
279                 if (p[i] != 0)
280                         return (ISC_R_MASKNONCONTIG);
281                 i++;
282         }
283         *lenp = nbytes * 8 + nbits;
284         return (ISC_R_SUCCESS);
285 }
286
287 void
288 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
289         memset(netaddr, 0, sizeof(*netaddr));
290         netaddr->family = AF_INET;
291         netaddr->type.in = *ina;
292 }
293
294 void
295 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
296         memset(netaddr, 0, sizeof(*netaddr));
297         netaddr->family = AF_INET6;
298         netaddr->type.in6 = *ina6;
299 }
300
301 isc_result_t
302 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
303 #ifdef ISC_PLATFORM_HAVESYSUNH
304         if (strlen(path) > sizeof(netaddr->type.un) - 1)
305                 return (ISC_R_NOSPACE);
306
307         memset(netaddr, 0, sizeof(*netaddr));
308         netaddr->family = AF_UNIX;
309         strcpy(netaddr->type.un, path);
310         netaddr->zone = 0;
311         return (ISC_R_SUCCESS);
312 #else
313         UNUSED(netaddr);
314         UNUSED(path);
315         return (ISC_R_NOTIMPLEMENTED);
316 #endif
317 }
318
319
320 void
321 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
322         /* we currently only support AF_INET6. */
323         REQUIRE(netaddr->family == AF_INET6);
324
325         netaddr->zone = zone;
326 }
327
328 isc_uint32_t
329 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
330         return (netaddr->zone);
331 }
332
333 void
334 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
335         int family = s->type.sa.sa_family;
336         t->family = family;
337         switch (family) {
338         case AF_INET:
339                 t->type.in = s->type.sin.sin_addr;
340                 t->zone = 0;
341                 break;
342         case AF_INET6:
343                 memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16);
344 #ifdef ISC_PLATFORM_HAVESCOPEID
345                 t->zone = s->type.sin6.sin6_scope_id;
346 #else
347                 t->zone = 0;
348 #endif
349                 break;
350 #ifdef ISC_PLATFORM_HAVESYSUNH
351         case AF_UNIX:
352                 memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
353                 t->zone = 0;
354                 break;
355 #endif
356         default:
357                 INSIST(0);
358         }
359 }
360
361 void
362 isc_netaddr_any(isc_netaddr_t *netaddr) {
363         memset(netaddr, 0, sizeof(*netaddr));
364         netaddr->family = AF_INET;
365         netaddr->type.in.s_addr = INADDR_ANY;
366 }
367
368 void
369 isc_netaddr_any6(isc_netaddr_t *netaddr) {
370         memset(netaddr, 0, sizeof(*netaddr));
371         netaddr->family = AF_INET6;
372         netaddr->type.in6 = in6addr_any;
373 }
374
375 isc_boolean_t
376 isc_netaddr_ismulticast(isc_netaddr_t *na) {
377         switch (na->family) {
378         case AF_INET:
379                 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
380         case AF_INET6:
381                 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
382         default:
383                 return (ISC_FALSE);  /* XXXMLG ? */
384         }
385 }
386
387 isc_boolean_t
388 isc_netaddr_isexperimental(isc_netaddr_t *na) {
389         switch (na->family) {
390         case AF_INET:
391                 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
392         default:
393                 return (ISC_FALSE);  /* XXXMLG ? */
394         }
395 }
396
397 isc_boolean_t
398 isc_netaddr_islinklocal(isc_netaddr_t *na) {
399         switch (na->family) {
400         case AF_INET:
401                 return (ISC_FALSE);
402         case AF_INET6:
403                 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
404         default:
405                 return (ISC_FALSE);
406         }
407 }
408
409 isc_boolean_t
410 isc_netaddr_issitelocal(isc_netaddr_t *na) {
411         switch (na->family) {
412         case AF_INET:
413                 return (ISC_FALSE);
414         case AF_INET6:
415                 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
416         default:
417                 return (ISC_FALSE);
418         }
419 }
420
421 void
422 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
423         isc_netaddr_t *src;
424
425         DE_CONST(s, src);       /* Must come before IN6_IS_ADDR_V4MAPPED. */
426
427         REQUIRE(s->family == AF_INET6);
428         REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
429
430         memset(t, 0, sizeof(*t));
431         t->family = AF_INET;
432         memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
433         return;
434 }