Annotation of embedaddon/ntp/lib/isc/unix/net.c, revision 1.1.1.1
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.40 2008/07/04 05:52:31 each Exp $ */
19:
20: #include <config.h>
21:
22: #include <sys/types.h>
23:
24: #if defined(HAVE_SYS_SYSCTL_H)
25: #if defined(HAVE_SYS_PARAM_H)
26: #include <sys/param.h>
27: #endif
28: #include <sys/sysctl.h>
29: #endif
30:
31: #include <errno.h>
32: #include <unistd.h>
33:
34: #include <isc/log.h>
35: #include <isc/msgs.h>
36: #include <isc/net.h>
37: #include <isc/once.h>
38: #include <isc/strerror.h>
39: #include <isc/string.h>
40: #include <isc/util.h>
41:
42: /*%
43: * Definitions about UDP port range specification. This is a total mess of
44: * portability variants: some use sysctl (but the sysctl names vary), some use
45: * system-specific interfaces, some have the same interface for IPv4 and IPv6,
46: * some separate them, etc...
47: */
48:
49: /*%
50: * The last resort defaults: use all non well known port space
51: */
52: #ifndef ISC_NET_PORTRANGELOW
53: #define ISC_NET_PORTRANGELOW 1024
54: #endif /* ISC_NET_PORTRANGELOW */
55: #ifndef ISC_NET_PORTRANGEHIGH
56: #define ISC_NET_PORTRANGEHIGH 65535
57: #endif /* ISC_NET_PORTRANGEHIGH */
58:
59: #ifdef HAVE_SYSCTLBYNAME
60:
61: /*%
62: * sysctl variants
63: */
64: #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
65: #define USE_SYSCTL_PORTRANGE
66: #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
67: #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
68: #define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst"
69: #define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast"
70: #endif
71:
72: #ifdef __NetBSD__
73: #define USE_SYSCTL_PORTRANGE
74: #define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
75: #define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
76: #define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin"
77: #define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax"
78: #endif
79:
80: #else /* !HAVE_SYSCTLBYNAME */
81:
82: #ifdef __OpenBSD__
83: #define USE_SYSCTL_PORTRANGE
84: #define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \
85: IPCTL_IPPORT_HIFIRSTAUTO }
86: #define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \
87: IPCTL_IPPORT_HILASTAUTO }
88: /* Same for IPv6 */
89: #define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW
90: #define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH
91: #endif
92:
93: #endif /* HAVE_SYSCTLBYNAME */
94:
95: #if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
96: const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
97: #endif
98:
99: #if defined(ISC_PLATFORM_HAVEIPV6)
100:
101: # if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
102: const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
103: # endif
104:
105: # if defined(WANT_IPV6)
106: static isc_once_t once_ipv6only = ISC_ONCE_INIT;
107: # endif
108:
109: # if defined(ISC_PLATFORM_HAVEIN6PKTINFO)
110: static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
111: # endif
112: #endif /* ISC_PLATFORM_HAVEIPV6 */
113:
114: static isc_once_t once = ISC_ONCE_INIT;
115:
116: static isc_result_t ipv4_result = ISC_R_NOTFOUND;
117: static isc_result_t ipv6_result = ISC_R_NOTFOUND;
118: static isc_result_t unix_result = ISC_R_NOTFOUND;
119: static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
120: static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
121:
122: static isc_result_t
123: try_proto(int domain) {
124: int s;
125: isc_result_t result = ISC_R_SUCCESS;
126: char strbuf[ISC_STRERRORSIZE];
127:
128: s = socket(domain, SOCK_STREAM, 0);
129: if (s == -1) {
130: switch (errno) {
131: #ifdef EAFNOSUPPORT
132: case EAFNOSUPPORT:
133: #endif
134: #ifdef EPROTONOSUPPORT
135: case EPROTONOSUPPORT:
136: #endif
137: #ifdef EINVAL
138: case EINVAL:
139: #endif
140: return (ISC_R_NOTFOUND);
141: default:
142: isc__strerror(errno, strbuf, sizeof(strbuf));
143: UNEXPECTED_ERROR(__FILE__, __LINE__,
144: "socket() %s: %s",
145: isc_msgcat_get(isc_msgcat,
146: ISC_MSGSET_GENERAL,
147: ISC_MSG_FAILED,
148: "failed"),
149: strbuf);
150: return (ISC_R_UNEXPECTED);
151: }
152: }
153:
154: #ifdef ISC_PLATFORM_HAVEIPV6
155: #ifdef WANT_IPV6
156: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
157: if (domain == PF_INET6) {
158: struct sockaddr_in6 sin6;
159: GETSOCKNAME_SOCKLEN_TYPE len; /* NTP local change */
160:
161: /*
162: * Check to see if IPv6 is broken, as is common on Linux.
163: */
164: len = sizeof(sin6);
165: if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
166: {
167: isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
168: ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
169: "retrieving the address of an IPv6 "
170: "socket from the kernel failed.");
171: isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
172: ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
173: "IPv6 is not supported.");
174: result = ISC_R_NOTFOUND;
175: } else {
176: if (len == sizeof(struct sockaddr_in6))
177: result = ISC_R_SUCCESS;
178: else {
179: isc_log_write(isc_lctx,
180: ISC_LOGCATEGORY_GENERAL,
181: ISC_LOGMODULE_SOCKET,
182: ISC_LOG_ERROR,
183: "IPv6 structures in kernel and "
184: "user space do not match.");
185: isc_log_write(isc_lctx,
186: ISC_LOGCATEGORY_GENERAL,
187: ISC_LOGMODULE_SOCKET,
188: ISC_LOG_ERROR,
189: "IPv6 is not supported.");
190: result = ISC_R_NOTFOUND;
191: }
192: }
193: }
194: #endif
195: #endif
196: #endif
197:
198: (void)close(s);
199:
200: return (result);
201: }
202:
203: static void
204: initialize_action(void) {
205: ipv4_result = try_proto(PF_INET);
206: #ifdef ISC_PLATFORM_HAVEIPV6
207: #ifdef WANT_IPV6
208: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
209: ipv6_result = try_proto(PF_INET6);
210: #endif
211: #endif
212: #endif
213: #ifdef ISC_PLATFORM_HAVESYSUNH
214: unix_result = try_proto(PF_UNIX);
215: #endif
216: }
217:
218: static void
219: initialize(void) {
220: RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
221: }
222:
223: isc_result_t
224: isc_net_probeipv4(void) {
225: initialize();
226: return (ipv4_result);
227: }
228:
229: isc_result_t
230: isc_net_probeipv6(void) {
231: initialize();
232: return (ipv6_result);
233: }
234:
235: isc_result_t
236: isc_net_probeunix(void) {
237: initialize();
238: return (unix_result);
239: }
240:
241: #ifdef ISC_PLATFORM_HAVEIPV6
242: #ifdef WANT_IPV6
243: static void
244: try_ipv6only(void) {
245: #ifdef IPV6_V6ONLY
246: int s, on;
247: char strbuf[ISC_STRERRORSIZE];
248: #endif
249: isc_result_t result;
250:
251: result = isc_net_probeipv6();
252: if (result != ISC_R_SUCCESS) {
253: ipv6only_result = result;
254: return;
255: }
256:
257: #ifndef IPV6_V6ONLY
258: ipv6only_result = ISC_R_NOTFOUND;
259: return;
260: #else
261: /* check for TCP sockets */
262: s = socket(PF_INET6, SOCK_STREAM, 0);
263: if (s == -1) {
264: isc__strerror(errno, strbuf, sizeof(strbuf));
265: UNEXPECTED_ERROR(__FILE__, __LINE__,
266: "socket() %s: %s",
267: isc_msgcat_get(isc_msgcat,
268: ISC_MSGSET_GENERAL,
269: ISC_MSG_FAILED,
270: "failed"),
271: strbuf);
272: ipv6only_result = ISC_R_UNEXPECTED;
273: return;
274: }
275:
276: on = 1;
277: if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
278: ipv6only_result = ISC_R_NOTFOUND;
279: goto close;
280: }
281:
282: close(s);
283:
284: /* check for UDP sockets */
285: s = socket(PF_INET6, SOCK_DGRAM, 0);
286: if (s == -1) {
287: isc__strerror(errno, strbuf, sizeof(strbuf));
288: UNEXPECTED_ERROR(__FILE__, __LINE__,
289: "socket() %s: %s",
290: isc_msgcat_get(isc_msgcat,
291: ISC_MSGSET_GENERAL,
292: ISC_MSG_FAILED,
293: "failed"),
294: strbuf);
295: ipv6only_result = ISC_R_UNEXPECTED;
296: return;
297: }
298:
299: on = 1;
300: if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
301: ipv6only_result = ISC_R_NOTFOUND;
302: goto close;
303: }
304:
305: close(s);
306:
307: ipv6only_result = ISC_R_SUCCESS;
308:
309: close:
310: close(s);
311: return;
312: #endif /* IPV6_V6ONLY */
313: }
314:
315: static void
316: initialize_ipv6only(void) {
317: RUNTIME_CHECK(isc_once_do(&once_ipv6only,
318: try_ipv6only) == ISC_R_SUCCESS);
319: }
320:
321: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
322: static void
323: try_ipv6pktinfo(void) {
324: int s, on;
325: char strbuf[ISC_STRERRORSIZE];
326: isc_result_t result;
327: int optname;
328:
329: result = isc_net_probeipv6();
330: if (result != ISC_R_SUCCESS) {
331: ipv6pktinfo_result = result;
332: return;
333: }
334:
335: /* we only use this for UDP sockets */
336: s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
337: if (s == -1) {
338: isc__strerror(errno, strbuf, sizeof(strbuf));
339: UNEXPECTED_ERROR(__FILE__, __LINE__,
340: "socket() %s: %s",
341: isc_msgcat_get(isc_msgcat,
342: ISC_MSGSET_GENERAL,
343: ISC_MSG_FAILED,
344: "failed"),
345: strbuf);
346: ipv6pktinfo_result = ISC_R_UNEXPECTED;
347: return;
348: }
349:
350: #ifdef IPV6_RECVPKTINFO
351: optname = IPV6_RECVPKTINFO;
352: #else
353: optname = IPV6_PKTINFO;
354: #endif
355: on = 1;
356: if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
357: ipv6pktinfo_result = ISC_R_NOTFOUND;
358: goto close;
359: }
360:
361: close(s);
362: ipv6pktinfo_result = ISC_R_SUCCESS;
363:
364: close:
365: close(s);
366: return;
367: }
368:
369: static void
370: initialize_ipv6pktinfo(void) {
371: RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
372: try_ipv6pktinfo) == ISC_R_SUCCESS);
373: }
374: #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
375: #endif /* WANT_IPV6 */
376: #endif /* ISC_PLATFORM_HAVEIPV6 */
377:
378: isc_result_t
379: isc_net_probe_ipv6only(void) {
380: #ifdef ISC_PLATFORM_HAVEIPV6
381: #ifdef WANT_IPV6
382: initialize_ipv6only();
383: #else
384: ipv6only_result = ISC_R_NOTFOUND;
385: #endif
386: #endif
387: return (ipv6only_result);
388: }
389:
390: isc_result_t
391: isc_net_probe_ipv6pktinfo(void) {
392: #ifdef ISC_PLATFORM_HAVEIPV6
393: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
394: #ifdef WANT_IPV6
395: initialize_ipv6pktinfo();
396: #else
397: ipv6pktinfo_result = ISC_R_NOTFOUND;
398: #endif
399: #endif
400: #endif
401: return (ipv6pktinfo_result);
402: }
403:
404: #if defined(USE_SYSCTL_PORTRANGE)
405: #if defined(HAVE_SYSCTLBYNAME)
406: static isc_result_t
407: getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
408: int port_low, port_high;
409: size_t portlen;
410: const char *sysctlname_lowport, *sysctlname_hiport;
411:
412: if (af == AF_INET) {
413: sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
414: sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
415: } else {
416: sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
417: sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
418: }
419: portlen = sizeof(portlen);
420: if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
421: NULL, 0) < 0) {
422: return (ISC_R_FAILURE);
423: }
424: portlen = sizeof(portlen);
425: if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
426: NULL, 0) < 0) {
427: return (ISC_R_FAILURE);
428: }
429: if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
430: return (ISC_R_RANGE);
431:
432: *low = (in_port_t)port_low;
433: *high = (in_port_t)port_high;
434:
435: return (ISC_R_SUCCESS);
436: }
437: #else /* !HAVE_SYSCTLBYNAME */
438: static isc_result_t
439: getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
440: int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW;
441: int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH;
442: int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW;
443: int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH;
444: int *mib_lo, *mib_hi, miblen;
445: int port_low, port_high;
446: size_t portlen;
447:
448: if (af == AF_INET) {
449: mib_lo = mib_lo4;
450: mib_hi = mib_hi4;
451: miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]);
452: } else {
453: mib_lo = mib_lo6;
454: mib_hi = mib_hi6;
455: miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]);
456: }
457:
458: portlen = sizeof(portlen);
459: if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) {
460: return (ISC_R_FAILURE);
461: }
462:
463: portlen = sizeof(portlen);
464: if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) {
465: return (ISC_R_FAILURE);
466: }
467:
468: if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
469: return (ISC_R_RANGE);
470:
471: *low = (in_port_t) port_low;
472: *high = (in_port_t) port_high;
473:
474: return (ISC_R_SUCCESS);
475: }
476: #endif /* HAVE_SYSCTLBYNAME */
477: #endif /* USE_SYSCTL_PORTRANGE */
478:
479: isc_result_t
480: isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
481: int result = ISC_R_FAILURE;
482:
483: REQUIRE(low != NULL && high != NULL);
484:
485: #if defined(USE_SYSCTL_PORTRANGE)
486: result = getudpportrange_sysctl(af, low, high);
487: #else
488: UNUSED(af);
489: #endif
490:
491: if (result != ISC_R_SUCCESS) {
492: *low = ISC_NET_PORTRANGELOW;
493: *high = ISC_NET_PORTRANGEHIGH;
494: }
495:
496: return (ISC_R_SUCCESS); /* we currently never fail in this function */
497: }
498:
499: void
500: isc_net_disableipv4(void) {
501: initialize();
502: if (ipv4_result == ISC_R_SUCCESS)
503: ipv4_result = ISC_R_DISABLED;
504: }
505:
506: void
507: isc_net_disableipv6(void) {
508: initialize();
509: if (ipv6_result == ISC_R_SUCCESS)
510: ipv6_result = ISC_R_DISABLED;
511: }
512:
513: void
514: isc_net_enableipv4(void) {
515: initialize();
516: if (ipv4_result == ISC_R_DISABLED)
517: ipv4_result = ISC_R_SUCCESS;
518: }
519:
520: void
521: isc_net_enableipv6(void) {
522: initialize();
523: if (ipv6_result == ISC_R_DISABLED)
524: ipv6_result = ISC_R_SUCCESS;
525: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>