Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isc / sockaddr.c
blob89562118f50a1f760c75e7b0e4f40331ee150044
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
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.
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.
18 /* $Id: sockaddr.c,v 1.48.2.5 2004/03/09 06:11:51 marka Exp $ */
20 #include <config.h>
22 #include <stdio.h>
24 #include <isc/buffer.h>
25 #include <isc/hash.h>
26 #include <isc/msgs.h>
27 #include <isc/netaddr.h>
28 #include <isc/print.h>
29 #include <isc/region.h>
30 #include <isc/sockaddr.h>
31 #include <isc/string.h>
32 #include <isc/util.h>
34 isc_boolean_t
35 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
36 REQUIRE(a != NULL && b != NULL);
38 if (a->length != b->length)
39 return (ISC_FALSE);
42 * We don't just memcmp because the sin_zero field isn't always
43 * zero.
46 if (a->type.sa.sa_family != b->type.sa.sa_family)
47 return (ISC_FALSE);
48 switch (a->type.sa.sa_family) {
49 case AF_INET:
50 if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
51 sizeof(a->type.sin.sin_addr)) != 0)
52 return (ISC_FALSE);
53 if (a->type.sin.sin_port != b->type.sin.sin_port)
54 return (ISC_FALSE);
55 break;
56 case AF_INET6:
57 if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
58 sizeof(a->type.sin6.sin6_addr)) != 0)
59 return (ISC_FALSE);
60 if (a->type.sin6.sin6_port != b->type.sin6.sin6_port)
61 return (ISC_FALSE);
62 break;
63 default:
64 if (memcmp(&a->type, &b->type, a->length) != 0)
65 return (ISC_FALSE);
67 return (ISC_TRUE);
70 isc_boolean_t
71 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
72 REQUIRE(a != NULL && b != NULL);
74 if (a->length != b->length)
75 return (ISC_FALSE);
77 if (a->type.sa.sa_family != b->type.sa.sa_family)
78 return (ISC_FALSE);
79 switch (a->type.sa.sa_family) {
80 case AF_INET:
81 if (memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
82 sizeof(a->type.sin.sin_addr)) != 0)
83 return (ISC_FALSE);
84 break;
85 case AF_INET6:
86 if (memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
87 sizeof(a->type.sin6.sin6_addr)) != 0)
88 return (ISC_FALSE);
89 break;
90 default:
91 if (memcmp(&a->type, &b->type, a->length) != 0)
92 return (ISC_FALSE);
94 return (ISC_TRUE);
97 isc_boolean_t
98 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
99 unsigned int prefixlen)
101 isc_netaddr_t na, nb;
102 isc_netaddr_fromsockaddr(&na, a);
103 isc_netaddr_fromsockaddr(&nb, b);
104 return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
107 isc_result_t
108 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
109 isc_result_t result;
110 isc_netaddr_t netaddr;
111 char pbuf[sizeof("65000")];
112 unsigned int plen;
113 isc_region_t avail;
115 REQUIRE(sockaddr != NULL);
118 * Do the port first, giving us the opportunity to check for
119 * unsupported address families before calling
120 * isc_netaddr_fromsockaddr().
122 switch (sockaddr->type.sa.sa_family) {
123 case AF_INET:
124 sprintf(pbuf, "%u", ntohs(sockaddr->type.sin.sin_port));
125 break;
126 case AF_INET6:
127 sprintf(pbuf, "%u", ntohs(sockaddr->type.sin6.sin6_port));
128 break;
129 default:
130 return (ISC_R_FAILURE);
133 plen = strlen(pbuf);
134 INSIST(plen < sizeof(pbuf));
136 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
137 result = isc_netaddr_totext(&netaddr, target);
138 if (result != ISC_R_SUCCESS)
139 return (result);
141 if (1 + plen + 1 > isc_buffer_availablelength(target))
142 return (ISC_R_NOSPACE);
144 isc_buffer_putmem(target, (const unsigned char *)"#", 1);
145 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
148 * Null terminate after used region.
150 isc_buffer_availableregion(target, &avail);
151 INSIST(avail.length >= 1);
152 avail.base[0] = '\0';
154 return (ISC_R_SUCCESS);
157 void
158 isc_sockaddr_format(isc_sockaddr_t *sa, char *array, unsigned int size) {
159 isc_result_t result;
160 isc_buffer_t buf;
162 isc_buffer_init(&buf, array, size);
163 result = isc_sockaddr_totext(sa, &buf);
164 if (result != ISC_R_SUCCESS) {
166 * The message is the same as in netaddr.c.
168 snprintf(array, size,
169 isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR,
170 ISC_MSG_UNKNOWNADDR,
171 "<unknown address, family %u>"),
172 sa->type.sa.sa_family);
173 array[size - 1] = '\0';
177 unsigned int
178 isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) {
179 unsigned int length = 0;
180 const unsigned char *s = NULL;
181 unsigned int h = 0;
182 unsigned int g;
183 unsigned int p = 0;
184 const struct in6_addr *in6;
186 REQUIRE(sockaddr != NULL);
187 switch (sockaddr->type.sa.sa_family) {
188 case AF_INET:
189 s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
190 p = ntohs(sockaddr->type.sin.sin_port);
191 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
192 break;
193 case AF_INET6:
194 in6 = &sockaddr->type.sin6.sin6_addr;
195 if (IN6_IS_ADDR_V4MAPPED(in6)) {
196 s = (const unsigned char *)&in6[12];
197 length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
198 } else {
199 s = (const unsigned char *)in6;
200 length = sizeof(sockaddr->type.sin6.sin6_addr);
202 p = ntohs(sockaddr->type.sin6.sin6_port);
203 break;
204 default:
205 UNEXPECTED_ERROR(__FILE__, __LINE__,
206 isc_msgcat_get(isc_msgcat,
207 ISC_MSGSET_SOCKADDR,
208 ISC_MSG_UNKNOWNFAMILY,
209 "unknown address family: %d"),
210 (int)sockaddr->type.sa.sa_family);
211 s = (const unsigned char *)&sockaddr->type;
212 length = sockaddr->length;
213 p = 0;
216 h = isc_hash_calc(s, length, ISC_TRUE);
217 if (!address_only) {
218 g = isc_hash_calc((const unsigned char *)&p, sizeof(p),
219 ISC_TRUE);
220 h = h ^ g; /* XXX: we should concatenate h and p first */
223 return (h);
226 void
227 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
229 memset(sockaddr, 0, sizeof(*sockaddr));
230 sockaddr->type.sin.sin_family = AF_INET;
231 #ifdef ISC_PLATFORM_HAVESALEN
232 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
233 #endif
234 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
235 sockaddr->type.sin.sin_port = 0;
236 sockaddr->length = sizeof(sockaddr->type.sin);
237 ISC_LINK_INIT(sockaddr, link);
240 void
241 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
243 memset(sockaddr, 0, sizeof(*sockaddr));
244 sockaddr->type.sin6.sin6_family = AF_INET6;
245 #ifdef ISC_PLATFORM_HAVESALEN
246 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
247 #endif
248 sockaddr->type.sin6.sin6_addr = in6addr_any;
249 sockaddr->type.sin6.sin6_port = 0;
250 sockaddr->length = sizeof(sockaddr->type.sin6);
251 ISC_LINK_INIT(sockaddr, link);
254 void
255 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
256 in_port_t port)
258 memset(sockaddr, 0, sizeof(*sockaddr));
259 sockaddr->type.sin.sin_family = AF_INET;
260 #ifdef ISC_PLATFORM_HAVESALEN
261 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
262 #endif
263 sockaddr->type.sin.sin_addr = *ina;
264 sockaddr->type.sin.sin_port = htons(port);
265 sockaddr->length = sizeof(sockaddr->type.sin);
266 ISC_LINK_INIT(sockaddr, link);
269 void
270 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
271 switch (pf) {
272 case AF_INET:
273 isc_sockaddr_any(sockaddr);
274 break;
275 case AF_INET6:
276 isc_sockaddr_any6(sockaddr);
277 break;
278 default:
279 INSIST(0);
283 void
284 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
285 in_port_t port)
287 memset(sockaddr, 0, sizeof(*sockaddr));
288 sockaddr->type.sin6.sin6_family = AF_INET6;
289 #ifdef ISC_PLATFORM_HAVESALEN
290 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
291 #endif
292 sockaddr->type.sin6.sin6_addr = *ina6;
293 sockaddr->type.sin6.sin6_port = htons(port);
294 sockaddr->length = sizeof(sockaddr->type.sin6);
295 ISC_LINK_INIT(sockaddr, link);
298 void
299 isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
300 in_port_t port)
302 memset(sockaddr, 0, sizeof(*sockaddr));
303 sockaddr->type.sin6.sin6_family = AF_INET6;
304 #ifdef ISC_PLATFORM_HAVESALEN
305 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
306 #endif
307 sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
308 sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
309 memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
310 sockaddr->type.sin6.sin6_port = htons(port);
311 sockaddr->length = sizeof(sockaddr->type.sin6);
312 ISC_LINK_INIT(sockaddr, link);
316 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
319 * Get the protocol family of 'sockaddr'.
322 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
324 * Assume that PF_xxx == AF_xxx for all AF and PF.
326 return (sockaddr->type.sa.sa_family);
327 #else
328 switch (sockaddr->type.sa.sa_family) {
329 case AF_INET:
330 return (PF_INET);
331 case AF_INET6:
332 return (PF_INET6);
333 default:
334 FATAL_ERROR(__FILE__, __LINE__,
335 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
336 ISC_MSG_UNKNOWNFAMILY,
337 "unknown address family: %d"),
338 (int)sockaddr->type.sa.sa_family);
340 #endif
343 void
344 isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
345 in_port_t port)
347 memset(sockaddr, 0, sizeof(*sockaddr));
348 sockaddr->type.sin.sin_family = na->family;
349 switch (na->family) {
350 case AF_INET:
351 sockaddr->length = sizeof(sockaddr->type.sin);
352 #ifdef ISC_PLATFORM_HAVESALEN
353 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
354 #endif
355 sockaddr->type.sin.sin_addr = na->type.in;
356 sockaddr->type.sin.sin_port = htons(port);
357 break;
358 case AF_INET6:
359 sockaddr->length = sizeof(sockaddr->type.sin6);
360 #ifdef ISC_PLATFORM_HAVESALEN
361 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
362 #endif
363 memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
364 sockaddr->type.sin6.sin6_port = htons(port);
365 break;
366 default:
367 INSIST(0);
369 ISC_LINK_INIT(sockaddr, link);
372 void
373 isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
374 switch (sockaddr->type.sa.sa_family) {
375 case AF_INET:
376 sockaddr->type.sin.sin_port = htons(port);
377 break;
378 case AF_INET6:
379 sockaddr->type.sin6.sin6_port = htons(port);
380 break;
381 default:
382 FATAL_ERROR(__FILE__, __LINE__,
383 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
384 ISC_MSG_UNKNOWNFAMILY,
385 "unknown address family: %d"),
386 (int)sockaddr->type.sa.sa_family);
390 in_port_t
391 isc_sockaddr_getport(isc_sockaddr_t *sockaddr) {
392 in_port_t port = 0;
394 switch (sockaddr->type.sa.sa_family) {
395 case AF_INET:
396 port = ntohs(sockaddr->type.sin.sin_port);
397 break;
398 case AF_INET6:
399 port = ntohs(sockaddr->type.sin6.sin6_port);
400 break;
401 default:
402 FATAL_ERROR(__FILE__, __LINE__,
403 isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR,
404 ISC_MSG_UNKNOWNFAMILY,
405 "unknown address family: %d"),
406 (int)sockaddr->type.sa.sa_family);
409 return (port);
412 isc_boolean_t
413 isc_sockaddr_ismulticast(isc_sockaddr_t *sockaddr) {
414 isc_netaddr_t netaddr;
416 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
417 return (isc_netaddr_ismulticast(&netaddr));
420 isc_boolean_t
421 isc_sockaddr_isexperimental(isc_sockaddr_t *sockaddr) {
422 isc_netaddr_t netaddr;
424 if (sockaddr->type.sa.sa_family == AF_INET) {
425 isc_netaddr_fromsockaddr(&netaddr, sockaddr);
426 return (isc_netaddr_isexperimental(&netaddr));
428 return (ISC_FALSE);