2 * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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: net.c,v 1.22.2.2.10.9 2005/03/17 03:58:33 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_once_t once = ISC_ONCE_INIT;
42 static isc_once_t once_ipv6only = ISC_ONCE_INIT;
43 static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
44 static isc_result_t ipv4_result = ISC_R_NOTFOUND;
45 static isc_result_t ipv6_result = ISC_R_NOTFOUND;
46 static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
47 static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
50 try_proto(int domain) {
52 isc_result_t result = ISC_R_SUCCESS;
53 char strbuf[ISC_STRERRORSIZE];
55 s = socket(domain, SOCK_STREAM, 0);
61 #ifdef EPROTONOSUPPORT
67 return (ISC_R_NOTFOUND);
69 isc__strerror(errno, strbuf, sizeof(strbuf));
70 UNEXPECTED_ERROR(__FILE__, __LINE__,
72 isc_msgcat_get(isc_msgcat,
77 return (ISC_R_UNEXPECTED);
81 #ifdef ISC_PLATFORM_HAVEIPV6
83 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
84 if (domain == PF_INET6) {
85 struct sockaddr_in6 sin6;
89 * Check to see if IPv6 is broken, as is common on Linux.
92 if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
94 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
95 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
96 "retrieving the address of an IPv6 "
97 "socket from the kernel failed.");
98 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
99 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
100 "IPv6 is not supported.");
101 result = ISC_R_NOTFOUND;
103 if (len == sizeof(struct sockaddr_in6))
104 result = ISC_R_SUCCESS;
106 isc_log_write(isc_lctx,
107 ISC_LOGCATEGORY_GENERAL,
108 ISC_LOGMODULE_SOCKET,
110 "IPv6 structures in kernel and "
111 "user space do not match.");
112 isc_log_write(isc_lctx,
113 ISC_LOGCATEGORY_GENERAL,
114 ISC_LOGMODULE_SOCKET,
116 "IPv6 is not supported.");
117 result = ISC_R_NOTFOUND;
131 initialize_action(void) {
132 ipv4_result = try_proto(PF_INET);
133 #ifdef ISC_PLATFORM_HAVEIPV6
135 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
136 ipv6_result = try_proto(PF_INET6);
144 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
148 isc_net_probeipv4(void) {
150 return (ipv4_result);
154 isc_net_probeipv6(void) {
156 return (ipv6_result);
159 #ifdef ISC_PLATFORM_HAVEIPV6
165 char strbuf[ISC_STRERRORSIZE];
169 result = isc_net_probeipv6();
170 if (result != ISC_R_SUCCESS) {
171 ipv6only_result = result;
176 ipv6only_result = ISC_R_NOTFOUND;
179 /* check for TCP sockets */
180 s = socket(PF_INET6, SOCK_STREAM, 0);
182 isc__strerror(errno, strbuf, sizeof(strbuf));
183 UNEXPECTED_ERROR(__FILE__, __LINE__,
185 isc_msgcat_get(isc_msgcat,
190 ipv6only_result = ISC_R_UNEXPECTED;
195 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
196 ipv6only_result = ISC_R_NOTFOUND;
202 /* check for UDP sockets */
203 s = socket(PF_INET6, SOCK_DGRAM, 0);
205 isc__strerror(errno, strbuf, sizeof(strbuf));
206 UNEXPECTED_ERROR(__FILE__, __LINE__,
208 isc_msgcat_get(isc_msgcat,
213 ipv6only_result = ISC_R_UNEXPECTED;
218 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
219 ipv6only_result = ISC_R_NOTFOUND;
225 ipv6only_result = ISC_R_SUCCESS;
230 #endif /* IPV6_V6ONLY */
234 initialize_ipv6only(void) {
235 RUNTIME_CHECK(isc_once_do(&once_ipv6only,
236 try_ipv6only) == ISC_R_SUCCESS);
238 #endif /* IPV6_V6ONLY */
240 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
242 try_ipv6pktinfo(void) {
244 char strbuf[ISC_STRERRORSIZE];
248 result = isc_net_probeipv6();
249 if (result != ISC_R_SUCCESS) {
250 ipv6pktinfo_result = result;
254 /* we only use this for UDP sockets */
255 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
257 isc__strerror(errno, strbuf, sizeof(strbuf));
258 UNEXPECTED_ERROR(__FILE__, __LINE__,
260 isc_msgcat_get(isc_msgcat,
265 ipv6pktinfo_result = ISC_R_UNEXPECTED;
269 #ifdef IPV6_RECVPKTINFO
270 optname = IPV6_RECVPKTINFO;
272 optname = IPV6_PKTINFO;
275 if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
276 ipv6pktinfo_result = ISC_R_NOTFOUND;
281 ipv6pktinfo_result = ISC_R_SUCCESS;
289 initialize_ipv6pktinfo(void) {
290 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
291 try_ipv6pktinfo) == ISC_R_SUCCESS);
293 #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
294 #endif /* WANT_IPV6 */
297 isc_net_probe_ipv6only(void) {
298 #ifdef ISC_PLATFORM_HAVEIPV6
300 initialize_ipv6only();
302 ipv6only_result = ISC_R_NOTFOUND;
305 return (ipv6only_result);
309 isc_net_probe_ipv6pktinfo(void) {
310 #ifdef ISC_PLATFORM_HAVEIPV6
311 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
313 initialize_ipv6pktinfo();
315 ipv6pktinfo_result = ISC_R_NOTFOUND;
319 return (ipv6pktinfo_result);
323 isc_net_disableipv4(void) {
325 if (ipv4_result == ISC_R_SUCCESS)
326 ipv4_result = ISC_R_DISABLED;
330 isc_net_disableipv6(void) {
332 if (ipv6_result == ISC_R_SUCCESS)
333 ipv6_result = ISC_R_DISABLED;
337 isc_net_enableipv4(void) {
339 if (ipv4_result == ISC_R_DISABLED)
340 ipv4_result = ISC_R_SUCCESS;
344 isc_net_enableipv6(void) {
346 if (ipv6_result == ISC_R_DISABLED)
347 ipv6_result = ISC_R_SUCCESS;