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>