4 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: sockaddr.c,v 1.70 2007/06/19 23:47:17 tbox Exp */
28 #include <isc/buffer.h>
31 #include <isc/netaddr.h>
32 #include <isc/print.h>
33 #include <isc/region.h>
34 #include <isc/sockaddr.h>
35 #include <isc/string.h>
39 isc_sockaddr_equal(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
40 return (isc_sockaddr_compare(a
, b
, ISC_SOCKADDR_CMPADDR
|
42 ISC_SOCKADDR_CMPSCOPE
));
46 isc_sockaddr_eqaddr(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
47 return (isc_sockaddr_compare(a
, b
, ISC_SOCKADDR_CMPADDR
|
48 ISC_SOCKADDR_CMPSCOPE
));
52 isc_sockaddr_compare(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
55 REQUIRE(a
!= NULL
&& b
!= NULL
);
57 if (a
->length
!= b
->length
)
61 * We don't just memcmp because the sin_zero field isn't always
65 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
67 switch (a
->type
.sa
.sa_family
) {
69 if ((flags
& ISC_SOCKADDR_CMPADDR
) != 0 &&
70 memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
71 sizeof(a
->type
.sin
.sin_addr
)) != 0)
73 if ((flags
& ISC_SOCKADDR_CMPPORT
) != 0 &&
74 a
->type
.sin
.sin_port
!= b
->type
.sin
.sin_port
)
78 if ((flags
& ISC_SOCKADDR_CMPADDR
) != 0 &&
79 memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
80 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
82 #ifdef ISC_PLATFORM_HAVESCOPEID
84 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
85 * ISC_FALSE if one of the scopes in zero.
87 if ((flags
& ISC_SOCKADDR_CMPSCOPE
) != 0 &&
88 a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
&&
89 ((flags
& ISC_SOCKADDR_CMPSCOPEZERO
) == 0 ||
90 (a
->type
.sin6
.sin6_scope_id
!= 0 &&
91 b
->type
.sin6
.sin6_scope_id
!= 0)))
94 if ((flags
& ISC_SOCKADDR_CMPPORT
) != 0 &&
95 a
->type
.sin6
.sin6_port
!= b
->type
.sin6
.sin6_port
)
99 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
106 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
107 unsigned int prefixlen
)
109 isc_netaddr_t na
, nb
;
110 isc_netaddr_fromsockaddr(&na
, a
);
111 isc_netaddr_fromsockaddr(&nb
, b
);
112 return (isc_netaddr_eqprefix(&na
, &nb
, prefixlen
));
116 isc_sockaddr_totext(const isc_sockaddr_t
*sockaddr
, isc_buffer_t
*target
) {
118 isc_netaddr_t netaddr
;
119 char pbuf
[sizeof("65000")];
123 REQUIRE(sockaddr
!= NULL
);
126 * Do the port first, giving us the opportunity to check for
127 * unsupported address families before calling
128 * isc_netaddr_fromsockaddr().
130 switch (sockaddr
->type
.sa
.sa_family
) {
132 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin
.sin_port
));
135 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin6
.sin6_port
));
137 #ifdef ISC_PLAFORM_HAVESYSUNH
139 plen
= strlen(sockaddr
->type
.sunix
.sun_path
);
140 if (plen
>= isc_buffer_availablelength(target
))
141 return (ISC_R_NOSPACE
);
143 isc_buffer_putmem(target
, sockaddr
->type
.sunix
.sun_path
, plen
);
146 * Null terminate after used region.
148 isc_buffer_availableregion(target
, &avail
);
149 INSIST(avail
.length
>= 1);
150 avail
.base
[0] = '\0';
152 return (ISC_R_SUCCESS
);
155 return (ISC_R_FAILURE
);
159 INSIST(plen
< sizeof(pbuf
));
161 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
162 result
= isc_netaddr_totext(&netaddr
, target
);
163 if (result
!= ISC_R_SUCCESS
)
166 if (1 + plen
+ 1 > isc_buffer_availablelength(target
))
167 return (ISC_R_NOSPACE
);
169 isc_buffer_putmem(target
, (const unsigned char *)"#", 1);
170 isc_buffer_putmem(target
, (const unsigned char *)pbuf
, plen
);
173 * Null terminate after used region.
175 isc_buffer_availableregion(target
, &avail
);
176 INSIST(avail
.length
>= 1);
177 avail
.base
[0] = '\0';
179 return (ISC_R_SUCCESS
);
183 isc_sockaddr_format(const isc_sockaddr_t
*sa
, char *array
, unsigned int size
) {
187 isc_buffer_init(&buf
, array
, size
);
188 result
= isc_sockaddr_totext(sa
, &buf
);
189 if (result
!= ISC_R_SUCCESS
) {
191 * The message is the same as in netaddr.c.
193 snprintf(array
, size
,
194 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
196 "<unknown address, family %u>"),
197 sa
->type
.sa
.sa_family
);
198 array
[size
- 1] = '\0';
203 isc_sockaddr_hash(const isc_sockaddr_t
*sockaddr
, isc_boolean_t address_only
) {
204 unsigned int length
= 0;
205 const unsigned char *s
= NULL
;
209 const struct in6_addr
*in6
;
211 REQUIRE(sockaddr
!= NULL
);
213 switch (sockaddr
->type
.sa
.sa_family
) {
215 s
= (const unsigned char *)&sockaddr
->type
.sin
.sin_addr
;
216 p
= ntohs(sockaddr
->type
.sin
.sin_port
);
217 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
220 in6
= &sockaddr
->type
.sin6
.sin6_addr
;
221 if (IN6_IS_ADDR_V4MAPPED(in6
)) {
222 s
= (const unsigned char *)&in6
[12];
223 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
225 s
= (const unsigned char *)in6
;
226 length
= sizeof(sockaddr
->type
.sin6
.sin6_addr
);
228 p
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
231 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
232 isc_msgcat_get(isc_msgcat
,
234 ISC_MSG_UNKNOWNFAMILY
,
235 "unknown address family: %d"),
236 (int)sockaddr
->type
.sa
.sa_family
);
237 s
= (const unsigned char *)&sockaddr
->type
;
238 length
= sockaddr
->length
;
242 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
244 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
246 h
= h
^ g
; /* XXX: we should concatenate h and p first */
253 isc_sockaddr_any(isc_sockaddr_t
*sockaddr
)
255 memset(sockaddr
, 0, sizeof(*sockaddr
));
256 sockaddr
->type
.sin
.sin_family
= AF_INET
;
257 #ifdef ISC_PLATFORM_HAVESALEN
258 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
260 sockaddr
->type
.sin
.sin_addr
.s_addr
= INADDR_ANY
;
261 sockaddr
->type
.sin
.sin_port
= 0;
262 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
263 ISC_LINK_INIT(sockaddr
, link
);
267 isc_sockaddr_any6(isc_sockaddr_t
*sockaddr
)
269 memset(sockaddr
, 0, sizeof(*sockaddr
));
270 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
271 #ifdef ISC_PLATFORM_HAVESALEN
272 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
274 sockaddr
->type
.sin6
.sin6_addr
= in6addr_any
;
275 sockaddr
->type
.sin6
.sin6_port
= 0;
276 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
277 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
= (short)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(const 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(const isc_sockaddr_t
*sockaddr
) {
443 isc_netaddr_t netaddr
;
445 if (sockaddr
->type
.sa
.sa_family
== AF_INET
||
446 sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
447 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
448 return (isc_netaddr_ismulticast(&netaddr
));
454 isc_sockaddr_isexperimental(const isc_sockaddr_t
*sockaddr
) {
455 isc_netaddr_t netaddr
;
457 if (sockaddr
->type
.sa
.sa_family
== AF_INET
) {
458 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
459 return (isc_netaddr_isexperimental(&netaddr
));
465 isc_sockaddr_issitelocal(const isc_sockaddr_t
*sockaddr
) {
466 isc_netaddr_t netaddr
;
468 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
469 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
470 return (isc_netaddr_issitelocal(&netaddr
));
476 isc_sockaddr_islinklocal(const isc_sockaddr_t
*sockaddr
) {
477 isc_netaddr_t netaddr
;
479 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
480 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
481 return (isc_netaddr_islinklocal(&netaddr
));
487 isc_sockaddr_frompath(isc_sockaddr_t
*sockaddr
, const char *path
) {
488 #ifdef ISC_PLATFORM_HAVESYSUNH
489 if (strlen(path
) >= sizeof(sockaddr
->type
.sunix
.sun_path
))
490 return (ISC_R_NOSPACE
);
491 memset(sockaddr
, 0, sizeof(*sockaddr
));
492 sockaddr
->length
= sizeof(sockaddr
->type
.sunix
);
493 sockaddr
->type
.sunix
.sun_family
= AF_UNIX
;
494 #ifdef ISC_PLATFORM_HAVESALEN
495 sockaddr
->type
.sunix
.sun_len
=
496 (unsigned char)sizeof(sockaddr
->type
.sunix
);
498 strcpy(sockaddr
->type
.sunix
.sun_path
, path
);
499 return (ISC_R_SUCCESS
);
503 return (ISC_R_NOTIMPLEMENTED
);