2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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.1.2.10 2004/05/15 03:46:12 jinmei Exp $ */
26 #include <isc/buffer.h>
28 * We currently don't need hashing here
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>
43 isc_sockaddr_equal(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
44 REQUIRE(a
!= NULL
&& b
!= NULL
);
46 if (a
->length
!= b
->length
)
50 * We don't just memcmp because the sin_zero field isn't always
54 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
56 switch (a
->type
.sa
.sa_family
) {
58 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
59 sizeof(a
->type
.sin
.sin_addr
)) != 0)
61 if (a
->type
.sin
.sin_port
!= b
->type
.sin
.sin_port
)
65 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
66 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
68 #ifdef ISC_PLATFORM_HAVESCOPEID
69 if (a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
)
72 if (a
->type
.sin6
.sin6_port
!= b
->type
.sin6
.sin6_port
)
76 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
83 isc_sockaddr_eqaddr(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
84 REQUIRE(a
!= NULL
&& b
!= NULL
);
86 if (a
->length
!= b
->length
)
89 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
91 switch (a
->type
.sa
.sa_family
) {
93 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
94 sizeof(a
->type
.sin
.sin_addr
)) != 0)
98 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
99 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
101 #ifdef ISC_PLATFORM_HAVESCOPEID
102 if (a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
)
107 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
114 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
115 unsigned int prefixlen
)
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
));
124 isc_sockaddr_totext(const isc_sockaddr_t
*sockaddr
, isc_buffer_t
*target
) {
126 isc_netaddr_t netaddr
;
127 char pbuf
[sizeof("65000")];
131 REQUIRE(sockaddr
!= NULL
);
134 * Do the port first, giving us the opportunity to check for
135 * unsupported address families before calling
136 * isc_netaddr_fromsockaddr().
138 switch (sockaddr
->type
.sa
.sa_family
) {
140 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin
.sin_port
));
143 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin6
.sin6_port
));
146 return (ISC_R_FAILURE
);
150 INSIST(plen
< sizeof(pbuf
));
152 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
153 result
= isc_netaddr_totext(&netaddr
, target
);
154 if (result
!= ISC_R_SUCCESS
)
157 if (1 + plen
+ 1 > isc_buffer_availablelength(target
))
158 return (ISC_R_NOSPACE
);
160 isc_buffer_putmem(target
, (const unsigned char *)"#", 1);
161 isc_buffer_putmem(target
, (const unsigned char *)pbuf
, plen
);
164 * Null terminate after used region.
166 isc_buffer_availableregion(target
, &avail
);
167 INSIST(avail
.length
>= 1);
168 avail
.base
[0] = '\0';
170 return (ISC_R_SUCCESS
);
174 isc_sockaddr_format(const isc_sockaddr_t
*sa
, char *array
, unsigned int size
) {
178 isc_buffer_init(&buf
, array
, size
);
179 result
= isc_sockaddr_totext(sa
, &buf
);
180 if (result
!= ISC_R_SUCCESS
) {
182 * The message is the same as in netaddr.c.
184 snprintf(array
, size
,
185 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
187 "<unknown address, family %u>"),
188 sa
->type
.sa
.sa_family
);
189 array
[size
- 1] = '\0';
195 * We currently don't need hashing here
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
;
204 const struct in6_addr
*in6
;
206 REQUIRE(sockaddr
!= NULL
);
208 switch (sockaddr
->type
.sa
.sa_family
) {
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
);
214 #if ISC_PLATFORM_HAVEIPV6
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
);
221 s
= (const unsigned char *)in6
;
222 length
= sizeof(sockaddr
->type
.sin6
.sin6_addr
);
224 p
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
228 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
229 isc_msgcat_get(isc_msgcat
,
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
;
239 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
241 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
243 h
= h
^ g
; /* XXX: we should concatenate h and p first */
251 isc_sockaddr_any(isc_sockaddr_t
*sockaddr
)
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
);
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
);
265 isc_sockaddr_any6(isc_sockaddr_t
*sockaddr
)
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
);
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
);
281 isc_sockaddr_fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
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
);
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
);
296 isc_sockaddr_anyofpf(isc_sockaddr_t
*sockaddr
, int pf
) {
299 isc_sockaddr_any(sockaddr
);
302 isc_sockaddr_any6(sockaddr
);
310 isc_sockaddr_fromin6(isc_sockaddr_t
*sockaddr
, const struct in6_addr
*ina6
,
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
);
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
);
325 isc_sockaddr_v6fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
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
);
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
);
342 isc_sockaddr_pf(const isc_sockaddr_t
*sockaddr
) {
345 * Get the protocol family of 'sockaddr'.
348 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
350 * Assume that PF_xxx == AF_xxx for all AF and PF.
352 return (sockaddr
->type
.sa
.sa_family
);
354 switch (sockaddr
->type
.sa
.sa_family
) {
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
);
370 isc_sockaddr_fromnetaddr(isc_sockaddr_t
*sockaddr
, const isc_netaddr_t
*na
,
373 memset(sockaddr
, 0, sizeof(*sockaddr
));
374 sockaddr
->type
.sin
.sin_family
= na
->family
;
375 switch (na
->family
) {
377 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
378 #ifdef ISC_PLATFORM_HAVESALEN
379 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
381 sockaddr
->type
.sin
.sin_addr
= na
->type
.in
;
382 sockaddr
->type
.sin
.sin_port
= htons(port
);
385 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
386 #ifdef ISC_PLATFORM_HAVESALEN
387 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
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
);
393 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
398 ISC_LINK_INIT(sockaddr
, link
);
402 isc_sockaddr_setport(isc_sockaddr_t
*sockaddr
, in_port_t port
) {
403 switch (sockaddr
->type
.sa
.sa_family
) {
405 sockaddr
->type
.sin
.sin_port
= htons(port
);
408 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
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
);
420 isc_sockaddr_getport(isc_sockaddr_t
*sockaddr
) {
423 switch (sockaddr
->type
.sa
.sa_family
) {
425 port
= ntohs(sockaddr
->type
.sin
.sin_port
);
428 port
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
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
);
442 isc_sockaddr_ismulticast(isc_sockaddr_t
*sockaddr
) {
443 isc_netaddr_t netaddr
;
445 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
446 return (isc_netaddr_ismulticast(&netaddr
));
450 isc_sockaddr_isexperimental(isc_sockaddr_t
*sockaddr
) {
451 isc_netaddr_t netaddr
;
453 if (sockaddr
->type
.sa
.sa_family
== AF_INET
) {
454 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
455 return (isc_netaddr_isexperimental(&netaddr
));
461 isc_sockaddr_issitelocal(isc_sockaddr_t
*sockaddr
) {
462 isc_netaddr_t netaddr
;
464 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
465 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
466 return (isc_netaddr_issitelocal(&netaddr
));
472 isc_sockaddr_islinklocal(isc_sockaddr_t
*sockaddr
) {
473 isc_netaddr_t netaddr
;
475 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
476 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
477 return (isc_netaddr_islinklocal(&netaddr
));