]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/lib/isc/win32/net.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / lib / isc / win32 / net.c
1 /*
2  * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012  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$ */
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, (const char *)&on,
174                        sizeof(on)) < 0) {
175                 ipv6only_result = ISC_R_NOTFOUND;
176                 goto close;
177         }
178
179         closesocket(s);
180
181         /* check for UDP sockets */
182         s = socket(PF_INET6, SOCK_DGRAM, 0);
183         if (s == INVALID_SOCKET) {
184                 isc__strerror(errno, strbuf, sizeof(strbuf));
185                 UNEXPECTED_ERROR(__FILE__, __LINE__,
186                                  "socket() %s: %s",
187                                  isc_msgcat_get(isc_msgcat,
188                                                 ISC_MSGSET_GENERAL,
189                                                 ISC_MSG_FAILED,
190                                                 "failed"),
191                                  strbuf);
192                 ipv6only_result = ISC_R_UNEXPECTED;
193                 return;
194         }
195
196         on = 1;
197         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on,
198                        sizeof(on)) < 0) {
199                 ipv6only_result = ISC_R_NOTFOUND;
200                 goto close;
201         }
202
203         ipv6only_result = ISC_R_SUCCESS;
204
205 close:
206         closesocket(s);
207         return;
208 #endif /* IPV6_V6ONLY */
209 }
210
211 static void
212 initialize_ipv6only(void) {
213         RUNTIME_CHECK(isc_once_do(&once_ipv6only,
214                                   try_ipv6only) == ISC_R_SUCCESS);
215 }
216
217 static void
218 try_ipv6pktinfo(void) {
219         int s, on;
220         char strbuf[ISC_STRERRORSIZE];
221         isc_result_t result;
222         int optname;
223
224         result = isc_net_probeipv6();
225         if (result != ISC_R_SUCCESS) {
226                 ipv6pktinfo_result = result;
227                 return;
228         }
229
230         /* we only use this for UDP sockets */
231         s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
232         if (s == INVALID_SOCKET) {
233                 isc__strerror(errno, strbuf, sizeof(strbuf));
234                 UNEXPECTED_ERROR(__FILE__, __LINE__,
235                                  "socket() %s: %s",
236                                  isc_msgcat_get(isc_msgcat,
237                                                 ISC_MSGSET_GENERAL,
238                                                 ISC_MSG_FAILED,
239                                                 "failed"),
240                                  strbuf);
241                 ipv6pktinfo_result = ISC_R_UNEXPECTED;
242                 return;
243         }
244
245 #ifdef IPV6_RECVPKTINFO
246         optname = IPV6_RECVPKTINFO;
247 #else
248         optname = IPV6_PKTINFO;
249 #endif
250         on = 1;
251         if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on,
252                        sizeof(on)) < 0) {
253                 ipv6pktinfo_result = ISC_R_NOTFOUND;
254                 goto close;
255         }
256
257         ipv6pktinfo_result = ISC_R_SUCCESS;
258
259 close:
260         closesocket(s);
261         return;
262 }
263
264 static void
265 initialize_ipv6pktinfo(void) {
266         RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
267                                   try_ipv6pktinfo) == ISC_R_SUCCESS);
268 }
269 #endif /* WANT_IPV6 */
270 #endif /* ISC_PLATFORM_HAVEIPV6 */
271
272 isc_result_t
273 isc_net_probe_ipv6only(void) {
274 #ifdef ISC_PLATFORM_HAVEIPV6
275 #ifdef WANT_IPV6
276         initialize_ipv6only();
277 #else
278         ipv6only_result = ISC_R_NOTFOUND;
279 #endif
280 #endif
281         return (ipv6only_result);
282 }
283
284 isc_result_t
285 isc_net_probe_ipv6pktinfo(void) {
286 #ifdef ISC_PLATFORM_HAVEIPV6
287 #ifdef WANT_IPV6
288         initialize_ipv6pktinfo();
289 #else
290         ipv6pktinfo_result = ISC_R_NOTFOUND;
291 #endif
292 #endif
293         return (ipv6pktinfo_result);
294 }
295
296 isc_result_t
297 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
298         int result = ISC_R_FAILURE;
299
300         REQUIRE(low != NULL && high != NULL);
301
302         UNUSED(af);
303
304         if (result != ISC_R_SUCCESS) {
305                 *low = ISC_NET_PORTRANGELOW;
306                 *high = ISC_NET_PORTRANGEHIGH;
307         }
308
309         return (ISC_R_SUCCESS); /* we currently never fail in this function */
310 }
311
312 void
313 isc_net_disableipv4(void) {
314         initialize();
315         if (ipv4_result == ISC_R_SUCCESS)
316                 ipv4_result = ISC_R_DISABLED;
317 }
318
319 void
320 isc_net_disableipv6(void) {
321         initialize();
322         if (ipv6_result == ISC_R_SUCCESS)
323                 ipv6_result = ISC_R_DISABLED;
324 }
325
326 void
327 isc_net_enableipv4(void) {
328         initialize();
329         if (ipv4_result == ISC_R_DISABLED)
330                 ipv4_result = ISC_R_SUCCESS;
331 }
332
333 void
334 isc_net_enableipv6(void) {
335         initialize();
336         if (ipv6_result == ISC_R_DISABLED)
337                 ipv6_result = ISC_R_SUCCESS;
338 }