1 /* $NetBSD: sockaddr.c,v 1.7 2014/12/10 04:37:59 christos Exp $ */
4 * Copyright (C) 2004-2007, 2010-2012, 2014 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.
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
) {
190 isc_buffer_init(&buf
, array
, size
);
191 result
= isc_sockaddr_totext(sa
, &buf
);
192 if (result
!= ISC_R_SUCCESS
) {
194 * The message is the same as in netaddr.c.
196 snprintf(array
, size
,
197 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_NETADDR
,
199 "<unknown address, family %u>"),
200 sa
->type
.sa
.sa_family
);
201 array
[size
- 1] = '\0';
206 isc_sockaddr_hash(const isc_sockaddr_t
*sockaddr
, isc_boolean_t address_only
) {
207 unsigned int length
= 0;
208 const unsigned char *s
= NULL
;
212 const struct in6_addr
*in6
;
214 REQUIRE(sockaddr
!= NULL
);
216 switch (sockaddr
->type
.sa
.sa_family
) {
218 s
= (const unsigned char *)&sockaddr
->type
.sin
.sin_addr
;
219 p
= ntohs(sockaddr
->type
.sin
.sin_port
);
220 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
223 in6
= &sockaddr
->type
.sin6
.sin6_addr
;
224 s
= (const unsigned char *)in6
;
225 if (IN6_IS_ADDR_V4MAPPED(in6
)) {
227 length
= sizeof(sockaddr
->type
.sin
.sin_addr
.s_addr
);
229 length
= sizeof(sockaddr
->type
.sin6
.sin6_addr
);
230 p
= ntohs(sockaddr
->type
.sin6
.sin6_port
);
233 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
234 isc_msgcat_get(isc_msgcat
,
236 ISC_MSG_UNKNOWNFAMILY
,
237 "unknown address family: %d"),
238 (int)sockaddr
->type
.sa
.sa_family
);
239 s
= (const unsigned char *)&sockaddr
->type
;
240 length
= sockaddr
->length
;
244 h
= isc_hash_calc(s
, length
, ISC_TRUE
);
246 g
= isc_hash_calc((const unsigned char *)&p
, sizeof(p
),
248 h
= h
^ g
; /* XXX: we should concatenate h and p first */
255 isc_sockaddr_any(isc_sockaddr_t
*sockaddr
)
257 memset(sockaddr
, 0, sizeof(*sockaddr
));
258 sockaddr
->type
.sin
.sin_family
= AF_INET
;
259 #ifdef ISC_PLATFORM_HAVESALEN
260 sockaddr
->type
.sin
.sin_len
= sizeof(sockaddr
->type
.sin
);
262 sockaddr
->type
.sin
.sin_addr
.s_addr
= INADDR_ANY
;
263 sockaddr
->type
.sin
.sin_port
= 0;
264 sockaddr
->length
= sizeof(sockaddr
->type
.sin
);
265 ISC_LINK_INIT(sockaddr
, link
);
269 isc_sockaddr_any6(isc_sockaddr_t
*sockaddr
)
271 memset(sockaddr
, 0, sizeof(*sockaddr
));
272 sockaddr
->type
.sin6
.sin6_family
= AF_INET6
;
273 #ifdef ISC_PLATFORM_HAVESALEN
274 sockaddr
->type
.sin6
.sin6_len
= sizeof(sockaddr
->type
.sin6
);
276 sockaddr
->type
.sin6
.sin6_addr
= in6addr_any
;
277 sockaddr
->type
.sin6
.sin6_port
= 0;
278 sockaddr
->length
= sizeof(sockaddr
->type
.sin6
);
279 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 memmove(&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 memmove(&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(const 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(const isc_sockaddr_t
*sockaddr
) {
445 isc_netaddr_t netaddr
;
447 if (sockaddr
->type
.sa
.sa_family
== AF_INET
||
448 sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
449 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
450 return (isc_netaddr_ismulticast(&netaddr
));
456 isc_sockaddr_isexperimental(const isc_sockaddr_t
*sockaddr
) {
457 isc_netaddr_t netaddr
;
459 if (sockaddr
->type
.sa
.sa_family
== AF_INET
) {
460 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
461 return (isc_netaddr_isexperimental(&netaddr
));
467 isc_sockaddr_issitelocal(const isc_sockaddr_t
*sockaddr
) {
468 isc_netaddr_t netaddr
;
470 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
471 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
472 return (isc_netaddr_issitelocal(&netaddr
));
478 isc_sockaddr_islinklocal(const isc_sockaddr_t
*sockaddr
) {
479 isc_netaddr_t netaddr
;
481 if (sockaddr
->type
.sa
.sa_family
== AF_INET6
) {
482 isc_netaddr_fromsockaddr(&netaddr
, sockaddr
);
483 return (isc_netaddr_islinklocal(&netaddr
));
489 isc_sockaddr_frompath(isc_sockaddr_t
*sockaddr
, const char *path
) {
490 #ifdef ISC_PLATFORM_HAVESYSUNH
491 if (strlen(path
) >= sizeof(sockaddr
->type
.sunix
.sun_path
))
492 return (ISC_R_NOSPACE
);
493 memset(sockaddr
, 0, sizeof(*sockaddr
));
494 sockaddr
->length
= sizeof(sockaddr
->type
.sunix
);
495 sockaddr
->type
.sunix
.sun_family
= AF_UNIX
;
496 #ifdef ISC_PLATFORM_HAVESALEN
497 sockaddr
->type
.sunix
.sun_len
=
498 (unsigned char)sizeof(sockaddr
->type
.sunix
);
500 strcpy(sockaddr
->type
.sunix
.sun_path
, path
);
501 return (ISC_R_SUCCESS
);
505 return (ISC_R_NOTIMPLEMENTED
);