2 * Copyright (C) 2004, 2005, 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: net.c,v 1.29.18.6 2007/09/13 23:46:26 tbox Exp $ */
29 #include <isc/strerror.h>
30 #include <isc/string.h>
33 #if defined(ISC_PLATFORM_HAVEIPV6)
34 # if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
35 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
38 # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
39 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
42 # if defined(WANT_IPV6)
43 static isc_once_t once_ipv6only = ISC_ONCE_INIT;
46 # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
47 static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
49 #endif /* ISC_PLATFORM_HAVEIPV6 */
51 static isc_once_t once = ISC_ONCE_INIT;
53 static isc_result_t ipv4_result = ISC_R_NOTFOUND;
54 static isc_result_t ipv6_result = ISC_R_NOTFOUND;
55 static isc_result_t unix_result = ISC_R_NOTFOUND;
56 static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
57 static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
60 try_proto(int domain) {
62 isc_result_t result = ISC_R_SUCCESS;
63 char strbuf[ISC_STRERRORSIZE];
65 s = socket(domain, SOCK_STREAM, 0);
71 #ifdef EPROTONOSUPPORT
77 return (ISC_R_NOTFOUND);
79 isc__strerror(errno, strbuf, sizeof(strbuf));
80 UNEXPECTED_ERROR(__FILE__, __LINE__,
82 isc_msgcat_get(isc_msgcat,
87 return (ISC_R_UNEXPECTED);
91 #ifdef ISC_PLATFORM_HAVEIPV6
93 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
94 if (domain == PF_INET6) {
95 struct sockaddr_in6 sin6;
99 * Check to see if IPv6 is broken, as is common on Linux.
102 if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
104 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
105 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
106 "retrieving the address of an IPv6 "
107 "socket from the kernel failed.");
108 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
109 ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
110 "IPv6 is not supported.");
111 result = ISC_R_NOTFOUND;
113 if (len == sizeof(struct sockaddr_in6))
114 result = ISC_R_SUCCESS;
116 isc_log_write(isc_lctx,
117 ISC_LOGCATEGORY_GENERAL,
118 ISC_LOGMODULE_SOCKET,
120 "IPv6 structures in kernel and "
121 "user space do not match.");
122 isc_log_write(isc_lctx,
123 ISC_LOGCATEGORY_GENERAL,
124 ISC_LOGMODULE_SOCKET,
126 "IPv6 is not supported.");
127 result = ISC_R_NOTFOUND;
141 initialize_action(void) {
142 ipv4_result = try_proto(PF_INET);
143 #ifdef ISC_PLATFORM_HAVEIPV6
145 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
146 ipv6_result = try_proto(PF_INET6);
150 #ifdef ISC_PLATFORM_HAVESYSUNH
151 unix_result = try_proto(PF_UNIX);
157 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
161 isc_net_probeipv4(void) {
163 return (ipv4_result);
167 isc_net_probeipv6(void) {
169 return (ipv6_result);
173 isc_net_probeunix(void) {
175 return (unix_result);
178 #ifdef ISC_PLATFORM_HAVEIPV6
184 char strbuf[ISC_STRERRORSIZE];
188 result = isc_net_probeipv6();
189 if (result != ISC_R_SUCCESS) {
190 ipv6only_result = result;
195 ipv6only_result = ISC_R_NOTFOUND;
198 /* check for TCP sockets */
199 s = socket(PF_INET6, SOCK_STREAM, 0);
201 isc__strerror(errno, strbuf, sizeof(strbuf));
202 UNEXPECTED_ERROR(__FILE__, __LINE__,
204 isc_msgcat_get(isc_msgcat,
209 ipv6only_result = ISC_R_UNEXPECTED;
214 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
215 ipv6only_result = ISC_R_NOTFOUND;
221 /* check for UDP sockets */
222 s = socket(PF_INET6, SOCK_DGRAM, 0);
224 isc__strerror(errno, strbuf, sizeof(strbuf));
225 UNEXPECTED_ERROR(__FILE__, __LINE__,
227 isc_msgcat_get(isc_msgcat,
232 ipv6only_result = ISC_R_UNEXPECTED;
237 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
238 ipv6only_result = ISC_R_NOTFOUND;
244 ipv6only_result = ISC_R_SUCCESS;
249 #endif /* IPV6_V6ONLY */
253 initialize_ipv6only(void) {
254 RUNTIME_CHECK(isc_once_do(&once_ipv6only,
255 try_ipv6only) == ISC_R_SUCCESS);
257 #endif /* WANT_IPV6 */
259 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
261 try_ipv6pktinfo(void) {
263 char strbuf[ISC_STRERRORSIZE];
267 result = isc_net_probeipv6();
268 if (result != ISC_R_SUCCESS) {
269 ipv6pktinfo_result = result;
273 /* we only use this for UDP sockets */
274 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
276 isc__strerror(errno, strbuf, sizeof(strbuf));
277 UNEXPECTED_ERROR(__FILE__, __LINE__,
279 isc_msgcat_get(isc_msgcat,
284 ipv6pktinfo_result = ISC_R_UNEXPECTED;
288 #ifdef IPV6_RECVPKTINFO
289 optname = IPV6_RECVPKTINFO;
291 optname = IPV6_PKTINFO;
294 if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
295 ipv6pktinfo_result = ISC_R_NOTFOUND;
300 ipv6pktinfo_result = ISC_R_SUCCESS;
308 initialize_ipv6pktinfo(void) {
309 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
310 try_ipv6pktinfo) == ISC_R_SUCCESS);
312 #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
313 #endif /* ISC_PLATFORM_HAVEIPV6 */
316 isc_net_probe_ipv6only(void) {
317 #ifdef ISC_PLATFORM_HAVEIPV6
319 initialize_ipv6only();
321 ipv6only_result = ISC_R_NOTFOUND;
324 return (ipv6only_result);
328 isc_net_probe_ipv6pktinfo(void) {
329 #ifdef ISC_PLATFORM_HAVEIPV6
330 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
332 initialize_ipv6pktinfo();
334 ipv6pktinfo_result = ISC_R_NOTFOUND;
338 return (ipv6pktinfo_result);
342 isc_net_disableipv4(void) {
344 if (ipv4_result == ISC_R_SUCCESS)
345 ipv4_result = ISC_R_DISABLED;
349 isc_net_disableipv6(void) {
351 if (ipv6_result == ISC_R_SUCCESS)
352 ipv6_result = ISC_R_DISABLED;
356 isc_net_enableipv4(void) {
358 if (ipv4_result == ISC_R_DISABLED)
359 ipv4_result = ISC_R_SUCCESS;
363 isc_net_enableipv6(void) {
365 if (ipv6_result == ISC_R_DISABLED)
366 ipv6_result = ISC_R_SUCCESS;