]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/ntp/lib/isc/netaddr.c
o Fix invalid TCP checksums with pf(4). [EN-16:02.pf]
[FreeBSD/releng/9.3.git] / contrib / ntp / 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 #include "ntp_stdlib.h"         /* NTP change for strlcpy, strlcat */
35
36 isc_boolean_t
37 isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) {
38         REQUIRE(a != NULL && b != NULL);
39
40         if (a->family != b->family)
41                 return (ISC_FALSE);
42
43         if (a->zone != b->zone)
44                 return (ISC_FALSE);
45
46         switch (a->family) {
47         case AF_INET:
48                 if (a->type.in.s_addr != b->type.in.s_addr)
49                         return (ISC_FALSE);
50                 break;
51         case AF_INET6:
52                 if (memcmp(&a->type.in6, &b->type.in6,
53                            sizeof(a->type.in6)) != 0 ||
54                     a->zone != b->zone)
55                         return (ISC_FALSE);
56                 break;
57 #ifdef ISC_PLATFORM_HAVESYSUNH
58         case AF_UNIX:
59                 if (strcmp(a->type.un, b->type.un) != 0)
60                         return (ISC_FALSE);
61                 break;
62 #endif
63         default:
64                 return (ISC_FALSE);
65         }
66         return (ISC_TRUE);
67 }
68
69 isc_boolean_t
70 isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b,
71                      unsigned int prefixlen)
72 {
73         const unsigned char *pa = NULL, *pb = NULL;
74         unsigned int ipabytes = 0; /* Length of whole IP address in bytes */
75         unsigned int nbytes;       /* Number of significant whole bytes */
76         unsigned int nbits;        /* Number of significant leftover bits */
77
78         REQUIRE(a != NULL && b != NULL);
79
80         if (a->family != b->family)
81                 return (ISC_FALSE);
82
83         if (a->zone != b->zone && b->zone != 0)
84                 return (ISC_FALSE);
85
86         switch (a->family) {
87         case AF_INET:
88                 pa = (const unsigned char *) &a->type.in;
89                 pb = (const unsigned char *) &b->type.in;
90                 ipabytes = 4;
91                 break;
92         case AF_INET6:
93                 pa = (const unsigned char *) &a->type.in6;
94                 pb = (const unsigned char *) &b->type.in6;
95                 ipabytes = 16;
96                 break;
97         default:
98                 return (ISC_FALSE);
99         }
100
101         /*
102          * Don't crash if we get a pattern like 10.0.0.1/9999999.
103          */
104         if (prefixlen > ipabytes * 8)
105                 prefixlen = ipabytes * 8;
106
107         nbytes = prefixlen / 8;
108         nbits = prefixlen % 8;
109
110         if (nbytes > 0) {
111                 if (memcmp(pa, pb, nbytes) != 0)
112                         return (ISC_FALSE);
113         }
114         if (nbits > 0) {
115                 unsigned int bytea, byteb, mask;
116                 INSIST(nbytes < ipabytes);
117                 INSIST(nbits < 8);
118                 bytea = pa[nbytes];
119                 byteb = pb[nbytes];
120                 mask = (0xFF << (8-nbits)) & 0xFF;
121                 if ((bytea & mask) != (byteb & mask))
122                         return (ISC_FALSE);
123         }
124         return (ISC_TRUE);
125 }
126
127 isc_result_t
128 isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) {
129         char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
130         char zbuf[sizeof("%4294967295")];
131         unsigned int alen;
132         int zlen;
133         const char *r;
134         const void *type;
135
136         REQUIRE(netaddr != NULL);
137
138         switch (netaddr->family) {
139         case AF_INET:
140                 type = &netaddr->type.in;
141                 break;
142         case AF_INET6:
143                 type = &netaddr->type.in6;
144                 break;
145 #ifdef ISC_PLATFORM_HAVESYSUNH
146         case AF_UNIX:
147                 alen = strlen(netaddr->type.un);
148                 if (alen > isc_buffer_availablelength(target))
149                         return (ISC_R_NOSPACE);
150                 isc_buffer_putmem(target,
151                                   (const unsigned char *)(netaddr->type.un),
152                                   alen);
153                 return (ISC_R_SUCCESS);
154 #endif
155         default:
156                 return (ISC_R_FAILURE);
157         }
158         r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf));
159         if (r == NULL)
160                 return (ISC_R_FAILURE);
161
162         alen = (unsigned int)strlen(abuf); /* no overflow possible */
163         INSIST(alen < sizeof(abuf));
164
165         zlen = 0;
166         if (netaddr->family == AF_INET6 && netaddr->zone != 0) {
167                 zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone);
168                 if (zlen < 0)
169                         return (ISC_R_FAILURE);
170                 INSIST((unsigned int)zlen < sizeof(zbuf));
171         }
172
173         if (alen + zlen > isc_buffer_availablelength(target))
174                 return (ISC_R_NOSPACE);
175
176         isc_buffer_putmem(target, (unsigned char *)abuf, alen);
177         isc_buffer_putmem(target, (unsigned char *)zbuf, zlen);
178
179         return (ISC_R_SUCCESS);
180 }
181
182 void
183 isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) {
184         isc_result_t result;
185         isc_buffer_t buf;
186
187         isc_buffer_init(&buf, array, size);
188         result = isc_netaddr_totext(na, &buf);
189
190         if (size == 0)
191                 return;
192
193         /*
194          * Null terminate.
195          */
196         if (result == ISC_R_SUCCESS) {
197                 if (isc_buffer_availablelength(&buf) >= 1)
198                         isc_buffer_putuint8(&buf, 0);
199                 else
200                         result = ISC_R_NOSPACE;
201         }
202
203         if (result != ISC_R_SUCCESS) {
204                 snprintf(array, size,
205                          "<%s %u>",
206                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
207                                         ISC_MSG_UNKNOWNADDR,
208                                         "unknown address, family"),
209                          na->family);
210                 array[size - 1] = '\0';
211         }
212 }
213
214
215 isc_result_t
216 isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
217         static const unsigned char zeros[16] = { 0 };
218         unsigned int nbits, nbytes, ipbytes = 0;
219         const unsigned char *p;
220
221         switch (na->family) {
222         case AF_INET:
223                 p = (const unsigned char *) &na->type.in;
224                 ipbytes = 4;
225                 if (prefixlen > 32)
226                         return (ISC_R_RANGE);
227                 break;
228         case AF_INET6:
229                 p = (const unsigned char *) &na->type.in6;
230                 ipbytes = 16;
231                 if (prefixlen > 128)
232                         return (ISC_R_RANGE);
233                 break;
234         default:
235                 return (ISC_R_NOTIMPLEMENTED);
236         }
237         nbytes = prefixlen / 8;
238         nbits = prefixlen % 8;
239         if (nbits != 0) {
240                 if ((p[nbytes] & (0xff>>nbits)) != 0U)
241                         return (ISC_R_FAILURE);
242                 nbytes++;
243         }
244         if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0)
245                 return (ISC_R_FAILURE);
246         return (ISC_R_SUCCESS);
247 }
248
249 isc_result_t
250 isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) {
251         unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i;
252         const unsigned char *p;
253
254         switch (s->family) {
255         case AF_INET:
256                 p = (const unsigned char *) &s->type.in;
257                 ipbytes = 4;
258                 break;
259         case AF_INET6:
260                 p = (const unsigned char *) &s->type.in6;
261                 ipbytes = 16;
262                 break;
263         default:
264                 return (ISC_R_NOTIMPLEMENTED);
265         }
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         strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un));
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 }