Annotation of embedaddon/ntp/lib/isc/win32/interfaceiter.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
        !             3:  * Copyright (C) 1999-2001  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.13.110.2 2009/01/18 23:47:41 tbox Exp $ */
        !            19: 
        !            20: #include <config.h>
        !            21: #include <winsock2.h>
        !            22: #include <ws2tcpip.h>
        !            23: #include <iphlpapi.h>
        !            24: #include <sys/types.h>
        !            25: 
        !            26: #include <stdio.h>
        !            27: #include <stdlib.h>
        !            28: #include <errno.h>
        !            29: 
        !            30: #include <isc/interfaceiter.h>
        !            31: #include <isc/mem.h>
        !            32: #include <isc/result.h>
        !            33: #include <isc/string.h>
        !            34: #include <isc/strerror.h>
        !            35: #include <isc/types.h>
        !            36: #include <isc/util.h>
        !            37: #include <isc/win32os.h>
        !            38: 
        !            39: void InitSockets(void);
        !            40: 
        !            41: 
        !            42: #define IFITER_MAGIC           0x49464954U     /* IFIT. */
        !            43: #define VALID_IFITER(t)                ((t) != NULL && (t)->magic == IFITER_MAGIC)
        !            44: 
        !            45: struct isc_interfaceiter {
        !            46:        unsigned int            magic;          /* Magic number. */
        !            47:        /* common fields */
        !            48:        isc_mem_t               *mctx;
        !            49:        isc_interface_t         current;        /* Current interface data. */
        !            50:        isc_result_t            result;         /* Last result code. */
        !            51:        /* fields used if GetAdaptersAddresses is available at runtime */
        !            52:        IP_ADAPTER_ADDRESSES *  ipaa;           /* GAA() result buffer */
        !            53:        ULONG                   ipaasize;       /* Bytes allocated */
        !            54:        IP_ADAPTER_ADDRESSES *  ipaaCur;        /* enumeration position */
        !            55:        IP_ADAPTER_UNICAST_ADDRESS *ipuaCur;    /* enumeration subposition */
        !            56:        /* fields used for the older address enumeration ioctls */
        !            57:        int                     socket;
        !            58:        INTERFACE_INFO          IFData;         /* Current Interface Info */
        !            59:        int                     numIF;          /* Current Interface count */
        !            60:        int                     v4IF;           /* Number of IPv4 Interfaces */
        !            61:        INTERFACE_INFO          *buf4;          /* Buffer for WSAIoctl data. */
        !            62:        unsigned int            buf4size;       /* Bytes allocated. */
        !            63:        INTERFACE_INFO          *pos4;          /* Current offset in IF List */
        !            64:        SOCKET_ADDRESS_LIST     *buf6;
        !            65:        unsigned int            buf6size;       /* Bytes allocated. */
        !            66:        unsigned int            pos6;           /* buf6 index, counts down */
        !            67:        struct in6_addr         loop__1;        /* ::1 node-scope localhost */
        !            68:        struct in6_addr         loopfe80__1;    /* fe80::1 link-scope localhost */
        !            69: };
        !            70: 
        !            71: typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)(
        !            72:     ULONG Family,
        !            73:     ULONG Flags,
        !            74:     PVOID Reserved,
        !            75:     PIP_ADAPTER_ADDRESSES AdapterAddresses,
        !            76:     PULONG SizePointer
        !            77: );
        !            78: 
        !            79: static isc_boolean_t           use_GAA;
        !            80: static isc_boolean_t           use_GAA_determined;
        !            81: static HMODULE                 hmod_iphlpapi;
        !            82: static PGETADAPTERSADDRESSES   pGAA;
        !            83: 
        !            84: 
        !            85: /*
        !            86:  * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
        !            87:  * We assume no sane system will have more than than 1K of IP addresses on
        !            88:  * all of its adapters.
        !            89:  */
        !            90: #define IFCONF_SIZE_INITIAL      16
        !            91: #define IFCONF_SIZE_INCREMENT    64
        !            92: #define IFCONF_SIZE_MAX                1040
        !            93: 
        !            94: 
        !            95: /* Common utility functions */
        !            96: 
        !            97: /*
        !            98:  * Windows always provides 255.255.255.255 as the the broadcast
        !            99:  * address.  ntpd needs to know the broadcast address which will target
        !           100:  * only that network interface, not all.  Reconstruct it from the
        !           101:  * address and mask.
        !           102:  */
        !           103: static void
        !           104: get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) {
        !           105: 
        !           106:        isc_uint32_t *  b;
        !           107:        isc_uint32_t    a, n;
        !           108: 
        !           109:        b = (isc_uint32_t *)&bcastaddr->type.in;
        !           110:        a = *(isc_uint32_t *)&addr->type.in;
        !           111:        n = *(isc_uint32_t *)&netmask->type.in;
        !           112: 
        !           113:        *b = a | ~n;
        !           114: }
        !           115: 
        !           116: isc_result_t
        !           117: isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
        !           118:        char strbuf[ISC_STRERRORSIZE];
        !           119:        isc_interfaceiter_t *iter;
        !           120:        isc_result_t result;
        !           121:        unsigned int major;
        !           122:        unsigned int minor;
        !           123:        unsigned int spmajor;
        !           124:        ULONG err;
        !           125:        int tries;
        !           126:        int error;
        !           127:        unsigned long bytesReturned = 0;
        !           128: 
        !           129:        REQUIRE(mctx != NULL);
        !           130:        REQUIRE(iterp != NULL);
        !           131:        REQUIRE(*iterp == NULL);
        !           132: 
        !           133:        iter = isc_mem_get(mctx, sizeof(*iter));
        !           134:        if (iter == NULL)
        !           135:                return (ISC_R_NOMEMORY);
        !           136: 
        !           137:        InitSockets();
        !           138: 
        !           139:        iter->mctx = mctx;
        !           140:        iter->ipaa = NULL;
        !           141:        iter->buf4 = NULL;
        !           142:        iter->buf6 = NULL;
        !           143:        iter->pos4 = NULL;
        !           144:        iter->ipaaCur = NULL;
        !           145:        iter->ipuaCur = NULL;
        !           146:        iter->ipaasize = 0;
        !           147:        iter->pos6 = 0;
        !           148:        iter->buf6size = 0;
        !           149:        iter->buf4size = 0;
        !           150:        iter->result = ISC_R_FAILURE;
        !           151:        iter->numIF = 0;
        !           152:        iter->v4IF = 0;
        !           153: 
        !           154:        /*
        !           155:         * Use GetAdaptersAddresses in preference to ioctls when running
        !           156:         * on Windows XP SP1 or later.  Earlier GetAdaptersAddresses do
        !           157:         * not appear to provide enough information to associate unicast
        !           158:         * addresses with their prefixes.
        !           159:         */
        !           160:        if (!use_GAA_determined) {
        !           161:                major = isc_win32os_majorversion();
        !           162:                minor = isc_win32os_minorversion();
        !           163:                spmajor = isc_win32os_servicepackmajor();
        !           164:                if (major > 5 || (5 == major &&
        !           165:                    (minor > 1 || (1 == minor && spmajor >= 1)))) {
        !           166:                        if (NULL == hmod_iphlpapi)
        !           167:                                hmod_iphlpapi = LoadLibrary("iphlpapi");
        !           168:                        if (NULL != hmod_iphlpapi)
        !           169:                                pGAA = (PGETADAPTERSADDRESSES)
        !           170:                                    GetProcAddress(
        !           171:                                        hmod_iphlpapi,
        !           172:                                        "GetAdaptersAddresses");
        !           173:                        if (NULL != pGAA)
        !           174:                                use_GAA = ISC_TRUE;
        !           175:                }
        !           176:                use_GAA_determined = ISC_TRUE;
        !           177:        }
        !           178: 
        !           179:        if (!use_GAA)
        !           180:                goto use_ioctls;
        !           181: 
        !           182:        iter->ipaasize = 16 * 1024;
        !           183: 
        !           184:        for (tries = 0; tries < 5; tries++) {
        !           185:                iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa,
        !           186:                                                 iter->ipaasize);
        !           187:                if (NULL == iter->ipaa) {
        !           188:                        result = ISC_R_NOMEMORY;
        !           189:                        goto put_iter;
        !           190:                }
        !           191:                err = (*pGAA)(
        !           192:                        AF_UNSPEC,
        !           193:                        GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST,
        !           194:                        NULL,
        !           195:                        iter->ipaa,
        !           196:                        &iter->ipaasize);
        !           197:                if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err)
        !           198:                        break;
        !           199:        }
        !           200: 
        !           201:        if (NO_ERROR != err) {
        !           202:                isc__strerror(err, strbuf, sizeof(strbuf));
        !           203:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           204:                                "GetAdaptersAddresses: %s",
        !           205:                                strbuf);
        !           206:                result = ISC_R_UNEXPECTED;
        !           207:                goto gaa_failure;
        !           208:        }
        !           209:        
        !           210:        iter->ipaaCur = iter->ipaa;
        !           211:        goto success;
        !           212: 
        !           213:  use_ioctls:
        !           214:        /*
        !           215:         * Create an unbound datagram socket to do the
        !           216:         * SIO_GET_INTERFACE_LIST WSAIoctl on.
        !           217:         */
        !           218:        if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        !           219:                error = WSAGetLastError();
        !           220:                if (error == WSAEAFNOSUPPORT)
        !           221:                        goto inet6_only;
        !           222:                isc__strerror(error, strbuf, sizeof(strbuf));
        !           223:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           224:                                "making interface scan socket: %s",
        !           225:                                strbuf);
        !           226:                result = ISC_R_UNEXPECTED;
        !           227:                goto put_iter;
        !           228:        }
        !           229: 
        !           230:        /*
        !           231:         * Get the interface configuration, allocating more memory if
        !           232:         * necessary.
        !           233:         */
        !           234:        iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
        !           235: 
        !           236:        for (;;) {
        !           237:                iter->buf4 = isc_mem_get(mctx, iter->buf4size);
        !           238:                if (iter->buf4 == NULL) {
        !           239:                        result = ISC_R_NOMEMORY;
        !           240:                        goto alloc_failure;
        !           241:                }
        !           242: 
        !           243:                if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
        !           244:                             0, 0, iter->buf4, iter->buf4size,
        !           245:                             &bytesReturned, 0, 0) == SOCKET_ERROR)
        !           246:                {
        !           247:                        error = WSAGetLastError();
        !           248:                        if (error != WSAEFAULT && error != WSAENOBUFS) {
        !           249:                                errno = error;
        !           250:                                isc__strerror(error, strbuf, sizeof(strbuf));
        !           251:                                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           252:                                                "get interface configuration: %s",
        !           253:                                                strbuf);
        !           254:                                result = ISC_R_UNEXPECTED;
        !           255:                                goto ioctl_failure;
        !           256:                        }
        !           257:                        /*
        !           258:                         * EINVAL.  Retry with a bigger buffer.
        !           259:                         */
        !           260:                } else {
        !           261:                        /*
        !           262:                         * The WSAIoctl succeeded.
        !           263:                         * If the number of the returned bytes is the same
        !           264:                         * as the buffer size, we will grow it just in
        !           265:                         * case and retry.
        !           266:                         */
        !           267:                        if (bytesReturned > 0 &&
        !           268:                            (bytesReturned < iter->buf4size))
        !           269:                                break;
        !           270:                }
        !           271:                if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
        !           272:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           273:                                         "get interface configuration: "
        !           274:                                         "maximum buffer size exceeded");
        !           275:                        result = ISC_R_UNEXPECTED;
        !           276:                        goto ioctl_failure;
        !           277:                }
        !           278:                isc_mem_put(mctx, iter->buf4, iter->buf4size);
        !           279: 
        !           280:                iter->buf4size += IFCONF_SIZE_INCREMENT *
        !           281:                        sizeof(INTERFACE_INFO);
        !           282:        }
        !           283: 
        !           284:        /*
        !           285:         * A newly created iterator has an undefined position
        !           286:         * until isc_interfaceiter_first() is called.
        !           287:         */
        !           288:        iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
        !           289: 
        !           290:        /* We don't need the socket any more, so close it */
        !           291:        closesocket(iter->socket);
        !           292: 
        !           293:  inet6_only:
        !           294:        /*
        !           295:         * Create an unbound datagram socket to do the
        !           296:         * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
        !           297:         */
        !           298:        if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
        !           299:                error = WSAGetLastError();
        !           300:                if (error == WSAEAFNOSUPPORT)
        !           301:                        goto success;
        !           302:                isc__strerror(error, strbuf, sizeof(strbuf));
        !           303:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           304:                                "making interface scan socket: %s",
        !           305:                                strbuf);
        !           306:                result = ISC_R_UNEXPECTED;
        !           307:                goto put_iter;
        !           308:        }
        !           309: 
        !           310:        /*
        !           311:         * Get the interface configuration, allocating more memory if
        !           312:         * necessary.
        !           313:         */
        !           314:        iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
        !           315:                         IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
        !           316: 
        !           317:        for (;;) {
        !           318:                iter->buf6 = isc_mem_get(mctx, iter->buf6size);
        !           319:                if (iter->buf6 == NULL) {
        !           320:                        result = ISC_R_NOMEMORY;
        !           321:                        goto ioctl_failure;
        !           322:                }
        !           323: 
        !           324:                if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
        !           325:                             0, 0, iter->buf6, iter->buf6size,
        !           326:                             &bytesReturned, 0, 0) == SOCKET_ERROR)
        !           327:                {
        !           328:                        error = WSAGetLastError();
        !           329:                        if (error != WSAEFAULT && error != WSAENOBUFS) {
        !           330:                                errno = error;
        !           331:                                isc__strerror(error, strbuf, sizeof(strbuf));
        !           332:                                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           333:                                                 "sio address list query: %s",
        !           334:                                                 strbuf);
        !           335:                                result = ISC_R_UNEXPECTED;
        !           336:                                goto ioctl6_failure;
        !           337:                        }
        !           338:                        /*
        !           339:                         * EINVAL.  Retry with a bigger buffer.
        !           340:                         */
        !           341:                } else
        !           342:                        break;
        !           343: 
        !           344:                if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
        !           345:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           346:                                         "get interface configuration: "
        !           347:                                         "maximum buffer size exceeded");
        !           348:                        result = ISC_R_UNEXPECTED;
        !           349:                        goto ioctl6_failure;
        !           350:                }
        !           351:                isc_mem_put(mctx, iter->buf6, iter->buf6size);
        !           352: 
        !           353:                iter->buf6size += IFCONF_SIZE_INCREMENT *
        !           354:                        sizeof(SOCKET_ADDRESS);
        !           355:        }
        !           356: 
        !           357:        /*
        !           358:         * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1].
        !           359:         * used by internal_current6().
        !           360:         */
        !           361:        memset(&iter->loop__1, 0, sizeof(iter->loop__1));
        !           362:        memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1));
        !           363:        iter->loop__1.s6_addr[15] = 1;
        !           364:        iter->loopfe80__1.s6_addr[15] = 1;
        !           365:        iter->loopfe80__1.s6_addr[0] = 0xfe;
        !           366:        iter->loopfe80__1.s6_addr[1] = 0x80;
        !           367: 
        !           368:        closesocket(iter->socket);
        !           369: 
        !           370:  success:
        !           371:        iter->magic = IFITER_MAGIC;
        !           372:        *iterp = iter;
        !           373:        return (ISC_R_SUCCESS);
        !           374: 
        !           375:  gaa_failure:
        !           376:        isc_mem_put(mctx, iter->ipaa, iter->ipaasize);
        !           377:        goto put_iter;
        !           378: 
        !           379:  ioctl6_failure:
        !           380:        isc_mem_put(mctx, iter->buf6, iter->buf6size);
        !           381: 
        !           382:  ioctl_failure:
        !           383:        if (iter->buf4 != NULL)
        !           384:                isc_mem_put(mctx, iter->buf4, iter->buf4size);
        !           385: 
        !           386:  alloc_failure:
        !           387:        if (iter->socket >= 0)
        !           388:                (void) closesocket(iter->socket);
        !           389: 
        !           390:  put_iter:
        !           391:        isc_mem_put(mctx, iter, sizeof(*iter));
        !           392:        return (result);
        !           393: }
        !           394: 
        !           395: static unsigned char
        !           396: GAA_find_prefix(isc_interfaceiter_t *iter) {
        !           397:        IP_ADAPTER_PREFIX *     ipap;
        !           398:        IP_ADAPTER_PREFIX *     ipap_match;
        !           399:        int                     match_len;
        !           400:        int                     max_len;
        !           401:        isc_netaddr_t           target;
        !           402:        u_short                 af;
        !           403:        isc_netaddr_t           pfx;
        !           404:        int                     pfx_len;
        !           405:        size_t                  nbytes;
        !           406:        unsigned char           nbits;
        !           407:        unsigned char *         pbits;
        !           408:        unsigned int            octets;
        !           409: 
        !           410:        match_len = 0;
        !           411:        ipap_match = NULL;
        !           412:        isc_netaddr_fromsockaddr(&target,
        !           413:            (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr);
        !           414:        af = (u_short)target.family;
        !           415:        INSIST(AF_INET == af || AF_INET6 == af);
        !           416:        max_len = (AF_INET6 == af) ? 128 : 32;
        !           417:        iter->current.netmask.family = af;
        !           418:        for (ipap = iter->ipaaCur->FirstPrefix;
        !           419:             ipap != NULL;
        !           420:             ipap = ipap->Next) {
        !           421:                if (ipap->Address.lpSockaddr->sa_family != af)
        !           422:                        continue;
        !           423:                isc_netaddr_fromsockaddr(&pfx,
        !           424:                    (isc_sockaddr_t *)ipap->Address.lpSockaddr);
        !           425:                pfx_len = ipap->PrefixLength;
        !           426:                INSIST(0 <= pfx_len && pfx_len <= max_len);
        !           427:                if (pfx_len > match_len && pfx_len < max_len &&
        !           428:                    isc_netaddr_eqprefix(&target, &pfx, pfx_len)) {
        !           429:                        ipap_match = ipap;
        !           430:                        match_len = pfx_len;
        !           431:                }
        !           432:        }
        !           433:        if (NULL == ipap_match) {
        !           434:                /* presume all-ones mask */
        !           435:                if (AF_INET6 == af)
        !           436:                        octets = sizeof(iter->current.netmask.type.in6);
        !           437:                else
        !           438:                        octets = sizeof(iter->current.netmask.type.in);
        !           439:                memset(&iter->current.netmask.type, 0xFF, octets);
        !           440:                return (8 * (unsigned char)octets);
        !           441:        }
        !           442:        nbytes = match_len / 8;
        !           443:        nbits = match_len % 8;
        !           444:        memset(&iter->current.netmask.type.in6, 0xFF, nbytes);
        !           445:        pbits = (void *)&iter->current.netmask.type.in6;
        !           446:        pbits += nbytes;
        !           447:        *pbits |= 0xFF << (8 - nbits);
        !           448:        return ((unsigned char)match_len);
        !           449: }
        !           450: 
        !           451: static isc_result_t
        !           452: internal_current_GAA(isc_interfaceiter_t *iter) {
        !           453:        IP_ADAPTER_ADDRESSES *adap;
        !           454:        IP_ADAPTER_UNICAST_ADDRESS *addr;
        !           455:        unsigned char prefix_len;
        !           456: 
        !           457:        REQUIRE(iter->ipaaCur != NULL);
        !           458:        REQUIRE(iter->ipuaCur != NULL);
        !           459:        adap = iter->ipaaCur;
        !           460:        addr = iter->ipuaCur;
        !           461:        if (IpDadStatePreferred != addr->DadState)
        !           462:                return (ISC_R_IGNORE);
        !           463:        memset(&iter->current, 0, sizeof(iter->current));
        !           464:        iter->current.af = addr->Address.lpSockaddr->sa_family;
        !           465:        isc_netaddr_fromsockaddr(&iter->current.address,
        !           466:            (isc_sockaddr_t *)addr->Address.lpSockaddr);
        !           467:        if (AF_INET6 == iter->current.af)
        !           468:                iter->current.ifindex = adap->Ipv6IfIndex;
        !           469:        iter->current.name[0] = '\0';
        !           470:        WideCharToMultiByte(
        !           471:                CP_ACP, 
        !           472:                0, 
        !           473:                adap->FriendlyName,
        !           474:                -1,
        !           475:                iter->current.name,
        !           476:                sizeof(iter->current.name),
        !           477:                NULL,
        !           478:                NULL);
        !           479:        iter->current.name[sizeof(iter->current.name) - 1] = '\0';
        !           480:        if (IfOperStatusUp == adap->OperStatus)
        !           481:                iter->current.flags |= INTERFACE_F_UP;
        !           482:        if (IF_TYPE_PPP == adap->IfType)
        !           483:                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
        !           484:        else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType)
        !           485:                iter->current.flags |= INTERFACE_F_LOOPBACK;
        !           486:        if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0)
        !           487:                iter->current.flags |= INTERFACE_F_MULTICAST;
        !           488:        if (IpSuffixOriginRandom == addr->SuffixOrigin)
        !           489:                iter->current.flags |= INTERFACE_F_PRIVACY;
        !           490: 
        !           491:        prefix_len = GAA_find_prefix(iter);
        !           492:        /* I'm failing to see a broadcast flag via GAA */
        !           493:        if (AF_INET == iter->current.af && prefix_len < 32 &&
        !           494:            (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) {
        !           495:                iter->current.flags |= INTERFACE_F_BROADCAST;
        !           496:                get_broadcastaddr(&iter->current.broadcast,
        !           497:                                  &iter->current.address,
        !           498:                                  &iter->current.netmask);
        !           499:        }
        !           500:        return (ISC_R_SUCCESS);
        !           501: }
        !           502: 
        !           503: /*
        !           504:  * Get information about the current interface to iter->current.
        !           505:  * If successful, return ISC_R_SUCCESS.
        !           506:  * If the interface has an unsupported address family, or if
        !           507:  * some operation on it fails, return ISC_R_IGNORE to make
        !           508:  * the higher-level iterator code ignore it.
        !           509:  */
        !           510: 
        !           511: static isc_result_t
        !           512: internal_current(isc_interfaceiter_t *iter) {
        !           513:        BOOL ifNamed = FALSE;
        !           514:        unsigned long flags;
        !           515: 
        !           516:        REQUIRE(VALID_IFITER(iter));
        !           517:        REQUIRE(iter->numIF >= 0);
        !           518: 
        !           519:        memset(&iter->current, 0, sizeof(iter->current));
        !           520:        iter->current.af = AF_INET;
        !           521: 
        !           522:        isc_netaddr_fromsockaddr(&iter->current.address,
        !           523:            (isc_sockaddr_t *)&(iter->IFData.iiAddress));
        !           524: 
        !           525:        /*
        !           526:         * Get interface flags.
        !           527:         */
        !           528: 
        !           529:        iter->current.flags = 0;
        !           530:        flags = iter->IFData.iiFlags;
        !           531: 
        !           532:        if ((flags & IFF_UP) != 0)
        !           533:                iter->current.flags |= INTERFACE_F_UP;
        !           534: 
        !           535:        if ((flags & IFF_BROADCAST) != 0)
        !           536:                iter->current.flags |= INTERFACE_F_BROADCAST;
        !           537: 
        !           538:        if ((flags & IFF_MULTICAST) != 0)
        !           539:                iter->current.flags |= INTERFACE_F_MULTICAST;
        !           540: 
        !           541:        if ((flags & IFF_POINTTOPOINT) != 0) {
        !           542:                iter->current.flags |= INTERFACE_F_POINTTOPOINT;
        !           543:                snprintf(iter->current.name, sizeof(iter->current.name),
        !           544:                         "PPP %d", iter->numIF);
        !           545:                ifNamed = TRUE;
        !           546:        }
        !           547: 
        !           548:        if ((flags & IFF_LOOPBACK) != 0) {
        !           549:                iter->current.flags |= INTERFACE_F_LOOPBACK;
        !           550:                snprintf(iter->current.name, sizeof(iter->current.name),
        !           551:                        "v4loop %d", iter->numIF);
        !           552:                ifNamed = TRUE;
        !           553:        }
        !           554: 
        !           555:        /*
        !           556:         * If the interface is point-to-point, get the destination address.
        !           557:         */
        !           558:        if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
        !           559:                isc_netaddr_fromsockaddr(&iter->current.dstaddress,
        !           560:                    (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress));
        !           561: 
        !           562:        /*
        !           563:         * Get the network mask.
        !           564:         */
        !           565:        isc_netaddr_fromsockaddr(&iter->current.netmask,
        !           566:            (isc_sockaddr_t *)&(iter->IFData.iiNetmask));
        !           567: 
        !           568:        /*
        !           569:         * If the interface is broadcast, get the broadcast address,
        !           570:         * based on the unicast address and network mask.
        !           571:         */
        !           572:        if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0)
        !           573:                get_broadcastaddr(&iter->current.broadcast,
        !           574:                                  &iter->current.address,
        !           575:                                  &iter->current.netmask);
        !           576: 
        !           577:        if (ifNamed == FALSE)
        !           578:                snprintf(iter->current.name, sizeof(iter->current.name),
        !           579:                        "IPv4 %d", iter->numIF);
        !           580: 
        !           581:        return (ISC_R_SUCCESS);
        !           582: }
        !           583: 
        !           584: static isc_result_t
        !           585: internal_current6(isc_interfaceiter_t *iter) {
        !           586:        BOOL ifNamed = FALSE;
        !           587:        struct sockaddr_in6 *psa6;
        !           588:        BOOL localhostSeen;
        !           589:        int i;
        !           590: 
        !           591:        REQUIRE(VALID_IFITER(iter));
        !           592:        REQUIRE(iter->pos6 >= 0);
        !           593:        REQUIRE(iter->buf6 != 0);
        !           594: 
        !           595:        memset(&iter->current, 0, sizeof(iter->current));
        !           596:        iter->current.af = AF_INET6;
        !           597: 
        !           598:        /*
        !           599:         * synthesize localhost ::1 before returning the rest, if ::1
        !           600:         * is not on the list.
        !           601:         */
        !           602:        if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) {
        !           603:                localhostSeen = FALSE;
        !           604:                for (i = 0; i < iter->buf6->iAddressCount; i++) {
        !           605:                        psa6 = (struct sockaddr_in6 *)
        !           606:                               iter->buf6->Address[i].lpSockaddr;
        !           607:                        if (!memcmp(&iter->loop__1, &psa6->sin6_addr,
        !           608:                                    sizeof(iter->loop__1))) {
        !           609:                                localhostSeen = TRUE;
        !           610:                                break;
        !           611:                        }
        !           612:                }
        !           613:                if (localhostSeen)
        !           614:                        iter->pos6 = iter->buf6->iAddressCount - 1;
        !           615:        }
        !           616: 
        !           617:        if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) {
        !           618:                isc_netaddr_fromsockaddr(&iter->current.address,
        !           619:                    (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr);
        !           620:        } else {
        !           621:                iter->current.address.family = AF_INET6;
        !           622:                memcpy(&iter->current.address.type.in6, &iter->loop__1,
        !           623:                       sizeof(iter->current.address.type.in6));
        !           624:        }
        !           625: 
        !           626:        /*
        !           627:         * Get interface flags.
        !           628:         */
        !           629: 
        !           630:        iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST;
        !           631: 
        !           632:        if (!memcmp(&iter->current.address.type.in6, &iter->loop__1,
        !           633:                    sizeof(iter->current.address.type.in6)) ||
        !           634:            !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1,
        !           635:                    sizeof(iter->current.address.type.in6))) {
        !           636: 
        !           637:                iter->current.flags |= INTERFACE_F_LOOPBACK;
        !           638:                snprintf(iter->current.name, sizeof(iter->current.name),
        !           639:                         "v6loop %d",
        !           640:                         iter->buf6->iAddressCount - iter->pos6);
        !           641:                ifNamed = TRUE;
        !           642:        }
        !           643: 
        !           644:        if (ifNamed == FALSE)
        !           645:                snprintf(iter->current.name, sizeof(iter->current.name),
        !           646:                         "IPv6 %d",
        !           647:                         iter->buf6->iAddressCount - iter->pos6);
        !           648: 
        !           649:        memset(iter->current.netmask.type.in6.s6_addr, 0xff,
        !           650:               sizeof(iter->current.netmask.type.in6.s6_addr));
        !           651:        iter->current.netmask.family = AF_INET6;
        !           652:        return (ISC_R_SUCCESS);
        !           653: }
        !           654: 
        !           655: static isc_result_t
        !           656: internal_next_GAA(isc_interfaceiter_t *iter) {
        !           657:        REQUIRE(use_GAA);
        !           658:        if (NULL == iter->ipaaCur)
        !           659:                return (ISC_R_NOMORE);
        !           660:        if (NULL == iter->ipuaCur)
        !           661:                iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress;
        !           662:        else
        !           663:                iter->ipuaCur = iter->ipuaCur->Next;
        !           664:        while (NULL == iter->ipuaCur) {
        !           665:                iter->ipaaCur = iter->ipaaCur->Next;
        !           666:                if (NULL == iter->ipaaCur)
        !           667:                        return (ISC_R_NOMORE);
        !           668:                iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress;
        !           669:        }
        !           670:        return (ISC_R_SUCCESS);
        !           671: }
        !           672: 
        !           673: /*
        !           674:  * Step the iterator to the next interface.  Unlike
        !           675:  * isc_interfaceiter_next(), this may leave the iterator
        !           676:  * positioned on an interface that will ultimately
        !           677:  * be ignored.  Return ISC_R_NOMORE if there are no more
        !           678:  * interfaces, otherwise ISC_R_SUCCESS.
        !           679:  */
        !           680: static isc_result_t
        !           681: internal_next(isc_interfaceiter_t *iter) {
        !           682:        if (iter->numIF >= iter->v4IF)
        !           683:                return (ISC_R_NOMORE);
        !           684: 
        !           685:        /*
        !           686:         * The first one needs to be set up to point to the last
        !           687:         * Element of the array.  Go to the end and back up
        !           688:         * Microsoft's implementation is peculiar for returning
        !           689:         * the list in reverse order
        !           690:         */
        !           691: 
        !           692:        if (iter->numIF == 0)
        !           693:                iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
        !           694: 
        !           695:        iter->pos4--;
        !           696:        if (&(iter->pos4) < &(iter->buf4))
        !           697:                return (ISC_R_NOMORE);
        !           698: 
        !           699:        memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
        !           700:        memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
        !           701:        iter->numIF++;
        !           702: 
        !           703:        return (ISC_R_SUCCESS);
        !           704: }
        !           705: 
        !           706: static isc_result_t
        !           707: internal_next6(isc_interfaceiter_t *iter) {
        !           708:        if (iter->pos6 == 0)
        !           709:                return (ISC_R_NOMORE);
        !           710:        iter->pos6--;
        !           711:        return (ISC_R_SUCCESS);
        !           712: }
        !           713: 
        !           714: isc_result_t
        !           715: isc_interfaceiter_current(isc_interfaceiter_t *iter,
        !           716:                          isc_interface_t *ifdata) {
        !           717:        REQUIRE(iter->result == ISC_R_SUCCESS);
        !           718:        memcpy(ifdata, &iter->current, sizeof(*ifdata));
        !           719:        return (ISC_R_SUCCESS);
        !           720: }
        !           721: 
        !           722: isc_result_t
        !           723: isc_interfaceiter_first(isc_interfaceiter_t *iter) {
        !           724:        REQUIRE(VALID_IFITER(iter));
        !           725:        REQUIRE(use_GAA_determined);
        !           726:        /*
        !           727:         * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses)
        !           728:         * intentionally omits localhost addresses [::1] and [::fe80] in
        !           729:         * some cases.  ntpd depends on enumerating [::1] to listen on
        !           730:         * it, and ntpq and ntpdc default to "localhost" as the target,
        !           731:         * so they will attempt to talk to [::1]:123 and fail. This
        !           732:         * means we need to synthesize ::1, which we will do first,
        !           733:         * hence iAddressCount + 1.  internal_next6() will decrement
        !           734:         * it before the first use as an index, and internal_current6()
        !           735:         * will treat pos6 == iAddressCount as a sign to synthesize
        !           736:         * [::1] if needed.
        !           737:         */
        !           738:        if (!use_GAA && iter->buf6 != NULL)
        !           739:                iter->pos6 = iter->buf6->iAddressCount + 1;
        !           740:        iter->result = ISC_R_SUCCESS;
        !           741:        return (isc_interfaceiter_next(iter));
        !           742: }
        !           743: 
        !           744: isc_result_t
        !           745: isc_interfaceiter_next(isc_interfaceiter_t *iter) {
        !           746:        isc_result_t result;
        !           747: 
        !           748:        REQUIRE(VALID_IFITER(iter));
        !           749:        REQUIRE(iter->result == ISC_R_SUCCESS);
        !           750:        REQUIRE(use_GAA_determined);
        !           751: 
        !           752:        if (use_GAA) {
        !           753:                do {
        !           754:                        result = internal_next_GAA(iter);
        !           755:                        if (ISC_R_NOMORE == result)
        !           756:                                goto set_result;
        !           757:                        result = internal_current_GAA(iter);
        !           758:                } while (ISC_R_IGNORE == result);
        !           759:                goto set_result;
        !           760:        }
        !           761: 
        !           762:        for (;;) {
        !           763:                result = internal_next(iter);
        !           764:                if (result == ISC_R_NOMORE) {
        !           765:                        result = internal_next6(iter);
        !           766:                        if (result != ISC_R_SUCCESS)
        !           767:                                break;
        !           768:                        result = internal_current6(iter);
        !           769:                        if (result != ISC_R_IGNORE)
        !           770:                                break;
        !           771:                } else if (result != ISC_R_SUCCESS)
        !           772:                        break;
        !           773:                result = internal_current(iter);
        !           774:                if (result != ISC_R_IGNORE)
        !           775:                        break;
        !           776:        }
        !           777:  set_result:
        !           778:        iter->result = result;
        !           779:        return (result);
        !           780: }
        !           781: 
        !           782: void
        !           783: isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
        !           784:        isc_interfaceiter_t *iter;
        !           785: 
        !           786:        REQUIRE(iterp != NULL);
        !           787:        iter = *iterp;
        !           788:        REQUIRE(VALID_IFITER(iter));
        !           789:        REQUIRE(use_GAA_determined);
        !           790: 
        !           791:        if (use_GAA) {
        !           792:                REQUIRE(NULL == iter->buf4);
        !           793:                REQUIRE(NULL == iter->buf4);
        !           794:                if (iter->ipaa != NULL)
        !           795:                        isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize);
        !           796:        } else {
        !           797:                REQUIRE(NULL == iter->ipaa);
        !           798:                if (iter->buf4 != NULL)
        !           799:                        isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
        !           800:                if (iter->buf6 != NULL)
        !           801:                        isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
        !           802:        }
        !           803: 
        !           804:        iter->magic = 0;
        !           805:        isc_mem_put(iter->mctx, iter, sizeof(*iter));
        !           806:        *iterp = NULL;
        !           807: }

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