2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.70 2007/06/19 23:47:17 tbox Exp $ */
26 #include <isc/buffer.h>
29 #include <isc/netaddr.h>
30 #include <isc/print.h>
31 #include <isc/region.h>
32 #include <isc/sockaddr.h>
33 #include <isc/string.h>
37 isc_sockaddr_equal(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
38 return (isc_sockaddr_compare(a
, b
, ISC_SOCKADDR_CMPADDR
|
40 ISC_SOCKADDR_CMPSCOPE
));
44 isc_sockaddr_eqaddr(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
) {
45 return (isc_sockaddr_compare(a
, b
, ISC_SOCKADDR_CMPADDR
|
46 ISC_SOCKADDR_CMPSCOPE
));
50 isc_sockaddr_compare(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
53 REQUIRE(a
!= NULL
&& b
!= NULL
);
55 if (a
->length
!= b
->length
)
59 * We don't just memcmp because the sin_zero field isn't always
63 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
65 switch (a
->type
.sa
.sa_family
) {
67 if ((flags
& ISC_SOCKADDR_CMPADDR
) != 0 &&
68 memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
69 sizeof(a
->type
.sin
.sin_addr
)) != 0)
71 if ((flags
& ISC_SOCKADDR_CMPPORT
) != 0 &&
72 a
->type
.sin
.sin_port
!= b
->type
.sin
.sin_port
)
76 if ((flags
& ISC_SOCKADDR_CMPADDR
) != 0 &&
77 memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
78 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
80 #ifdef ISC_PLATFORM_HAVESCOPEID
82 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
83 * ISC_FALSE if one of the scopes in zero.
85 if ((flags
& ISC_SOCKADDR_CMPSCOPE
) != 0 &&
86 a
->type
.sin6
.sin6_scope_id
!= b
->type
.sin6
.sin6_scope_id
&&
87 ((flags
& ISC_SOCKADDR_CMPSCOPEZERO
) == 0 ||
88 (a
->type
.sin6
.sin6_scope_id
!= 0 &&
89 b
->type
.sin6
.sin6_scope_id
!= 0)))
92 if ((flags
& ISC_SOCKADDR_CMPPORT
) != 0 &&
93 a
->type
.sin6
.sin6_port
!= b
->type
.sin6
.sin6_port
)
97 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
104 isc_sockaddr_eqaddrprefix(const isc_sockaddr_t
*a
, const isc_sockaddr_t
*b
,
105 unsigned int prefixlen
)
107 isc_netaddr_t na
, nb
;
108 isc_netaddr_fromsockaddr(&na
, a
);
109 isc_netaddr_fromsockaddr(&nb
, b
);
110 return (isc_netaddr_eqprefix(&na
, &nb
, prefixlen
));
114 isc_sockaddr_totext(const isc_sockaddr_t
*sockaddr
, isc_buffer_t
*target
) {
116 isc_netaddr_t netaddr
;
117 char pbuf
[sizeof("65000")];
121 REQUIRE(sockaddr
!= NULL
);
124 * Do the port first, giving us the opportunity to check for
125 * unsupported address families before calling
126 * isc_netaddr_fromsockaddr().
128 switch (sockaddr
->type
.sa
.sa_family
) {
130 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin
.sin_port
));
133 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(sockaddr
->type
.sin6
.sin6_port
));
135 #ifdef ISC_PLAFORM_HAVESYSUNH
137 plen
= strlen(sockaddr
->type
.sunix
.sun_path
);
138 if (plen
>= isc_buffer_availablelength(target
))
139 return (ISC_R_NOSPACE
);
141 isc_buffer_putmem(target
, sockaddr
->type
.sunix
.sun_path
, plen
);
144 * Null terminate after used region.
146 isc_buffer_availableregion(target
, &avail
);
147 INSIST(avail
.length
>= 1);
148 avail
.base
[0] = '\0';
150 return (ISC_R_SUCCESS
);
153 return (ISC_R_FAILURE
);
157 INSIST(plen
< sizeof(pbuf
));
159 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
160 result
= isc_netaddr_totext(&netaddr
, target
);
161 if (result
!= ISC_R_SUCCESS
)
164 if (1 + plen
+ 1 > isc_buffer_availablelength(target
))
165 return (ISC_R_NOSPACE
);
167 isc_buffer_putmem(target
, (const unsigned char *)"#", 1);
168 isc_buffer_putmem(target
, (const unsigned char *)pbuf
, plen
);
171 * Null terminate after used region.
173 isc_buffer_availableregion(target
, &avail
);
174 INSIST(avail
.length
>= 1);
175 avail
.base
[0] = '\0';
177 return (ISC_R_SUCCESS
);
181 isc_sockaddr_format(const isc_sockaddr_t
*sa
, char *array
, unsigned int size
) {
185 isc_buffer_init(&buf
, array
, size
);
186 result
= isc_sockaddr_totext(sa
, &buf
);
187 if (result
!= ISC_R_SUCCESS
) {
189 * The message is the same as in netaddr.c.
191 snprintf(array
, size
,
192 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
194 "<unknown address, family %u>"),
195 sa
->type
.sa
.sa_family
);
196 array
[size
- 1] = '\0';
201 isc_sockaddr_hash(const isc_sockaddr_t
*sockaddr
, isc_boolean_t address_only
) {
202 unsigned int length
= 0;
203 const unsigned char *s
= NULL
;
207 const struct in6_addr
*in6
;
209 REQUIRE(sockaddr
!= NULL
);
211 switch (sockaddr
->type
.sa
.sa_family
) {
213 s
= (const unsigned char *)&sockaddr
->type
.sin
.sin_addr
;
214 p
= ntohs(sockaddr
->type
.sin
.sin_port
);
215 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
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
);
229 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
230 isc_msgcat_get(isc_msgcat
,
232 ISC_MSG_UNKNOWNFAMILY
,
233 "unknown address family: %d"),
234 (int)sockaddr
->type
.sa
.sa_family
);
235 s
= (const unsigned char *)&sockaddr
->type
;
236 length
= sockaddr
->length
;
240 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
242 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
244 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 memset(sockaddr
, 0, sizeof(*sockaddr
));
268 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
269 #ifdef ISC_PLATFORM_HAVESALEN
270 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
272 sockaddr
->type
.sin6
.sin6_addr
= in6addr_any
;
273 sockaddr
->type
.sin6
.sin6_port
= 0;
274 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
275 ISC_LINK_INIT(sockaddr
, link
);
279 isc_sockaddr_fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
282 memset(sockaddr
, 0, sizeof(*sockaddr
));
283 sockaddr
->type
.sin
.sin_family
= AF_INET
;
284 #ifdef ISC_PLATFORM_HAVESALEN
285 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
287 sockaddr
->type
.sin
.sin_addr
= *ina
;
288 sockaddr
->type
.sin
.sin_port
= htons(port
);
289 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
290 ISC_LINK_INIT(sockaddr
, link
);
294 isc_sockaddr_anyofpf(isc_sockaddr_t
*sockaddr
, int pf
) {
297 isc_sockaddr_any(sockaddr
);
300 isc_sockaddr_any6(sockaddr
);
308 isc_sockaddr_fromin6(isc_sockaddr_t
*sockaddr
, const struct in6_addr
*ina6
,
311 memset(sockaddr
, 0, sizeof(*sockaddr
));
312 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
313 #ifdef ISC_PLATFORM_HAVESALEN
314 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
316 sockaddr
->type
.sin6
.sin6_addr
= *ina6
;
317 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
318 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
319 ISC_LINK_INIT(sockaddr
, link
);
323 isc_sockaddr_v6fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
326 memset(sockaddr
, 0, sizeof(*sockaddr
));
327 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
328 #ifdef ISC_PLATFORM_HAVESALEN
329 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
331 sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[10] = 0xff;
332 sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[11] = 0xff;
333 memcpy(&sockaddr
->type
.sin6
.sin6_addr
.s6_addr
[12], ina
, 4);
334 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
335 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
336 ISC_LINK_INIT(sockaddr
, link
);
340 isc_sockaddr_pf(const isc_sockaddr_t
*sockaddr
) {
343 * Get the protocol family of 'sockaddr'.
346 #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
348 * Assume that PF_xxx == AF_xxx for all AF and PF.
350 return (sockaddr
->type
.sa
.sa_family
);
352 switch (sockaddr
->type
.sa
.sa_family
) {
358 FATAL_ERROR(__FILE__
, __LINE__
,
359 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
360 ISC_MSG_UNKNOWNFAMILY
,
361 "unknown address family: %d"),
362 (int)sockaddr
->type
.sa
.sa_family
);
368 isc_sockaddr_fromnetaddr(isc_sockaddr_t
*sockaddr
, const isc_netaddr_t
*na
,
371 memset(sockaddr
, 0, sizeof(*sockaddr
));
372 sockaddr
->type
.sin
.sin_family
= na
->family
;
373 switch (na
->family
) {
375 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
376 #ifdef ISC_PLATFORM_HAVESALEN
377 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
379 sockaddr
->type
.sin
.sin_addr
= na
->type
.in
;
380 sockaddr
->type
.sin
.sin_port
= htons(port
);
383 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
384 #ifdef ISC_PLATFORM_HAVESALEN
385 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
387 memcpy(&sockaddr
->type
.sin6
.sin6_addr
, &na
->type
.in6
, 16);
388 #ifdef ISC_PLATFORM_HAVESCOPEID
389 sockaddr
->type
.sin6
.sin6_scope_id
= isc_netaddr_getzone(na
);
391 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
396 ISC_LINK_INIT(sockaddr
, link
);
400 isc_sockaddr_setport(isc_sockaddr_t
*sockaddr
, in_port_t port
) {
401 switch (sockaddr
->type
.sa
.sa_family
) {
403 sockaddr
->type
.sin
.sin_port
= htons(port
);
406 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
409 FATAL_ERROR(__FILE__
, __LINE__
,
410 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
411 ISC_MSG_UNKNOWNFAMILY
,
412 "unknown address family: %d"),
413 (int)sockaddr
->type
.sa
.sa_family
);
418 isc_sockaddr_getport(const isc_sockaddr_t
*sockaddr
) {
421 switch (sockaddr
->type
.sa
.sa_family
) {
423 port
= ntohs(sockaddr
->type
.sin
.sin_port
);
426 port
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
429 FATAL_ERROR(__FILE__
, __LINE__
,
430 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_SOCKADDR
,
431 ISC_MSG_UNKNOWNFAMILY
,
432 "unknown address family: %d"),
433 (int)sockaddr
->type
.sa
.sa_family
);
440 isc_sockaddr_ismulticast(const isc_sockaddr_t
*sockaddr
) {
441 isc_netaddr_t netaddr
;
443 if (sockaddr
->type
.sa
.sa_family
== AF_INET
||
444 sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
445 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
446 return (isc_netaddr_ismulticast(&netaddr
));
452 isc_sockaddr_isexperimental(const 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(const 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(const 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
));
485 isc_sockaddr_frompath(isc_sockaddr_t
*sockaddr
, const char *path
) {
486 #ifdef ISC_PLATFORM_HAVESYSUNH
487 if (strlen(path
) >= sizeof(sockaddr
->type
.sunix
.sun_path
))
488 return (ISC_R_NOSPACE
);
489 memset(sockaddr
, 0, sizeof(*sockaddr
));
490 sockaddr
->length
= sizeof(sockaddr
->type
.sunix
);
491 sockaddr
->type
.sunix
.sun_family
= AF_UNIX
;
492 #ifdef ISC_PLATFORM_HAVESALEN
493 sockaddr
->type
.sunix
.sun_len
=
494 (unsigned char)sizeof(sockaddr
->type
.sunix
);
496 strcpy(sockaddr
->type
.sunix
.sun_path
, path
);
497 return (ISC_R_SUCCESS
);
501 return (ISC_R_NOTIMPLEMENTED
);