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

1.1       misho       1: /*
                      2:  * Copyright (C) 2004, 2005, 2007  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: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp $ */
                     19: 
                     20: /*! \file
                     21:  * \brief
                     22:  * Obtain the list of network interfaces using sysctl.
                     23:  * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
                     24:  * and 19.16.
                     25:  */
                     26: 
                     27: #include <sys/param.h>
                     28: #include <sys/sysctl.h>
                     29: 
                     30: #include <net/route.h>
                     31: #include <net/if_dl.h>
                     32: 
                     33: /* XXX what about Alpha? */
                     34: #ifdef sgi
                     35: #define ROUNDUP(a) ((a) > 0 ? \
                     36:                (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \
                     37:                sizeof(__uint64_t))
                     38: #else
                     39: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
                     40:                     : sizeof(long))
                     41: #endif
                     42: 
                     43: #define IFITER_MAGIC           ISC_MAGIC('I', 'F', 'I', 'S')
                     44: #define VALID_IFITER(t)                ISC_MAGIC_VALID(t, IFITER_MAGIC)
                     45: 
                     46: struct isc_interfaceiter {
                     47:        unsigned int            magic;          /* Magic number. */
                     48:        isc_mem_t               *mctx;
                     49:        void                    *buf;           /* Buffer for sysctl data. */
                     50:        unsigned int            bufsize;        /* Bytes allocated. */
                     51:        unsigned int            bufused;        /* Bytes used. */
                     52:        unsigned int            pos;            /* Current offset in
                     53:                                                   sysctl data. */
                     54:        isc_interface_t         current;        /* Current interface data. */
                     55:        isc_result_t            result;         /* Last result code. */
                     56: };
                     57: 
                     58: static int mib[6] = {
                     59:        CTL_NET,
                     60:        PF_ROUTE,
                     61:         0,
                     62:        0,                      /* Any address family. */
                     63:         NET_RT_IFLIST,
                     64:        0                       /* Flags. */
                     65: };
                     66: 
                     67: isc_result_t
                     68: isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
                     69:        isc_interfaceiter_t *iter;
                     70:        isc_result_t result;
                     71:        size_t bufsize;
                     72:        size_t bufused;
                     73:        char strbuf[ISC_STRERRORSIZE];
                     74: 
                     75:        REQUIRE(mctx != NULL);
                     76:        REQUIRE(iterp != NULL);
                     77:        REQUIRE(*iterp == NULL);
                     78: 
                     79:        iter = isc_mem_get(mctx, sizeof(*iter));
                     80:        if (iter == NULL)
                     81:                return (ISC_R_NOMEMORY);
                     82: 
                     83:        iter->mctx = mctx;
                     84:        iter->buf = 0;
                     85: 
                     86:        /*
                     87:         * Determine the amount of memory needed.
                     88:         */
                     89:        bufsize = 0;
                     90:        if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
                     91:                isc__strerror(errno, strbuf, sizeof(strbuf));
                     92:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                     93:                                 isc_msgcat_get(isc_msgcat,
                     94:                                                ISC_MSGSET_IFITERSYSCTL,
                     95:                                                ISC_MSG_GETIFLISTSIZE,
                     96:                                                "getting interface "
                     97:                                                "list size: sysctl: %s"),
                     98:                                 strbuf);
                     99:                result = ISC_R_UNEXPECTED;
                    100:                goto failure;
                    101:        }
                    102:        iter->bufsize = bufsize;
                    103: 
                    104:        iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
                    105:        if (iter->buf == NULL) {
                    106:                result = ISC_R_NOMEMORY;
                    107:                goto failure;
                    108:        }
                    109: 
                    110:        bufused = bufsize;
                    111:        if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
                    112:                isc__strerror(errno, strbuf, sizeof(strbuf));
                    113:                UNEXPECTED_ERROR(__FILE__, __LINE__,
                    114:                                 isc_msgcat_get(isc_msgcat,
                    115:                                                ISC_MSGSET_IFITERSYSCTL,
                    116:                                                ISC_MSG_GETIFLIST,
                    117:                                                "getting interface list: "
                    118:                                                "sysctl: %s"),
                    119:                                 strbuf);
                    120:                result = ISC_R_UNEXPECTED;
                    121:                goto failure;
                    122:        }
                    123:        iter->bufused = bufused;
                    124:        INSIST(iter->bufused <= iter->bufsize);
                    125: 
                    126:        /*
                    127:         * A newly created iterator has an undefined position
                    128:         * until isc_interfaceiter_first() is called.
                    129:         */
                    130:        iter->pos = (unsigned int) -1;
                    131:        iter->result = ISC_R_FAILURE;
                    132: 
                    133:        iter->magic = IFITER_MAGIC;
                    134:        *iterp = iter;
                    135:        return (ISC_R_SUCCESS);
                    136: 
                    137:  failure:
                    138:        if (iter->buf != NULL)
                    139:                isc_mem_put(mctx, iter->buf, iter->bufsize);
                    140:        isc_mem_put(mctx, iter, sizeof(*iter));
                    141:        return (result);
                    142: }
                    143: 
                    144: /*
                    145:  * Get information about the current interface to iter->current.
                    146:  * If successful, return ISC_R_SUCCESS.
                    147:  * If the interface has an unsupported address family,
                    148:  * return ISC_R_IGNORE.  In case of other failure,
                    149:  * return ISC_R_UNEXPECTED.
                    150:  */
                    151: 
                    152: static isc_result_t
                    153: internal_current(isc_interfaceiter_t *iter) {
                    154:        struct ifa_msghdr *ifam, *ifam_end;
                    155: 
                    156:        REQUIRE(VALID_IFITER(iter));
                    157:        REQUIRE (iter->pos < (unsigned int) iter->bufused);
                    158: 
                    159:        ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
                    160:        ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
                    161: 
                    162:        if (ifam->ifam_type == RTM_IFINFO) {
                    163:                struct if_msghdr *ifm = (struct if_msghdr *) ifam;
                    164:                struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
                    165:                unsigned int namelen;
                    166: 
                    167:                memset(&iter->current, 0, sizeof(iter->current));
                    168: 
                    169:                iter->current.ifindex = sdl->sdl_index;
                    170:                namelen = sdl->sdl_nlen;
                    171:                if (namelen > sizeof(iter->current.name) - 1)
                    172:                        namelen = sizeof(iter->current.name) - 1;
                    173: 
                    174:                memset(iter->current.name, 0, sizeof(iter->current.name));
                    175:                memcpy(iter->current.name, sdl->sdl_data, namelen);
                    176: 
                    177:                iter->current.flags = 0;
                    178: 
                    179:                if ((ifam->ifam_flags & IFF_UP) != 0)
                    180:                        iter->current.flags |= INTERFACE_F_UP;
                    181: 
                    182:                if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
                    183:                        iter->current.flags |= INTERFACE_F_POINTTOPOINT;
                    184: 
                    185:                if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
                    186:                        iter->current.flags |= INTERFACE_F_LOOPBACK;
                    187: 
                    188:                if ((ifam->ifam_flags & IFF_BROADCAST) != 0)
                    189:                        iter->current.flags |= INTERFACE_F_BROADCAST;
                    190: 
                    191: #ifdef IFF_MULTICAST
                    192:                if ((ifam->ifam_flags & IFF_MULTICAST) != 0)
                    193:                        iter->current.flags |= INTERFACE_F_MULTICAST;
                    194: #endif
                    195: 
                    196:                /*
                    197:                 * This is not an interface address.
                    198:                 * Force another iteration.
                    199:                 */
                    200:                return (ISC_R_IGNORE);
                    201:        } else if (ifam->ifam_type == RTM_NEWADDR) {
                    202:                int i;
                    203:                int family;
                    204:                struct sockaddr *mask_sa = NULL;
                    205:                struct sockaddr *addr_sa = NULL;
                    206:                struct sockaddr *dst_sa = NULL;
                    207: 
                    208:                struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
                    209:                family = sa->sa_family;
                    210: 
                    211:                for (i = 0; i < RTAX_MAX; i++)
                    212:                {
                    213:                        if ((ifam->ifam_addrs & (1 << i)) == 0)
                    214:                                continue;
                    215: 
                    216:                        INSIST(sa < (struct sockaddr *) ifam_end);
                    217: 
                    218:                        switch (i) {
                    219:                        case RTAX_NETMASK: /* Netmask */
                    220:                                mask_sa = sa;
                    221:                                break;
                    222:                        case RTAX_IFA: /* Interface address */
                    223:                                addr_sa = sa;
                    224:                                break;
                    225:                        case RTAX_BRD: /* Broadcast or destination address */
                    226:                                dst_sa = sa;
                    227:                                break;
                    228:                        }
                    229: #ifdef ISC_PLATFORM_HAVESALEN
                    230:                        sa = (struct sockaddr *)((char*)(sa)
                    231:                                         + ROUNDUP(sa->sa_len));
                    232: #else
                    233: #ifdef sgi
                    234:                        /*
                    235:                         * Do as the contributed SGI code does.
                    236:                         */
                    237:                        sa = (struct sockaddr *)((char*)(sa)
                    238:                                         + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
                    239: #else
                    240:                        /* XXX untested. */
                    241:                        sa = (struct sockaddr *)((char*)(sa)
                    242:                                         + ROUNDUP(sizeof(struct sockaddr)));
                    243: #endif
                    244: #endif
                    245:                }
                    246: 
                    247:                if (addr_sa == NULL)
                    248:                        return (ISC_R_IGNORE);
                    249: 
                    250:                family = addr_sa->sa_family;
                    251:                if (family != AF_INET && family != AF_INET6)
                    252:                        return (ISC_R_IGNORE);
                    253: 
                    254:                iter->current.af = family;
                    255: 
                    256:                get_addr(family, &iter->current.address, addr_sa,
                    257:                         iter->current.name);
                    258: 
                    259:                if (mask_sa != NULL)
                    260:                        get_addr(family, &iter->current.netmask, mask_sa,
                    261:                                 iter->current.name);
                    262: 
                    263:                if (dst_sa != NULL &&
                    264:                    (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
                    265:                        get_addr(family, &iter->current.dstaddress, dst_sa,
                    266:                                 iter->current.name);
                    267: 
                    268:                if (dst_sa != NULL &&
                    269:                    (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
                    270:                        get_addr(family, &iter->current.broadcast, dst_sa,
                    271:                                 iter->current.name);
                    272: 
                    273:                return (ISC_R_SUCCESS);
                    274:        } else {
                    275:                printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
                    276:                                      ISC_MSG_UNEXPECTEDTYPE,
                    277:                                      "warning: unexpected interface list "
                    278:                                      "message type\n"));
                    279:                return (ISC_R_IGNORE);
                    280:        }
                    281: }
                    282: 
                    283: /*
                    284:  * Step the iterator to the next interface.  Unlike
                    285:  * isc_interfaceiter_next(), this may leave the iterator
                    286:  * positioned on an interface that will ultimately
                    287:  * be ignored.  Return ISC_R_NOMORE if there are no more
                    288:  * interfaces, otherwise ISC_R_SUCCESS.
                    289:  */
                    290: static isc_result_t
                    291: internal_next(isc_interfaceiter_t *iter) {
                    292:        struct ifa_msghdr *ifam;
                    293:        REQUIRE (iter->pos < (unsigned int) iter->bufused);
                    294: 
                    295:        ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
                    296: 
                    297:        iter->pos += ifam->ifam_msglen;
                    298: 
                    299:        if (iter->pos >= iter->bufused)
                    300:                return (ISC_R_NOMORE);
                    301: 
                    302:        return (ISC_R_SUCCESS);
                    303: }
                    304: 
                    305: static void
                    306: internal_destroy(isc_interfaceiter_t *iter) {
                    307:        UNUSED(iter); /* Unused. */
                    308:        /*
                    309:         * Do nothing.
                    310:         */
                    311: }
                    312: 
                    313: static
                    314: void internal_first(isc_interfaceiter_t *iter) {
                    315:        iter->pos = 0;
                    316: }

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