Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_iph/kernel_iph_net.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Martin Willi
        !             3:  * Copyright (C) 2013 revosec AG
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: /* Windows 7, for some iphlpapi.h functionality */
        !            17: #define _WIN32_WINNT 0x0601
        !            18: #include <winsock2.h>
        !            19: #include <ws2ipdef.h>
        !            20: #include <windows.h>
        !            21: #include <ntddndis.h>
        !            22: #include <naptypes.h>
        !            23: #include <iphlpapi.h>
        !            24: 
        !            25: #include "kernel_iph_net.h"
        !            26: 
        !            27: #include <daemon.h>
        !            28: #include <threading/mutex.h>
        !            29: #include <collections/linked_list.h>
        !            30: #include <processing/jobs/callback_job.h>
        !            31: 
        !            32: 
        !            33: /** delay before firing roam events (ms) */
        !            34: #define ROAM_DELAY 500
        !            35: 
        !            36: typedef struct private_kernel_iph_net_t private_kernel_iph_net_t;
        !            37: 
        !            38: /**
        !            39:  * Private data of kernel_iph_net implementation.
        !            40:  */
        !            41: struct private_kernel_iph_net_t {
        !            42: 
        !            43:        /**
        !            44:         * Public interface.
        !            45:         */
        !            46:        kernel_iph_net_t public;
        !            47: 
        !            48:        /**
        !            49:         * NotifyIpInterfaceChange() handle
        !            50:         */
        !            51:        HANDLE changes;
        !            52: 
        !            53:        /**
        !            54:         * EnableRouter() OVERLAPPED
        !            55:         */
        !            56:        OVERLAPPED router;
        !            57: 
        !            58:        /**
        !            59:         * Mutex to access interface list
        !            60:         */
        !            61:        mutex_t *mutex;
        !            62: 
        !            63:        /**
        !            64:         * Known interfaces, as iface_t
        !            65:         */
        !            66:        linked_list_t *ifaces;
        !            67: 
        !            68:        /**
        !            69:         * Earliest time of the next roam event
        !            70:         */
        !            71:        timeval_t roam_next;
        !            72: 
        !            73:        /**
        !            74:         * Roam event due to address change?
        !            75:         */
        !            76:        bool roam_address;
        !            77: };
        !            78: 
        !            79: /**
        !            80:  * Interface entry
        !            81:  */
        !            82: typedef struct  {
        !            83:        /** interface index */
        !            84:        DWORD ifindex;
        !            85:        /** interface name */
        !            86:        char *ifname;
        !            87:        /** interface description */
        !            88:        char *ifdesc;
        !            89:        /** type of interface */
        !            90:        DWORD iftype;
        !            91:        /** interface status */
        !            92:        IF_OPER_STATUS status;
        !            93:        /** list of known addresses, as host_t */
        !            94:        linked_list_t *addrs;
        !            95: } iface_t;
        !            96: 
        !            97: /**
        !            98:  * Clean up an iface_t
        !            99:  */
        !           100: static void iface_destroy(iface_t *this)
        !           101: {
        !           102:        this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
        !           103:        free(this->ifname);
        !           104:        free(this->ifdesc);
        !           105:        free(this);
        !           106: }
        !           107: 
        !           108: /**
        !           109:  * Enum names for Windows IF_OPER_STATUS
        !           110:  */
        !           111: ENUM(if_oper_names, IfOperStatusUp, IfOperStatusLowerLayerDown,
        !           112:        "Up",
        !           113:        "Down",
        !           114:        "Testing",
        !           115:        "Unknown",
        !           116:        "Dormant",
        !           117:        "NotPresent",
        !           118:        "LowerLayerDown",
        !           119: );
        !           120: 
        !           121: /**
        !           122:  * Callback function that raises the delayed roam event
        !           123:  */
        !           124: static job_requeue_t roam_event(private_kernel_iph_net_t *this)
        !           125: {
        !           126:        bool address;
        !           127: 
        !           128:        this->mutex->lock(this->mutex);
        !           129:        address = this->roam_address;
        !           130:        this->roam_address = FALSE;
        !           131:        this->mutex->unlock(this->mutex);
        !           132: 
        !           133:        charon->kernel->roam(charon->kernel, address);
        !           134:        return JOB_REQUEUE_NONE;
        !           135: }
        !           136: 
        !           137: /**
        !           138:  * Fire delayed roam event, caller should hold mutex
        !           139:  */
        !           140: static void fire_roam_event(private_kernel_iph_net_t *this, bool address)
        !           141: {
        !           142:        timeval_t now;
        !           143: 
        !           144:        time_monotonic(&now);
        !           145:        this->roam_address |= address;
        !           146:        if (timercmp(&now, &this->roam_next, >))
        !           147:        {
        !           148:                timeval_add_ms(&now, ROAM_DELAY);
        !           149:                this->roam_next = now;
        !           150:                lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
        !           151:                                                        callback_job_create((callback_job_cb_t)roam_event,
        !           152:                                                                                                this, NULL, NULL),
        !           153:                                                        ROAM_DELAY);
        !           154:        }
        !           155: }
        !           156: 
        !           157: /**
        !           158:  * Update addresses for an iface entry
        !           159:  */
        !           160: static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
        !           161:                                                 IP_ADAPTER_ADDRESSES *addr, bool log)
        !           162: {
        !           163:        IP_ADAPTER_UNICAST_ADDRESS *current;
        !           164:        enumerator_t *enumerator;
        !           165:        linked_list_t *list;
        !           166:        host_t *host, *old;
        !           167:        bool changes = FALSE;
        !           168: 
        !           169:        list = entry->addrs;
        !           170:        entry->addrs = linked_list_create();
        !           171: 
        !           172:        for (current = addr->FirstUnicastAddress; current; current = current->Next)
        !           173:        {
        !           174:                if (current->Address.lpSockaddr->sa_family == AF_INET6)
        !           175:                {
        !           176:                        struct sockaddr_in6 *sin;
        !           177: 
        !           178:                        sin = (struct sockaddr_in6*)current->Address.lpSockaddr;
        !           179:                        if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
        !           180:                        {
        !           181:                                continue;
        !           182:                        }
        !           183:                }
        !           184: 
        !           185:                host = host_create_from_sockaddr(current->Address.lpSockaddr);
        !           186:                if (host)
        !           187:                {
        !           188:                        bool found = FALSE;
        !           189: 
        !           190:                        enumerator = list->create_enumerator(list);
        !           191:                        while (enumerator->enumerate(enumerator, &old))
        !           192:                        {
        !           193:                                if (host->ip_equals(host, old))
        !           194:                                {
        !           195:                                        list->remove_at(list, enumerator);
        !           196:                                        old->destroy(old);
        !           197:                                        found = TRUE;
        !           198:                                }
        !           199:                        }
        !           200:                        enumerator->destroy(enumerator);
        !           201: 
        !           202:                        entry->addrs->insert_last(entry->addrs, host);
        !           203: 
        !           204:                        if (!found && log)
        !           205:                        {
        !           206:                                DBG1(DBG_KNL, "%H appeared on interface %u '%s'",
        !           207:                                         host, entry->ifindex, entry->ifdesc);
        !           208:                                changes = TRUE;
        !           209:                        }
        !           210:                }
        !           211:        }
        !           212: 
        !           213:        while (list->remove_first(list, (void**)&old) == SUCCESS)
        !           214:        {
        !           215:                if (log)
        !           216:                {
        !           217:                        DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
        !           218:                                 old, entry->ifindex, entry->ifdesc);
        !           219:                        changes = TRUE;
        !           220:                }
        !           221:                old->destroy(old);
        !           222:        }
        !           223:        list->destroy(list);
        !           224: 
        !           225:        if (changes)
        !           226:        {
        !           227:                fire_roam_event(this, TRUE);
        !           228:        }
        !           229: }
        !           230: 
        !           231: /**
        !           232:  * Add an interface entry
        !           233:  */
        !           234: static void add_interface(private_kernel_iph_net_t *this,
        !           235:                                                  IP_ADAPTER_ADDRESSES *addr, bool log)
        !           236: {
        !           237:        enumerator_t *enumerator;
        !           238:        iface_t *entry;
        !           239:        bool exists = FALSE;
        !           240: 
        !           241:        this->mutex->lock(this->mutex);
        !           242:        enumerator = this->ifaces->create_enumerator(this->ifaces);
        !           243:        while (enumerator->enumerate(enumerator, &entry))
        !           244:        {
        !           245:                if (entry->ifindex == addr->IfIndex)
        !           246:                {
        !           247:                        exists = TRUE;
        !           248:                        break;
        !           249:                }
        !           250:        }
        !           251:        enumerator->destroy(enumerator);
        !           252:        this->mutex->unlock(this->mutex);
        !           253: 
        !           254:        if (!exists)
        !           255:        {
        !           256:                char desc[128] = "";
        !           257: 
        !           258:                wcstombs(desc, addr->Description, sizeof(desc));
        !           259: 
        !           260:                INIT(entry,
        !           261:                        .ifindex = addr->IfIndex,
        !           262:                        .ifname = strdup(addr->AdapterName),
        !           263:                        .ifdesc = strdup(desc),
        !           264:                        .iftype = addr->IfType,
        !           265:                        .status = addr->OperStatus,
        !           266:                        .addrs = linked_list_create(),
        !           267:                );
        !           268: 
        !           269:                if (log)
        !           270:                {
        !           271:                        DBG1(DBG_KNL, "interface %u '%s' appeared",
        !           272:                                 entry->ifindex, entry->ifdesc);
        !           273:                }
        !           274: 
        !           275:                this->mutex->lock(this->mutex);
        !           276:                update_addrs(this, entry, addr, log);
        !           277:                this->ifaces->insert_last(this->ifaces, entry);
        !           278:                this->mutex->unlock(this->mutex);
        !           279:        }
        !           280: }
        !           281: 
        !           282: /**
        !           283:  * Remove an interface entry that is gone
        !           284:  */
        !           285: static void remove_interface(private_kernel_iph_net_t *this, NET_IFINDEX index)
        !           286: {
        !           287:        enumerator_t *enumerator;
        !           288:        iface_t *entry;
        !           289: 
        !           290:        this->mutex->lock(this->mutex);
        !           291:        enumerator = this->ifaces->create_enumerator(this->ifaces);
        !           292:        while (enumerator->enumerate(enumerator, &entry))
        !           293:        {
        !           294:                if (entry->ifindex == index)
        !           295:                {
        !           296:                        this->ifaces->remove_at(this->ifaces, enumerator);
        !           297:                        DBG1(DBG_KNL, "interface %u '%s' disappeared",
        !           298:                                 entry->ifindex, entry->ifdesc);
        !           299:                        iface_destroy(entry);
        !           300:                        fire_roam_event(this, TRUE);
        !           301:                }
        !           302:        }
        !           303:        enumerator->destroy(enumerator);
        !           304:        this->mutex->unlock(this->mutex);
        !           305: }
        !           306: 
        !           307: /**
        !           308:  * Update an interface entry changed
        !           309:  */
        !           310: static void update_interface(private_kernel_iph_net_t *this,
        !           311:                                                         IP_ADAPTER_ADDRESSES *addr)
        !           312: {
        !           313:        enumerator_t *enumerator;
        !           314:        iface_t *entry;
        !           315: 
        !           316:        this->mutex->lock(this->mutex);
        !           317:        enumerator = this->ifaces->create_enumerator(this->ifaces);
        !           318:        while (enumerator->enumerate(enumerator, &entry))
        !           319:        {
        !           320:                if (entry->ifindex == addr->IfIndex)
        !           321:                {
        !           322:                        if (entry->status != addr->OperStatus)
        !           323:                        {
        !           324:                                DBG1(DBG_KNL, "interface %u '%s' changed state from %N to %N",
        !           325:                                         entry->ifindex, entry->ifdesc, if_oper_names,
        !           326:                                         entry->status, if_oper_names, addr->OperStatus);
        !           327:                                entry->status = addr->OperStatus;
        !           328:                                fire_roam_event(this, TRUE);
        !           329:                        }
        !           330:                        update_addrs(this, entry, addr, TRUE);
        !           331:                }
        !           332:        }
        !           333:        enumerator->destroy(enumerator);
        !           334:        this->mutex->unlock(this->mutex);
        !           335: }
        !           336: 
        !           337: /**
        !           338:  * MinGW gets MIB_IPINTERFACE_ROW wrong, as it packs InterfaceLuid just after
        !           339:  * Family. Fix that with our own version of the struct header.
        !           340:  */
        !           341: typedef struct {
        !           342:        ADDRESS_FAMILY Family;
        !           343:        union {
        !           344:                ULONG64 Value;
        !           345:                struct {
        !           346:                        ULONG64 Reserved :24;
        !           347:                        ULONG64 NetLuidIndex :24;
        !           348:                        ULONG64 IfType :16;
        !           349:                } Info;
        !           350:        } InterfaceLuid;
        !           351:        NET_IFINDEX InterfaceIndex;
        !           352:        /* more would go here if needed */
        !           353: } MIB_IPINTERFACE_ROW_FIXUP;
        !           354: 
        !           355: /**
        !           356:  * NotifyIpInterfaceChange() callback
        !           357:  */
        !           358: static void WINAPI change_interface(void *user, PMIB_IPINTERFACE_ROW row_badal,
        !           359:                                                                        MIB_NOTIFICATION_TYPE type)
        !           360: {
        !           361:        private_kernel_iph_net_t *this = user;
        !           362:        MIB_IPINTERFACE_ROW_FIXUP* row = (MIB_IPINTERFACE_ROW_FIXUP*)row_badal;
        !           363:        IP_ADAPTER_ADDRESSES addrs[64], *current;
        !           364:        ULONG res, size = sizeof(addrs);
        !           365: 
        !           366:        if (row && type == MibDeleteInstance)
        !           367:        {
        !           368:                remove_interface(this, row->InterfaceIndex);
        !           369:        }
        !           370:        else
        !           371:        {
        !           372:                res = GetAdaptersAddresses(AF_UNSPEC,
        !           373:                                                GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
        !           374:                                                GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
        !           375:                                                NULL, addrs, &size);
        !           376:                if (res == NO_ERROR)
        !           377:                {
        !           378:                        current = addrs;
        !           379:                        while (current)
        !           380:                        {
        !           381:                                /* row is NULL only on MibInitialNotification */
        !           382:                                if (!row || row->InterfaceIndex == current->IfIndex)
        !           383:                                {
        !           384:                                        switch (type)
        !           385:                                        {
        !           386:                                                case MibParameterNotification:
        !           387:                                                        update_interface(this, current);
        !           388:                                                        break;
        !           389:                                                case MibInitialNotification:
        !           390:                                                        add_interface(this, current, FALSE);
        !           391:                                                        break;
        !           392:                                                case MibAddInstance:
        !           393:                                                        add_interface(this, current, TRUE);
        !           394:                                                        break;
        !           395:                                                default:
        !           396:                                                        break;
        !           397:                                        }
        !           398:                                }
        !           399:                                current = current->Next;
        !           400:                        }
        !           401:                }
        !           402:                else
        !           403:                {
        !           404:                        DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res);
        !           405:                }
        !           406:        }
        !           407: }
        !           408: 
        !           409: /**
        !           410:  * Get an iface entry for a local address, does no locking
        !           411:  */
        !           412: static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip)
        !           413: {
        !           414:        enumerator_t *ifaces, *addrs;
        !           415:        iface_t *entry, *found = NULL;
        !           416:        host_t *host;
        !           417: 
        !           418:        ifaces = this->ifaces->create_enumerator(this->ifaces);
        !           419:        while (!found && ifaces->enumerate(ifaces, &entry))
        !           420:        {
        !           421:                addrs = entry->addrs->create_enumerator(entry->addrs);
        !           422:                while (!found && addrs->enumerate(addrs, &host))
        !           423:                {
        !           424:                        if (host->ip_equals(host, ip))
        !           425:                        {
        !           426:                                found = entry;
        !           427:                        }
        !           428:                }
        !           429:                addrs->destroy(addrs);
        !           430:        }
        !           431:        ifaces->destroy(ifaces);
        !           432: 
        !           433:        return found;
        !           434: }
        !           435: 
        !           436: METHOD(kernel_net_t, get_interface_name, bool,
        !           437:        private_kernel_iph_net_t *this, host_t* ip, char **name)
        !           438: {
        !           439:        iface_t *entry;
        !           440: 
        !           441:        this->mutex->lock(this->mutex);
        !           442:        entry = address2entry(this, ip);
        !           443:        if (entry && name)
        !           444:        {
        !           445:                *name = strdup(entry->ifname);
        !           446:        }
        !           447:        this->mutex->unlock(this->mutex);
        !           448: 
        !           449:        return entry != NULL;
        !           450: }
        !           451: 
        !           452: /**
        !           453:  * Address enumerator
        !           454:  */
        !           455: typedef struct {
        !           456:        /** implements enumerator_t */
        !           457:        enumerator_t public;
        !           458:        /** what kind of address should we enumerate? */
        !           459:        kernel_address_type_t which;
        !           460:        /** enumerator over interfaces */
        !           461:        enumerator_t *ifaces;
        !           462:        /** current enumerator over addresses, or NULL */
        !           463:        enumerator_t *addrs;
        !           464:        /** mutex to unlock on destruction */
        !           465:        mutex_t *mutex;
        !           466: } addr_enumerator_t;
        !           467: 
        !           468: METHOD(enumerator_t, addr_enumerate, bool,
        !           469:        addr_enumerator_t *this, va_list args)
        !           470: {
        !           471:        iface_t *entry;
        !           472:        host_t **host;
        !           473: 
        !           474:        VA_ARGS_VGET(args, host);
        !           475: 
        !           476:        while (TRUE)
        !           477:        {
        !           478:                while (!this->addrs)
        !           479:                {
        !           480:                        if (!this->ifaces->enumerate(this->ifaces, &entry))
        !           481:                        {
        !           482:                                return FALSE;
        !           483:                        }
        !           484:                        if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK &&
        !           485:                                !(this->which & ADDR_TYPE_LOOPBACK))
        !           486:                        {
        !           487:                                continue;
        !           488:                        }
        !           489:                        if (entry->status != IfOperStatusUp &&
        !           490:                                !(this->which & ADDR_TYPE_DOWN))
        !           491:                        {
        !           492:                                continue;
        !           493:                        }
        !           494:                        this->addrs = entry->addrs->create_enumerator(entry->addrs);
        !           495:                }
        !           496:                if (this->addrs->enumerate(this->addrs, host))
        !           497:                {
        !           498:                        return TRUE;
        !           499:                }
        !           500:                this->addrs->destroy(this->addrs);
        !           501:                this->addrs = NULL;
        !           502:        }
        !           503: }
        !           504: 
        !           505: METHOD(enumerator_t, addr_destroy, void,
        !           506:        addr_enumerator_t *this)
        !           507: {
        !           508:        DESTROY_IF(this->addrs);
        !           509:        this->ifaces->destroy(this->ifaces);
        !           510:        this->mutex->unlock(this->mutex);
        !           511:        free(this);
        !           512: }
        !           513: 
        !           514: METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
        !           515:        private_kernel_iph_net_t *this, kernel_address_type_t which)
        !           516: {
        !           517:        addr_enumerator_t *enumerator;
        !           518: 
        !           519:        if (!(which & ADDR_TYPE_REGULAR))
        !           520:        {
        !           521:                /* we currently have no virtual, but regular IPs only */
        !           522:                return enumerator_create_empty();
        !           523:        }
        !           524: 
        !           525:        this->mutex->lock(this->mutex);
        !           526: 
        !           527:        INIT(enumerator,
        !           528:                .public = {
        !           529:                        .enumerate = enumerator_enumerate_default,
        !           530:                        .venumerate = _addr_enumerate,
        !           531:                        .destroy = _addr_destroy,
        !           532:                },
        !           533:                .which = which,
        !           534:                .ifaces = this->ifaces->create_enumerator(this->ifaces),
        !           535:                .mutex = this->mutex,
        !           536:        );
        !           537:        return &enumerator->public;
        !           538: }
        !           539: 
        !           540: METHOD(kernel_net_t, get_source_addr, host_t*,
        !           541:        private_kernel_iph_net_t *this, host_t *dest, host_t *src)
        !           542: {
        !           543:        MIB_IPFORWARD_ROW2 route;
        !           544:        SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
        !           545:        DWORD res, index = 0;
        !           546: 
        !           547:        res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
        !           548:        if (res != NO_ERROR)
        !           549:        {
        !           550:                DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
        !           551:                return NULL;
        !           552:        }
        !           553: 
        !           554:        sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
        !           555:        if (src)
        !           556:        {
        !           557:                sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
        !           558:        }
        !           559:        res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
        !           560:        if (res != NO_ERROR)
        !           561:        {
        !           562:                DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res);
        !           563:                return NULL;
        !           564:        }
        !           565:        return host_create_from_sockaddr((struct sockaddr*)&best);
        !           566: }
        !           567: 
        !           568: METHOD(kernel_net_t, get_nexthop, host_t*,
        !           569:        private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src,
        !           570:        char **iface)
        !           571: {
        !           572:        MIB_IPFORWARD_ROW2 route;
        !           573:        SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
        !           574:        DWORD res, index = 0;
        !           575:        host_t *nexthop;
        !           576: 
        !           577:        res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
        !           578:        if (res != NO_ERROR)
        !           579:        {
        !           580:                DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
        !           581:                return NULL;
        !           582:        }
        !           583: 
        !           584:        sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
        !           585:        if (src)
        !           586:        {
        !           587:                sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
        !           588:        }
        !           589:        res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
        !           590:        if (res != NO_ERROR)
        !           591:        {
        !           592:                DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res);
        !           593:                return NULL;
        !           594:        }
        !           595:        nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop);
        !           596:        if (nexthop)
        !           597:        {
        !           598:                if (!nexthop->is_anyaddr(nexthop))
        !           599:                {
        !           600:                        if (iface)
        !           601:                        {
        !           602:                                *iface = NULL;
        !           603:                        }
        !           604:                        return nexthop;
        !           605:                }
        !           606:                nexthop->destroy(nexthop);
        !           607:        }
        !           608:        return NULL;
        !           609: }
        !           610: 
        !           611: METHOD(kernel_net_t, add_ip, status_t,
        !           612:        private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
        !           613:        char *iface_name)
        !           614: {
        !           615:        return NOT_SUPPORTED;
        !           616: }
        !           617: 
        !           618: METHOD(kernel_net_t, del_ip, status_t,
        !           619:        private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
        !           620:        bool wait)
        !           621: {
        !           622:        return NOT_SUPPORTED;
        !           623: }
        !           624: 
        !           625: /**
        !           626:  * Add or remove a route
        !           627:  */
        !           628: static status_t manage_route(private_kernel_iph_net_t *this, bool add,
        !           629:                                        chunk_t dst, uint8_t prefixlen, host_t *gtw, char *name)
        !           630: {
        !           631:        MIB_IPFORWARD_ROW2 row = {
        !           632:                .DestinationPrefix = {
        !           633:                        .PrefixLength = prefixlen,
        !           634:                },
        !           635:                .SitePrefixLength = prefixlen,
        !           636:                .ValidLifetime = INFINITE,
        !           637:                .PreferredLifetime = INFINITE,
        !           638:                .Metric = 10,
        !           639:                .Protocol = MIB_IPPROTO_NETMGMT,
        !           640:        };
        !           641:        enumerator_t *enumerator;
        !           642:        iface_t *entry;
        !           643:        ULONG ret;
        !           644: 
        !           645:        this->mutex->lock(this->mutex);
        !           646:        enumerator = this->ifaces->create_enumerator(this->ifaces);
        !           647:        while (enumerator->enumerate(enumerator, &entry))
        !           648:        {
        !           649:                if (streq(name, entry->ifname))
        !           650:                {
        !           651:                        row.InterfaceIndex = entry->ifindex;
        !           652:                        break;
        !           653:                }
        !           654:        }
        !           655:        enumerator->destroy(enumerator);
        !           656:        this->mutex->unlock(this->mutex);
        !           657: 
        !           658:        if (!row.InterfaceIndex)
        !           659:        {
        !           660:                return NOT_FOUND;
        !           661:        }
        !           662:        switch (dst.len)
        !           663:        {
        !           664:                case 4:
        !           665:                        row.DestinationPrefix.Prefix.si_family = AF_INET;
        !           666:                        memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr,
        !           667:                                   dst.ptr, dst.len);
        !           668:                        break;
        !           669:                case 16:
        !           670:                        row.DestinationPrefix.Prefix.si_family = AF_INET6;
        !           671:                        memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr,
        !           672:                                   dst.ptr, dst.len);
        !           673:                        break;
        !           674:                default:
        !           675:                        return FAILED;
        !           676:        }
        !           677:        if (gtw)
        !           678:        {
        !           679:                memcpy(&row.NextHop, gtw->get_sockaddr(gtw),
        !           680:                           *gtw->get_sockaddr_len(gtw));
        !           681:        }
        !           682: 
        !           683:        if (add)
        !           684:        {
        !           685:                ret = CreateIpForwardEntry2(&row);
        !           686:        }
        !           687:        else
        !           688:        {
        !           689:                ret = DeleteIpForwardEntry2(&row);
        !           690:        }
        !           691:        if (ret != NO_ERROR)
        !           692:        {
        !           693:                DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret);
        !           694:                return FAILED;
        !           695:        }
        !           696: 
        !           697:        if (add)
        !           698:        {
        !           699:                ret = EnableRouter(NULL, &this->router);
        !           700:                if (ret != ERROR_IO_PENDING)
        !           701:                {
        !           702:                        DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret);
        !           703:                }
        !           704:        }
        !           705:        else
        !           706:        {
        !           707:                ret = UnenableRouter(&this->router, NULL);
        !           708:                if (ret != NO_ERROR)
        !           709:                {
        !           710:                        DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret);
        !           711:                }
        !           712:        }
        !           713:        return SUCCESS;
        !           714: }
        !           715: 
        !           716: METHOD(kernel_net_t, add_route, status_t,
        !           717:        private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
        !           718:        host_t *gateway, host_t *src, char *name, bool pass)
        !           719: {
        !           720:        return manage_route(this, TRUE, dst, prefixlen, gateway, name);
        !           721: }
        !           722: 
        !           723: METHOD(kernel_net_t, del_route, status_t,
        !           724:        private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
        !           725:        host_t *gateway, host_t *src, char *name, bool pass)
        !           726: {
        !           727:        return manage_route(this, FALSE, dst, prefixlen, gateway, name);
        !           728: }
        !           729: 
        !           730: METHOD(kernel_net_t, destroy, void,
        !           731:        private_kernel_iph_net_t *this)
        !           732: {
        !           733:        if (this->changes)
        !           734:        {
        !           735:                CancelMibChangeNotify2(this->changes);
        !           736:        }
        !           737:        CloseHandle(this->router.hEvent);
        !           738:        this->mutex->destroy(this->mutex);
        !           739:        this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy);
        !           740:        free(this);
        !           741: }
        !           742: 
        !           743: /*
        !           744:  * Described in header.
        !           745:  */
        !           746: kernel_iph_net_t *kernel_iph_net_create()
        !           747: {
        !           748:        private_kernel_iph_net_t *this;
        !           749:        ULONG res;
        !           750: 
        !           751:        INIT(this,
        !           752:                .public = {
        !           753:                        .interface = {
        !           754:                                .get_interface = _get_interface_name,
        !           755:                                .create_address_enumerator = _create_address_enumerator,
        !           756:                                .get_source_addr = _get_source_addr,
        !           757:                                .get_nexthop = _get_nexthop,
        !           758:                                .add_ip = _add_ip,
        !           759:                                .del_ip = _del_ip,
        !           760:                                .add_route = _add_route,
        !           761:                                .del_route = _del_route,
        !           762:                                .destroy = _destroy,
        !           763:                        },
        !           764:                },
        !           765:                .router = {
        !           766:                        .hEvent = CreateEvent(NULL, FALSE, FALSE, NULL),
        !           767:                },
        !           768:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           769:                .ifaces = linked_list_create(),
        !           770:        );
        !           771:        /* PIPINTERFACE_CHANGE_CALLBACK is not using WINAPI in MinGW, which seems
        !           772:         * to be wrong. Force a cast to our WINAPI call */
        !           773:        res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface,
        !           774:                                                                  this, TRUE, &this->changes);
        !           775:        if (res != NO_ERROR)
        !           776:        {
        !           777:                DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx",
        !           778:                         res);
        !           779:                destroy(this);
        !           780:                return NULL;
        !           781:        }
        !           782: 
        !           783:        return &this->public;
        !           784: }

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