Annotation of embedaddon/ntp/lib/isc/unix/interfaceiter.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2004, 2005, 2007-2009  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: interfaceiter.c,v 1.44.120.2 2009/02/16 23:47:15 tbox Exp $ */
                     19: 
                     20: /*! \file */
                     21: 
                     22: #include <config.h>
                     23: 
                     24: #include <sys/types.h>
                     25: #include <sys/ioctl.h>
                     26: #ifdef HAVE_SYS_SOCKIO_H
                     27: #include <sys/sockio.h>                /* Required for ifiter_ioctl.c. */
                     28: #endif
                     29: 
                     30: #include <stdio.h>
                     31: #include <stdlib.h>
                     32: #include <unistd.h>
                     33: #include <errno.h>
                     34: 
                     35: #include <isc/interfaceiter.h>
                     36: #include <isc/log.h>
                     37: #include <isc/magic.h>
                     38: #include <isc/mem.h>
                     39: #include <isc/msgs.h>
                     40: #include <isc/net.h>
                     41: #include <isc/print.h>
                     42: #include <isc/result.h>
                     43: #include <isc/strerror.h>
                     44: #include <isc/string.h>
                     45: #include <isc/types.h>
                     46: #include <isc/util.h>
                     47: 
                     48: /* Must follow <isc/net.h>. */
                     49: #ifdef HAVE_NET_IF6_H
                     50: #include <net/if6.h>
                     51: #endif
                     52: #include <net/if.h>
                     53: 
                     54: #ifdef HAVE_LINUX_IF_ADDR_H
                     55: # include <linux/if_addr.h>
                     56: #endif
                     57: 
                     58: /* Common utility functions */
                     59: 
                     60: /*%
                     61:  * Extract the network address part from a "struct sockaddr".
                     62:  * \brief
                     63:  * The address family is given explicitly
                     64:  * instead of using src->sa_family, because the latter does not work
                     65:  * for copying a network mask obtained by SIOCGIFNETMASK (it does
                     66:  * not have a valid address family).
                     67:  */
                     68: 
                     69: static void
                     70: get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
                     71:         char *ifname)
                     72: {
                     73:        struct sockaddr_in6 *sa6;
                     74: 
                     75: #if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
                     76:     !defined(ISC_PLATFORM_HAVESCOPEID)
                     77:        UNUSED(ifname);
                     78: #endif
                     79: 
                     80:        /* clear any remaining value for safety */
                     81:        memset(dst, 0, sizeof(*dst));
                     82: 
                     83:        dst->family = family;
                     84:        switch (family) {
                     85:        case AF_INET:
                     86:                memcpy(&dst->type.in,
                     87:                       &((struct sockaddr_in *)(void *)src)->sin_addr,
                     88:                       sizeof(struct in_addr));
                     89:                break;
                     90:        case AF_INET6:
                     91:                sa6 = (struct sockaddr_in6 *)(void *)src;
                     92:                memcpy(&dst->type.in6, &sa6->sin6_addr,
                     93:                       sizeof(struct in6_addr));
                     94: #ifdef ISC_PLATFORM_HAVESCOPEID
                     95:                if (sa6->sin6_scope_id != 0)
                     96:                        isc_netaddr_setzone(dst, sa6->sin6_scope_id);
                     97:                else {
                     98:                        /*
                     99:                         * BSD variants embed scope zone IDs in the 128bit
                    100:                         * address as a kernel internal form.  Unfortunately,
                    101:                         * the embedded IDs are not hidden from applications
                    102:                         * when getting access to them by sysctl or ioctl.
                    103:                         * We convert the internal format to the pure address
                    104:                         * part and the zone ID part.
                    105:                         * Since multicast addresses should not appear here
                    106:                         * and they cannot be distinguished from netmasks,
                    107:                         * we only consider unicast link-local addresses.
                    108:                         */
                    109:                        if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
                    110:                                isc_uint16_t zone16;
                    111: 
                    112:                                memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
                    113:                                       sizeof(zone16));
                    114:                                zone16 = ntohs(zone16);
                    115:                                if (zone16 != 0) {
                    116:                                        /* the zone ID is embedded */
                    117:                                        isc_netaddr_setzone(dst,
                    118:                                                            (isc_uint32_t)zone16);
                    119:                                        dst->type.in6.s6_addr[2] = 0;
                    120:                                        dst->type.in6.s6_addr[3] = 0;
                    121: #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
                    122:                                } else if (ifname != NULL) {
                    123:                                        unsigned int zone;
                    124: 
                    125:                                        /*
                    126:                                         * sin6_scope_id is still not provided,
                    127:                                         * but the corresponding interface name
                    128:                                         * is know.  Use the interface ID as
                    129:                                         * the link ID.
                    130:                                         */
                    131:                                        zone = if_nametoindex(ifname);
                    132:                                        if (zone != 0) {
                    133:                                                isc_netaddr_setzone(dst,
                    134:                                                                    (isc_uint32_t)zone);
                    135:                                        }
                    136: #endif
                    137:                                }
                    138:                        }
                    139:                }
                    140: #endif
                    141:                break;
                    142:        default:
                    143:                INSIST(0);
                    144:                break;
                    145:        }
                    146: }
                    147: 
                    148: /*
                    149:  * Include system-dependent code.
                    150:  */
                    151: 
                    152: #ifdef __linux
                    153: #define ISC_IF_INET6_SZ \
                    154:     sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
                    155: static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
                    156: static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
                    157: static void linux_if_inet6_first(isc_interfaceiter_t *iter);
                    158: #endif
                    159: 
                    160: #if HAVE_GETIFADDRS
                    161: #include "ifiter_getifaddrs.c"
                    162: #elif HAVE_IFLIST_SYSCTL
                    163: #include "ifiter_sysctl.c"
                    164: #else
                    165: #include "ifiter_ioctl.c"
                    166: #endif
                    167: 
                    168: #ifdef __linux
                    169: static void
                    170: linux_if_inet6_first(isc_interfaceiter_t *iter) {
                    171:        if (iter->proc != NULL) {
                    172:                rewind(iter->proc);
                    173:                (void)linux_if_inet6_next(iter);
                    174:        } else
                    175:                iter->valid = ISC_R_NOMORE;
                    176: }
                    177: 
                    178: static isc_result_t
                    179: linux_if_inet6_next(isc_interfaceiter_t *iter) {
                    180:        if (iter->proc != NULL &&
                    181:            fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
                    182:                iter->valid = ISC_R_SUCCESS;
                    183:        else
                    184:                iter->valid = ISC_R_NOMORE;
                    185:        return (iter->valid);
                    186: }
                    187: 
                    188: static isc_result_t
                    189: linux_if_inet6_current(isc_interfaceiter_t *iter) {
                    190:        char address[33];
                    191:        char name[IF_NAMESIZE+1];
                    192:        char strbuf[ISC_STRERRORSIZE];
                    193:        struct in6_addr addr6;
                    194:        unsigned int ifindex;
                    195:        int prefix, scope, flags;
                    196:        struct ifreq ifreq;
                    197:        int res;
                    198:        unsigned int i;
                    199: 
                    200:        if (iter->valid != ISC_R_SUCCESS)
                    201:                return (iter->valid);
                    202:        if (iter->proc == NULL) {
                    203:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
                    204:                              ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
                    205:                              "/proc/net/if_inet6:iter->proc == NULL");
                    206:                return (ISC_R_FAILURE);
                    207:        }
                    208: 
                    209:        res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
                    210:                     address, &ifindex, &prefix, &scope, &flags, name);
                    211:        if (res != 6) {
                    212:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
                    213:                              ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
                    214:                              "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
                    215:                              res);
                    216:                return (ISC_R_FAILURE);
                    217:        }
                    218:        if (strlen(address) != 32) {
                    219:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
                    220:                              ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
                    221:                              "/proc/net/if_inet6:strlen(%s) != 32", address);
                    222:                return (ISC_R_FAILURE);
                    223:        }
                    224:        /*
                    225:        ** Ignore DAD addresses --
                    226:        ** we can't bind to them until they are resolved
                    227:        */
                    228: #ifdef IFA_F_TENTATIVE
                    229:        if (flags & IFA_F_TENTATIVE)
                    230:                return (ISC_R_IGNORE);
                    231: #endif
                    232: 
                    233:        for (i = 0; i < 16; i++) {
                    234:                unsigned char byte;
                    235:                static const char hex[] = "0123456789abcdef";
                    236:                byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
                    237:                       (strchr(hex, address[i * 2 + 1]) - hex);
                    238:                addr6.s6_addr[i] = byte;
                    239:        }
                    240:        iter->current.af = AF_INET6;
                    241:        iter->current.flags = 0;
                    242:        memset(&ifreq, 0, sizeof(ifreq));
                    243:        INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
                    244:        strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
                    245: 
                    246:        if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
                    247:                isc__strerror(errno, strbuf, sizeof(strbuf));
                    248:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                    249:                                "%s: getting interface flags: %s",
                    250:                                ifreq.ifr_name, strbuf);
                    251:                return (ISC_R_IGNORE);
                    252:        }
                    253: 
                    254:        if ((ifreq.ifr_flags & IFF_UP) != 0)
                    255:                iter->current.flags |= INTERFACE_F_UP;
                    256: #ifdef IFF_POINTOPOINT
                    257:        if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
                    258:                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
                    259: #endif
                    260:        if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
                    261:                iter->current.flags |= INTERFACE_F_LOOPBACK;
                    262:        if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
                    263:                iter->current.flags |= INTERFACE_F_BROADCAST;
                    264: #ifdef IFF_MULTICAST
                    265:        if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
                    266:                iter->current.flags |= INTERFACE_F_MULTICAST;
                    267: #endif
                    268: 
                    269:        isc_netaddr_fromin6(&iter->current.address, &addr6);
                    270:        iter->current.ifindex = ifindex;
                    271:        if (isc_netaddr_islinklocal(&iter->current.address)) {
                    272:                isc_netaddr_setzone(&iter->current.address,
                    273:                                    (isc_uint32_t)ifindex);
                    274:        }
                    275:        for (i = 0; i < 16; i++) {
                    276:                if (prefix > 8) {
                    277:                        addr6.s6_addr[i] = 0xff;
                    278:                        prefix -= 8;
                    279:                } else {
                    280:                        addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
                    281:                        prefix = 0;
                    282:                }
                    283:        }
                    284:        isc_netaddr_fromin6(&iter->current.netmask, &addr6);
                    285:        strncpy(iter->current.name, name, sizeof(iter->current.name));
                    286:        return (ISC_R_SUCCESS);
                    287: }
                    288: #endif
                    289: 
                    290: /*
                    291:  * The remaining code is common to the sysctl and ioctl case.
                    292:  */
                    293: 
                    294: isc_result_t
                    295: isc_interfaceiter_current(isc_interfaceiter_t *iter,
                    296:                          isc_interface_t *ifdata)
                    297: {
                    298:        REQUIRE(iter->result == ISC_R_SUCCESS);
                    299:        memcpy(ifdata, &iter->current, sizeof(*ifdata));
                    300:        return (ISC_R_SUCCESS);
                    301: }
                    302: 
                    303: isc_result_t
                    304: isc_interfaceiter_first(isc_interfaceiter_t *iter) {
                    305:        isc_result_t result;
                    306: 
                    307:        REQUIRE(VALID_IFITER(iter));
                    308: 
                    309:        internal_first(iter);
                    310:        for (;;) {
                    311:                result = internal_current(iter);
                    312:                if (result != ISC_R_IGNORE)
                    313:                        break;
                    314:                result = internal_next(iter);
                    315:                if (result != ISC_R_SUCCESS)
                    316:                        break;
                    317:        }
                    318:        iter->result = result;
                    319:        return (result);
                    320: }
                    321: 
                    322: isc_result_t
                    323: isc_interfaceiter_next(isc_interfaceiter_t *iter) {
                    324:        isc_result_t result;
                    325: 
                    326:        REQUIRE(VALID_IFITER(iter));
                    327:        REQUIRE(iter->result == ISC_R_SUCCESS);
                    328: 
                    329:        for (;;) {
                    330:                result = internal_next(iter);
                    331:                if (result != ISC_R_SUCCESS)
                    332:                        break;
                    333:                result = internal_current(iter);
                    334:                if (result != ISC_R_IGNORE)
                    335:                        break;
                    336:        }
                    337:        iter->result = result;
                    338:        return (result);
                    339: }
                    340: 
                    341: void
                    342: isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
                    343: {
                    344:        isc_interfaceiter_t *iter;
                    345:        REQUIRE(iterp != NULL);
                    346:        iter = *iterp;
                    347:        REQUIRE(VALID_IFITER(iter));
                    348: 
                    349:        internal_destroy(iter);
                    350:        if (iter->buf != NULL)
                    351:                isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
                    352: 
                    353:        iter->magic = 0;
                    354:        isc_mem_put(iter->mctx, iter, sizeof(*iter));
                    355:        *iterp = NULL;
                    356: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>