Annotation of embedaddon/ntp/lib/isc/unix/net.c, revision 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>