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