]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/libisc/sockaddr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / libisc / sockaddr.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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: sockaddr.c,v 1.48.2.1.2.10 2004/05/15 03:46:12 jinmei Exp $ */
19
20 #include <config.h>
21
22 #define ISC_ONLY_IPV6
23
24 #include <stdio.h>
25
26 #include <isc/buffer.h>
27 /*
28  * We currently don't need hashing here
29  */
30 #if 0
31 #include <isc/hash.h>
32 #endif
33
34 #include <isc/msgs.h>
35 #include <isc/netaddr.h>
36 #include <isc/print.h>
37 #include <isc/region.h>
38 #include <isc/sockaddr.h>
39 #include <isc/string.h>
40 #include <isc/util.h>
41
42 isc_boolean_t
43 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
44         REQUIRE(a != NULL && b != NULL);
45
46         if (a->length != b->length)
47                 return (ISC_FALSE);
48
49         /*
50          * We don't just memcmp because the sin_zero field isn't always
51          * zero.
52          */
53
54         if (a->type.sa.sa_family != b->type.sa.sa_family)
55                 return (ISC_FALSE);
56         switch (a->type.sa.sa_family) {
57         case AF_INET:
58                 if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
59                            sizeof(a->type.sin.sin_addr)) != 0)
60                         return (ISC_FALSE);
61                 if (a->type.sin.sin_port != b->type.sin.sin_port)
62                         return (ISC_FALSE);
63                 break;
64         case AF_INET6:
65                 if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
66                            sizeof(a->type.sin6.sin6_addr)) != 0)
67                         return (ISC_FALSE);
68 #ifdef ISC_PLATFORM_HAVESCOPEID
69                 if (a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id)
70                         return (ISC_FALSE);
71 #endif
72                 if (a->type.sin6.sin6_port != b->type.sin6.sin6_port)
73                         return (ISC_FALSE);
74                 break;
75         default:
76                 if (memcmp(&a->type, &b->type, a->length) != 0)
77                         return (ISC_FALSE);
78         }
79         return (ISC_TRUE);
80 }
81
82 isc_boolean_t
83 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
84         REQUIRE(a != NULL && b != NULL);
85
86         if (a->length != b->length)
87                 return (ISC_FALSE);
88
89         if (a->type.sa.sa_family != b->type.sa.sa_family)
90                 return (ISC_FALSE);
91         switch (a->type.sa.sa_family) {
92         case AF_INET:
93                 if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
94                            sizeof(a->type.sin.sin_addr)) != 0)
95                         return (ISC_FALSE);
96                 break;
97         case AF_INET6:
98                 if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
99                            sizeof(a->type.sin6.sin6_addr)) != 0)
100                         return (ISC_FALSE);
101 #ifdef ISC_PLATFORM_HAVESCOPEID
102                 if (a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id)
103                         return (ISC_FALSE);
104 #endif
105                 break;
106         default:
107                 if (memcmp(&a->type, &b->type, a->length) != 0)
108                         return (ISC_FALSE);
109         }
110         return (ISC_TRUE);
111 }
112
113 isc_boolean_t
114 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
115                           unsigned int prefixlen)
116 {
117         isc_netaddr_t na, nb;
118         isc_netaddr_fromsockaddr(&na, a);
119         isc_netaddr_fromsockaddr(&nb, b);
120         return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
121 }
122
123 isc_result_t
124 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
125         isc_result_t result;
126         isc_netaddr_t netaddr;
127         char pbuf[sizeof("65000")];
128         unsigned int plen;
129         isc_region_t avail;
130
131         REQUIRE(sockaddr != NULL);
132
133         /*
134          * Do the port first, giving us the opportunity to check for
135          * unsupported address families before calling
136          * isc_netaddr_fromsockaddr().
137          */
138         switch (sockaddr->type.sa.sa_family) {
139         case AF_INET:
140                 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
141                 break;
142         case AF_INET6:
143                 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
144                 break;
145         default:
146                 return (ISC_R_FAILURE);
147         }
148
149         plen = strlen(pbuf);
150         INSIST(plen < sizeof(pbuf));
151
152         isc_netaddr_fromsockaddr(&netaddr, sockaddr);
153         result = isc_netaddr_totext(&netaddr, target);
154         if (result != ISC_R_SUCCESS)
155                 return (result);
156
157         if (1 + plen + 1 > isc_buffer_availablelength(target))
158                 return (ISC_R_NOSPACE);
159
160         isc_buffer_putmem(target, (const unsigned char *)"#", 1);
161         isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
162
163         /*
164          * Null terminate after used region.
165          */
166         isc_buffer_availableregion(target, &avail);
167         INSIST(avail.length >= 1);
168         avail.base[0] = '\0';
169
170         return (ISC_R_SUCCESS);
171 }
172
173 void
174 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
175         isc_result_t result;
176         isc_buffer_t buf;
177
178         isc_buffer_init(&buf, array, size);
179         result = isc_sockaddr_totext(sa, &buf);
180         if (result != ISC_R_SUCCESS) {
181                 /*
182                  * The message is the same as in netaddr.c.
183                  */
184                 snprintf(array, size,
185                          isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
186                                         ISC_MSG_UNKNOWNADDR,
187                                         "<unknown address, family %u>"),
188                          sa->type.sa.sa_family);
189                 array[size - 1] = '\0';
190         }
191 }
192
193 #if 0
194 /*
195  * We currently don't need hashing here
196  */
197 unsigned int
198 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
199         unsigned int length = 0;
200         const unsigned char *s = NULL;
201         unsigned int h = 0;
202         unsigned int g;
203         unsigned int p = 0;
204         const struct in6_addr *in6;
205
206         REQUIRE(sockaddr != NULL);
207
208         switch (sockaddr->type.sa.sa_family) {
209         case AF_INET:
210                 s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
211                 p = ntohs(sockaddr->type.sin.sin_port);
212                 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
213                 break;
214 #if ISC_PLATFORM_HAVEIPV6
215         case AF_INET6:
216                 in6 = &sockaddr->type.sin6.sin6_addr;
217                 if (IN6_IS_ADDR_V4MAPPED(in6)) {
218                         s = (const unsigned char *)&in6[12];
219                         length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
220                 } else {
221                         s = (const unsigned char *)in6;
222                         length = sizeof(sockaddr->type.sin6.sin6_addr);
223                 }
224                 p = ntohs(sockaddr->type.sin6.sin6_port);
225                 break;
226 #endif
227         default:
228                 UNEXPECTED_ERROR(__FILE__, __LINE__,
229                                  isc_msgcat_get(isc_msgcat,
230                                                 ISC_MSGSET_SOCKADDR,
231                                                 ISC_MSG_UNKNOWNFAMILY,
232                                                 "unknown address family: %d"),
233                                              (int)sockaddr->type.sa.sa_family);
234                 s = (const unsigned char *)&sockaddr->type;
235                 length = sockaddr->length;
236                 p = 0;
237         }
238
239         h = isc_hash_calc(s, length, ISC_TRUE);
240         if (!address_only) {
241                 g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
242                                   ISC_TRUE);
243                 h = h ^ g; /* XXX: we should concatenate h and p first */
244         }
245
246         return (h);
247 }
248 #endif
249
250 void
251 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
252 {
253         memset(sockaddr, 0, sizeof(*sockaddr));
254         sockaddr->type.sin.sin_family = AF_INET;
255 #ifdef ISC_PLATFORM_HAVESALEN
256         sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
257 #endif
258         sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
259         sockaddr->type.sin.sin_port = 0;
260         sockaddr->length = sizeof(sockaddr->type.sin);
261         ISC_LINK_INIT(sockaddr, link);
262 }
263
264 void
265 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
266 {
267 #ifdef ISC_PLATFORM_HAVEIPV6
268         memset(sockaddr, 0, sizeof(*sockaddr));
269         sockaddr->type.sin6.sin6_family = AF_INET6;
270 #ifdef ISC_PLATFORM_HAVESALEN
271         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
272 #endif
273         sockaddr->type.sin6.sin6_addr = in6addr_any;
274         sockaddr->type.sin6.sin6_port = 0;
275         sockaddr->length = sizeof(sockaddr->type.sin6);
276         ISC_LINK_INIT(sockaddr, link);
277 #endif
278 }
279
280 void
281 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
282                     in_port_t port)
283 {
284         memset(sockaddr, 0, sizeof(*sockaddr));
285         sockaddr->type.sin.sin_family = AF_INET;
286 #ifdef ISC_PLATFORM_HAVESALEN
287         sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
288 #endif
289         sockaddr->type.sin.sin_addr = *ina;
290         sockaddr->type.sin.sin_port = htons(port);
291         sockaddr->length = sizeof(sockaddr->type.sin);
292         ISC_LINK_INIT(sockaddr, link);
293 }
294
295 void
296 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
297      switch (pf) {
298      case AF_INET:
299              isc_sockaddr_any(sockaddr);
300              break;
301      case AF_INET6:
302              isc_sockaddr_any6(sockaddr);
303              break;
304      default:
305              INSIST(0);
306      }
307 }
308
309 void
310 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
311                      in_port_t port)
312 {
313         memset(sockaddr, 0, sizeof(*sockaddr));
314         sockaddr->type.sin6.sin6_family = AF_INET6;
315 #ifdef ISC_PLATFORM_HAVESALEN
316         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
317 #endif
318         sockaddr->type.sin6.sin6_addr = *ina6;
319         sockaddr->type.sin6.sin6_port = htons(port);
320         sockaddr->length = sizeof(sockaddr->type.sin6);
321         ISC_LINK_INIT(sockaddr, link);
322 }
323
324 void
325 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
326                       in_port_t port)
327 {
328         memset(sockaddr, 0, sizeof(*sockaddr));
329         sockaddr->type.sin6.sin6_family = AF_INET6;
330 #ifdef ISC_PLATFORM_HAVESALEN
331         sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
332 #endif
333         sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
334         sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
335         memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
336         sockaddr->type.sin6.sin6_port = htons(port);
337         sockaddr->length = sizeof(sockaddr->type.sin6);
338         ISC_LINK_INIT(sockaddr, link);
339 }
340
341 int
342 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
343
344         /*
345          * Get the protocol family of 'sockaddr'.
346          */
347
348 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
349         /*
350          * Assume that PF_xxx == AF_xxx for all AF and PF.
351          */
352         return (sockaddr->type.sa.sa_family);
353 #else
354         switch (sockaddr->type.sa.sa_family) {
355         case AF_INET:
356                 return (PF_INET);
357         case AF_INET6:
358                 return (PF_INET6);
359         default:
360                 FATAL_ERROR(__FILE__, __LINE__,
361                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
362                                            ISC_MSG_UNKNOWNFAMILY,
363                                            "unknown address family: %d"),
364                             (int)sockaddr->type.sa.sa_family);
365         }
366 #endif
367 }
368
369 void
370 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
371                     in_port_t port)
372 {
373         memset(sockaddr, 0, sizeof(*sockaddr));
374         sockaddr->type.sin.sin_family = na->family;
375         switch (na->family) {
376         case AF_INET:
377                 sockaddr->length = sizeof(sockaddr->type.sin);
378 #ifdef ISC_PLATFORM_HAVESALEN
379                 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
380 #endif
381                 sockaddr->type.sin.sin_addr = na->type.in;
382                 sockaddr->type.sin.sin_port = htons(port);
383                 break;
384         case AF_INET6:
385                 sockaddr->length = sizeof(sockaddr->type.sin6);
386 #ifdef ISC_PLATFORM_HAVESALEN
387                 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
388 #endif
389                 memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
390 #ifdef ISC_PLATFORM_HAVESCOPEID
391                 sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
392 #endif
393                 sockaddr->type.sin6.sin6_port = htons(port);
394                 break;
395         default:
396                 INSIST(0);
397         }
398         ISC_LINK_INIT(sockaddr, link);
399 }
400
401 void
402 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
403         switch (sockaddr->type.sa.sa_family) {
404         case AF_INET:
405                 sockaddr->type.sin.sin_port = htons(port);
406                 break;
407         case AF_INET6:
408                 sockaddr->type.sin6.sin6_port = htons(port);
409                 break;
410         default:
411                 FATAL_ERROR(__FILE__, __LINE__,
412                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
413                                            ISC_MSG_UNKNOWNFAMILY,
414                                            "unknown address family: %d"),
415                             (int)sockaddr->type.sa.sa_family);
416         }
417 }
418
419 in_port_t
420 isc_sockaddr_getport(isc_sockaddr_t *sockaddr) {
421         in_port_t port = 0;
422
423         switch (sockaddr->type.sa.sa_family) {
424         case AF_INET:
425                 port = ntohs(sockaddr->type.sin.sin_port);
426                 break;
427         case AF_INET6:
428                 port = ntohs(sockaddr->type.sin6.sin6_port);
429                 break;
430         default:
431                 FATAL_ERROR(__FILE__, __LINE__,
432                             isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
433                                            ISC_MSG_UNKNOWNFAMILY,
434                                            "unknown address family: %d"),
435                             (int)sockaddr->type.sa.sa_family);
436         }
437
438         return (port);
439 }
440
441 isc_boolean_t
442 isc_sockaddr_ismulticast(isc_sockaddr_t *sockaddr) {
443         isc_netaddr_t netaddr;
444
445         isc_netaddr_fromsockaddr(&netaddr, sockaddr);
446         return (isc_netaddr_ismulticast(&netaddr));
447 }
448
449 isc_boolean_t
450 isc_sockaddr_isexperimental(isc_sockaddr_t *sockaddr) {
451         isc_netaddr_t netaddr;
452
453         if (sockaddr->type.sa.sa_family == AF_INET) {
454                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
455                 return (isc_netaddr_isexperimental(&netaddr));
456         }
457         return (ISC_FALSE);
458 }
459
460 isc_boolean_t
461 isc_sockaddr_issitelocal(isc_sockaddr_t *sockaddr) {
462         isc_netaddr_t netaddr;
463
464         if (sockaddr->type.sa.sa_family == AF_INET6) {
465                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
466                 return (isc_netaddr_issitelocal(&netaddr));
467         }
468         return (ISC_FALSE);
469 }
470
471 isc_boolean_t
472 isc_sockaddr_islinklocal(isc_sockaddr_t *sockaddr) {
473         isc_netaddr_t netaddr;
474
475         if (sockaddr->type.sa.sa_family == AF_INET6) {
476                 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
477                 return (isc_netaddr_islinklocal(&netaddr));
478         }
479         return (ISC_FALSE);
480 }