|
|
1.1 misho 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: }