BIND - Update BIND to 9.5.2
[dragonfly.git] / contrib / bind-9.5.2 / lib / isc / netaddr.c
1 /*
2  * Copyright (C) 2004, 2005, 2007  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: netaddr.c,v 1.38 2007/06/18 23:47:44 tbox Exp $ */
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, *pb;
73         unsigned int ipabytes; /* 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                 pa = pb = NULL; /* Avoid silly compiler warning. */
98                 ipabytes = 0; /* Ditto. */
99                 return (ISC_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         nbytes = prefixlen / 8;
109         nbits = prefixlen % 8;
110
111         if (nbytes > 0) {
112                 if (memcmp(pa, pb, nbytes) != 0)
113                         return (ISC_FALSE);
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 (ISC_FALSE);
124         }
125         return (ISC_TRUE);
126 }
127
128 isc_result_t
129 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
130         char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
131         char zbuf[sizeof("%4294967295")];
132         unsigned int alen;
133         int zlen;
134         const char *r;
135         const void *type;
136
137         REQUIRE(netaddr != NULL);
138
139         switch (netaddr->family) {
140         case AF_INET:
141                 type = &netaddr->type.in;
142                 break;
143         case AF_INET6:
144                 type = &netaddr->type.in6;
145                 break;
146 #ifdef ISC_PLATFORM_HAVESYSUNH
147         case AF_UNIX:
148                 alen = strlen(netaddr->type.un);
149                 if (alen > isc_buffer_availablelength(target))
150                         return (ISC_R_NOSPACE);
151                 isc_buffer_putmem(target,
152                                   (const unsigned char *)(netaddr->type.un),
153                                   alen);
154                 return (ISC_R_SUCCESS);
155 #endif
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         alen = strlen(abuf);
164         INSIST(alen < sizeof(abuf));
165
166         zlen = 0;
167         if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
168                 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
169                 if (zlen < 0)
170                         return (ISC_R_FAILURE);
171                 INSIST((unsigned int)zlen < sizeof(zbuf));
172         }
173
174         if (alen + zlen > isc_buffer_availablelength(target))
175                 return (ISC_R_NOSPACE);
176
177         isc_buffer_putmem(target, (unsigned char *)abuf, alen);
178         isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
179
180         return (ISC_R_SUCCESS);
181 }
182
183 void
184 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
185         isc_result_t result;
186         isc_buffer_t buf;
187
188         isc_buffer_init(&buf, array, size);
189         result = isc_netaddr_totext(na, &buf);
190
191         /*
192          * Null terminate.
193          */
194         if (result == ISC_R_SUCCESS) {
195                 if (isc_buffer_availablelength(&buf) >= 1)
196                         isc_buffer_putuint8(&buf, 0);
197                 else
198                         result = ISC_R_NOSPACE;
199         }
200
201         if (result != ISC_R_SUCCESS) {
202                 snprintf(array, size,
203                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
204                                         ISC_MSG_UNKNOWNADDR,
205                                         "<unknown address, family %u>"),
206                          na->family);
207                 array[size - 1] = '\0';
208         }
209 }
210
211
212 isc_result_t
213 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
214         static const unsigned char zeros[16];
215         unsigned int nbits, nbytes, ipbytes;
216         const unsigned char *p;
217
218         switch (na->family) {
219         case AF_INET:
220                 p = (const unsigned char *) &na->type.in;
221                 ipbytes = 4;
222                 if (prefixlen > 32)
223                         return (ISC_R_RANGE);
224                 break;
225         case AF_INET6:
226                 p = (const unsigned char *) &na->type.in6;
227                 ipbytes = 16;
228                 if (prefixlen > 128)
229                         return (ISC_R_RANGE);
230                 break;
231         default:
232                 ipbytes = 0;
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, nbytes, ipbytes, 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                 ipbytes = 0;
263                 return (ISC_R_NOTIMPLEMENTED);
264         }
265         nbytes = nbits = 0;
266         for (i = 0; i < ipbytes; i++) {
267                 if (p[i] != 0xFF)
268                         break;
269         }
270         nbytes = i;
271         if (i < ipbytes) {
272                 unsigned int c = p[nbytes];
273                 while ((c & 0x80) != 0 && nbits < 8) {
274                         c <<= 1; nbits++;
275                 }
276                 if ((c & 0xFF) != 0)
277                         return (ISC_R_MASKNONCONTIG);
278                 i++;
279         }
280         for (; i < ipbytes; i++) {
281                 if (p[i] != 0)
282                         return (ISC_R_MASKNONCONTIG);
283                 i++;
284         }
285         *lenp = nbytes * 8 + nbits;
286         return (ISC_R_SUCCESS);
287 }
288
289 void
290 isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) {
291         memset(netaddr, 0, sizeof(*netaddr));
292         netaddr->family = AF_INET;
293         netaddr->type.in = *ina;
294 }
295
296 void
297 isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) {
298         memset(netaddr, 0, sizeof(*netaddr));
299         netaddr->family = AF_INET6;
300         netaddr->type.in6 = *ina6;
301 }
302
303 isc_result_t
304 isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) {
305 #ifdef ISC_PLATFORM_HAVESYSUNH
306         if (strlen(path) > sizeof(netaddr->type.un) - 1)
307                 return (ISC_R_NOSPACE);
308
309         memset(netaddr, 0, sizeof(*netaddr));
310         netaddr->family = AF_UNIX;
311         strcpy(netaddr->type.un, path);
312         netaddr->zone = 0;
313         return (ISC_R_SUCCESS);
314 #else 
315         UNUSED(netaddr);
316         UNUSED(path);
317         return (ISC_R_NOTIMPLEMENTED);
318 #endif
319 }
320
321
322 void
323 isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) {
324         /* we currently only support AF_INET6. */
325         REQUIRE(netaddr->family == AF_INET6);
326
327         netaddr->zone = zone;
328 }
329
330 isc_uint32_t
331 isc_netaddr_getzone(const isc_netaddr_t *netaddr) {
332         return (netaddr->zone);
333 }
334
335 void
336 isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) {
337         int family = s->type.sa.sa_family;
338         t->family = family;
339         switch (family) {
340         case AF_INET:
341                 t->type.in = s->type.sin.sin_addr;
342                 t->zone = 0;
343                 break;
344         case AF_INET6:
345                 memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16);
346 #ifdef ISC_PLATFORM_HAVESCOPEID
347                 t->zone = s->type.sin6.sin6_scope_id;
348 #else
349                 t->zone = 0;
350 #endif
351                 break;
352 #ifdef ISC_PLATFORM_HAVESYSUNH
353         case AF_UNIX:
354                 memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un));
355                 t->zone = 0;
356                 break;
357 #endif
358         default:
359                 INSIST(0);
360         }
361 }
362
363 void
364 isc_netaddr_any(isc_netaddr_t *netaddr) {
365         memset(netaddr, 0, sizeof(*netaddr));
366         netaddr->family = AF_INET;
367         netaddr->type.in.s_addr = INADDR_ANY;
368 }
369
370 void
371 isc_netaddr_any6(isc_netaddr_t *netaddr) {
372         memset(netaddr, 0, sizeof(*netaddr));
373         netaddr->family = AF_INET6;
374         netaddr->type.in6 = in6addr_any;
375 }
376
377 isc_boolean_t
378 isc_netaddr_ismulticast(isc_netaddr_t *na) {
379         switch (na->family) {
380         case AF_INET:
381                 return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr)));
382         case AF_INET6:
383                 return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6)));
384         default:
385                 return (ISC_FALSE);  /* XXXMLG ? */
386         }
387 }
388
389 isc_boolean_t
390 isc_netaddr_isexperimental(isc_netaddr_t *na) {
391         switch (na->family) {
392         case AF_INET:
393                 return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr)));
394         default:
395                 return (ISC_FALSE);  /* XXXMLG ? */
396         }
397 }
398
399 isc_boolean_t
400 isc_netaddr_islinklocal(isc_netaddr_t *na) {
401         switch (na->family) {
402         case AF_INET:
403                 return (ISC_FALSE);
404         case AF_INET6:
405                 return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6)));
406         default:
407                 return (ISC_FALSE);
408         }
409 }
410
411 isc_boolean_t
412 isc_netaddr_issitelocal(isc_netaddr_t *na) {
413         switch (na->family) {
414         case AF_INET:
415                 return (ISC_FALSE);
416         case AF_INET6:
417                 return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6)));
418         default:
419                 return (ISC_FALSE);
420         }
421 }
422
423 void
424 isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
425         isc_netaddr_t *src;
426
427         DE_CONST(s, src);       /* Must come before IN6_IS_ADDR_V4MAPPED. */
428
429         REQUIRE(s->family == AF_INET6);
430         REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6));
431
432         memset(t, 0, sizeof(*t));
433         t->family = AF_INET;
434         memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4);
435         return;
436 }