1 /* $NetBSD: net.c,v 1.4 2006/06/13 22:36:36 christos Exp $ */
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: net.c,v 1.22.2.2.10.7 2004/04/29 01:31:22 marka Exp */
29 #include <isc/strerror.h>
30 #include <isc/string.h>
33 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
34 const struct in6_addr isc_net_in6addrany
= IN6ADDR_ANY_INIT
;
37 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
38 const struct in6_addr isc_net_in6addrloop
= IN6ADDR_LOOPBACK_INIT
;
41 static isc_boolean_t once
= ISC_FALSE
;
43 static isc_once_t once_ipv6only
= ISC_ONCE_INIT
;
44 static isc_once_t once_ipv6pktinfo
= ISC_ONCE_INIT
;
46 static isc_result_t ipv4_result
= ISC_R_NOTFOUND
;
47 static isc_result_t ipv6_result
= ISC_R_NOTFOUND
;
48 static isc_result_t ipv6only_result
= ISC_R_NOTFOUND
;
49 static isc_result_t ipv6pktinfo_result
= ISC_R_NOTFOUND
;
52 try_proto(int domain
) {
54 isc_result_t result
= ISC_R_SUCCESS
;
55 char strbuf
[ISC_STRERRORSIZE
];
57 s
= socket(domain
, SOCK_STREAM
, 0);
63 #ifdef EPROTONOSUPPORT
69 return (ISC_R_NOTFOUND
);
71 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
72 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
73 "socket() failed: %s",
75 return (ISC_R_UNEXPECTED
);
79 #ifdef ISC_PLATFORM_HAVEIPV6
81 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
82 if (domain
== PF_INET6
) {
83 struct sockaddr_in6 sin6
;
84 GETSOCKNAME_SOCKLEN_TYPE len
;
87 * Check to see if IPv6 is broken, as is common on Linux.
90 if (getsockname(s
, (struct sockaddr
*)&sin6
, &len
) < 0)
92 result
= ISC_R_NOTFOUND
;
94 if (len
== sizeof(struct sockaddr_in6
))
95 result
= ISC_R_SUCCESS
;
97 result
= ISC_R_NOTFOUND
;
111 initialize_action(void) {
112 ipv4_result
= try_proto(PF_INET
);
113 #ifdef ISC_PLATFORM_HAVEIPV6
115 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
116 ipv6_result
= try_proto(PF_INET6
);
124 if(once
== ISC_FALSE
) {
131 isc_net_probeipv4(void) {
133 return (ipv4_result
);
137 isc_net_probeipv6(void) {
139 return (ipv6_result
);
142 #ifdef ISC_PLATFORM_HAVEIPV6
148 char strbuf
[ISC_STRERRORSIZE
];
152 result
= isc_net_probeipv6();
153 if (result
!= ISC_R_SUCCESS
) {
154 ipv6only_result
= result
;
159 ipv6only_result
= ISC_R_NOTFOUND
;
162 /* check for TCP sockets */
163 s
= socket(PF_INET6
, SOCK_STREAM
, 0);
165 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
166 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
167 "socket() failed: %s",
169 ipv6only_result
= ISC_R_UNEXPECTED
;
174 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) < 0) {
175 ipv6only_result
= ISC_R_NOTFOUND
;
181 /* check for UDP sockets */
182 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
184 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
185 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
186 "socket() failed: %s",
188 ipv6only_result
= ISC_R_UNEXPECTED
;
193 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) < 0) {
194 ipv6only_result
= ISC_R_NOTFOUND
;
200 ipv6only_result
= ISC_R_SUCCESS
;
205 #endif /* IPV6_V6ONLY */
209 initialize_ipv6only(void) {
210 RUNTIME_CHECK(isc_once_do(&once_ipv6only
,
211 try_ipv6only
) == ISC_R_SUCCESS
);
215 try_ipv6pktinfo(void) {
217 char strbuf
[ISC_STRERRORSIZE
];
221 result
= isc_net_probeipv6();
222 if (result
!= ISC_R_SUCCESS
) {
223 ipv6pktinfo_result
= result
;
227 /* we only use this for UDP sockets */
228 s
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
230 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
231 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
232 "socket() failed: %s",
234 ipv6pktinfo_result
= ISC_R_UNEXPECTED
;
238 #ifdef IPV6_RECVPKTINFO
239 optname
= IPV6_RECVPKTINFO
;
241 optname
= IPV6_PKTINFO
;
244 if (setsockopt(s
, IPPROTO_IPV6
, optname
, &on
, sizeof(on
)) < 0) {
245 ipv6pktinfo_result
= ISC_R_NOTFOUND
;
250 ipv6pktinfo_result
= ISC_R_SUCCESS
;
258 initialize_ipv6pktinfo(void) {
259 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo
,
260 try_ipv6pktinfo
) == ISC_R_SUCCESS
);
262 #endif /* WANT_IPV6 */
263 #endif /* ISC_PLATFORM_HAVEIPV6 */
266 isc_net_probe_ipv6only(void) {
267 #ifdef ISC_PLATFORM_HAVEIPV6
269 initialize_ipv6only();
271 ipv6only_result
= ISC_R_NOTFOUND
;
274 return (ipv6only_result
);
278 isc_net_probe_ipv6pktinfo(void) {
279 #ifdef ISC_PLATFORM_HAVEIPV6
281 initialize_ipv6pktinfo();
283 ipv6pktinfo_result
= ISC_R_NOTFOUND
;
286 return (ipv6pktinfo_result
);
290 isc_net_disableipv4(void) {
292 if (ipv4_result
== ISC_R_SUCCESS
)
293 ipv4_result
= ISC_R_DISABLED
;
297 isc_net_disableipv6(void) {
299 if (ipv6_result
== ISC_R_SUCCESS
)
300 ipv6_result
= ISC_R_DISABLED
;
304 isc_net_enableipv4(void) {
306 if (ipv4_result
== ISC_R_DISABLED
)
307 ipv4_result
= ISC_R_SUCCESS
;
311 isc_net_enableipv6(void) {
313 if (ipv6_result
== ISC_R_DISABLED
)
314 ipv6_result
= ISC_R_SUCCESS
;