4 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and 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.48.2.1.2.10 2004/05/15 03:46:12 jinmei Exp */
28 #include <isc/buffer.h>
30 * We currently don't need hashing here
37 #include <isc/netaddr.h>
38 #include <isc/print.h>
39 #include <isc/region.h>
40 #include <isc/sockaddr.h>
41 #include <isc/string.h>
45 isc_sockaddr_equal(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
46 REQUIRE(a
!= NULL
&& b
!= NULL
);
48 if (a
->length
!= b
->length
)
52 * We don't just memcmp because the sin_zero field isn't always
56 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
58 switch (a
->type
.sa
.sa_family
) {
60 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
61 sizeof(a
->type
.sin
.sin_addr
)) != 0)
63 if (a
->type
.sin
.sin_port
!= b
->type
.sin
.sin_port
)
67 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
68 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
70 #ifdef ISC_PLATFORM_HAVESCOPEID
71 if (a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
)
74 if (a
->type
.sin6
.sin6_port
!= b
->type
.sin6
.sin6_port
)
78 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
85 isc_sockaddr_eqaddr(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
86 REQUIRE(a
!= NULL
&& b
!= NULL
);
88 if (a
->length
!= b
->length
)
91 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
93 switch (a
->type
.sa
.sa_family
) {
95 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
96 sizeof(a
->type
.sin
.sin_addr
)) != 0)
100 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
101 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
103 #ifdef ISC_PLATFORM_HAVESCOPEID
104 if (a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
)
109 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
116 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
117 unsigned int prefixlen
)
119 isc_netaddr_t na
, nb
;
120 isc_netaddr_fromsockaddr(&na
, a
);
121 isc_netaddr_fromsockaddr(&nb
, b
);
122 return (isc_netaddr_eqprefix(&na
, &nb
, prefixlen
));
126 isc_sockaddr_totext(const isc_sockaddr_t
*sockaddr
, isc_buffer_t
*target
) {
128 isc_netaddr_t netaddr
;
129 char pbuf
[sizeof("65000")];
133 REQUIRE(sockaddr
!= NULL
);
136 * Do the port first, giving us the opportunity to check for
137 * unsupported address families before calling
138 * isc_netaddr_fromsockaddr().
140 switch (sockaddr
->type
.sa
.sa_family
) {
142 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin
.sin_port
));
145 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin6
.sin6_port
));
148 return (ISC_R_FAILURE
);
152 INSIST(plen
< sizeof(pbuf
));
154 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
155 result
= isc_netaddr_totext(&netaddr
, target
);
156 if (result
!= ISC_R_SUCCESS
)
159 if (1 + plen
+ 1 > isc_buffer_availablelength(target
))
160 return (ISC_R_NOSPACE
);
162 isc_buffer_putmem(target
, (const unsigned char *)"#", 1);
163 isc_buffer_putmem(target
, (const unsigned char *)pbuf
, plen
);
166 * Null terminate after used region.
168 isc_buffer_availableregion(target
, &avail
);
169 INSIST(avail
.length
>= 1);
170 avail
.base
[0] = '\0';
172 return (ISC_R_SUCCESS
);
176 isc_sockaddr_format(const isc_sockaddr_t
*sa
, char *array
, unsigned int size
) {
180 isc_buffer_init(&buf
, array
, size
);
181 result
= isc_sockaddr_totext(sa
, &buf
);
182 if (result
!= ISC_R_SUCCESS
) {
184 * The message is the same as in netaddr.c.
186 snprintf(array
, size
,
187 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
189 "<unknown address, family %u>"),
190 sa
->type
.sa
.sa_family
);
191 array
[size
- 1] = '\0';
197 * We currently don't need hashing here
200 isc_sockaddr_hash(const isc_sockaddr_t
*sockaddr
, isc_boolean_t address_only
) {
201 unsigned int length
= 0;
202 const unsigned char *s
= NULL
;
206 const struct in6_addr
*in6
;
208 REQUIRE(sockaddr
!= NULL
);
210 switch (sockaddr
->type
.sa
.sa_family
) {
212 s
= (const unsigned char *)&sockaddr
->type
.sin
.sin_addr
;
213 p
= ntohs(sockaddr
->type
.sin
.sin_port
);
214 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
216 #if ISC_PLATFORM_HAVEIPV6
218 in6
= &sockaddr
->type
.sin6
.sin6_addr
;
219 if (IN6_IS_ADDR_V4MAPPED(in6
)) {
220 s
= (const unsigned char *)&in6
[12];
221 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
223 s
= (const unsigned char *)in6
;
224 length
= sizeof(sockaddr
->type
.sin6
.sin6_addr
);
226 p
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
230 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
231 isc_msgcat_get(isc_msgcat
,
233 ISC_MSG_UNKNOWNFAMILY
,
234 "unknown address family: %d"),
235 (int)sockaddr
->type
.sa
.sa_family
);
236 s
= (const unsigned char *)&sockaddr
->type
;
237 length
= sockaddr
->length
;
241 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
243 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
245 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 #ifdef ISC_PLATFORM_HAVEIPV6
270 memset(sockaddr
, 0, sizeof(*sockaddr
));
271 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
272 #ifdef ISC_PLATFORM_HAVESALEN
273 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
275 sockaddr
->type
.sin6
.sin6_addr
= in6addr_any
;
276 sockaddr
->type
.sin6
.sin6_port
= 0;
277 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
278 ISC_LINK_INIT(sockaddr
, link
);
283 isc_sockaddr_fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
286 memset(sockaddr
, 0, sizeof(*sockaddr
));
287 sockaddr
->type
.sin
.sin_family
= AF_INET
;
288 #ifdef ISC_PLATFORM_HAVESALEN
289 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
291 sockaddr
->type
.sin
.sin_addr
= *ina
;
292 sockaddr
->type
.sin
.sin_port
= htons(port
);
293 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
294 ISC_LINK_INIT(sockaddr
, link
);
298 isc_sockaddr_anyofpf(isc_sockaddr_t
*sockaddr
, int pf
) {
301 isc_sockaddr_any(sockaddr
);
304 isc_sockaddr_any6(sockaddr
);
312 isc_sockaddr_fromin6(isc_sockaddr_t
*sockaddr
, const struct in6_addr
*ina6
,
315 memset(sockaddr
, 0, sizeof(*sockaddr
));
316 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
317 #ifdef ISC_PLATFORM_HAVESALEN
318 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
320 sockaddr
->type
.sin6
.sin6_addr
= *ina6
;
321 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
322 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
323 ISC_LINK_INIT(sockaddr
, link
);
327 isc_sockaddr_v6fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
330 memset(sockaddr
, 0, sizeof(*sockaddr
));
331 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
332 #ifdef ISC_PLATFORM_HAVESALEN
333 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
335 sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[10] = 0xff;
336 sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[11] = 0xff;
337 memcpy(&sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[12], ina
, 4);
338 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
339 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
340 ISC_LINK_INIT(sockaddr
, link
);
344 isc_sockaddr_pf(const isc_sockaddr_t
*sockaddr
) {
347 * Get the protocol family of 'sockaddr'.
350 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
352 * Assume that PF_xxx == AF_xxx for all AF and PF.
354 return (sockaddr
->type
.sa
.sa_family
);
356 switch (sockaddr
->type
.sa
.sa_family
) {
362 FATAL_ERROR(__FILE__
, __LINE__
,
363 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
364 ISC_MSG_UNKNOWNFAMILY
,
365 "unknown address family: %d"),
366 (int)sockaddr
->type
.sa
.sa_family
);
372 isc_sockaddr_fromnetaddr(isc_sockaddr_t
*sockaddr
, const isc_netaddr_t
*na
,
375 memset(sockaddr
, 0, sizeof(*sockaddr
));
376 sockaddr
->type
.sin
.sin_family
= na
->family
;
377 switch (na
->family
) {
379 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
380 #ifdef ISC_PLATFORM_HAVESALEN
381 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
383 sockaddr
->type
.sin
.sin_addr
= na
->type
.in
;
384 sockaddr
->type
.sin
.sin_port
= htons(port
);
387 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
388 #ifdef ISC_PLATFORM_HAVESALEN
389 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
391 memcpy(&sockaddr
->type
.sin6
.sin6_addr
, &na
->type
.in6
, 16);
392 #ifdef ISC_PLATFORM_HAVESCOPEID
393 sockaddr
->type
.sin6
.sin6_scope_id
= isc_netaddr_getzone(na
);
395 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
400 ISC_LINK_INIT(sockaddr
, link
);
404 isc_sockaddr_setport(isc_sockaddr_t
*sockaddr
, in_port_t port
) {
405 switch (sockaddr
->type
.sa
.sa_family
) {
407 sockaddr
->type
.sin
.sin_port
= htons(port
);
410 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
413 FATAL_ERROR(__FILE__
, __LINE__
,
414 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
415 ISC_MSG_UNKNOWNFAMILY
,
416 "unknown address family: %d"),
417 (int)sockaddr
->type
.sa
.sa_family
);
422 isc_sockaddr_getport(isc_sockaddr_t
*sockaddr
) {
425 switch (sockaddr
->type
.sa
.sa_family
) {
427 port
= ntohs(sockaddr
->type
.sin
.sin_port
);
430 port
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
433 FATAL_ERROR(__FILE__
, __LINE__
,
434 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
435 ISC_MSG_UNKNOWNFAMILY
,
436 "unknown address family: %d"),
437 (int)sockaddr
->type
.sa
.sa_family
);
444 isc_sockaddr_ismulticast(isc_sockaddr_t
*sockaddr
) {
445 isc_netaddr_t netaddr
;
447 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
448 return (isc_netaddr_ismulticast(&netaddr
));
452 isc_sockaddr_isexperimental(isc_sockaddr_t
*sockaddr
) {
453 isc_netaddr_t netaddr
;
455 if (sockaddr
->type
.sa
.sa_family
== AF_INET
) {
456 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
457 return (isc_netaddr_isexperimental(&netaddr
));
463 isc_sockaddr_issitelocal(isc_sockaddr_t
*sockaddr
) {
464 isc_netaddr_t netaddr
;
466 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
467 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
468 return (isc_netaddr_issitelocal(&netaddr
));
474 isc_sockaddr_islinklocal(isc_sockaddr_t
*sockaddr
) {
475 isc_netaddr_t netaddr
;
477 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
478 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
479 return (isc_netaddr_islinklocal(&netaddr
));