Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_iph/kernel_iph_net.c, revision 1.1.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>