]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/isc/win32/net.c
Virgin import of ntpd 4.2.6p5.
[FreeBSD/FreeBSD.git] / lib / isc / win32 / net.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: net.c,v 1.18 2008/08/08 05:06:49 marka Exp $ */
19
20 #include <config.h>
21
22 #include <errno.h>
23 #include <unistd.h>
24
25 #include <isc/log.h>
26 #include <isc/msgs.h>
27 #include <isc/net.h>
28 #include <isc/once.h>
29 #include <isc/strerror.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32
33 /*%
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...
38  */
39
40 /*%
41  * The last resort defaults: use all non well known port space
42  */
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 */
49
50 #if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
51 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
52 #endif
53
54 #if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
55 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
56 #endif
57
58
59 static isc_once_t       once = ISC_ONCE_INIT;
60 static isc_once_t       once_ipv6only = ISC_ONCE_INIT;
61 static isc_once_t       once_ipv6pktinfo = ISC_ONCE_INIT;
62 static isc_result_t     ipv4_result = ISC_R_NOTFOUND;
63 static isc_result_t     ipv6_result = ISC_R_NOTFOUND;
64 static isc_result_t     ipv6only_result = ISC_R_NOTFOUND;
65 static isc_result_t     ipv6pktinfo_result = ISC_R_NOTFOUND;
66
67 void InitSockets(void);
68
69 static isc_result_t
70 try_proto(int domain) {
71         SOCKET s;
72         char strbuf[ISC_STRERRORSIZE];
73         int errval;
74
75         s = socket(domain, SOCK_STREAM, IPPROTO_TCP);
76         if (s == INVALID_SOCKET) {
77                 errval = WSAGetLastError();
78                 switch (errval) {
79                 case WSAEAFNOSUPPORT:
80                 case WSAEPROTONOSUPPORT:
81                 case WSAEINVAL:
82                         return (ISC_R_NOTFOUND);
83                 default:
84                         isc__strerror(errval, strbuf, sizeof(strbuf));
85                         UNEXPECTED_ERROR(__FILE__, __LINE__,
86                                          "socket() %s: %s",
87                                          isc_msgcat_get(isc_msgcat,
88                                                         ISC_MSGSET_GENERAL,
89                                                         ISC_MSG_FAILED,
90                                                         "failed"),
91                                          strbuf);
92                         return (ISC_R_UNEXPECTED);
93                 }
94         }
95
96         closesocket(s);
97
98         return (ISC_R_SUCCESS);
99 }
100
101 static void
102 initialize_action(void) {
103         InitSockets();
104         ipv4_result = try_proto(PF_INET);
105 #ifdef ISC_PLATFORM_HAVEIPV6
106 #ifdef WANT_IPV6
107 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
108         ipv6_result = try_proto(PF_INET6);
109 #endif
110 #endif
111 #endif
112 }
113
114 static void
115 initialize(void) {
116         RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
117 }
118
119 isc_result_t
120 isc_net_probeipv4(void) {
121         initialize();
122         return (ipv4_result);
123 }
124
125 isc_result_t
126 isc_net_probeipv6(void) {
127         initialize();
128         return (ipv6_result);
129 }
130
131 isc_result_t
132 isc_net_probeunix(void) {
133         return (ISC_R_NOTFOUND);
134 }
135
136 #ifdef ISC_PLATFORM_HAVEIPV6
137 #ifdef WANT_IPV6
138 static void
139 try_ipv6only(void) {
140 #ifdef IPV6_V6ONLY
141         SOCKET s;
142         int on;
143         char strbuf[ISC_STRERRORSIZE];
144 #endif
145         isc_result_t result;
146
147         result = isc_net_probeipv6();
148         if (result != ISC_R_SUCCESS) {
149                 ipv6only_result = result;
150                 return;
151         }
152
153 #ifndef IPV6_V6ONLY
154         ipv6only_result = ISC_R_NOTFOUND;
155         return;
156 #else
157         /* check for TCP sockets */
158         s = socket(PF_INET6, SOCK_STREAM, 0);
159         if (s == INVALID_SOCKET) {
160                 isc__strerror(errno, strbuf, sizeof(strbuf));
161                 UNEXPECTED_ERROR(__FILE__, __LINE__,
162                                  "socket() %s: %s",
163                                  isc_msgcat_get(isc_msgcat,
164                                                 ISC_MSGSET_GENERAL,
165                                                 ISC_MSG_FAILED,
166                                                 "failed"),
167                                  strbuf);
168                 ipv6only_result = ISC_R_UNEXPECTED;
169                 return;
170         }
171
172         on = 1;
173         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
174                 ipv6only_result = ISC_R_NOTFOUND;
175                 goto close;
176         }
177
178         closesocket(s);
179
180         /* check for UDP sockets */
181         s = socket(PF_INET6, SOCK_DGRAM, 0);
182         if (s == INVALID_SOCKET) {
183                 isc__strerror(errno, strbuf, sizeof(strbuf));
184                 UNEXPECTED_ERROR(__FILE__, __LINE__,
185                                  "socket() %s: %s",
186                                  isc_msgcat_get(isc_msgcat,
187                                                 ISC_MSGSET_GENERAL,
188                                                 ISC_MSG_FAILED,
189                                                 "failed"),
190                                  strbuf);
191                 ipv6only_result = ISC_R_UNEXPECTED;
192                 return;
193         }
194
195         on = 1;
196         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
197                 ipv6only_result = ISC_R_NOTFOUND;
198                 goto close;
199         }
200
201         ipv6only_result = ISC_R_SUCCESS;
202
203 close:
204         closesocket(s);
205         return;
206 #endif /* IPV6_V6ONLY */
207 }
208
209 static void
210 initialize_ipv6only(void) {
211         RUNTIME_CHECK(isc_once_do(&once_ipv6only,
212                                   try_ipv6only) == ISC_R_SUCCESS);
213 }
214
215 static void
216 try_ipv6pktinfo(void) {
217         int s, on;
218         char strbuf[ISC_STRERRORSIZE];
219         isc_result_t result;
220         int optname;
221
222         result = isc_net_probeipv6();
223         if (result != ISC_R_SUCCESS) {
224                 ipv6pktinfo_result = result;
225                 return;
226         }
227
228         /* we only use this for UDP sockets */
229         s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
230         if (s == INVALID_SOCKET) {
231                 isc__strerror(errno, strbuf, sizeof(strbuf));
232                 UNEXPECTED_ERROR(__FILE__, __LINE__,
233                                  "socket() %s: %s",
234                                  isc_msgcat_get(isc_msgcat,
235                                                 ISC_MSGSET_GENERAL,
236                                                 ISC_MSG_FAILED,
237                                                 "failed"),
238                                  strbuf);
239                 ipv6pktinfo_result = ISC_R_UNEXPECTED;
240                 return;
241         }
242
243 #ifdef IPV6_RECVPKTINFO
244         optname = IPV6_RECVPKTINFO;
245 #else
246         optname = IPV6_PKTINFO;
247 #endif
248         on = 1;
249         if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on,
250                        sizeof(on)) < 0) {
251                 ipv6pktinfo_result = ISC_R_NOTFOUND;
252                 goto close;
253         }
254
255         ipv6pktinfo_result = ISC_R_SUCCESS;
256
257 close:
258         closesocket(s);
259         return;
260 }
261
262 static void
263 initialize_ipv6pktinfo(void) {
264         RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
265                                   try_ipv6pktinfo) == ISC_R_SUCCESS);
266 }
267 #endif /* WANT_IPV6 */
268 #endif /* ISC_PLATFORM_HAVEIPV6 */
269
270 isc_result_t
271 isc_net_probe_ipv6only(void) {
272 #ifdef ISC_PLATFORM_HAVEIPV6
273 #ifdef WANT_IPV6
274         initialize_ipv6only();
275 #else
276         ipv6only_result = ISC_R_NOTFOUND;
277 #endif
278 #endif
279         return (ipv6only_result);
280 }
281
282 isc_result_t
283 isc_net_probe_ipv6pktinfo(void) {
284 #ifdef ISC_PLATFORM_HAVEIPV6
285 #ifdef WANT_IPV6
286         initialize_ipv6pktinfo();
287 #else
288         ipv6pktinfo_result = ISC_R_NOTFOUND;
289 #endif
290 #endif
291         return (ipv6pktinfo_result);
292 }
293
294 isc_result_t
295 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
296         int result = ISC_R_FAILURE;
297
298         REQUIRE(low != NULL && high != NULL);
299
300         UNUSED(af);
301
302         if (result != ISC_R_SUCCESS) {
303                 *low = ISC_NET_PORTRANGELOW;
304                 *high = ISC_NET_PORTRANGEHIGH;
305         }
306
307         return (ISC_R_SUCCESS); /* we currently never fail in this function */
308 }
309
310 void
311 isc_net_disableipv4(void) {
312         initialize();
313         if (ipv4_result == ISC_R_SUCCESS)
314                 ipv4_result = ISC_R_DISABLED;
315 }
316
317 void
318 isc_net_disableipv6(void) {
319         initialize();
320         if (ipv6_result == ISC_R_SUCCESS)
321                 ipv6_result = ISC_R_DISABLED;
322 }
323
324 void
325 isc_net_enableipv4(void) {
326         initialize();
327         if (ipv4_result == ISC_R_DISABLED)
328                 ipv4_result = ISC_R_SUCCESS;
329 }
330
331 void
332 isc_net_enableipv6(void) {
333         initialize();
334         if (ipv6_result == ISC_R_DISABLED)
335                 ipv6_result = ISC_R_SUCCESS;
336 }