2 * Copyright (C) 2004, 2005, 2007-2009 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.20 2009/09/08 23:41:50 tbox Exp $ */
29 #include <isc/strerror.h>
30 #include <isc/string.h>
34 * Definitions about UDP port range specification. This is a total mess of
35 * portability variants: some use sysctl (but the sysctl names vary), some use
36 * system-specific interfaces, some have the same interface for IPv4 and IPv6,
37 * some separate them, etc...
41 * The last resort defaults: use all non well known port space
43 #ifndef ISC_NET_PORTRANGELOW
44 #define ISC_NET_PORTRANGELOW 1024
45 #endif /* ISC_NET_PORTRANGELOW */
46 #ifndef ISC_NET_PORTRANGEHIGH
47 #define ISC_NET_PORTRANGEHIGH 65535
48 #endif /* ISC_NET_PORTRANGEHIGH */
50 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
51 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
54 static isc_once_t once = ISC_ONCE_INIT;
55 static isc_once_t once_ipv6only = ISC_ONCE_INIT;
56 static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
57 static isc_result_t ipv4_result = ISC_R_NOTFOUND;
58 static isc_result_t ipv6_result = ISC_R_NOTFOUND;
59 static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
60 static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
62 void InitSockets(void);
65 try_proto(int domain) {
67 isc_result_t result = ISC_R_SUCCESS;
68 char strbuf[ISC_STRERRORSIZE];
71 s = socket(domain, SOCK_STREAM, IPPROTO_TCP);
72 if (s == INVALID_SOCKET) {
73 errval = WSAGetLastError();
76 case WSAEPROTONOSUPPORT:
78 return (ISC_R_NOTFOUND);
80 isc__strerror(errval, strbuf, sizeof(strbuf));
81 UNEXPECTED_ERROR(__FILE__, __LINE__,
83 isc_msgcat_get(isc_msgcat,
88 return (ISC_R_UNEXPECTED);
94 return (ISC_R_SUCCESS);
98 initialize_action(void) {
100 ipv4_result = try_proto(PF_INET);
101 #ifdef ISC_PLATFORM_HAVEIPV6
103 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
104 ipv6_result = try_proto(PF_INET6);
112 RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
116 isc_net_probeipv4(void) {
118 return (ipv4_result);
122 isc_net_probeipv6(void) {
124 return (ipv6_result);
128 isc_net_probeunix(void) {
129 return (ISC_R_NOTFOUND);
132 #ifdef ISC_PLATFORM_HAVEIPV6
139 char strbuf[ISC_STRERRORSIZE];
143 result = isc_net_probeipv6();
144 if (result != ISC_R_SUCCESS) {
145 ipv6only_result = result;
150 ipv6only_result = ISC_R_NOTFOUND;
153 /* check for TCP sockets */
154 s = socket(PF_INET6, SOCK_STREAM, 0);
155 if (s == INVALID_SOCKET) {
156 isc__strerror(errno, strbuf, sizeof(strbuf));
157 UNEXPECTED_ERROR(__FILE__, __LINE__,
159 isc_msgcat_get(isc_msgcat,
164 ipv6only_result = ISC_R_UNEXPECTED;
169 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
170 ipv6only_result = ISC_R_NOTFOUND;
176 /* check for UDP sockets */
177 s = socket(PF_INET6, SOCK_DGRAM, 0);
178 if (s == INVALID_SOCKET) {
179 isc__strerror(errno, strbuf, sizeof(strbuf));
180 UNEXPECTED_ERROR(__FILE__, __LINE__,
182 isc_msgcat_get(isc_msgcat,
187 ipv6only_result = ISC_R_UNEXPECTED;
192 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
193 ipv6only_result = ISC_R_NOTFOUND;
197 ipv6only_result = ISC_R_SUCCESS;
202 #endif /* IPV6_V6ONLY */
206 initialize_ipv6only(void) {
207 RUNTIME_CHECK(isc_once_do(&once_ipv6only,
208 try_ipv6only) == ISC_R_SUCCESS);
212 try_ipv6pktinfo(void) {
214 char strbuf[ISC_STRERRORSIZE];
218 result = isc_net_probeipv6();
219 if (result != ISC_R_SUCCESS) {
220 ipv6pktinfo_result = result;
224 /* we only use this for UDP sockets */
225 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
226 if (s == INVALID_SOCKET) {
227 isc__strerror(errno, strbuf, sizeof(strbuf));
228 UNEXPECTED_ERROR(__FILE__, __LINE__,
230 isc_msgcat_get(isc_msgcat,
235 ipv6pktinfo_result = ISC_R_UNEXPECTED;
239 #ifdef IPV6_RECVPKTINFO
240 optname = IPV6_RECVPKTINFO;
242 optname = IPV6_PKTINFO;
245 if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on,
247 ipv6pktinfo_result = ISC_R_NOTFOUND;
251 ipv6pktinfo_result = ISC_R_SUCCESS;
259 initialize_ipv6pktinfo(void) {
260 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
261 try_ipv6pktinfo) == ISC_R_SUCCESS);
263 #endif /* WANT_IPV6 */
264 #endif /* ISC_PLATFORM_HAVEIPV6 */
267 isc_net_probe_ipv6only(void) {
268 #ifdef ISC_PLATFORM_HAVEIPV6
270 initialize_ipv6only();
272 ipv6only_result = ISC_R_NOTFOUND;
275 return (ipv6only_result);
279 isc_net_probe_ipv6pktinfo(void) {
280 #ifdef ISC_PLATFORM_HAVEIPV6
282 initialize_ipv6pktinfo();
284 ipv6pktinfo_result = ISC_R_NOTFOUND;
287 return (ipv6pktinfo_result);
291 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
292 int result = ISC_R_FAILURE;
294 REQUIRE(low != NULL && high != NULL);
298 if (result != ISC_R_SUCCESS) {
299 *low = ISC_NET_PORTRANGELOW;
300 *high = ISC_NET_PORTRANGEHIGH;
303 return (ISC_R_SUCCESS); /* we currently never fail in this function */
307 isc_net_disableipv4(void) {
309 if (ipv4_result == ISC_R_SUCCESS)
310 ipv4_result = ISC_R_DISABLED;
314 isc_net_disableipv6(void) {
316 if (ipv6_result == ISC_R_SUCCESS)
317 ipv6_result = ISC_R_DISABLED;
321 isc_net_enableipv4(void) {
323 if (ipv4_result == ISC_R_DISABLED)
324 ipv4_result = ISC_R_SUCCESS;
328 isc_net_enableipv6(void) {
330 if (ipv6_result == ISC_R_DISABLED)
331 ipv6_result = ISC_R_SUCCESS;