]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/ntp/lib/isc/win32/net.c
o Fix invalid TCP checksums with pf(4). [EN-16:02.pf]
[FreeBSD/releng/9.3.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         SOCKET s;
220         int on;
221         char strbuf[ISC_STRERRORSIZE];
222         isc_result_t result;
223         int optname;
224
225         result = isc_net_probeipv6();
226         if (result != ISC_R_SUCCESS) {
227                 ipv6pktinfo_result = result;
228                 return;
229         }
230
231         /* we only use this for UDP sockets */
232         s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
233         if (s == INVALID_SOCKET) {
234                 isc__strerror(errno, strbuf, sizeof(strbuf));
235                 UNEXPECTED_ERROR(__FILE__, __LINE__,
236                                  "socket() %s: %s",
237                                  isc_msgcat_get(isc_msgcat,
238                                                 ISC_MSGSET_GENERAL,
239                                                 ISC_MSG_FAILED,
240                                                 "failed"),
241                                  strbuf);
242                 ipv6pktinfo_result = ISC_R_UNEXPECTED;
243                 return;
244         }
245
246 #ifdef IPV6_RECVPKTINFO
247         optname = IPV6_RECVPKTINFO;
248 #else
249         optname = IPV6_PKTINFO;
250 #endif
251         on = 1;
252         if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on,
253                        sizeof(on)) < 0) {
254                 ipv6pktinfo_result = ISC_R_NOTFOUND;
255                 goto close;
256         }
257
258         ipv6pktinfo_result = ISC_R_SUCCESS;
259
260 close:
261         closesocket(s);
262         return;
263 }
264
265 static void
266 initialize_ipv6pktinfo(void) {
267         RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
268                                   try_ipv6pktinfo) == ISC_R_SUCCESS);
269 }
270 #endif /* WANT_IPV6 */
271 #endif /* ISC_PLATFORM_HAVEIPV6 */
272
273 isc_result_t
274 isc_net_probe_ipv6only(void) {
275 #ifdef ISC_PLATFORM_HAVEIPV6
276 #ifdef WANT_IPV6
277         initialize_ipv6only();
278 #else
279         ipv6only_result = ISC_R_NOTFOUND;
280 #endif
281 #endif
282         return (ipv6only_result);
283 }
284
285 isc_result_t
286 isc_net_probe_ipv6pktinfo(void) {
287 #ifdef ISC_PLATFORM_HAVEIPV6
288 #ifdef WANT_IPV6
289         initialize_ipv6pktinfo();
290 #else
291         ipv6pktinfo_result = ISC_R_NOTFOUND;
292 #endif
293 #endif
294         return (ipv6pktinfo_result);
295 }
296
297 isc_result_t
298 isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
299         int result = ISC_R_FAILURE;
300
301         REQUIRE(low != NULL && high != NULL);
302
303         UNUSED(af);
304
305         if (result != ISC_R_SUCCESS) {
306                 *low = ISC_NET_PORTRANGELOW;
307                 *high = ISC_NET_PORTRANGEHIGH;
308         }
309
310         return (ISC_R_SUCCESS); /* we currently never fail in this function */
311 }
312
313 void
314 isc_net_disableipv4(void) {
315         initialize();
316         if (ipv4_result == ISC_R_SUCCESS)
317                 ipv4_result = ISC_R_DISABLED;
318 }
319
320 void
321 isc_net_disableipv6(void) {
322         initialize();
323         if (ipv6_result == ISC_R_SUCCESS)
324                 ipv6_result = ISC_R_DISABLED;
325 }
326
327 void
328 isc_net_enableipv4(void) {
329         initialize();
330         if (ipv4_result == ISC_R_DISABLED)
331                 ipv4_result = ISC_R_SUCCESS;
332 }
333
334 void
335 isc_net_enableipv6(void) {
336         initialize();
337         if (ipv6_result == ISC_R_DISABLED)
338                 ipv6_result = ISC_R_SUCCESS;
339 }