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 $ */
24 #include <isc/buffer.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>
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
)
42 * We don't just memcmp because the sin_zero field isn't always
46 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
48 switch (a
->type
.sa
.sa_family
) {
50 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
51 sizeof(a
->type
.sin
.sin_addr
)) != 0)
53 if (a
->type
.sin
.sin_port
!= b
->type
.sin
.sin_port
)
57 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
58 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
60 if (a
->type
.sin6
.sin6_port
!= b
->type
.sin6
.sin6_port
)
64 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
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
)
77 if (a
->type
.sa
.sa_family
!= b
->type
.sa
.sa_family
)
79 switch (a
->type
.sa
.sa_family
) {
81 if (memcmp(&a
->type
.sin
.sin_addr
, &b
->type
.sin
.sin_addr
,
82 sizeof(a
->type
.sin
.sin_addr
)) != 0)
86 if (memcmp(&a
->type
.sin6
.sin6_addr
, &b
->type
.sin6
.sin6_addr
,
87 sizeof(a
->type
.sin6
.sin6_addr
)) != 0)
91 if (memcmp(&a
->type
, &b
->type
, a
->length
) != 0)
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
));
108 isc_sockaddr_totext(const isc_sockaddr_t
*sockaddr
, isc_buffer_t
*target
) {
110 isc_netaddr_t netaddr
;
111 char pbuf
[sizeof("65000")];
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
) {
124 sprintf(pbuf
, "%u", ntohs(sockaddr
->type
.sin
.sin_port
));
127 sprintf(pbuf
, "%u", ntohs(sockaddr
->type
.sin6
.sin6_port
));
130 return (ISC_R_FAILURE
);
134 INSIST(plen
< sizeof(pbuf
));
136 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
137 result
= isc_netaddr_totext(&netaddr
, target
);
138 if (result
!= ISC_R_SUCCESS
)
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
);
158 isc_sockaddr_format(isc_sockaddr_t
*sa
, char *array
, unsigned int size
) {
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
,
171 "<unknown address, family %u>"),
172 sa
->type
.sa
.sa_family
);
173 array
[size
- 1] = '\0';
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
;
184 const struct in6_addr
*in6
;
186 REQUIRE(sockaddr
!= NULL
);
187 switch (sockaddr
->type
.sa
.sa_family
) {
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
);
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
);
199 s
= (const unsigned char *)in6
;
200 length
= sizeof(sockaddr
->type
.sin6
.sin6_addr
);
202 p
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
205 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
206 isc_msgcat_get(isc_msgcat
,
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
;
216 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
218 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
220 h
= h
^ g
; /* XXX: we should concatenate h and p first */
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
);
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
);
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
);
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
);
255 isc_sockaddr_fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
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
);
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
);
270 isc_sockaddr_anyofpf(isc_sockaddr_t
*sockaddr
, int pf
) {
273 isc_sockaddr_any(sockaddr
);
276 isc_sockaddr_any6(sockaddr
);
284 isc_sockaddr_fromin6(isc_sockaddr_t
*sockaddr
, const struct in6_addr
*ina6
,
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
);
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
);
299 isc_sockaddr_v6fromin(isc_sockaddr_t
*sockaddr
, const struct in_addr
*ina
,
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
);
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
);
328 switch (sockaddr
->type
.sa
.sa_family
) {
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
);
344 isc_sockaddr_fromnetaddr(isc_sockaddr_t
*sockaddr
, const isc_netaddr_t
*na
,
347 memset(sockaddr
, 0, sizeof(*sockaddr
));
348 sockaddr
->type
.sin
.sin_family
= na
->family
;
349 switch (na
->family
) {
351 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
352 #ifdef ISC_PLATFORM_HAVESALEN
353 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
355 sockaddr
->type
.sin
.sin_addr
= na
->type
.in
;
356 sockaddr
->type
.sin
.sin_port
= htons(port
);
359 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
360 #ifdef ISC_PLATFORM_HAVESALEN
361 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
363 memcpy(&sockaddr
->type
.sin6
.sin6_addr
, &na
->type
.in6
, 16);
364 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
369 ISC_LINK_INIT(sockaddr
, link
);
373 isc_sockaddr_setport(isc_sockaddr_t
*sockaddr
, in_port_t port
) {
374 switch (sockaddr
->type
.sa
.sa_family
) {
376 sockaddr
->type
.sin
.sin_port
= htons(port
);
379 sockaddr
->type
.sin6
.sin6_port
= htons(port
);
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
);
391 isc_sockaddr_getport(isc_sockaddr_t
*sockaddr
) {
394 switch (sockaddr
->type
.sa
.sa_family
) {
396 port
= ntohs(sockaddr
->type
.sin
.sin_port
);
399 port
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
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
);
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
));
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
));