Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008-2019 Tobias Brunner
        !             3:  * Copyright (C) 2005-2008 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: /*
        !            18:  * Copyright (C) 2010 secunet Security Networks AG
        !            19:  * Copyright (C) 2010 Thomas Egerer
        !            20:  *
        !            21:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !            22:  * of this software and associated documentation files (the "Software"), to deal
        !            23:  * in the Software without restriction, including without limitation the rights
        !            24:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            25:  * copies of the Software, and to permit persons to whom the Software is
        !            26:  * furnished to do so, subject to the following conditions:
        !            27:  *
        !            28:  * The above copyright notice and this permission notice shall be included in
        !            29:  * all copies or substantial portions of the Software.
        !            30:  *
        !            31:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            32:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            33:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        !            34:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            35:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            36:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            37:  * THE SOFTWARE.
        !            38:  */
        !            39: 
        !            40: #include <sys/socket.h>
        !            41: #include <sys/utsname.h>
        !            42: #include <linux/netlink.h>
        !            43: #include <linux/rtnetlink.h>
        !            44: #include <linux/if_addrlabel.h>
        !            45: #include <unistd.h>
        !            46: #include <errno.h>
        !            47: #include <net/if.h>
        !            48: #ifdef HAVE_LINUX_FIB_RULES_H
        !            49: #include <linux/fib_rules.h>
        !            50: #endif
        !            51: 
        !            52: #include "kernel_netlink_net.h"
        !            53: #include "kernel_netlink_shared.h"
        !            54: 
        !            55: #include <daemon.h>
        !            56: #include <utils/debug.h>
        !            57: #include <threading/mutex.h>
        !            58: #include <threading/rwlock.h>
        !            59: #include <threading/rwlock_condvar.h>
        !            60: #include <threading/spinlock.h>
        !            61: #include <collections/hashtable.h>
        !            62: #include <collections/linked_list.h>
        !            63: #include <processing/jobs/callback_job.h>
        !            64: 
        !            65: /** delay before firing roam events (ms) */
        !            66: #define ROAM_DELAY 100
        !            67: 
        !            68: /** delay before reinstalling routes (ms) */
        !            69: #define ROUTE_DELAY 100
        !            70: 
        !            71: /** maximum recursion when searching for addresses in get_route() */
        !            72: #define MAX_ROUTE_RECURSION 2
        !            73: 
        !            74: #ifndef ROUTING_TABLE
        !            75: #define ROUTING_TABLE 0
        !            76: #endif
        !            77: 
        !            78: #ifndef ROUTING_TABLE_PRIO
        !            79: #define ROUTING_TABLE_PRIO 0
        !            80: #endif
        !            81: 
        !            82: /** multicast groups (for groups > 31 setsockopt has to be used) */
        !            83: #define nl_group(group) (1 << (group - 1))
        !            84: 
        !            85: ENUM(rt_msg_names, RTM_NEWLINK, RTM_GETRULE,
        !            86:        "RTM_NEWLINK",
        !            87:        "RTM_DELLINK",
        !            88:        "RTM_GETLINK",
        !            89:        "RTM_SETLINK",
        !            90:        "RTM_NEWADDR",
        !            91:        "RTM_DELADDR",
        !            92:        "RTM_GETADDR",
        !            93:        "23",
        !            94:        "RTM_NEWROUTE",
        !            95:        "RTM_DELROUTE",
        !            96:        "RTM_GETROUTE",
        !            97:        "27",
        !            98:        "RTM_NEWNEIGH",
        !            99:        "RTM_DELNEIGH",
        !           100:        "RTM_GETNEIGH",
        !           101:        "31",
        !           102:        "RTM_NEWRULE",
        !           103:        "RTM_DELRULE",
        !           104:        "RTM_GETRULE",
        !           105: );
        !           106: 
        !           107: typedef struct addr_entry_t addr_entry_t;
        !           108: 
        !           109: /**
        !           110:  * IP address in an iface_entry_t
        !           111:  */
        !           112: struct addr_entry_t {
        !           113: 
        !           114:        /** the ip address */
        !           115:        host_t *ip;
        !           116: 
        !           117:        /** address flags */
        !           118:        u_char flags;
        !           119: 
        !           120:        /** scope of the address */
        !           121:        u_char scope;
        !           122: 
        !           123:        /** number of times this IP is used, if virtual (i.e. managed by us) */
        !           124:        u_int refcount;
        !           125: 
        !           126:        /** TRUE once it is installed, if virtual */
        !           127:        bool installed;
        !           128: };
        !           129: 
        !           130: /**
        !           131:  * destroy a addr_entry_t object
        !           132:  */
        !           133: static void addr_entry_destroy(addr_entry_t *this)
        !           134: {
        !           135:        this->ip->destroy(this->ip);
        !           136:        free(this);
        !           137: }
        !           138: 
        !           139: typedef struct iface_entry_t iface_entry_t;
        !           140: 
        !           141: /**
        !           142:  * A network interface on this system, containing addr_entry_t's
        !           143:  */
        !           144: struct iface_entry_t {
        !           145: 
        !           146:        /** interface index */
        !           147:        int ifindex;
        !           148: 
        !           149:        /** name of the interface */
        !           150:        char ifname[IFNAMSIZ];
        !           151: 
        !           152:        /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
        !           153:        u_int flags;
        !           154: 
        !           155:        /** list of addresses as host_t */
        !           156:        linked_list_t *addrs;
        !           157: 
        !           158:        /** TRUE if usable by config */
        !           159:        bool usable;
        !           160: };
        !           161: 
        !           162: /**
        !           163:  * destroy an interface entry
        !           164:  */
        !           165: static void iface_entry_destroy(iface_entry_t *this)
        !           166: {
        !           167:        this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
        !           168:        free(this);
        !           169: }
        !           170: 
        !           171: CALLBACK(iface_entry_by_index, bool,
        !           172:        iface_entry_t *this, va_list args)
        !           173: {
        !           174:        int ifindex;
        !           175: 
        !           176:        VA_ARGS_VGET(args, ifindex);
        !           177:        return this->ifindex == ifindex;
        !           178: }
        !           179: 
        !           180: CALLBACK(iface_entry_by_name, bool,
        !           181:        iface_entry_t *this, va_list args)
        !           182: {
        !           183:        char *ifname;
        !           184: 
        !           185:        VA_ARGS_VGET(args, ifname);
        !           186:        return streq(this->ifname, ifname);
        !           187: }
        !           188: 
        !           189: /**
        !           190:  * check if an interface is up
        !           191:  */
        !           192: static inline bool iface_entry_up(iface_entry_t *iface)
        !           193: {
        !           194:        return (iface->flags & IFF_UP) == IFF_UP;
        !           195: }
        !           196: 
        !           197: /**
        !           198:  * check if an interface is up and usable
        !           199:  */
        !           200: static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
        !           201: {
        !           202:        return iface->usable && iface_entry_up(iface);
        !           203: }
        !           204: 
        !           205: typedef struct addr_map_entry_t addr_map_entry_t;
        !           206: 
        !           207: /**
        !           208:  * Entry that maps an IP address to an interface entry
        !           209:  */
        !           210: struct addr_map_entry_t {
        !           211:        /** The IP address */
        !           212:        host_t *ip;
        !           213: 
        !           214:        /** The address entry for this IP address */
        !           215:        addr_entry_t *addr;
        !           216: 
        !           217:        /** The interface this address is installed on */
        !           218:        iface_entry_t *iface;
        !           219: };
        !           220: 
        !           221: /**
        !           222:  * Hash a addr_map_entry_t object, all entries with the same IP address
        !           223:  * are stored in the same bucket
        !           224:  */
        !           225: static u_int addr_map_entry_hash(addr_map_entry_t *this)
        !           226: {
        !           227:        return chunk_hash(this->ip->get_address(this->ip));
        !           228: }
        !           229: 
        !           230: /**
        !           231:  * Compare two addr_map_entry_t objects, two entries are equal if they are
        !           232:  * installed on the same interface
        !           233:  */
        !           234: static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b)
        !           235: {
        !           236:        return a->iface->ifindex == b->iface->ifindex &&
        !           237:                   a->ip->ip_equals(a->ip, b->ip);
        !           238: }
        !           239: 
        !           240: /**
        !           241:  * Used with get_match this finds an address entry if it is installed on
        !           242:  * an up and usable interface
        !           243:  */
        !           244: static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a,
        !           245:                                                                                           addr_map_entry_t *b)
        !           246: {
        !           247:        return iface_entry_up_and_usable(b->iface) &&
        !           248:                   a->ip->ip_equals(a->ip, b->ip);
        !           249: }
        !           250: 
        !           251: /**
        !           252:  * Used with get_match this finds an address entry if it is installed on
        !           253:  * any active local interface
        !           254:  */
        !           255: static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b)
        !           256: {
        !           257:        return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip);
        !           258: }
        !           259: 
        !           260: /**
        !           261:  * Used with get_match this finds an address entry if it is installed on
        !           262:  * any local interface
        !           263:  */
        !           264: static bool addr_map_entry_match(addr_map_entry_t *a, addr_map_entry_t *b)
        !           265: {
        !           266:        return a->ip->ip_equals(a->ip, b->ip);
        !           267: }
        !           268: 
        !           269: typedef struct net_change_t net_change_t;
        !           270: 
        !           271: /**
        !           272:  * Queued network changes
        !           273:  */
        !           274: struct net_change_t {
        !           275:        /** Name of the interface that got activated (or an IP appeared on) */
        !           276:        char *if_name;
        !           277: };
        !           278: 
        !           279: /**
        !           280:  * Destroy a net_change_t object
        !           281:  */
        !           282: static void net_change_destroy(net_change_t *this)
        !           283: {
        !           284:        free(this->if_name);
        !           285:        free(this);
        !           286: }
        !           287: 
        !           288: /**
        !           289:  * Hash a net_change_t object
        !           290:  */
        !           291: static u_int net_change_hash(net_change_t *this)
        !           292: {
        !           293:        return chunk_hash(chunk_create(this->if_name, strlen(this->if_name)));
        !           294: }
        !           295: 
        !           296: /**
        !           297:  * Compare two net_change_t objects
        !           298:  */
        !           299: static bool net_change_equals(net_change_t *a, net_change_t *b)
        !           300: {
        !           301:        return streq(a->if_name, b->if_name);
        !           302: }
        !           303: 
        !           304: typedef struct private_kernel_netlink_net_t private_kernel_netlink_net_t;
        !           305: 
        !           306: /**
        !           307:  * Private variables and functions of kernel_netlink_net class.
        !           308:  */
        !           309: struct private_kernel_netlink_net_t {
        !           310:        /**
        !           311:         * Public part of the kernel_netlink_net_t object.
        !           312:         */
        !           313:        kernel_netlink_net_t public;
        !           314: 
        !           315:        /**
        !           316:         * lock to access various lists and maps
        !           317:         */
        !           318:        rwlock_t *lock;
        !           319: 
        !           320:        /**
        !           321:         * condition variable to signal virtual IP add/removal
        !           322:         */
        !           323:        rwlock_condvar_t *condvar;
        !           324: 
        !           325:        /**
        !           326:         * Cached list of interfaces and its addresses (iface_entry_t)
        !           327:         */
        !           328:        linked_list_t *ifaces;
        !           329: 
        !           330:        /**
        !           331:         * Map for IP addresses to iface_entry_t objects (addr_map_entry_t)
        !           332:         */
        !           333:        hashtable_t *addrs;
        !           334: 
        !           335:        /**
        !           336:         * Map for virtual IP addresses to iface_entry_t objects (addr_map_entry_t)
        !           337:         */
        !           338:        hashtable_t *vips;
        !           339: 
        !           340:        /**
        !           341:         * netlink rt socket (routing)
        !           342:         */
        !           343:        netlink_socket_t *socket;
        !           344: 
        !           345:        /**
        !           346:         * Netlink rt socket to receive address change events
        !           347:         */
        !           348:        int socket_events;
        !           349: 
        !           350:        /**
        !           351:         * earliest time of the next roam event
        !           352:         */
        !           353:        timeval_t next_roam;
        !           354: 
        !           355:        /**
        !           356:         * roam event due to address change
        !           357:         */
        !           358:        bool roam_address;
        !           359: 
        !           360:        /**
        !           361:         * lock to check and update roam event time
        !           362:         */
        !           363:        spinlock_t *roam_lock;
        !           364: 
        !           365:        /**
        !           366:         * routing table to install routes
        !           367:         */
        !           368:        uint32_t routing_table;
        !           369: 
        !           370:        /**
        !           371:         * priority of used routing table
        !           372:         */
        !           373:        uint32_t routing_table_prio;
        !           374: 
        !           375:        /**
        !           376:         * installed routes
        !           377:         */
        !           378:        hashtable_t *routes;
        !           379: 
        !           380:        /**
        !           381:         * mutex for routes
        !           382:         */
        !           383:        mutex_t *routes_lock;
        !           384: 
        !           385:        /**
        !           386:         * interface changes which may trigger route reinstallation
        !           387:         */
        !           388:        hashtable_t *net_changes;
        !           389: 
        !           390:        /**
        !           391:         * mutex for route reinstallation triggers
        !           392:         */
        !           393:        mutex_t *net_changes_lock;
        !           394: 
        !           395:        /**
        !           396:         * time of last route reinstallation
        !           397:         */
        !           398:        timeval_t last_route_reinstall;
        !           399: 
        !           400:        /**
        !           401:         * whether to react to RTM_NEWROUTE or RTM_DELROUTE events
        !           402:         */
        !           403:        bool process_route;
        !           404: 
        !           405:        /**
        !           406:         * whether to react to RTM_NEWRULE or RTM_DELRULE events
        !           407:         */
        !           408:        bool process_rules;
        !           409: 
        !           410:        /**
        !           411:         * whether to trigger roam events
        !           412:         */
        !           413:        bool roam_events;
        !           414: 
        !           415:        /**
        !           416:         * whether to install IPsec policy routes
        !           417:         */
        !           418:        bool install_routes;
        !           419: 
        !           420:        /**
        !           421:         * whether to actually install virtual IPs
        !           422:         */
        !           423:        bool install_virtual_ip;
        !           424: 
        !           425:        /**
        !           426:         * the name of the interface virtual IP addresses are installed on
        !           427:         */
        !           428:        char *install_virtual_ip_on;
        !           429: 
        !           430:        /**
        !           431:         * whether preferred source addresses can be specified for IPv6 routes
        !           432:         */
        !           433:        bool rta_prefsrc_for_ipv6;
        !           434: 
        !           435:        /**
        !           436:         * whether marks can be used in route lookups
        !           437:         */
        !           438:        bool rta_mark;
        !           439: 
        !           440:        /**
        !           441:         * the mark excluded from the routing rule used for virtual IPs
        !           442:         */
        !           443:        mark_t routing_mark;
        !           444: 
        !           445:        /**
        !           446:         * whether to prefer temporary IPv6 addresses over public ones
        !           447:         */
        !           448:        bool prefer_temporary_addrs;
        !           449: 
        !           450:        /**
        !           451:         * list with routing tables to be excluded from route lookup
        !           452:         */
        !           453:        linked_list_t *rt_exclude;
        !           454: 
        !           455:        /**
        !           456:         * MTU to set on installed routes
        !           457:         */
        !           458:        uint32_t mtu;
        !           459: 
        !           460:        /**
        !           461:         * MSS to set on installed routes
        !           462:         */
        !           463:        uint32_t mss;
        !           464: };
        !           465: 
        !           466: /**
        !           467:  * Forward declaration
        !           468:  */
        !           469: static status_t manage_srcroute(private_kernel_netlink_net_t *this,
        !           470:                                                                int nlmsg_type, int flags, chunk_t dst_net,
        !           471:                                                                uint8_t prefixlen, host_t *gateway,
        !           472:                                                                host_t *src_ip, char *if_name, bool pass);
        !           473: 
        !           474: /**
        !           475:  * Clear the queued network changes.
        !           476:  */
        !           477: static void net_changes_clear(private_kernel_netlink_net_t *this)
        !           478: {
        !           479:        enumerator_t *enumerator;
        !           480:        net_change_t *change;
        !           481: 
        !           482:        enumerator = this->net_changes->create_enumerator(this->net_changes);
        !           483:        while (enumerator->enumerate(enumerator, NULL, (void**)&change))
        !           484:        {
        !           485:                this->net_changes->remove_at(this->net_changes, enumerator);
        !           486:                net_change_destroy(change);
        !           487:        }
        !           488:        enumerator->destroy(enumerator);
        !           489: }
        !           490: 
        !           491: /**
        !           492:  * Act upon queued network changes.
        !           493:  */
        !           494: static job_requeue_t reinstall_routes(private_kernel_netlink_net_t *this)
        !           495: {
        !           496:        enumerator_t *enumerator;
        !           497:        route_entry_t *route;
        !           498: 
        !           499:        this->net_changes_lock->lock(this->net_changes_lock);
        !           500:        this->routes_lock->lock(this->routes_lock);
        !           501: 
        !           502:        enumerator = this->routes->create_enumerator(this->routes);
        !           503:        while (enumerator->enumerate(enumerator, NULL, (void**)&route))
        !           504:        {
        !           505:                net_change_t *change, lookup = {
        !           506:                        .if_name = route->if_name,
        !           507:                };
        !           508:                if (route->pass || !route->if_name)
        !           509:                {       /* no need to reinstall these, they don't reference interfaces */
        !           510:                        continue;
        !           511:                }
        !           512:                /* check if a change for the outgoing interface is queued */
        !           513:                change = this->net_changes->get(this->net_changes, &lookup);
        !           514:                if (!change)
        !           515:                {       /* in case src_ip is not on the outgoing interface */
        !           516:                        if (this->public.interface.get_interface(&this->public.interface,
        !           517:                                                                                                route->src_ip, &lookup.if_name))
        !           518:                        {
        !           519:                                if (!streq(lookup.if_name, route->if_name))
        !           520:                                {
        !           521:                                        change = this->net_changes->get(this->net_changes, &lookup);
        !           522:                                }
        !           523:                                free(lookup.if_name);
        !           524:                        }
        !           525:                }
        !           526:                if (change)
        !           527:                {
        !           528:                        manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
        !           529:                                                        route->dst_net, route->prefixlen, route->gateway,
        !           530:                                                        route->src_ip, route->if_name, route->pass);
        !           531:                }
        !           532:        }
        !           533:        enumerator->destroy(enumerator);
        !           534:        this->routes_lock->unlock(this->routes_lock);
        !           535: 
        !           536:        net_changes_clear(this);
        !           537:        this->net_changes_lock->unlock(this->net_changes_lock);
        !           538:        return JOB_REQUEUE_NONE;
        !           539: }
        !           540: 
        !           541: /**
        !           542:  * Queue route reinstallation caused by network changes for a given interface.
        !           543:  *
        !           544:  * The route reinstallation is delayed for a while and only done once for
        !           545:  * several calls during this delay, in order to avoid doing it too often.
        !           546:  * The interface name is freed.
        !           547:  */
        !           548: static void queue_route_reinstall(private_kernel_netlink_net_t *this,
        !           549:                                                                  char *if_name)
        !           550: {
        !           551:        net_change_t *update, *found;
        !           552:        timeval_t now;
        !           553:        job_t *job;
        !           554: 
        !           555:        INIT(update,
        !           556:                .if_name = if_name
        !           557:        );
        !           558: 
        !           559:        this->net_changes_lock->lock(this->net_changes_lock);
        !           560:        found = this->net_changes->put(this->net_changes, update, update);
        !           561:        if (found)
        !           562:        {
        !           563:                net_change_destroy(found);
        !           564:        }
        !           565:        time_monotonic(&now);
        !           566:        if (timercmp(&now, &this->last_route_reinstall, >))
        !           567:        {
        !           568:                timeval_add_ms(&now, ROUTE_DELAY);
        !           569:                this->last_route_reinstall = now;
        !           570: 
        !           571:                job = (job_t*)callback_job_create((callback_job_cb_t)reinstall_routes,
        !           572:                                                                                  this, NULL, NULL);
        !           573:                lib->scheduler->schedule_job_ms(lib->scheduler, job, ROUTE_DELAY);
        !           574:        }
        !           575:        this->net_changes_lock->unlock(this->net_changes_lock);
        !           576: }
        !           577: 
        !           578: /**
        !           579:  * check if the given IP is known as virtual IP and currently installed
        !           580:  *
        !           581:  * this function will also return TRUE if the virtual IP entry disappeared.
        !           582:  * in that case the returned entry will be NULL.
        !           583:  *
        !           584:  * this->lock must be held when calling this function
        !           585:  */
        !           586: static bool is_vip_installed_or_gone(private_kernel_netlink_net_t *this,
        !           587:                                                                         host_t *ip, addr_map_entry_t **entry)
        !           588: {
        !           589:        addr_map_entry_t lookup = {
        !           590:                .ip = ip,
        !           591:        };
        !           592: 
        !           593:        *entry = this->vips->get_match(this->vips, &lookup,
        !           594:                                                                  (void*)addr_map_entry_match);
        !           595:        if (*entry == NULL)
        !           596:        {       /* the virtual IP disappeared */
        !           597:                return TRUE;
        !           598:        }
        !           599:        return (*entry)->addr->installed;
        !           600: }
        !           601: 
        !           602: /**
        !           603:  * check if the given IP is known as virtual IP
        !           604:  *
        !           605:  * this->lock must be held when calling this function
        !           606:  */
        !           607: static bool is_known_vip(private_kernel_netlink_net_t *this, host_t *ip)
        !           608: {
        !           609:        addr_map_entry_t lookup = {
        !           610:                .ip = ip,
        !           611:        };
        !           612: 
        !           613:        return this->vips->get_match(this->vips, &lookup,
        !           614:                                                                (void*)addr_map_entry_match) != NULL;
        !           615: }
        !           616: 
        !           617: /**
        !           618:  * Add an address map entry
        !           619:  */
        !           620: static void addr_map_entry_add(hashtable_t *map, addr_entry_t *addr,
        !           621:                                                           iface_entry_t *iface)
        !           622: {
        !           623:        addr_map_entry_t *entry;
        !           624: 
        !           625:        INIT(entry,
        !           626:                .ip = addr->ip,
        !           627:                .addr = addr,
        !           628:                .iface = iface,
        !           629:        );
        !           630:        entry = map->put(map, entry, entry);
        !           631:        free(entry);
        !           632: }
        !           633: 
        !           634: /**
        !           635:  * Remove an address map entry
        !           636:  */
        !           637: static void addr_map_entry_remove(hashtable_t *map, addr_entry_t *addr,
        !           638:                                                                  iface_entry_t *iface)
        !           639: {
        !           640:        addr_map_entry_t *entry, lookup = {
        !           641:                .ip = addr->ip,
        !           642:                .addr = addr,
        !           643:                .iface = iface,
        !           644:        };
        !           645: 
        !           646:        entry = map->remove(map, &lookup);
        !           647:        free(entry);
        !           648: }
        !           649: 
        !           650: /**
        !           651:  * Check if an address or net (addr with prefix net bits) is in
        !           652:  * subnet (net with net_len net bits)
        !           653:  */
        !           654: static bool addr_in_subnet(chunk_t addr, int prefix, chunk_t net, int net_len)
        !           655: {
        !           656:        static const u_char mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
        !           657:        int byte = 0;
        !           658: 
        !           659:        if (net_len == 0)
        !           660:        {       /* any address matches a /0 network */
        !           661:                return TRUE;
        !           662:        }
        !           663:        if (addr.len != net.len || net_len > 8 * net.len || prefix < net_len)
        !           664:        {
        !           665:                return FALSE;
        !           666:        }
        !           667:        /* scan through all bytes in network order */
        !           668:        while (net_len > 0)
        !           669:        {
        !           670:                if (net_len < 8)
        !           671:                {
        !           672:                        return (mask[net_len] & addr.ptr[byte]) == (mask[net_len] & net.ptr[byte]);
        !           673:                }
        !           674:                else
        !           675:                {
        !           676:                        if (addr.ptr[byte] != net.ptr[byte])
        !           677:                        {
        !           678:                                return FALSE;
        !           679:                        }
        !           680:                        byte++;
        !           681:                        net_len -= 8;
        !           682:                }
        !           683:        }
        !           684:        return TRUE;
        !           685: }
        !           686: 
        !           687: /**
        !           688:  * Check if the given address is in subnet (net with net_len net bits)
        !           689:  */
        !           690: static bool host_in_subnet(host_t *host, chunk_t net, int net_len)
        !           691: {
        !           692:        chunk_t addr;
        !           693: 
        !           694:        addr = host->get_address(host);
        !           695:        return addr_in_subnet(addr, addr.len * 8, net, net_len);
        !           696: }
        !           697: 
        !           698: /**
        !           699:  * Determine the type or scope of the given unicast IP address.  This is not
        !           700:  * the same thing returned in rtm_scope/ifa_scope.
        !           701:  *
        !           702:  * We use return values as defined in RFC 6724 (referring to RFC 4291).
        !           703:  */
        !           704: static u_char get_scope(host_t *ip)
        !           705: {
        !           706:        chunk_t addr;
        !           707: 
        !           708:        addr = ip->get_address(ip);
        !           709:        switch (addr.len)
        !           710:        {
        !           711:                case 4:
        !           712:                        /* we use the mapping defined in RFC 6724, 3.2 */
        !           713:                        if (addr.ptr[0] == 127)
        !           714:                        {       /* link-local, same as the IPv6 loopback address */
        !           715:                                return 2;
        !           716:                        }
        !           717:                        if (addr.ptr[0] == 169 && addr.ptr[1] == 254)
        !           718:                        {       /* link-local */
        !           719:                                return 2;
        !           720:                        }
        !           721:                        break;
        !           722:                case 16:
        !           723:                        if (IN6_IS_ADDR_LOOPBACK((struct in6_addr*)addr.ptr))
        !           724:                        {       /* link-local, according to RFC 4291, 2.5.3 */
        !           725:                                return 2;
        !           726:                        }
        !           727:                        if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr*)addr.ptr))
        !           728:                        {
        !           729:                                return 2;
        !           730:                        }
        !           731:                        if (IN6_IS_ADDR_SITELOCAL((struct in6_addr*)addr.ptr))
        !           732:                        {       /* deprecated, according to RFC 4291, 2.5.7 */
        !           733:                                return 5;
        !           734:                        }
        !           735:                        break;
        !           736:                default:
        !           737:                        break;
        !           738:        }
        !           739:        /* global */
        !           740:        return 14;
        !           741: }
        !           742: 
        !           743: /**
        !           744:  * Determine the label of the given unicast IP address.
        !           745:  *
        !           746:  * We currently only support the default table given in RFC 6724:
        !           747:  *
        !           748:  *  Prefix        Precedence Label
        !           749:  *  ::1/128               50     0
        !           750:  *  ::/0                  40     1
        !           751:  *  ::ffff:0:0/96         35     4
        !           752:  *  2002::/16             30     2
        !           753:  *  2001::/32              5     5
        !           754:  *  fc00::/7               3    13
        !           755:  *  ::/96                  1     3
        !           756:  *  fec0::/10              1    11
        !           757:  *  3ffe::/16              1    12
        !           758:  */
        !           759: static u_char get_label(host_t *ip)
        !           760: {
        !           761:        struct {
        !           762:                chunk_t net;
        !           763:                u_char prefix;
        !           764:                u_char label;
        !           765:        } priorities[] = {
        !           766:                /* priority table ordered by prefix */
        !           767:                /* ::1/128 */
        !           768:                { chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           769:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01), 128, 0 },
        !           770:                /* ::ffff:0:0/96 */
        !           771:                { chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           772:                                                   0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00), 96, 4 },
        !           773:                /* ::/96 */
        !           774:                { chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           775:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 96, 3 },
        !           776:                /* 2001::/32 */
        !           777:                { chunk_from_chars(0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           778:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 32, 5 },
        !           779:                /* 2002::/16 */
        !           780:                { chunk_from_chars(0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           781:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 16, 2 },
        !           782:                /* 3ffe::/16 */
        !           783:                { chunk_from_chars(0x3f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           784:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 16, 12 },
        !           785:                /* fec0::/10 */
        !           786:                { chunk_from_chars(0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           787:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 10, 11 },
        !           788:                /* fc00::/7 */
        !           789:                { chunk_from_chars(0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        !           790:                                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 7, 13 },
        !           791:        };
        !           792:        int i;
        !           793: 
        !           794:        for (i = 0; i < countof(priorities); i++)
        !           795:        {
        !           796:                if (host_in_subnet(ip, priorities[i].net, priorities[i].prefix))
        !           797:                {
        !           798:                        return priorities[i].label;
        !           799:                }
        !           800:        }
        !           801:        /* ::/0 */
        !           802:        return 1;
        !           803: }
        !           804: 
        !           805: /**
        !           806:  * Returns the length of the common prefix in bits up to the length of a's
        !           807:  * prefix, defined by RFC 6724 as the portion of the address not including the
        !           808:  * interface ID, which is 64-bit for most unicast addresses (see RFC 4291).
        !           809:  */
        !           810: static u_char common_prefix(host_t *a, host_t *b)
        !           811: {
        !           812:        chunk_t aa, ba;
        !           813:        u_char byte, bits = 0, match;
        !           814: 
        !           815:        aa = a->get_address(a);
        !           816:        ba = b->get_address(b);
        !           817:        for (byte = 0; byte < 8; byte++)
        !           818:        {
        !           819:                if (aa.ptr[byte] != ba.ptr[byte])
        !           820:                {
        !           821:                        match = aa.ptr[byte] ^ ba.ptr[byte];
        !           822:                        for (bits = 8; match; match >>= 1)
        !           823:                        {
        !           824:                                bits--;
        !           825:                        }
        !           826:                        break;
        !           827:                }
        !           828:        }
        !           829:        return byte * 8 + bits;
        !           830: }
        !           831: 
        !           832: /**
        !           833:  * Compare two IP addresses and return TRUE if the second address is the better
        !           834:  * choice of the two to reach the destination.
        !           835:  * For IPv6 we approximately follow RFC 6724.
        !           836:  */
        !           837: static bool is_address_better(private_kernel_netlink_net_t *this,
        !           838:                                                          addr_entry_t *a, addr_entry_t *b, host_t *d)
        !           839: {
        !           840:        u_char sa, sb, sd, la, lb, ld, pa, pb;
        !           841: 
        !           842:        /* rule 2: prefer appropriate scope */
        !           843:        if (d)
        !           844:        {
        !           845:                sa = get_scope(a->ip);
        !           846:                sb = get_scope(b->ip);
        !           847:                sd = get_scope(d);
        !           848:                if (sa < sb)
        !           849:                {
        !           850:                        return sa < sd;
        !           851:                }
        !           852:                else if (sb < sa)
        !           853:                {
        !           854:                        return sb >= sd;
        !           855:                }
        !           856:        }
        !           857:        if (a->ip->get_family(a->ip) == AF_INET)
        !           858:        {       /* stop here for IPv4, default to addresses found earlier */
        !           859:                return FALSE;
        !           860:        }
        !           861:        /* rule 3: avoid deprecated addresses (RFC 4862) */
        !           862:        if ((a->flags & IFA_F_DEPRECATED) != (b->flags & IFA_F_DEPRECATED))
        !           863:        {
        !           864:                return a->flags & IFA_F_DEPRECATED;
        !           865:        }
        !           866:        /* rule 4 is not applicable as we don't know if an address is a home or
        !           867:         * care-of addresses.
        !           868:         * rule 5 does not apply as we only compare addresses from one interface
        !           869:         */
        !           870:        /* rule 6: prefer matching label */
        !           871:        if (d)
        !           872:        {
        !           873:                la = get_label(a->ip);
        !           874:                lb = get_label(b->ip);
        !           875:                ld = get_label(d);
        !           876:                if (la == ld && lb != ld)
        !           877:                {
        !           878:                        return FALSE;
        !           879:                }
        !           880:                else if (lb == ld && la != ld)
        !           881:                {
        !           882:                        return TRUE;
        !           883:                }
        !           884:        }
        !           885:        /* rule 7: prefer temporary addresses (WE REVERSE THIS BY DEFAULT!) */
        !           886:        if ((a->flags & IFA_F_TEMPORARY) != (b->flags & IFA_F_TEMPORARY))
        !           887:        {
        !           888:                if (this->prefer_temporary_addrs)
        !           889:                {
        !           890:                        return b->flags & IFA_F_TEMPORARY;
        !           891:                }
        !           892:                return a->flags & IFA_F_TEMPORARY;
        !           893:        }
        !           894:        /* rule 8: use longest matching prefix */
        !           895:        if (d)
        !           896:        {
        !           897:                pa = common_prefix(a->ip, d);
        !           898:                pb = common_prefix(b->ip, d);
        !           899:                if (pa != pb)
        !           900:                {
        !           901:                        return pb > pa;
        !           902:                }
        !           903:        }
        !           904:        /* default to addresses found earlier */
        !           905:        return FALSE;
        !           906: }
        !           907: 
        !           908: /**
        !           909:  * Get a non-virtual IP address on the given interfaces and optionally in a
        !           910:  * given subnet.
        !           911:  *
        !           912:  * If a candidate address is given, we first search for that address and if not
        !           913:  * found return the address as above.
        !           914:  * Returned host is a clone, has to be freed by caller.
        !           915:  *
        !           916:  * this->lock must be held when calling this function.
        !           917:  */
        !           918: static host_t *get_matching_address(private_kernel_netlink_net_t *this,
        !           919:                                                                        int *ifindex, int family, chunk_t net,
        !           920:                                                                        uint8_t mask, host_t *dest,
        !           921:                                                                        host_t *candidate)
        !           922: {
        !           923:        enumerator_t *ifaces, *addrs;
        !           924:        iface_entry_t *iface;
        !           925:        addr_entry_t *addr, *best = NULL;
        !           926:        bool candidate_matched = FALSE;
        !           927: 
        !           928:        ifaces = this->ifaces->create_enumerator(this->ifaces);
        !           929:        while (ifaces->enumerate(ifaces, &iface))
        !           930:        {
        !           931:                if (iface->usable && (!ifindex || iface->ifindex == *ifindex))
        !           932:                {       /* only use matching interfaces not excluded by config */
        !           933:                        addrs = iface->addrs->create_enumerator(iface->addrs);
        !           934:                        while (addrs->enumerate(addrs, &addr))
        !           935:                        {
        !           936:                                if (addr->refcount ||
        !           937:                                        addr->ip->get_family(addr->ip) != family)
        !           938:                                {       /* ignore virtual IP addresses and ensure family matches */
        !           939:                                        continue;
        !           940:                                }
        !           941:                                if (net.ptr && !host_in_subnet(addr->ip, net, mask))
        !           942:                                {       /* optionally match a subnet */
        !           943:                                        continue;
        !           944:                                }
        !           945:                                if (candidate && candidate->ip_equals(candidate, addr->ip))
        !           946:                                {       /* stop if we find the candidate */
        !           947:                                        best = addr;
        !           948:                                        candidate_matched = TRUE;
        !           949:                                        break;
        !           950:                                }
        !           951:                                else if (!best || is_address_better(this, best, addr, dest))
        !           952:                                {
        !           953:                                        best = addr;
        !           954:                                }
        !           955:                        }
        !           956:                        addrs->destroy(addrs);
        !           957:                        if (ifindex || candidate_matched)
        !           958:                        {
        !           959:                                break;
        !           960:                        }
        !           961:                }
        !           962:        }
        !           963:        ifaces->destroy(ifaces);
        !           964:        return best ? best->ip->clone(best->ip) : NULL;
        !           965: }
        !           966: 
        !           967: /**
        !           968:  * Get a non-virtual IP address on the given interface.
        !           969:  *
        !           970:  * If a candidate address is given, we first search for that address and if not
        !           971:  * found return the address as above.
        !           972:  * Returned host is a clone, has to be freed by caller.
        !           973:  *
        !           974:  * this->lock must be held when calling this function.
        !           975:  */
        !           976: static host_t *get_interface_address(private_kernel_netlink_net_t *this,
        !           977:                                                                         int ifindex, int family, host_t *dest,
        !           978:                                                                         host_t *candidate)
        !           979: {
        !           980:        return get_matching_address(this, &ifindex, family, chunk_empty, 0, dest,
        !           981:                                                                candidate);
        !           982: }
        !           983: 
        !           984: /**
        !           985:  * Get a non-virtual IP address in the given subnet.
        !           986:  *
        !           987:  * If a candidate address is given, we first search for that address and if not
        !           988:  * found return the address as above.
        !           989:  * Returned host is a clone, has to be freed by caller.
        !           990:  *
        !           991:  * this->lock must be held when calling this function.
        !           992:  */
        !           993: static host_t *get_subnet_address(private_kernel_netlink_net_t *this,
        !           994:                                                                  int family, chunk_t net, uint8_t mask,
        !           995:                                                                  host_t *dest, host_t *candidate)
        !           996: {
        !           997:        return get_matching_address(this, NULL, family, net, mask, dest, candidate);
        !           998: }
        !           999: 
        !          1000: /**
        !          1001:  * callback function that raises the delayed roam event
        !          1002:  */
        !          1003: static job_requeue_t roam_event(private_kernel_netlink_net_t *this)
        !          1004: {
        !          1005:        bool address;
        !          1006: 
        !          1007:        this->roam_lock->lock(this->roam_lock);
        !          1008:        address = this->roam_address;
        !          1009:        this->roam_address = FALSE;
        !          1010:        this->roam_lock->unlock(this->roam_lock);
        !          1011:        charon->kernel->roam(charon->kernel, address);
        !          1012:        return JOB_REQUEUE_NONE;
        !          1013: }
        !          1014: 
        !          1015: /**
        !          1016:  * fire a roaming event. we delay it for a bit and fire only one event
        !          1017:  * for multiple calls. otherwise we would create too many events.
        !          1018:  */
        !          1019: static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)
        !          1020: {
        !          1021:        timeval_t now;
        !          1022:        job_t *job;
        !          1023: 
        !          1024:        if (!this->roam_events)
        !          1025:        {
        !          1026:                return;
        !          1027:        }
        !          1028: 
        !          1029:        time_monotonic(&now);
        !          1030:        this->roam_lock->lock(this->roam_lock);
        !          1031:        this->roam_address |= address;
        !          1032:        if (!timercmp(&now, &this->next_roam, >))
        !          1033:        {
        !          1034:                this->roam_lock->unlock(this->roam_lock);
        !          1035:                return;
        !          1036:        }
        !          1037:        timeval_add_ms(&now, ROAM_DELAY);
        !          1038:        this->next_roam = now;
        !          1039:        this->roam_lock->unlock(this->roam_lock);
        !          1040: 
        !          1041:        job = (job_t*)callback_job_create((callback_job_cb_t)roam_event,
        !          1042:                                                                          this, NULL, NULL);
        !          1043:        lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY);
        !          1044: }
        !          1045: 
        !          1046: /**
        !          1047:  * check if an interface with a given index is up and usable
        !          1048:  *
        !          1049:  * this->lock must be locked when calling this function
        !          1050:  */
        !          1051: static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
        !          1052:                                                                           int index)
        !          1053: {
        !          1054:        iface_entry_t *iface;
        !          1055: 
        !          1056:        if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
        !          1057:                                                                 (void**)&iface, index))
        !          1058:        {
        !          1059:                return iface_entry_up_and_usable(iface);
        !          1060:        }
        !          1061:        return FALSE;
        !          1062: }
        !          1063: 
        !          1064: /**
        !          1065:  * unregister the current addr_entry_t from the hashtable it is stored in
        !          1066:  *
        !          1067:  * this->lock must be locked when calling this function
        !          1068:  */
        !          1069: CALLBACK(addr_entry_unregister, void,
        !          1070:        addr_entry_t *addr, va_list args)
        !          1071: {
        !          1072:        private_kernel_netlink_net_t *this;
        !          1073:        iface_entry_t *iface;
        !          1074: 
        !          1075:        VA_ARGS_VGET(args, iface, this);
        !          1076:        if (addr->refcount)
        !          1077:        {
        !          1078:                addr_map_entry_remove(this->vips, addr, iface);
        !          1079:                this->condvar->broadcast(this->condvar);
        !          1080:                return;
        !          1081:        }
        !          1082:        addr_map_entry_remove(this->addrs, addr, iface);
        !          1083: }
        !          1084: 
        !          1085: /**
        !          1086:  * process RTM_NEWLINK/RTM_DELLINK from kernel
        !          1087:  */
        !          1088: static void process_link(private_kernel_netlink_net_t *this,
        !          1089:                                                 struct nlmsghdr *hdr, bool event)
        !          1090: {
        !          1091:        struct ifinfomsg* msg = NLMSG_DATA(hdr);
        !          1092:        struct rtattr *rta = IFLA_RTA(msg);
        !          1093:        size_t rtasize = IFLA_PAYLOAD (hdr);
        !          1094:        enumerator_t *enumerator;
        !          1095:        iface_entry_t *current, *entry = NULL;
        !          1096:        char *name = NULL;
        !          1097:        bool update = FALSE, update_routes = FALSE;
        !          1098: 
        !          1099:        while (RTA_OK(rta, rtasize))
        !          1100:        {
        !          1101:                switch (rta->rta_type)
        !          1102:                {
        !          1103:                        case IFLA_IFNAME:
        !          1104:                                name = RTA_DATA(rta);
        !          1105:                                break;
        !          1106:                }
        !          1107:                rta = RTA_NEXT(rta, rtasize);
        !          1108:        }
        !          1109:        if (!name)
        !          1110:        {
        !          1111:                name = "(unknown)";
        !          1112:        }
        !          1113: 
        !          1114:        this->lock->write_lock(this->lock);
        !          1115:        switch (hdr->nlmsg_type)
        !          1116:        {
        !          1117:                case RTM_NEWLINK:
        !          1118:                {
        !          1119:                        if (!this->ifaces->find_first(this->ifaces, iface_entry_by_index,
        !          1120:                                                                                 (void**)&entry, msg->ifi_index))
        !          1121:                        {
        !          1122:                                INIT(entry,
        !          1123:                                        .ifindex = msg->ifi_index,
        !          1124:                                        .addrs = linked_list_create(),
        !          1125:                                );
        !          1126:                                this->ifaces->insert_last(this->ifaces, entry);
        !          1127:                        }
        !          1128:                        strncpy(entry->ifname, name, IFNAMSIZ);
        !          1129:                        entry->ifname[IFNAMSIZ-1] = '\0';
        !          1130:                        entry->usable = charon->kernel->is_interface_usable(charon->kernel,
        !          1131:                                                                                                                                name);
        !          1132:                        if (event && entry->usable)
        !          1133:                        {
        !          1134:                                if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
        !          1135:                                {
        !          1136:                                        update = update_routes = TRUE;
        !          1137:                                        DBG1(DBG_KNL, "interface %s activated", name);
        !          1138:                                }
        !          1139:                                if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP))
        !          1140:                                {
        !          1141:                                        update = TRUE;
        !          1142:                                        DBG1(DBG_KNL, "interface %s deactivated", name);
        !          1143:                                }
        !          1144:                        }
        !          1145:                        entry->flags = msg->ifi_flags;
        !          1146:                        break;
        !          1147:                }
        !          1148:                case RTM_DELLINK:
        !          1149:                {
        !          1150:                        enumerator = this->ifaces->create_enumerator(this->ifaces);
        !          1151:                        while (enumerator->enumerate(enumerator, &current))
        !          1152:                        {
        !          1153:                                if (current->ifindex == msg->ifi_index)
        !          1154:                                {
        !          1155:                                        if (event && current->usable)
        !          1156:                                        {
        !          1157:                                                update = TRUE;
        !          1158:                                                DBG1(DBG_KNL, "interface %s deleted", current->ifname);
        !          1159:                                        }
        !          1160:                                        /* TODO: move virtual IPs installed on this interface to
        !          1161:                                         * another interface? */
        !          1162:                                        this->ifaces->remove_at(this->ifaces, enumerator);
        !          1163:                                        current->addrs->invoke_function(current->addrs,
        !          1164:                                                                                addr_entry_unregister, current, this);
        !          1165:                                        iface_entry_destroy(current);
        !          1166:                                        break;
        !          1167:                                }
        !          1168:                        }
        !          1169:                        enumerator->destroy(enumerator);
        !          1170:                        break;
        !          1171:                }
        !          1172:        }
        !          1173:        this->lock->unlock(this->lock);
        !          1174: 
        !          1175:        if (update_routes && event)
        !          1176:        {
        !          1177:                queue_route_reinstall(this, strdup(name));
        !          1178:        }
        !          1179: 
        !          1180:        if (update && event)
        !          1181:        {
        !          1182:                fire_roam_event(this, TRUE);
        !          1183:        }
        !          1184: }
        !          1185: 
        !          1186: /**
        !          1187:  * process RTM_NEWADDR/RTM_DELADDR from kernel
        !          1188:  */
        !          1189: static void process_addr(private_kernel_netlink_net_t *this,
        !          1190:                                                 struct nlmsghdr *hdr, bool event)
        !          1191: {
        !          1192:        struct ifaddrmsg* msg = NLMSG_DATA(hdr);
        !          1193:        struct rtattr *rta = IFA_RTA(msg);
        !          1194:        size_t rtasize = IFA_PAYLOAD (hdr);
        !          1195:        host_t *host = NULL;
        !          1196:        iface_entry_t *iface;
        !          1197:        chunk_t local = chunk_empty, address = chunk_empty;
        !          1198:        char *route_ifname = NULL;
        !          1199:        bool update = FALSE, found = FALSE, changed = FALSE;
        !          1200: 
        !          1201:        while (RTA_OK(rta, rtasize))
        !          1202:        {
        !          1203:                switch (rta->rta_type)
        !          1204:                {
        !          1205:                        case IFA_LOCAL:
        !          1206:                                local.ptr = RTA_DATA(rta);
        !          1207:                                local.len = RTA_PAYLOAD(rta);
        !          1208:                                break;
        !          1209:                        case IFA_ADDRESS:
        !          1210:                                address.ptr = RTA_DATA(rta);
        !          1211:                                address.len = RTA_PAYLOAD(rta);
        !          1212:                                break;
        !          1213:                }
        !          1214:                rta = RTA_NEXT(rta, rtasize);
        !          1215:        }
        !          1216: 
        !          1217:        /* For PPP interfaces, we need the IFA_LOCAL address,
        !          1218:         * IFA_ADDRESS is the peers address. But IFA_LOCAL is
        !          1219:         * not included in all cases (IPv6?), so fallback to IFA_ADDRESS. */
        !          1220:        if (local.ptr)
        !          1221:        {
        !          1222:                host = host_create_from_chunk(msg->ifa_family, local, 0);
        !          1223:        }
        !          1224:        else if (address.ptr)
        !          1225:        {
        !          1226:                host = host_create_from_chunk(msg->ifa_family, address, 0);
        !          1227:        }
        !          1228: 
        !          1229:        if (host == NULL)
        !          1230:        {       /* bad family? */
        !          1231:                return;
        !          1232:        }
        !          1233: 
        !          1234:        this->lock->write_lock(this->lock);
        !          1235:        if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
        !          1236:                                                                 (void**)&iface, msg->ifa_index))
        !          1237:        {
        !          1238:                addr_map_entry_t *entry, lookup = {
        !          1239:                        .ip = host,
        !          1240:                        .iface = iface,
        !          1241:                };
        !          1242:                addr_entry_t *addr;
        !          1243: 
        !          1244:                entry = this->vips->get(this->vips, &lookup);
        !          1245:                if (entry)
        !          1246:                {
        !          1247:                        if (hdr->nlmsg_type == RTM_NEWADDR)
        !          1248:                        {       /* mark as installed and signal waiting threads */
        !          1249:                                entry->addr->installed = TRUE;
        !          1250:                        }
        !          1251:                        else
        !          1252:                        {       /* the address was already marked as uninstalled */
        !          1253:                                addr = entry->addr;
        !          1254:                                iface->addrs->remove(iface->addrs, addr, NULL);
        !          1255:                                addr_map_entry_remove(this->vips, addr, iface);
        !          1256:                                addr_entry_destroy(addr);
        !          1257:                        }
        !          1258:                        /* no roam events etc. for virtual IPs */
        !          1259:                        this->condvar->broadcast(this->condvar);
        !          1260:                        this->lock->unlock(this->lock);
        !          1261:                        host->destroy(host);
        !          1262:                        return;
        !          1263:                }
        !          1264:                entry = this->addrs->get(this->addrs, &lookup);
        !          1265:                if (entry)
        !          1266:                {
        !          1267:                        if (hdr->nlmsg_type == RTM_DELADDR)
        !          1268:                        {
        !          1269:                                found = TRUE;
        !          1270:                                addr = entry->addr;
        !          1271:                                iface->addrs->remove(iface->addrs, addr, NULL);
        !          1272:                                if (iface->usable)
        !          1273:                                {
        !          1274:                                        changed = TRUE;
        !          1275:                                        DBG1(DBG_KNL, "%H disappeared from %s", host,
        !          1276:                                                 iface->ifname);
        !          1277:                                }
        !          1278:                                addr_map_entry_remove(this->addrs, addr, iface);
        !          1279:                                addr_entry_destroy(addr);
        !          1280:                        }
        !          1281:                }
        !          1282:                else
        !          1283:                {
        !          1284:                        if (hdr->nlmsg_type == RTM_NEWADDR)
        !          1285:                        {
        !          1286:                                found = TRUE;
        !          1287:                                changed = TRUE;
        !          1288:                                route_ifname = strdup(iface->ifname);
        !          1289:                                INIT(addr,
        !          1290:                                        .ip = host->clone(host),
        !          1291:                                        .flags = msg->ifa_flags,
        !          1292:                                        .scope = msg->ifa_scope,
        !          1293:                                );
        !          1294:                                iface->addrs->insert_last(iface->addrs, addr);
        !          1295:                                addr_map_entry_add(this->addrs, addr, iface);
        !          1296:                                if (event && iface->usable)
        !          1297:                                {
        !          1298:                                        DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
        !          1299:                                }
        !          1300:                        }
        !          1301:                }
        !          1302:                if (found && (iface->flags & IFF_UP))
        !          1303:                {
        !          1304:                        update = TRUE;
        !          1305:                }
        !          1306:                if (!iface->usable)
        !          1307:                {       /* ignore events for interfaces excluded by config */
        !          1308:                        update = changed = FALSE;
        !          1309:                }
        !          1310:        }
        !          1311:        this->lock->unlock(this->lock);
        !          1312: 
        !          1313:        if (update && event && route_ifname)
        !          1314:        {
        !          1315:                queue_route_reinstall(this, route_ifname);
        !          1316:        }
        !          1317:        else
        !          1318:        {
        !          1319:                free(route_ifname);
        !          1320:        }
        !          1321:        host->destroy(host);
        !          1322: 
        !          1323:        /* send an update to all IKE_SAs */
        !          1324:        if (update && event && changed)
        !          1325:        {
        !          1326:                fire_roam_event(this, TRUE);
        !          1327:        }
        !          1328: }
        !          1329: 
        !          1330: /**
        !          1331:  * process RTM_NEWROUTE and RTM_DELROUTE from kernel
        !          1332:  */
        !          1333: static void process_route(private_kernel_netlink_net_t *this,
        !          1334:                                                  struct nlmsghdr *hdr)
        !          1335: {
        !          1336:        struct rtmsg* msg = NLMSG_DATA(hdr);
        !          1337:        struct rtattr *rta = RTM_RTA(msg);
        !          1338:        size_t rtasize = RTM_PAYLOAD(hdr);
        !          1339:        uint32_t rta_oif = 0;
        !          1340:        host_t *host = NULL;
        !          1341: 
        !          1342:        /* ignore routes added by us or in the local routing table (local addrs) */
        !          1343:        if (msg->rtm_table && (msg->rtm_table == this->routing_table ||
        !          1344:                                                   msg->rtm_table == RT_TABLE_LOCAL))
        !          1345:        {
        !          1346:                return;
        !          1347:        }
        !          1348:        else if (msg->rtm_flags & RTM_F_CLONED)
        !          1349:        {       /* ignore cached routes, seem to be created a lot for IPv6 */
        !          1350:                return;
        !          1351:        }
        !          1352: 
        !          1353:        while (RTA_OK(rta, rtasize))
        !          1354:        {
        !          1355:                switch (rta->rta_type)
        !          1356:                {
        !          1357: #ifdef HAVE_RTA_TABLE
        !          1358:                        case RTA_TABLE:
        !          1359:                                /* also check against extended table ID */
        !          1360:                                if (RTA_PAYLOAD(rta) == sizeof(uint32_t) &&
        !          1361:                                        this->routing_table == *(uint32_t*)RTA_DATA(rta))
        !          1362:                                {
        !          1363:                                        return;
        !          1364:                                }
        !          1365:                                break;
        !          1366: #endif /* HAVE_RTA_TABLE */
        !          1367:                        case RTA_PREFSRC:
        !          1368:                                DESTROY_IF(host);
        !          1369:                                host = host_create_from_chunk(msg->rtm_family,
        !          1370:                                                        chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), 0);
        !          1371:                                break;
        !          1372:                        case RTA_OIF:
        !          1373:                                if (RTA_PAYLOAD(rta) == sizeof(rta_oif))
        !          1374:                                {
        !          1375:                                        rta_oif = *(uint32_t*)RTA_DATA(rta);
        !          1376:                                }
        !          1377:                                break;
        !          1378:                }
        !          1379:                rta = RTA_NEXT(rta, rtasize);
        !          1380:        }
        !          1381:        this->lock->read_lock(this->lock);
        !          1382:        if (rta_oif && !is_interface_up_and_usable(this, rta_oif))
        !          1383:        {       /* ignore route changes for interfaces that are ignored or down */
        !          1384:                this->lock->unlock(this->lock);
        !          1385:                DESTROY_IF(host);
        !          1386:                return;
        !          1387:        }
        !          1388:        if (!host && rta_oif)
        !          1389:        {
        !          1390:                host = get_interface_address(this, rta_oif, msg->rtm_family,
        !          1391:                                                                         NULL, NULL);
        !          1392:        }
        !          1393:        if (!host || is_known_vip(this, host))
        !          1394:        {       /* ignore routes added for virtual IPs */
        !          1395:                this->lock->unlock(this->lock);
        !          1396:                DESTROY_IF(host);
        !          1397:                return;
        !          1398:        }
        !          1399:        this->lock->unlock(this->lock);
        !          1400:        fire_roam_event(this, FALSE);
        !          1401:        host->destroy(host);
        !          1402: }
        !          1403: 
        !          1404: /**
        !          1405:  * process RTM_NEW|DELRULE from kernel
        !          1406:  */
        !          1407: static void process_rule(private_kernel_netlink_net_t *this,
        !          1408:                                                 struct nlmsghdr *hdr)
        !          1409: {
        !          1410: #ifdef HAVE_LINUX_FIB_RULES_H
        !          1411:        struct rtmsg* msg = NLMSG_DATA(hdr);
        !          1412:        struct rtattr *rta = RTM_RTA(msg);
        !          1413:        size_t rtasize = RTM_PAYLOAD(hdr);
        !          1414: 
        !          1415:        /* ignore rules added by us or in the local routing table (local addrs) */
        !          1416:        if (msg->rtm_table && (msg->rtm_table == this->routing_table ||
        !          1417:                                                   msg->rtm_table == RT_TABLE_LOCAL))
        !          1418:        {
        !          1419:                return;
        !          1420:        }
        !          1421: 
        !          1422:        while (RTA_OK(rta, rtasize))
        !          1423:        {
        !          1424:                switch (rta->rta_type)
        !          1425:                {
        !          1426:                        case FRA_TABLE:
        !          1427:                                /* also check against extended table ID */
        !          1428:                                if (RTA_PAYLOAD(rta) == sizeof(uint32_t) &&
        !          1429:                                        this->routing_table == *(uint32_t*)RTA_DATA(rta))
        !          1430:                                {
        !          1431:                                        return;
        !          1432:                                }
        !          1433:                                break;
        !          1434:                }
        !          1435:                rta = RTA_NEXT(rta, rtasize);
        !          1436:        }
        !          1437:        fire_roam_event(this, FALSE);
        !          1438: #endif
        !          1439: }
        !          1440: 
        !          1441: /**
        !          1442:  * Receives events from kernel
        !          1443:  */
        !          1444: static bool receive_events(private_kernel_netlink_net_t *this, int fd,
        !          1445:                                                   watcher_event_t event)
        !          1446: {
        !          1447:        char response[netlink_get_buflen()];
        !          1448:        struct nlmsghdr *hdr = (struct nlmsghdr*)response;
        !          1449:        struct sockaddr_nl addr;
        !          1450:        socklen_t addr_len = sizeof(addr);
        !          1451:        int len;
        !          1452: 
        !          1453:        len = recvfrom(this->socket_events, response, sizeof(response),
        !          1454:                                   MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len);
        !          1455:        if (len < 0)
        !          1456:        {
        !          1457:                switch (errno)
        !          1458:                {
        !          1459:                        case EINTR:
        !          1460:                                /* interrupted, try again */
        !          1461:                                return TRUE;
        !          1462:                        case EAGAIN:
        !          1463:                                /* no data ready, select again */
        !          1464:                                return TRUE;
        !          1465:                        default:
        !          1466:                                DBG1(DBG_KNL, "unable to receive from RT event socket %s (%d)",
        !          1467:                                         strerror(errno), errno);
        !          1468:                                sleep(1);
        !          1469:                                return TRUE;
        !          1470:                }
        !          1471:        }
        !          1472: 
        !          1473:        if (addr.nl_pid != 0)
        !          1474:        {       /* not from kernel. not interested, try another one */
        !          1475:                return TRUE;
        !          1476:        }
        !          1477: 
        !          1478:        while (NLMSG_OK(hdr, len))
        !          1479:        {
        !          1480:                /* looks good so far, dispatch netlink message */
        !          1481:                switch (hdr->nlmsg_type)
        !          1482:                {
        !          1483:                        case RTM_NEWADDR:
        !          1484:                        case RTM_DELADDR:
        !          1485:                                process_addr(this, hdr, TRUE);
        !          1486:                                break;
        !          1487:                        case RTM_NEWLINK:
        !          1488:                        case RTM_DELLINK:
        !          1489:                                process_link(this, hdr, TRUE);
        !          1490:                                break;
        !          1491:                        case RTM_NEWROUTE:
        !          1492:                        case RTM_DELROUTE:
        !          1493:                                if (this->process_route)
        !          1494:                                {
        !          1495:                                        process_route(this, hdr);
        !          1496:                                }
        !          1497:                                break;
        !          1498:                        case RTM_NEWRULE:
        !          1499:                        case RTM_DELRULE:
        !          1500:                                if (this->process_rules)
        !          1501:                                {
        !          1502:                                        process_rule(this, hdr);
        !          1503:                                }
        !          1504:                                break;
        !          1505:                        default:
        !          1506:                                break;
        !          1507:                }
        !          1508:                hdr = NLMSG_NEXT(hdr, len);
        !          1509:        }
        !          1510:        return TRUE;
        !          1511: }
        !          1512: 
        !          1513: /** enumerator over addresses */
        !          1514: typedef struct {
        !          1515:        private_kernel_netlink_net_t* this;
        !          1516:        /** which addresses to enumerate */
        !          1517:        kernel_address_type_t which;
        !          1518: } address_enumerator_t;
        !          1519: 
        !          1520: CALLBACK(address_enumerator_destroy, void,
        !          1521:        address_enumerator_t *data)
        !          1522: {
        !          1523:        data->this->lock->unlock(data->this->lock);
        !          1524:        free(data);
        !          1525: }
        !          1526: 
        !          1527: CALLBACK(filter_addresses, bool,
        !          1528:        address_enumerator_t *data, enumerator_t *orig, va_list args)
        !          1529: {
        !          1530:        addr_entry_t *addr;
        !          1531:        host_t **out;
        !          1532: 
        !          1533:        VA_ARGS_VGET(args, out);
        !          1534: 
        !          1535:        while (orig->enumerate(orig, &addr))
        !          1536:        {
        !          1537:                if (!(data->which & ADDR_TYPE_VIRTUAL) && addr->refcount)
        !          1538:                {       /* skip virtual interfaces added by us */
        !          1539:                        continue;
        !          1540:                }
        !          1541:                if (!(data->which & ADDR_TYPE_REGULAR) && !addr->refcount)
        !          1542:                {       /* address is regular, but not requested */
        !          1543:                        continue;
        !          1544:                }
        !          1545:                if (addr->flags & IFA_F_DEPRECATED ||
        !          1546:                        addr->scope >= RT_SCOPE_LINK)
        !          1547:                {       /* skip deprecated addresses or those with an unusable scope */
        !          1548:                        continue;
        !          1549:                }
        !          1550:                if (addr->ip->get_family(addr->ip) == AF_INET6)
        !          1551:                {       /* handle temporary IPv6 addresses according to config */
        !          1552:                        bool temporary = (addr->flags & IFA_F_TEMPORARY) == IFA_F_TEMPORARY;
        !          1553:                        if (data->this->prefer_temporary_addrs != temporary)
        !          1554:                        {
        !          1555:                                continue;
        !          1556:                        }
        !          1557:                }
        !          1558:                *out = addr->ip;
        !          1559:                return TRUE;
        !          1560:        }
        !          1561:        return FALSE;
        !          1562: }
        !          1563: 
        !          1564: /**
        !          1565:  * enumerator constructor for interfaces
        !          1566:  */
        !          1567: static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
        !          1568:                                                                                         address_enumerator_t *data)
        !          1569: {
        !          1570:        return enumerator_create_filter(
        !          1571:                                                iface->addrs->create_enumerator(iface->addrs),
        !          1572:                                                filter_addresses, data, NULL);
        !          1573: }
        !          1574: 
        !          1575: CALLBACK(filter_interfaces, bool,
        !          1576:        address_enumerator_t *data, enumerator_t *orig, va_list args)
        !          1577: {
        !          1578:        iface_entry_t *iface, **out;
        !          1579: 
        !          1580:        VA_ARGS_VGET(args, out);
        !          1581: 
        !          1582:        while (orig->enumerate(orig, &iface))
        !          1583:        {
        !          1584:                if (!(data->which & ADDR_TYPE_IGNORED) && !iface->usable)
        !          1585:                {       /* skip interfaces excluded by config */
        !          1586:                        continue;
        !          1587:                }
        !          1588:                if (!(data->which & ADDR_TYPE_LOOPBACK) && (iface->flags & IFF_LOOPBACK))
        !          1589:                {       /* ignore loopback devices */
        !          1590:                        continue;
        !          1591:                }
        !          1592:                if (!(data->which & ADDR_TYPE_DOWN) && !(iface->flags & IFF_UP))
        !          1593:                {       /* skip interfaces not up */
        !          1594:                        continue;
        !          1595:                }
        !          1596:                *out = iface;
        !          1597:                return TRUE;
        !          1598:        }
        !          1599:        return FALSE;
        !          1600: }
        !          1601: 
        !          1602: METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
        !          1603:        private_kernel_netlink_net_t *this, kernel_address_type_t which)
        !          1604: {
        !          1605:        address_enumerator_t *data;
        !          1606: 
        !          1607:        INIT(data,
        !          1608:                .this = this,
        !          1609:                .which = which,
        !          1610:        );
        !          1611: 
        !          1612:        this->lock->read_lock(this->lock);
        !          1613:        return enumerator_create_nested(
        !          1614:                                enumerator_create_filter(
        !          1615:                                        this->ifaces->create_enumerator(this->ifaces),
        !          1616:                                        filter_interfaces, data, NULL),
        !          1617:                                (void*)create_iface_enumerator, data,
        !          1618:                                address_enumerator_destroy);
        !          1619: }
        !          1620: 
        !          1621: METHOD(kernel_net_t, get_interface_name, bool,
        !          1622:        private_kernel_netlink_net_t *this, host_t* ip, char **name)
        !          1623: {
        !          1624:        addr_map_entry_t *entry, lookup = {
        !          1625:                .ip = ip,
        !          1626:        };
        !          1627: 
        !          1628:        if (ip->is_anyaddr(ip))
        !          1629:        {
        !          1630:                return FALSE;
        !          1631:        }
        !          1632:        this->lock->read_lock(this->lock);
        !          1633:        /* first try to find it on an up and usable interface */
        !          1634:        entry = this->addrs->get_match(this->addrs, &lookup,
        !          1635:                                                                  (void*)addr_map_entry_match_up_and_usable);
        !          1636:        if (entry)
        !          1637:        {
        !          1638:                if (name)
        !          1639:                {
        !          1640:                        *name = strdup(entry->iface->ifname);
        !          1641:                        DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
        !          1642:                }
        !          1643:                this->lock->unlock(this->lock);
        !          1644:                return TRUE;
        !          1645:        }
        !          1646:        /* in a second step, consider virtual IPs installed by us */
        !          1647:        entry = this->vips->get_match(this->vips, &lookup,
        !          1648:                                                                  (void*)addr_map_entry_match_up_and_usable);
        !          1649:        if (entry)
        !          1650:        {
        !          1651:                if (name)
        !          1652:                {
        !          1653:                        *name = strdup(entry->iface->ifname);
        !          1654:                        DBG2(DBG_KNL, "virtual IP %H is on interface %s", ip, *name);
        !          1655:                }
        !          1656:                this->lock->unlock(this->lock);
        !          1657:                return TRUE;
        !          1658:        }
        !          1659:        /* maybe it is installed on an ignored interface */
        !          1660:        entry = this->addrs->get_match(this->addrs, &lookup,
        !          1661:                                                                  (void*)addr_map_entry_match_up);
        !          1662:        if (!entry)
        !          1663:        {
        !          1664:                DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip);
        !          1665:        }
        !          1666:        this->lock->unlock(this->lock);
        !          1667:        return FALSE;
        !          1668: }
        !          1669: 
        !          1670: /**
        !          1671:  * get the index of an interface by name
        !          1672:  */
        !          1673: static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
        !          1674: {
        !          1675:        iface_entry_t *iface;
        !          1676:        int ifindex = 0;
        !          1677: 
        !          1678:        DBG2(DBG_KNL, "getting iface index for %s", name);
        !          1679: 
        !          1680:        this->lock->read_lock(this->lock);
        !          1681:        if (this->ifaces->find_first(this->ifaces, iface_entry_by_name,
        !          1682:                                                                (void**)&iface, name))
        !          1683:        {
        !          1684:                ifindex = iface->ifindex;
        !          1685:        }
        !          1686:        this->lock->unlock(this->lock);
        !          1687: 
        !          1688:        if (ifindex == 0)
        !          1689:        {
        !          1690:                DBG1(DBG_KNL, "unable to get interface index for %s", name);
        !          1691:        }
        !          1692:        return ifindex;
        !          1693: }
        !          1694: 
        !          1695: /**
        !          1696:  * get the name of an interface by index (allocated)
        !          1697:  */
        !          1698: static char *get_interface_name_by_index(private_kernel_netlink_net_t *this,
        !          1699:                                                                                 int index)
        !          1700: {
        !          1701:        iface_entry_t *iface;
        !          1702:        char *name = NULL;
        !          1703: 
        !          1704:        DBG2(DBG_KNL, "getting iface name for index %d", index);
        !          1705: 
        !          1706:        this->lock->read_lock(this->lock);
        !          1707:        if (this->ifaces->find_first(this->ifaces, iface_entry_by_index,
        !          1708:                                                                (void**)&iface, index))
        !          1709:        {
        !          1710:                name = strdup(iface->ifname);
        !          1711:        }
        !          1712:        this->lock->unlock(this->lock);
        !          1713: 
        !          1714:        if (!name)
        !          1715:        {
        !          1716:                DBG1(DBG_KNL, "unable to get interface name for %d", index);
        !          1717:        }
        !          1718:        return name;
        !          1719: }
        !          1720: 
        !          1721: /**
        !          1722:  * Store information about a route retrieved via RTNETLINK
        !          1723:  */
        !          1724: typedef struct {
        !          1725:        chunk_t gtw;
        !          1726:        chunk_t pref_src;
        !          1727:        chunk_t dst;
        !          1728:        chunk_t src;
        !          1729:        host_t *src_host;
        !          1730:        uint8_t dst_len;
        !          1731:        uint8_t src_len;
        !          1732:        uint32_t table;
        !          1733:        uint32_t oif;
        !          1734:        uint32_t priority;
        !          1735: } rt_entry_t;
        !          1736: 
        !          1737: /**
        !          1738:  * Free a route entry
        !          1739:  */
        !          1740: static void rt_entry_destroy(rt_entry_t *this)
        !          1741: {
        !          1742:        DESTROY_IF(this->src_host);
        !          1743:        free(this);
        !          1744: }
        !          1745: 
        !          1746: /**
        !          1747:  * Check if the route received with RTM_NEWROUTE is usable based on its type.
        !          1748:  */
        !          1749: static bool route_usable(struct nlmsghdr *hdr, bool allow_local)
        !          1750: {
        !          1751:        struct rtmsg *msg;
        !          1752: 
        !          1753:        msg = NLMSG_DATA(hdr);
        !          1754:        switch (msg->rtm_type)
        !          1755:        {
        !          1756:                case RTN_BLACKHOLE:
        !          1757:                case RTN_UNREACHABLE:
        !          1758:                case RTN_PROHIBIT:
        !          1759:                case RTN_THROW:
        !          1760:                        return FALSE;
        !          1761:                case RTN_LOCAL:
        !          1762:                        return allow_local;
        !          1763:                default:
        !          1764:                        return TRUE;
        !          1765:        }
        !          1766: }
        !          1767: 
        !          1768: /**
        !          1769:  * Parse route received with RTM_NEWROUTE. The given rt_entry_t object will be
        !          1770:  * reused if not NULL.
        !          1771:  *
        !          1772:  * Returned chunks point to internal data of the Netlink message.
        !          1773:  */
        !          1774: static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route)
        !          1775: {
        !          1776:        struct rtattr *rta;
        !          1777:        struct rtmsg *msg;
        !          1778:        size_t rtasize;
        !          1779: 
        !          1780:        msg = NLMSG_DATA(hdr);
        !          1781:        rta = RTM_RTA(msg);
        !          1782:        rtasize = RTM_PAYLOAD(hdr);
        !          1783: 
        !          1784:        if (route)
        !          1785:        {
        !          1786:                *route = (rt_entry_t){
        !          1787:                        .dst_len = msg->rtm_dst_len,
        !          1788:                        .src_len = msg->rtm_src_len,
        !          1789:                        .table = msg->rtm_table,
        !          1790:                };
        !          1791:        }
        !          1792:        else
        !          1793:        {
        !          1794:                INIT(route,
        !          1795:                        .dst_len = msg->rtm_dst_len,
        !          1796:                        .src_len = msg->rtm_src_len,
        !          1797:                        .table = msg->rtm_table,
        !          1798:                );
        !          1799:        }
        !          1800: 
        !          1801:        while (RTA_OK(rta, rtasize))
        !          1802:        {
        !          1803:                switch (rta->rta_type)
        !          1804:                {
        !          1805:                        case RTA_PREFSRC:
        !          1806:                                route->pref_src = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
        !          1807:                                break;
        !          1808:                        case RTA_GATEWAY:
        !          1809:                                route->gtw = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
        !          1810:                                break;
        !          1811:                        case RTA_DST:
        !          1812:                                route->dst = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
        !          1813:                                break;
        !          1814:                        case RTA_SRC:
        !          1815:                                route->src = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta));
        !          1816:                                break;
        !          1817:                        case RTA_OIF:
        !          1818:                                if (RTA_PAYLOAD(rta) == sizeof(route->oif))
        !          1819:                                {
        !          1820:                                        route->oif = *(uint32_t*)RTA_DATA(rta);
        !          1821:                                }
        !          1822:                                break;
        !          1823:                        case RTA_PRIORITY:
        !          1824:                                if (RTA_PAYLOAD(rta) == sizeof(route->priority))
        !          1825:                                {
        !          1826:                                        route->priority = *(uint32_t*)RTA_DATA(rta);
        !          1827:                                }
        !          1828:                                break;
        !          1829: #ifdef HAVE_RTA_TABLE
        !          1830:                        case RTA_TABLE:
        !          1831:                                if (RTA_PAYLOAD(rta) == sizeof(route->table))
        !          1832:                                {
        !          1833:                                        route->table = *(uint32_t*)RTA_DATA(rta);
        !          1834:                                }
        !          1835:                                break;
        !          1836: #endif /* HAVE_RTA_TABLE*/
        !          1837:                }
        !          1838:                rta = RTA_NEXT(rta, rtasize);
        !          1839:        }
        !          1840:        return route;
        !          1841: }
        !          1842: 
        !          1843: /**
        !          1844:  * Get a route: If "nexthop", the nexthop is returned. source addr otherwise.
        !          1845:  */
        !          1846: static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
        !          1847:                                                 int prefix, bool nexthop, host_t *candidate,
        !          1848:                                                 char **iface, u_int recursion)
        !          1849: {
        !          1850:        netlink_buf_t request;
        !          1851:        struct nlmsghdr *hdr, *out, *current;
        !          1852:        struct rtmsg *msg;
        !          1853:        chunk_t chunk;
        !          1854:        size_t len;
        !          1855:        linked_list_t *routes;
        !          1856:        rt_entry_t *route = NULL, *best = NULL;
        !          1857:        enumerator_t *enumerator;
        !          1858:        host_t *addr = NULL;
        !          1859:        bool match_net;
        !          1860:        int family;
        !          1861: 
        !          1862:        if (recursion > MAX_ROUTE_RECURSION)
        !          1863:        {
        !          1864:                return NULL;
        !          1865:        }
        !          1866:        chunk = dest->get_address(dest);
        !          1867:        len = chunk.len * 8;
        !          1868:        prefix = prefix < 0 ? len : min(prefix, len);
        !          1869:        match_net = prefix != len;
        !          1870: 
        !          1871:        memset(&request, 0, sizeof(request));
        !          1872: 
        !          1873:        family = dest->get_family(dest);
        !          1874:        hdr = &request.hdr;
        !          1875:        hdr->nlmsg_flags = NLM_F_REQUEST;
        !          1876:        hdr->nlmsg_type = RTM_GETROUTE;
        !          1877:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !          1878: 
        !          1879:        msg = NLMSG_DATA(hdr);
        !          1880:        msg->rtm_family = family;
        !          1881:        if (!match_net && this->rta_mark && this->routing_mark.value)
        !          1882:        {
        !          1883:                /* if our routing rule excludes packets with a certain mark we can
        !          1884:                 * get the preferred route without having to dump all routes */
        !          1885:                chunk = chunk_from_thing(this->routing_mark.value);
        !          1886:                netlink_add_attribute(hdr, RTA_MARK, chunk, sizeof(request));
        !          1887:        }
        !          1888:        else if (family == AF_INET || this->rta_prefsrc_for_ipv6 ||
        !          1889:                         this->routing_table || match_net)
        !          1890:        {       /* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes.
        !          1891:                 * as we want to ignore routes with virtual IPs we cannot use DUMP
        !          1892:                 * if these routes are not installed in a separate table */
        !          1893:                if (this->install_routes)
        !          1894:                {
        !          1895:                        hdr->nlmsg_flags |= NLM_F_DUMP;
        !          1896:                }
        !          1897:        }
        !          1898:        if (candidate)
        !          1899:        {
        !          1900:                chunk = candidate->get_address(candidate);
        !          1901:                if (hdr->nlmsg_flags & NLM_F_DUMP)
        !          1902:                {
        !          1903:                        netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
        !          1904:                }
        !          1905:                else
        !          1906:                {
        !          1907:                        netlink_add_attribute(hdr, RTA_SRC, chunk, sizeof(request));
        !          1908:                }
        !          1909:        }
        !          1910:        /* we use this below to match against the routes */
        !          1911:        chunk = dest->get_address(dest);
        !          1912:        if (!match_net)
        !          1913:        {
        !          1914:                netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
        !          1915:        }
        !          1916: 
        !          1917:        if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
        !          1918:        {
        !          1919:                DBG2(DBG_KNL, "getting %s to reach %H/%d failed",
        !          1920:                         nexthop ? "nexthop" : "address", dest, prefix);
        !          1921:                return NULL;
        !          1922:        }
        !          1923:        routes = linked_list_create();
        !          1924:        this->lock->read_lock(this->lock);
        !          1925: 
        !          1926:        for (current = out; NLMSG_OK(current, len);
        !          1927:                 current = NLMSG_NEXT(current, len))
        !          1928:        {
        !          1929:                switch (current->nlmsg_type)
        !          1930:                {
        !          1931:                        case NLMSG_DONE:
        !          1932:                                break;
        !          1933:                        case RTM_NEWROUTE:
        !          1934:                        {
        !          1935:                                rt_entry_t *other;
        !          1936:                                uintptr_t table;
        !          1937: 
        !          1938:                                if (!route_usable(current, TRUE))
        !          1939:                                {
        !          1940:                                        continue;
        !          1941:                                }
        !          1942:                                route = parse_route(current, route);
        !          1943: 
        !          1944:                                table = (uintptr_t)route->table;
        !          1945:                                if (this->rt_exclude->find_first(this->rt_exclude, NULL,
        !          1946:                                                                                                 (void**)&table))
        !          1947:                                {       /* route is from an excluded routing table */
        !          1948:                                        continue;
        !          1949:                                }
        !          1950:                                if (this->routing_table != 0 &&
        !          1951:                                        route->table == this->routing_table)
        !          1952:                                {       /* route is from our own ipsec routing table */
        !          1953:                                        continue;
        !          1954:                                }
        !          1955:                                if (route->oif && !is_interface_up_and_usable(this, route->oif))
        !          1956:                                {       /* interface is down */
        !          1957:                                        continue;
        !          1958:                                }
        !          1959:                                if (!addr_in_subnet(chunk, prefix, route->dst, route->dst_len))
        !          1960:                                {       /* route destination does not contain dest */
        !          1961:                                        continue;
        !          1962:                                }
        !          1963:                                if (route->pref_src.ptr)
        !          1964:                                {       /* verify source address, if any */
        !          1965:                                        host_t *src = host_create_from_chunk(msg->rtm_family,
        !          1966:                                                                                                                 route->pref_src, 0);
        !          1967:                                        if (src && is_known_vip(this, src))
        !          1968:                                        {       /* ignore routes installed by us */
        !          1969:                                                src->destroy(src);
        !          1970:                                                continue;
        !          1971:                                        }
        !          1972:                                        route->src_host = src;
        !          1973:                                }
        !          1974:                                /* insert route, sorted by network prefix and priority */
        !          1975:                                enumerator = routes->create_enumerator(routes);
        !          1976:                                while (enumerator->enumerate(enumerator, &other))
        !          1977:                                {
        !          1978:                                        if (route->dst_len > other->dst_len)
        !          1979:                                        {
        !          1980:                                                break;
        !          1981:                                        }
        !          1982:                                        if (route->dst_len == other->dst_len &&
        !          1983:                                                route->priority < other->priority)
        !          1984:                                        {
        !          1985:                                                break;
        !          1986:                                        }
        !          1987:                                }
        !          1988:                                routes->insert_before(routes, enumerator, route);
        !          1989:                                enumerator->destroy(enumerator);
        !          1990:                                route = NULL;
        !          1991:                                continue;
        !          1992:                        }
        !          1993:                        default:
        !          1994:                                continue;
        !          1995:                }
        !          1996:                break;
        !          1997:        }
        !          1998:        if (route)
        !          1999:        {
        !          2000:                rt_entry_destroy(route);
        !          2001:        }
        !          2002: 
        !          2003:        /* now we have a list of routes matching dest, sorted by net prefix.
        !          2004:         * we will look for source addresses for these routes and select the one
        !          2005:         * with the preferred source address, if possible */
        !          2006:        enumerator = routes->create_enumerator(routes);
        !          2007:        while (enumerator->enumerate(enumerator, &route))
        !          2008:        {
        !          2009:                if (route->src_host)
        !          2010:                {       /* got a source address with the route, if no preferred source
        !          2011:                         * is given or it matches we are done, as this is the best route */
        !          2012:                        if (!candidate || candidate->ip_equals(candidate, route->src_host))
        !          2013:                        {
        !          2014:                                best = route;
        !          2015:                                break;
        !          2016:                        }
        !          2017:                        else if (route->oif)
        !          2018:                        {       /* no match yet, maybe it is assigned to the same interface */
        !          2019:                                host_t *src = get_interface_address(this, route->oif,
        !          2020:                                                                                        msg->rtm_family, dest, candidate);
        !          2021:                                if (src && src->ip_equals(src, candidate))
        !          2022:                                {
        !          2023:                                        route->src_host->destroy(route->src_host);
        !          2024:                                        route->src_host = src;
        !          2025:                                        best = route;
        !          2026:                                        break;
        !          2027:                                }
        !          2028:                                DESTROY_IF(src);
        !          2029:                        }
        !          2030:                        /* no luck yet with the source address. if this is the best (first)
        !          2031:                         * route we store it as fallback in case we don't find a route with
        !          2032:                         * the preferred source */
        !          2033:                        best = best ?: route;
        !          2034:                        continue;
        !          2035:                }
        !          2036:                if (route->src.ptr)
        !          2037:                {       /* no src, but a source selector, try to find a matching address */
        !          2038:                        route->src_host = get_subnet_address(this, msg->rtm_family,
        !          2039:                                                                                        route->src, route->src_len, dest,
        !          2040:                                                                                        candidate);
        !          2041:                        if (route->src_host)
        !          2042:                        {       /* we handle this address the same as the one above */
        !          2043:                                if (!candidate ||
        !          2044:                                         candidate->ip_equals(candidate, route->src_host))
        !          2045:                                {
        !          2046:                                        best = route;
        !          2047:                                        break;
        !          2048:                                }
        !          2049:                                best = best ?: route;
        !          2050:                                continue;
        !          2051:                        }
        !          2052:                }
        !          2053:                if (route->oif)
        !          2054:                {       /* no src, but an interface - get address from it */
        !          2055:                        route->src_host = get_interface_address(this, route->oif,
        !          2056:                                                                                        msg->rtm_family, dest, candidate);
        !          2057:                        if (route->src_host)
        !          2058:                        {       /* more of the same */
        !          2059:                                if (!candidate ||
        !          2060:                                         candidate->ip_equals(candidate, route->src_host))
        !          2061:                                {
        !          2062:                                        best = route;
        !          2063:                                        break;
        !          2064:                                }
        !          2065:                                best = best ?: route;
        !          2066:                                continue;
        !          2067:                        }
        !          2068:                }
        !          2069:                if (route->gtw.ptr)
        !          2070:                {       /* no src, no iface, but a gateway - lookup src to reach gtw */
        !          2071:                        host_t *gtw;
        !          2072: 
        !          2073:                        gtw = host_create_from_chunk(msg->rtm_family, route->gtw, 0);
        !          2074:                        if (gtw && !gtw->ip_equals(gtw, dest))
        !          2075:                        {
        !          2076:                                route->src_host = get_route(this, gtw, -1, FALSE, candidate,
        !          2077:                                                                                        iface, recursion + 1);
        !          2078:                        }
        !          2079:                        DESTROY_IF(gtw);
        !          2080:                        if (route->src_host)
        !          2081:                        {       /* more of the same */
        !          2082:                                if (!candidate ||
        !          2083:                                         candidate->ip_equals(candidate, route->src_host))
        !          2084:                                {
        !          2085:                                        best = route;
        !          2086:                                        break;
        !          2087:                                }
        !          2088:                                best = best ?: route;
        !          2089:                        }
        !          2090:                }
        !          2091:        }
        !          2092:        enumerator->destroy(enumerator);
        !          2093: 
        !          2094:        if (nexthop)
        !          2095:        {       /* nexthop lookup, return gateway and oif if any */
        !          2096:                if (iface)
        !          2097:                {
        !          2098:                        *iface = NULL;
        !          2099:                }
        !          2100:                if (best || routes->get_first(routes, (void**)&best) == SUCCESS)
        !          2101:                {
        !          2102:                        addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0);
        !          2103:                        if (iface && best->oif)
        !          2104:                        {
        !          2105:                                *iface = get_interface_name_by_index(this, best->oif);
        !          2106:                        }
        !          2107:                }
        !          2108:                if (!addr && !match_net)
        !          2109:                {       /* fallback to destination address */
        !          2110:                        addr = dest->clone(dest);
        !          2111:                }
        !          2112:        }
        !          2113:        else
        !          2114:        {
        !          2115:                if (best)
        !          2116:                {
        !          2117:                        addr = best->src_host->clone(best->src_host);
        !          2118:                }
        !          2119:        }
        !          2120:        this->lock->unlock(this->lock);
        !          2121:        routes->destroy_function(routes, (void*)rt_entry_destroy);
        !          2122:        free(out);
        !          2123: 
        !          2124:        if (addr)
        !          2125:        {
        !          2126:                if (nexthop && iface && *iface)
        !          2127:                {
        !          2128:                        DBG2(DBG_KNL, "using %H as nexthop and %s as dev to reach %H/%d",
        !          2129:                                 addr, *iface, dest, prefix);
        !          2130:                }
        !          2131:                else
        !          2132:                {
        !          2133:                        DBG2(DBG_KNL, "using %H as %s to reach %H/%d", addr,
        !          2134:                                 nexthop ? "nexthop" : "address", dest, prefix);
        !          2135:                }
        !          2136:        }
        !          2137:        else if (!recursion)
        !          2138:        {
        !          2139:                DBG2(DBG_KNL, "no %s found to reach %H/%d",
        !          2140:                         nexthop ? "nexthop" : "address", dest, prefix);
        !          2141:        }
        !          2142:        return addr;
        !          2143: }
        !          2144: 
        !          2145: METHOD(kernel_net_t, get_source_addr, host_t*,
        !          2146:        private_kernel_netlink_net_t *this, host_t *dest, host_t *src)
        !          2147: {
        !          2148:        return get_route(this, dest, -1, FALSE, src, NULL, 0);
        !          2149: }
        !          2150: 
        !          2151: METHOD(kernel_net_t, get_nexthop, host_t*,
        !          2152:        private_kernel_netlink_net_t *this, host_t *dest, int prefix, host_t *src,
        !          2153:        char **iface)
        !          2154: {
        !          2155:        return get_route(this, dest, prefix, TRUE, src, iface, 0);
        !          2156: }
        !          2157: 
        !          2158: /** enumerator over subnets */
        !          2159: typedef struct {
        !          2160:        enumerator_t public;
        !          2161:        private_kernel_netlink_net_t *private;
        !          2162:        /** message from the kernel */
        !          2163:        struct nlmsghdr *msg;
        !          2164:        /** current message from the kernel */
        !          2165:        struct nlmsghdr *current;
        !          2166:        /** remaining length */
        !          2167:        size_t len;
        !          2168:        /** last subnet enumerated */
        !          2169:        host_t *net;
        !          2170:        /** interface of current net */
        !          2171:        char ifname[IFNAMSIZ];
        !          2172: } subnet_enumerator_t;
        !          2173: 
        !          2174: METHOD(enumerator_t, destroy_subnet_enumerator, void,
        !          2175:        subnet_enumerator_t *this)
        !          2176: {
        !          2177:        DESTROY_IF(this->net);
        !          2178:        free(this->msg);
        !          2179:        free(this);
        !          2180: }
        !          2181: 
        !          2182: METHOD(enumerator_t, enumerate_subnets, bool,
        !          2183:        subnet_enumerator_t *this, va_list args)
        !          2184: {
        !          2185:        host_t **net;
        !          2186:        uint8_t *mask;
        !          2187:        char **ifname;
        !          2188: 
        !          2189:        VA_ARGS_VGET(args, net, mask, ifname);
        !          2190: 
        !          2191:        if (!this->current)
        !          2192:        {
        !          2193:                this->current = this->msg;
        !          2194:        }
        !          2195:        else
        !          2196:        {
        !          2197:                this->current = NLMSG_NEXT(this->current, this->len);
        !          2198:                DESTROY_IF(this->net);
        !          2199:                this->net = NULL;
        !          2200:        }
        !          2201: 
        !          2202:        while (NLMSG_OK(this->current, this->len))
        !          2203:        {
        !          2204:                switch (this->current->nlmsg_type)
        !          2205:                {
        !          2206:                        case NLMSG_DONE:
        !          2207:                                break;
        !          2208:                        case RTM_NEWROUTE:
        !          2209:                        {
        !          2210:                                rt_entry_t route;
        !          2211: 
        !          2212:                                if (!route_usable(this->current, FALSE))
        !          2213:                                {
        !          2214:                                        break;
        !          2215:                                }
        !          2216:                                parse_route(this->current, &route);
        !          2217: 
        !          2218:                                if (route.table && (
        !          2219:                                                        route.table == RT_TABLE_LOCAL ||
        !          2220:                                                        route.table == this->private->routing_table))
        !          2221:                                {       /* ignore our own and the local routing tables */
        !          2222:                                        break;
        !          2223:                                }
        !          2224:                                else if (route.gtw.ptr)
        !          2225:                                {       /* ignore routes via gateway/next hop */
        !          2226:                                        break;
        !          2227:                                }
        !          2228: 
        !          2229:                                if (route.dst.ptr && route.oif &&
        !          2230:                                        if_indextoname(route.oif, this->ifname))
        !          2231:                                {
        !          2232:                                        this->net = host_create_from_chunk(AF_UNSPEC, route.dst, 0);
        !          2233:                                        *net = this->net;
        !          2234:                                        *mask = route.dst_len;
        !          2235:                                        *ifname = this->ifname;
        !          2236:                                        return TRUE;
        !          2237:                                }
        !          2238:                                break;
        !          2239:                        }
        !          2240:                        default:
        !          2241:                                break;
        !          2242:                }
        !          2243:                this->current = NLMSG_NEXT(this->current, this->len);
        !          2244:        }
        !          2245:        return FALSE;
        !          2246: }
        !          2247: 
        !          2248: METHOD(kernel_net_t, create_local_subnet_enumerator, enumerator_t*,
        !          2249:        private_kernel_netlink_net_t *this)
        !          2250: {
        !          2251:        netlink_buf_t request;
        !          2252:        struct nlmsghdr *hdr, *out;
        !          2253:        struct rtmsg *msg;
        !          2254:        size_t len;
        !          2255:        subnet_enumerator_t *enumerator;
        !          2256: 
        !          2257:        memset(&request, 0, sizeof(request));
        !          2258: 
        !          2259:        hdr = &request.hdr;
        !          2260:        hdr->nlmsg_flags = NLM_F_REQUEST;
        !          2261:        hdr->nlmsg_type = RTM_GETROUTE;
        !          2262:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !          2263:        hdr->nlmsg_flags |= NLM_F_DUMP;
        !          2264: 
        !          2265:        msg = NLMSG_DATA(hdr);
        !          2266:        msg->rtm_scope = RT_SCOPE_LINK;
        !          2267: 
        !          2268:        if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
        !          2269:        {
        !          2270:                DBG2(DBG_KNL, "enumerating local subnets failed");
        !          2271:                return enumerator_create_empty();
        !          2272:        }
        !          2273: 
        !          2274:        INIT(enumerator,
        !          2275:                .public = {
        !          2276:                        .enumerate = enumerator_enumerate_default,
        !          2277:                        .venumerate = _enumerate_subnets,
        !          2278:                        .destroy = _destroy_subnet_enumerator,
        !          2279:                },
        !          2280:                .private = this,
        !          2281:                .msg = out,
        !          2282:                .len = len,
        !          2283:        );
        !          2284:        return &enumerator->public;
        !          2285: }
        !          2286: 
        !          2287: /**
        !          2288:  * Manages the creation and deletion of IPv6 address labels for virtual IPs.
        !          2289:  * By setting the appropriate nlmsg_type the label is either added or removed.
        !          2290:  */
        !          2291: static status_t manage_addrlabel(private_kernel_netlink_net_t *this,
        !          2292:                                                                 int nlmsg_type, host_t *ip)
        !          2293: {
        !          2294:        netlink_buf_t request;
        !          2295:        struct nlmsghdr *hdr;
        !          2296:        struct ifaddrlblmsg *msg;
        !          2297:        chunk_t chunk;
        !          2298:        uint32_t label;
        !          2299: 
        !          2300:        memset(&request, 0, sizeof(request));
        !          2301: 
        !          2302:        chunk = ip->get_address(ip);
        !          2303: 
        !          2304:        hdr = &request.hdr;
        !          2305:        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        !          2306:        if (nlmsg_type == RTM_NEWADDRLABEL)
        !          2307:        {
        !          2308:                hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
        !          2309:        }
        !          2310:        hdr->nlmsg_type = nlmsg_type;
        !          2311:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg));
        !          2312: 
        !          2313:        msg = NLMSG_DATA(hdr);
        !          2314:        msg->ifal_family = ip->get_family(ip);
        !          2315:        msg->ifal_prefixlen = chunk.len * 8;
        !          2316: 
        !          2317:        netlink_add_attribute(hdr, IFAL_ADDRESS, chunk, sizeof(request));
        !          2318:        /* doesn't really matter as default labels are < 20 but this makes it kinda
        !          2319:         * recognizable */
        !          2320:        label = 220;
        !          2321:        netlink_add_attribute(hdr, IFAL_LABEL, chunk_from_thing(label),
        !          2322:                                                  sizeof(request));
        !          2323: 
        !          2324:        return this->socket->send_ack(this->socket, hdr);
        !          2325: }
        !          2326: 
        !          2327: /**
        !          2328:  * Manages the creation and deletion of ip addresses on an interface.
        !          2329:  * By setting the appropriate nlmsg_type, the ip will be set or unset.
        !          2330:  */
        !          2331: static status_t manage_ipaddr(private_kernel_netlink_net_t *this, int nlmsg_type,
        !          2332:                                                          int flags, int if_index, host_t *ip, int prefix)
        !          2333: {
        !          2334:        netlink_buf_t request;
        !          2335:        struct nlmsghdr *hdr;
        !          2336:        struct ifaddrmsg *msg;
        !          2337:        chunk_t chunk;
        !          2338: 
        !          2339:        memset(&request, 0, sizeof(request));
        !          2340: 
        !          2341:        chunk = ip->get_address(ip);
        !          2342: 
        !          2343:        hdr = &request.hdr;
        !          2344:        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
        !          2345:        hdr->nlmsg_type = nlmsg_type;
        !          2346:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
        !          2347: 
        !          2348:        msg = NLMSG_DATA(hdr);
        !          2349:        msg->ifa_family = ip->get_family(ip);
        !          2350:        msg->ifa_flags = 0;
        !          2351:        msg->ifa_prefixlen = prefix < 0 ? chunk.len * 8 : prefix;
        !          2352:        msg->ifa_scope = RT_SCOPE_UNIVERSE;
        !          2353:        msg->ifa_index = if_index;
        !          2354: 
        !          2355:        netlink_add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request));
        !          2356: 
        !          2357:        if (ip->get_family(ip) == AF_INET6)
        !          2358:        {
        !          2359: #ifdef IFA_F_NODAD
        !          2360:                msg->ifa_flags |= IFA_F_NODAD;
        !          2361: #endif
        !          2362:                if (this->rta_prefsrc_for_ipv6)
        !          2363:                {
        !          2364:                        /* if source routes are possible we set a label for this virtual IP
        !          2365:                         * so it gets only used if forced by our route, and not by the
        !          2366:                         * default IPv6 address selection */
        !          2367:                        int labelop = nlmsg_type == RTM_NEWADDR ? RTM_NEWADDRLABEL
        !          2368:                                                                                                        : RTM_DELADDRLABEL;
        !          2369:                        if (manage_addrlabel(this, labelop, ip) != SUCCESS)
        !          2370:                        {
        !          2371:                                /* if we can't use address labels we let the virtual IP get
        !          2372:                                 * deprecated immediately (but mark it as valid forever), which
        !          2373:                                 * should also avoid that it gets used by the default address
        !          2374:                                 * selection */
        !          2375:                                struct ifa_cacheinfo cache = {
        !          2376:                                        .ifa_valid = 0xFFFFFFFF,
        !          2377:                                        .ifa_prefered = 0,
        !          2378:                                };
        !          2379:                                netlink_add_attribute(hdr, IFA_CACHEINFO,
        !          2380:                                                                          chunk_from_thing(cache), sizeof(request));
        !          2381:                        }
        !          2382:                }
        !          2383:        }
        !          2384:        return this->socket->send_ack(this->socket, hdr);
        !          2385: }
        !          2386: 
        !          2387: METHOD(kernel_net_t, add_ip, status_t,
        !          2388:        private_kernel_netlink_net_t *this, host_t *virtual_ip, int prefix,
        !          2389:        char *iface_name)
        !          2390: {
        !          2391:        addr_map_entry_t *entry, lookup = {
        !          2392:                .ip = virtual_ip,
        !          2393:        };
        !          2394:        iface_entry_t *iface = NULL;
        !          2395: 
        !          2396:        if (!this->install_virtual_ip)
        !          2397:        {       /* disabled by config */
        !          2398:                return SUCCESS;
        !          2399:        }
        !          2400: 
        !          2401:        this->lock->write_lock(this->lock);
        !          2402:        /* the virtual IP might actually be installed as regular IP, in which case
        !          2403:         * we don't track it as virtual IP */
        !          2404:        entry = this->addrs->get_match(this->addrs, &lookup,
        !          2405:                                                                  (void*)addr_map_entry_match);
        !          2406:        if (!entry)
        !          2407:        {       /* otherwise it might already be installed as virtual IP */
        !          2408:                entry = this->vips->get_match(this->vips, &lookup,
        !          2409:                                                                         (void*)addr_map_entry_match);
        !          2410:                if (entry)
        !          2411:                {       /* the vip we found can be in one of three states: 1) installed and
        !          2412:                         * ready, 2) just added by another thread, but not yet confirmed to
        !          2413:                         * be installed by the kernel, 3) just deleted, but not yet gone.
        !          2414:                         * Then while we wait below, several things could happen (as we
        !          2415:                         * release the lock).  For instance, the interface could disappear,
        !          2416:                         * or the IP is finally deleted, and it reappears on a different
        !          2417:                         * interface. All these cases are handled by the call below. */
        !          2418:                        while (!is_vip_installed_or_gone(this, virtual_ip, &entry))
        !          2419:                        {
        !          2420:                                this->condvar->wait(this->condvar, this->lock);
        !          2421:                        }
        !          2422:                        if (entry)
        !          2423:                        {
        !          2424:                                entry->addr->refcount++;
        !          2425:                        }
        !          2426:                }
        !          2427:        }
        !          2428:        if (entry)
        !          2429:        {
        !          2430:                DBG2(DBG_KNL, "virtual IP %H is already installed on %s", virtual_ip,
        !          2431:                         entry->iface->ifname);
        !          2432:                this->lock->unlock(this->lock);
        !          2433:                return SUCCESS;
        !          2434:        }
        !          2435:        /* try to find the target interface, either by config or via src ip */
        !          2436:        if (!this->install_virtual_ip_on ||
        !          2437:                !this->ifaces->find_first(this->ifaces, iface_entry_by_name,
        !          2438:                                                                 (void**)&iface, this->install_virtual_ip_on))
        !          2439:        {
        !          2440:                if (!this->ifaces->find_first(this->ifaces, iface_entry_by_name,
        !          2441:                                                                         (void**)&iface, iface_name))
        !          2442:                {       /* if we don't find the requested interface we just use the first */
        !          2443:                        this->ifaces->get_first(this->ifaces, (void**)&iface);
        !          2444:                }
        !          2445:        }
        !          2446:        if (iface)
        !          2447:        {
        !          2448:                addr_entry_t *addr;
        !          2449:                char *ifname;
        !          2450:                int ifi;
        !          2451: 
        !          2452:                INIT(addr,
        !          2453:                        .ip = virtual_ip->clone(virtual_ip),
        !          2454:                        .refcount = 1,
        !          2455:                        .scope = RT_SCOPE_UNIVERSE,
        !          2456:                );
        !          2457:                iface->addrs->insert_last(iface->addrs, addr);
        !          2458:                addr_map_entry_add(this->vips, addr, iface);
        !          2459:                ifi = iface->ifindex;
        !          2460:                this->lock->unlock(this->lock);
        !          2461:                if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
        !          2462:                                                  ifi, virtual_ip, prefix) == SUCCESS)
        !          2463:                {
        !          2464:                        this->lock->write_lock(this->lock);
        !          2465:                        while (!is_vip_installed_or_gone(this, virtual_ip, &entry))
        !          2466:                        {       /* wait until address appears */
        !          2467:                                this->condvar->wait(this->condvar, this->lock);
        !          2468:                        }
        !          2469:                        if (entry)
        !          2470:                        {       /* we fail if the interface got deleted in the meantime */
        !          2471:                                ifname = strdup(entry->iface->ifname);
        !          2472:                                this->lock->unlock(this->lock);
        !          2473:                                DBG2(DBG_KNL, "virtual IP %H installed on %s",
        !          2474:                                         virtual_ip, ifname);
        !          2475:                                /* during IKEv1 reauthentication, children get moved from
        !          2476:                                 * old the new SA before the virtual IP is available. This
        !          2477:                                 * kills the route for our virtual IP, reinstall. */
        !          2478:                                queue_route_reinstall(this, ifname);
        !          2479:                                return SUCCESS;
        !          2480:                        }
        !          2481:                        this->lock->unlock(this->lock);
        !          2482:                }
        !          2483:                DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
        !          2484:                return FAILED;
        !          2485:        }
        !          2486:        this->lock->unlock(this->lock);
        !          2487:        DBG1(DBG_KNL, "no interface available, unable to install virtual IP %H",
        !          2488:                 virtual_ip);
        !          2489:        return FAILED;
        !          2490: }
        !          2491: 
        !          2492: METHOD(kernel_net_t, del_ip, status_t,
        !          2493:        private_kernel_netlink_net_t *this, host_t *virtual_ip, int prefix,
        !          2494:        bool wait)
        !          2495: {
        !          2496:        addr_map_entry_t *entry, lookup = {
        !          2497:                .ip = virtual_ip,
        !          2498:        };
        !          2499: 
        !          2500:        if (!this->install_virtual_ip)
        !          2501:        {       /* disabled by config */
        !          2502:                return SUCCESS;
        !          2503:        }
        !          2504: 
        !          2505:        DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
        !          2506: 
        !          2507:        this->lock->write_lock(this->lock);
        !          2508:        entry = this->vips->get_match(this->vips, &lookup,
        !          2509:                                                                 (void*)addr_map_entry_match);
        !          2510:        if (!entry)
        !          2511:        {       /* we didn't install this IP as virtual IP */
        !          2512:                entry = this->addrs->get_match(this->addrs, &lookup,
        !          2513:                                                                          (void*)addr_map_entry_match);
        !          2514:                if (entry)
        !          2515:                {
        !          2516:                        DBG2(DBG_KNL, "not deleting existing IP %H on %s", virtual_ip,
        !          2517:                                 entry->iface->ifname);
        !          2518:                        this->lock->unlock(this->lock);
        !          2519:                        return SUCCESS;
        !          2520:                }
        !          2521:                DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
        !          2522:                this->lock->unlock(this->lock);
        !          2523:                return FAILED;
        !          2524:        }
        !          2525:        if (entry->addr->refcount == 1)
        !          2526:        {
        !          2527:                status_t status;
        !          2528:                int ifi;
        !          2529: 
        !          2530:                /* we set this flag so that threads calling add_ip will block and wait
        !          2531:                 * until the entry is gone, also so we can wait below */
        !          2532:                entry->addr->installed = FALSE;
        !          2533:                ifi = entry->iface->ifindex;
        !          2534:                this->lock->unlock(this->lock);
        !          2535:                status = manage_ipaddr(this, RTM_DELADDR, 0, ifi, virtual_ip, prefix);
        !          2536:                if (status == SUCCESS && wait)
        !          2537:                {       /* wait until the address is really gone */
        !          2538:                        this->lock->write_lock(this->lock);
        !          2539:                        while (is_known_vip(this, virtual_ip))
        !          2540:                        {
        !          2541:                                this->condvar->wait(this->condvar, this->lock);
        !          2542:                        }
        !          2543:                        this->lock->unlock(this->lock);
        !          2544:                }
        !          2545:                return status;
        !          2546:        }
        !          2547:        else
        !          2548:        {
        !          2549:                entry->addr->refcount--;
        !          2550:        }
        !          2551:        DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
        !          2552:                 virtual_ip);
        !          2553:        this->lock->unlock(this->lock);
        !          2554:        return SUCCESS;
        !          2555: }
        !          2556: 
        !          2557: /**
        !          2558:  * Manages source routes in the routing table.
        !          2559:  * By setting the appropriate nlmsg_type, the route gets added or removed.
        !          2560:  */
        !          2561: static status_t manage_srcroute(private_kernel_netlink_net_t *this,
        !          2562:                                                                int nlmsg_type, int flags, chunk_t dst_net,
        !          2563:                                                                uint8_t prefixlen, host_t *gateway,
        !          2564:                                                                host_t *src_ip, char *if_name, bool pass)
        !          2565: {
        !          2566:        netlink_buf_t request;
        !          2567:        struct nlmsghdr *hdr;
        !          2568:        struct rtmsg *msg;
        !          2569:        struct rtattr *rta;
        !          2570:        int ifindex;
        !          2571:        chunk_t chunk;
        !          2572: 
        !          2573:        /* if route is 0.0.0.0/0, we can't install it, as it would
        !          2574:         * overwrite the default route. Instead, we add two routes:
        !          2575:         * 0.0.0.0/1 and 128.0.0.0/1 */
        !          2576:        if (this->routing_table == 0 && prefixlen == 0)
        !          2577:        {
        !          2578:                chunk_t half_net;
        !          2579:                uint8_t half_prefixlen;
        !          2580:                status_t status;
        !          2581: 
        !          2582:                half_net = chunk_alloca(dst_net.len);
        !          2583:                memset(half_net.ptr, 0, half_net.len);
        !          2584:                half_prefixlen = 1;
        !          2585:                /* no throw routes in the main table */
        !          2586:                status = manage_srcroute(this, nlmsg_type, flags, half_net,
        !          2587:                                                        half_prefixlen, gateway, src_ip, if_name, FALSE);
        !          2588:                half_net.ptr[0] |= 0x80;
        !          2589:                status |= manage_srcroute(this, nlmsg_type, flags, half_net,
        !          2590:                                                        half_prefixlen, gateway, src_ip, if_name, FALSE);
        !          2591:                return status;
        !          2592:        }
        !          2593: 
        !          2594:        memset(&request, 0, sizeof(request));
        !          2595: 
        !          2596:        hdr = &request.hdr;
        !          2597:        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
        !          2598:        hdr->nlmsg_type = nlmsg_type;
        !          2599:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !          2600: 
        !          2601:        msg = NLMSG_DATA(hdr);
        !          2602:        msg->rtm_family = (dst_net.len == 4) ? AF_INET : AF_INET6;
        !          2603:        msg->rtm_dst_len = prefixlen;
        !          2604:        msg->rtm_protocol = RTPROT_STATIC;
        !          2605:        msg->rtm_type = pass ? RTN_THROW : RTN_UNICAST;
        !          2606:        msg->rtm_scope = RT_SCOPE_UNIVERSE;
        !          2607: 
        !          2608:        if (this->routing_table < 256)
        !          2609:        {
        !          2610:                msg->rtm_table = this->routing_table;
        !          2611:        }
        !          2612:        else
        !          2613:        {
        !          2614: #ifdef HAVE_RTA_TABLE
        !          2615:                chunk = chunk_from_thing(this->routing_table);
        !          2616:                netlink_add_attribute(hdr, RTA_TABLE, chunk, sizeof(request));
        !          2617: #else
        !          2618:                DBG1(DBG_KNL, "routing table IDs > 255 are not supported");
        !          2619:                return FAILED;
        !          2620: #endif /* HAVE_RTA_TABLE */
        !          2621:        }
        !          2622:        netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request));
        !          2623: 
        !          2624:        /* only when installing regular routes do we need all the parameters,
        !          2625:         * deletes are done by destination net (except if metrics are used, which
        !          2626:         * we don't support), for throw routes we don't need any of them either */
        !          2627:        if (nlmsg_type == RTM_NEWROUTE && !pass)
        !          2628:        {
        !          2629:                chunk = src_ip->get_address(src_ip);
        !          2630:                netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
        !          2631:                if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
        !          2632:                {
        !          2633:                        chunk = gateway->get_address(gateway);
        !          2634:                        netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
        !          2635:                }
        !          2636:                ifindex = get_interface_index(this, if_name);
        !          2637:                chunk.ptr = (char*)&ifindex;
        !          2638:                chunk.len = sizeof(ifindex);
        !          2639:                netlink_add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
        !          2640: 
        !          2641:                if (this->mtu || this->mss)
        !          2642:                {
        !          2643:                        chunk = chunk_alloca(RTA_LENGTH((sizeof(struct rtattr) +
        !          2644:                                                                                         sizeof(uint32_t)) * 2));
        !          2645:                        chunk.len = 0;
        !          2646:                        rta = (struct rtattr*)chunk.ptr;
        !          2647:                        if (this->mtu)
        !          2648:                        {
        !          2649:                                rta->rta_type = RTAX_MTU;
        !          2650:                                rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
        !          2651:                                memcpy(RTA_DATA(rta), &this->mtu, sizeof(uint32_t));
        !          2652:                                chunk.len = rta->rta_len;
        !          2653:                        }
        !          2654:                        if (this->mss)
        !          2655:                        {
        !          2656:                                rta = (struct rtattr*)(chunk.ptr + RTA_ALIGN(chunk.len));
        !          2657:                                rta->rta_type = RTAX_ADVMSS;
        !          2658:                                rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
        !          2659:                                memcpy(RTA_DATA(rta), &this->mss, sizeof(uint32_t));
        !          2660:                                chunk.len = RTA_ALIGN(chunk.len) + rta->rta_len;
        !          2661:                        }
        !          2662:                        netlink_add_attribute(hdr, RTA_METRICS, chunk, sizeof(request));
        !          2663:                }
        !          2664:        }
        !          2665:        return this->socket->send_ack(this->socket, hdr);
        !          2666: }
        !          2667: 
        !          2668: /**
        !          2669:  * Helper struct used to check routes
        !          2670:  */
        !          2671: typedef struct {
        !          2672:        /** the entry we look for */
        !          2673:        route_entry_t route;
        !          2674:        /** kernel interface */
        !          2675:        private_kernel_netlink_net_t *this;
        !          2676: } route_entry_lookup_t;
        !          2677: 
        !          2678: /**
        !          2679:  * Check if a matching route entry has a VIP associated
        !          2680:  */
        !          2681: static bool route_with_vip(route_entry_lookup_t *a, route_entry_t *b)
        !          2682: {
        !          2683:        if (chunk_equals(a->route.dst_net, b->dst_net) &&
        !          2684:                a->route.prefixlen == b->prefixlen &&
        !          2685:                is_known_vip(a->this, b->src_ip))
        !          2686:        {
        !          2687:                return TRUE;
        !          2688:        }
        !          2689:        return FALSE;
        !          2690: }
        !          2691: 
        !          2692: /**
        !          2693:  * Check if there is any route entry with a matching destination
        !          2694:  */
        !          2695: static bool route_with_dst(route_entry_lookup_t *a, route_entry_t *b)
        !          2696: {
        !          2697:        if (chunk_equals(a->route.dst_net, b->dst_net) &&
        !          2698:                a->route.prefixlen == b->prefixlen)
        !          2699:        {
        !          2700:                return TRUE;
        !          2701:        }
        !          2702:        return FALSE;
        !          2703: }
        !          2704: 
        !          2705: METHOD(kernel_net_t, add_route, status_t,
        !          2706:        private_kernel_netlink_net_t *this, chunk_t dst_net, uint8_t prefixlen,
        !          2707:        host_t *gateway, host_t *src_ip, char *if_name, bool pass)
        !          2708: {
        !          2709:        status_t status;
        !          2710:        route_entry_t *found;
        !          2711:        route_entry_lookup_t lookup = {
        !          2712:                .route = {
        !          2713:                        .dst_net = dst_net,
        !          2714:                        .prefixlen = prefixlen,
        !          2715:                        .gateway = gateway,
        !          2716:                        .src_ip = src_ip,
        !          2717:                        .if_name = if_name,
        !          2718:                        .pass = pass,
        !          2719:                },
        !          2720:                .this = this,
        !          2721:        };
        !          2722: 
        !          2723:        if (!this->routing_table)
        !          2724:        {       /* treat these as regular routes if installing in the main table */
        !          2725:                pass = lookup.route.pass = FALSE;
        !          2726:        }
        !          2727: 
        !          2728:        this->routes_lock->lock(this->routes_lock);
        !          2729:        found = this->routes->get(this->routes, &lookup.route);
        !          2730:        if (found)
        !          2731:        {
        !          2732:                this->routes_lock->unlock(this->routes_lock);
        !          2733:                return ALREADY_DONE;
        !          2734:        }
        !          2735: 
        !          2736:        /* don't replace the route if we already have one with a VIP installed,
        !          2737:         * but keep track of it in case that other route is uninstalled */
        !          2738:        this->lock->read_lock(this->lock);
        !          2739:        if (!is_known_vip(this, src_ip))
        !          2740:        {
        !          2741:                found = this->routes->get_match(this->routes, &lookup,
        !          2742:                                                                                (void*)route_with_vip);
        !          2743:        }
        !          2744:        this->lock->unlock(this->lock);
        !          2745:        if (found)
        !          2746:        {
        !          2747:                status = SUCCESS;
        !          2748:        }
        !          2749:        else
        !          2750:        {
        !          2751:                status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
        !          2752:                                                                 dst_net, prefixlen, gateway, src_ip, if_name,
        !          2753:                                                                 pass);
        !          2754:        }
        !          2755:        if (status == SUCCESS)
        !          2756:        {
        !          2757:                found = route_entry_clone(&lookup.route);
        !          2758:                this->routes->put(this->routes, found, found);
        !          2759:        }
        !          2760:        this->routes_lock->unlock(this->routes_lock);
        !          2761:        return status;
        !          2762: }
        !          2763: 
        !          2764: METHOD(kernel_net_t, del_route, status_t,
        !          2765:        private_kernel_netlink_net_t *this, chunk_t dst_net, uint8_t prefixlen,
        !          2766:        host_t *gateway, host_t *src_ip, char *if_name, bool pass)
        !          2767: {
        !          2768:        status_t status;
        !          2769:        route_entry_t *found;
        !          2770:        route_entry_lookup_t lookup = {
        !          2771:                .route = {
        !          2772:                        .dst_net = dst_net,
        !          2773:                        .prefixlen = prefixlen,
        !          2774:                        .gateway = gateway,
        !          2775:                        .src_ip = src_ip,
        !          2776:                        .if_name = if_name,
        !          2777:                        .pass = pass,
        !          2778:                },
        !          2779:                .this = this,
        !          2780:        };
        !          2781: 
        !          2782:        if (!this->routing_table)
        !          2783:        {       /* treat these as regular routes if installing in the main table */
        !          2784:                pass = lookup.route.pass = FALSE;
        !          2785:        }
        !          2786: 
        !          2787:        this->routes_lock->lock(this->routes_lock);
        !          2788:        found = this->routes->remove(this->routes, &lookup.route);
        !          2789:        if (!found)
        !          2790:        {
        !          2791:                this->routes_lock->unlock(this->routes_lock);
        !          2792:                return NOT_FOUND;
        !          2793:        }
        !          2794:        route_entry_destroy(found);
        !          2795: 
        !          2796:        /* check if there are any other routes for the same destination and if
        !          2797:         * so update the route, otherwise uninstall it */
        !          2798:        this->lock->read_lock(this->lock);
        !          2799:        found = this->routes->get_match(this->routes, &lookup,
        !          2800:                                                                        (void*)route_with_vip);
        !          2801:        this->lock->unlock(this->lock);
        !          2802:        if (!found)
        !          2803:        {
        !          2804:                found = this->routes->get_match(this->routes, &lookup,
        !          2805:                                                                                (void*)route_with_dst);
        !          2806:        }
        !          2807:        if (found)
        !          2808:        {
        !          2809:                status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
        !          2810:                                                        found->dst_net, found->prefixlen, found->gateway,
        !          2811:                                                        found->src_ip, found->if_name, found->pass);
        !          2812:        }
        !          2813:        else
        !          2814:        {
        !          2815:                status = manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen,
        !          2816:                                                                 gateway, src_ip, if_name, pass);
        !          2817:        }
        !          2818:        this->routes_lock->unlock(this->routes_lock);
        !          2819:        return status;
        !          2820: }
        !          2821: 
        !          2822: /**
        !          2823:  * Initialize a list of local addresses.
        !          2824:  */
        !          2825: static status_t init_address_list(private_kernel_netlink_net_t *this)
        !          2826: {
        !          2827:        netlink_buf_t request;
        !          2828:        struct nlmsghdr *out, *current, *in;
        !          2829:        struct rtgenmsg *msg;
        !          2830:        size_t len;
        !          2831:        enumerator_t *ifaces, *addrs;
        !          2832:        iface_entry_t *iface;
        !          2833:        addr_entry_t *addr;
        !          2834: 
        !          2835:        DBG2(DBG_KNL, "known interfaces and IP addresses:");
        !          2836: 
        !          2837:        memset(&request, 0, sizeof(request));
        !          2838: 
        !          2839:        in = &request.hdr;
        !          2840:        in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
        !          2841:        in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
        !          2842:        msg = NLMSG_DATA(in);
        !          2843:        msg->rtgen_family = AF_UNSPEC;
        !          2844: 
        !          2845:        /* get all links */
        !          2846:        in->nlmsg_type = RTM_GETLINK;
        !          2847:        if (this->socket->send(this->socket, in, &out, &len) != SUCCESS)
        !          2848:        {
        !          2849:                return FAILED;
        !          2850:        }
        !          2851:        current = out;
        !          2852:        while (NLMSG_OK(current, len))
        !          2853:        {
        !          2854:                switch (current->nlmsg_type)
        !          2855:                {
        !          2856:                        case NLMSG_DONE:
        !          2857:                                break;
        !          2858:                        case RTM_NEWLINK:
        !          2859:                                process_link(this, current, FALSE);
        !          2860:                                /* fall through */
        !          2861:                        default:
        !          2862:                                current = NLMSG_NEXT(current, len);
        !          2863:                                continue;
        !          2864:                }
        !          2865:                break;
        !          2866:        }
        !          2867:        free(out);
        !          2868: 
        !          2869:        /* get all interface addresses */
        !          2870:        in->nlmsg_type = RTM_GETADDR;
        !          2871:        if (this->socket->send(this->socket, in, &out, &len) != SUCCESS)
        !          2872:        {
        !          2873:                return FAILED;
        !          2874:        }
        !          2875:        current = out;
        !          2876:        while (NLMSG_OK(current, len))
        !          2877:        {
        !          2878:                switch (current->nlmsg_type)
        !          2879:                {
        !          2880:                        case NLMSG_DONE:
        !          2881:                                break;
        !          2882:                        case RTM_NEWADDR:
        !          2883:                                process_addr(this, current, FALSE);
        !          2884:                                /* fall through */
        !          2885:                        default:
        !          2886:                                current = NLMSG_NEXT(current, len);
        !          2887:                                continue;
        !          2888:                }
        !          2889:                break;
        !          2890:        }
        !          2891:        free(out);
        !          2892: 
        !          2893:        this->lock->read_lock(this->lock);
        !          2894:        ifaces = this->ifaces->create_enumerator(this->ifaces);
        !          2895:        while (ifaces->enumerate(ifaces, &iface))
        !          2896:        {
        !          2897:                if (iface_entry_up_and_usable(iface))
        !          2898:                {
        !          2899:                        DBG2(DBG_KNL, "  %s", iface->ifname);
        !          2900:                        addrs = iface->addrs->create_enumerator(iface->addrs);
        !          2901:                        while (addrs->enumerate(addrs, (void**)&addr))
        !          2902:                        {
        !          2903:                                DBG2(DBG_KNL, "    %H", addr->ip);
        !          2904:                        }
        !          2905:                        addrs->destroy(addrs);
        !          2906:                }
        !          2907:        }
        !          2908:        ifaces->destroy(ifaces);
        !          2909:        this->lock->unlock(this->lock);
        !          2910:        return SUCCESS;
        !          2911: }
        !          2912: 
        !          2913: /**
        !          2914:  * create or delete a rule to use our routing table
        !          2915:  */
        !          2916: static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
        !          2917:                                                        int family, uint32_t table, uint32_t prio)
        !          2918: {
        !          2919:        netlink_buf_t request;
        !          2920:        struct nlmsghdr *hdr;
        !          2921:        struct rtmsg *msg;
        !          2922:        chunk_t chunk;
        !          2923:        char *fwmark;
        !          2924: 
        !          2925:        memset(&request, 0, sizeof(request));
        !          2926:        hdr = &request.hdr;
        !          2927:        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        !          2928:        hdr->nlmsg_type = nlmsg_type;
        !          2929:        if (nlmsg_type == RTM_NEWRULE)
        !          2930:        {
        !          2931:                hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
        !          2932:        }
        !          2933:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
        !          2934: 
        !          2935:        msg = NLMSG_DATA(hdr);
        !          2936:        msg->rtm_family = family;
        !          2937:        msg->rtm_protocol = RTPROT_BOOT;
        !          2938:        msg->rtm_scope = RT_SCOPE_UNIVERSE;
        !          2939:        msg->rtm_type = RTN_UNICAST;
        !          2940: 
        !          2941:        if (this->routing_table < 256)
        !          2942:        {
        !          2943:                msg->rtm_table = table;
        !          2944:        }
        !          2945:        else
        !          2946:        {
        !          2947: #ifdef HAVE_LINUX_FIB_RULES_H
        !          2948:                chunk = chunk_from_thing(table);
        !          2949:                netlink_add_attribute(hdr, FRA_TABLE, chunk, sizeof(request));
        !          2950: #else
        !          2951:                DBG1(DBG_KNL, "routing table IDs > 255 are not supported");
        !          2952:                return FAILED;
        !          2953: #endif /* HAVE_LINUX_FIB_RULES_H */
        !          2954:        }
        !          2955:        chunk = chunk_from_thing(prio);
        !          2956:        netlink_add_attribute(hdr, RTA_PRIORITY, chunk, sizeof(request));
        !          2957: 
        !          2958:        fwmark = lib->settings->get_str(lib->settings,
        !          2959:                                                        "%s.plugins.kernel-netlink.fwmark", NULL, lib->ns);
        !          2960:        if (fwmark)
        !          2961:        {
        !          2962: #ifdef HAVE_LINUX_FIB_RULES_H
        !          2963:                mark_t mark;
        !          2964: 
        !          2965:                if (fwmark[0] == '!')
        !          2966:                {
        !          2967:                        msg->rtm_flags |= FIB_RULE_INVERT;
        !          2968:                        fwmark++;
        !          2969:                }
        !          2970:                if (mark_from_string(fwmark, MARK_OP_NONE, &mark))
        !          2971:                {
        !          2972:                        chunk = chunk_from_thing(mark.value);
        !          2973:                        netlink_add_attribute(hdr, FRA_FWMARK, chunk, sizeof(request));
        !          2974:                        chunk = chunk_from_thing(mark.mask);
        !          2975:                        netlink_add_attribute(hdr, FRA_FWMASK, chunk, sizeof(request));
        !          2976:                        if (msg->rtm_flags & FIB_RULE_INVERT)
        !          2977:                        {
        !          2978:                                this->routing_mark = mark;
        !          2979:                        }
        !          2980:                }
        !          2981: #else
        !          2982:                DBG1(DBG_KNL, "setting firewall mark on routing rule is not supported");
        !          2983: #endif /* HAVE_LINUX_FIB_RULES_H */
        !          2984:        }
        !          2985:        return this->socket->send_ack(this->socket, hdr);
        !          2986: }
        !          2987: 
        !          2988: /**
        !          2989:  * check for kernel features (currently only via version number)
        !          2990:  */
        !          2991: static void check_kernel_features(private_kernel_netlink_net_t *this)
        !          2992: {
        !          2993:        struct utsname utsname;
        !          2994:        int a, b, c;
        !          2995: 
        !          2996:        if (uname(&utsname) == 0)
        !          2997:        {
        !          2998:                switch(sscanf(utsname.release, "%d.%d.%d", &a, &b, &c))
        !          2999:                {
        !          3000:                        case 3:
        !          3001:                                if (a == 2)
        !          3002:                                {
        !          3003:                                        if (b == 6 && c >= 36)
        !          3004:                                        {
        !          3005:                                                this->rta_mark = TRUE;
        !          3006:                                        }
        !          3007:                                        DBG2(DBG_KNL, "detected Linux %d.%d.%d, no support for "
        !          3008:                                                 "RTA_PREFSRC for IPv6 routes", a, b, c);
        !          3009:                                        break;
        !          3010:                                }
        !          3011:                                /* fall-through */
        !          3012:                        case 2:
        !          3013:                                /* only 3.x+ uses two part version numbers */
        !          3014:                                this->rta_prefsrc_for_ipv6 = TRUE;
        !          3015:                                this->rta_mark = TRUE;
        !          3016:                                break;
        !          3017:                        default:
        !          3018:                                break;
        !          3019:                }
        !          3020:        }
        !          3021: }
        !          3022: 
        !          3023: /**
        !          3024:  * Destroy an address to iface map
        !          3025:  */
        !          3026: static void addr_map_destroy(hashtable_t *map)
        !          3027: {
        !          3028:        enumerator_t *enumerator;
        !          3029:        addr_map_entry_t *addr;
        !          3030: 
        !          3031:        enumerator = map->create_enumerator(map);
        !          3032:        while (enumerator->enumerate(enumerator, NULL, (void**)&addr))
        !          3033:        {
        !          3034:                free(addr);
        !          3035:        }
        !          3036:        enumerator->destroy(enumerator);
        !          3037:        map->destroy(map);
        !          3038: }
        !          3039: 
        !          3040: METHOD(kernel_net_t, destroy, void,
        !          3041:        private_kernel_netlink_net_t *this)
        !          3042: {
        !          3043:        enumerator_t *enumerator;
        !          3044:        route_entry_t *route;
        !          3045: 
        !          3046:        if (this->routing_table)
        !          3047:        {
        !          3048:                manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table,
        !          3049:                                        this->routing_table_prio);
        !          3050:                manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table,
        !          3051:                                        this->routing_table_prio);
        !          3052:        }
        !          3053:        if (this->socket_events > 0)
        !          3054:        {
        !          3055:                lib->watcher->remove(lib->watcher, this->socket_events);
        !          3056:                close(this->socket_events);
        !          3057:        }
        !          3058:        enumerator = this->routes->create_enumerator(this->routes);
        !          3059:        while (enumerator->enumerate(enumerator, NULL, (void**)&route))
        !          3060:        {
        !          3061:                manage_srcroute(this, RTM_DELROUTE, 0, route->dst_net, route->prefixlen,
        !          3062:                                                route->gateway, route->src_ip, route->if_name,
        !          3063:                                                route->pass);
        !          3064:                route_entry_destroy(route);
        !          3065:        }
        !          3066:        enumerator->destroy(enumerator);
        !          3067:        this->routes->destroy(this->routes);
        !          3068:        this->routes_lock->destroy(this->routes_lock);
        !          3069:        DESTROY_IF(this->socket);
        !          3070: 
        !          3071:        net_changes_clear(this);
        !          3072:        this->net_changes->destroy(this->net_changes);
        !          3073:        this->net_changes_lock->destroy(this->net_changes_lock);
        !          3074: 
        !          3075:        addr_map_destroy(this->addrs);
        !          3076:        addr_map_destroy(this->vips);
        !          3077: 
        !          3078:        this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
        !          3079:        this->rt_exclude->destroy(this->rt_exclude);
        !          3080:        this->roam_lock->destroy(this->roam_lock);
        !          3081:        this->condvar->destroy(this->condvar);
        !          3082:        this->lock->destroy(this->lock);
        !          3083:        free(this);
        !          3084: }
        !          3085: 
        !          3086: /*
        !          3087:  * Described in header.
        !          3088:  */
        !          3089: kernel_netlink_net_t *kernel_netlink_net_create()
        !          3090: {
        !          3091:        private_kernel_netlink_net_t *this;
        !          3092:        enumerator_t *enumerator;
        !          3093:        bool register_for_events = TRUE;
        !          3094:        char *exclude;
        !          3095: 
        !          3096:        INIT(this,
        !          3097:                .public = {
        !          3098:                        .interface = {
        !          3099:                                .get_interface = _get_interface_name,
        !          3100:                                .create_address_enumerator = _create_address_enumerator,
        !          3101:                                .create_local_subnet_enumerator = _create_local_subnet_enumerator,
        !          3102:                                .get_source_addr = _get_source_addr,
        !          3103:                                .get_nexthop = _get_nexthop,
        !          3104:                                .add_ip = _add_ip,
        !          3105:                                .del_ip = _del_ip,
        !          3106:                                .add_route = _add_route,
        !          3107:                                .del_route = _del_route,
        !          3108:                                .destroy = _destroy,
        !          3109:                        },
        !          3110:                },
        !          3111:                .socket = netlink_socket_create(NETLINK_ROUTE, rt_msg_names,
        !          3112:                        lib->settings->get_bool(lib->settings,
        !          3113:                                "%s.plugins.kernel-netlink.parallel_route", FALSE, lib->ns)),
        !          3114:                .rt_exclude = linked_list_create(),
        !          3115:                .routes = hashtable_create((hashtable_hash_t)route_entry_hash,
        !          3116:                                                                   (hashtable_equals_t)route_entry_equals, 16),
        !          3117:                .net_changes = hashtable_create(
        !          3118:                                                                   (hashtable_hash_t)net_change_hash,
        !          3119:                                                                   (hashtable_equals_t)net_change_equals, 16),
        !          3120:                .addrs = hashtable_create(
        !          3121:                                                                (hashtable_hash_t)addr_map_entry_hash,
        !          3122:                                                                (hashtable_equals_t)addr_map_entry_equals, 16),
        !          3123:                .vips = hashtable_create((hashtable_hash_t)addr_map_entry_hash,
        !          3124:                                                                 (hashtable_equals_t)addr_map_entry_equals, 16),
        !          3125:                .routes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
        !          3126:                .net_changes_lock = mutex_create(MUTEX_TYPE_DEFAULT),
        !          3127:                .ifaces = linked_list_create(),
        !          3128:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        !          3129:                .condvar = rwlock_condvar_create(),
        !          3130:                .roam_lock = spinlock_create(),
        !          3131:                .routing_table = lib->settings->get_int(lib->settings,
        !          3132:                                                "%s.routing_table", ROUTING_TABLE, lib->ns),
        !          3133:                .routing_table_prio = lib->settings->get_int(lib->settings,
        !          3134:                                                "%s.routing_table_prio", ROUTING_TABLE_PRIO, lib->ns),
        !          3135:                .process_route = lib->settings->get_bool(lib->settings,
        !          3136:                                                "%s.process_route", TRUE, lib->ns),
        !          3137:                .install_routes = lib->settings->get_bool(lib->settings,
        !          3138:                                                "%s.install_routes", TRUE, lib->ns),
        !          3139:                .install_virtual_ip = lib->settings->get_bool(lib->settings,
        !          3140:                                                "%s.install_virtual_ip", TRUE, lib->ns),
        !          3141:                .install_virtual_ip_on = lib->settings->get_str(lib->settings,
        !          3142:                                                "%s.install_virtual_ip_on", NULL, lib->ns),
        !          3143:                .prefer_temporary_addrs = lib->settings->get_bool(lib->settings,
        !          3144:                                                "%s.prefer_temporary_addrs", FALSE, lib->ns),
        !          3145:                .roam_events = lib->settings->get_bool(lib->settings,
        !          3146:                                                "%s.plugins.kernel-netlink.roam_events", TRUE, lib->ns),
        !          3147:                .process_rules = lib->settings->get_bool(lib->settings,
        !          3148:                                                "%s.plugins.kernel-netlink.process_rules", FALSE, lib->ns),
        !          3149:                .mtu = lib->settings->get_int(lib->settings,
        !          3150:                                                "%s.plugins.kernel-netlink.mtu", 0, lib->ns),
        !          3151:                .mss = lib->settings->get_int(lib->settings,
        !          3152:                                                "%s.plugins.kernel-netlink.mss", 0, lib->ns),
        !          3153:        );
        !          3154:        timerclear(&this->last_route_reinstall);
        !          3155:        timerclear(&this->next_roam);
        !          3156: 
        !          3157:        check_kernel_features(this);
        !          3158: 
        !          3159:        if (streq(lib->ns, "starter"))
        !          3160:        {       /* starter has no threads, so we do not register for kernel events */
        !          3161:                register_for_events = FALSE;
        !          3162:        }
        !          3163: 
        !          3164:        exclude = lib->settings->get_str(lib->settings,
        !          3165:                                                                         "%s.ignore_routing_tables", NULL, lib->ns);
        !          3166:        if (exclude)
        !          3167:        {
        !          3168:                char *token;
        !          3169:                uintptr_t table;
        !          3170: 
        !          3171:                enumerator = enumerator_create_token(exclude, " ", " ");
        !          3172:                while (enumerator->enumerate(enumerator, &token))
        !          3173:                {
        !          3174:                        errno = 0;
        !          3175:                        table = strtoul(token, NULL, 10);
        !          3176: 
        !          3177:                        if (errno == 0)
        !          3178:                        {
        !          3179:                                this->rt_exclude->insert_last(this->rt_exclude, (void*)table);
        !          3180:                        }
        !          3181:                }
        !          3182:                enumerator->destroy(enumerator);
        !          3183:        }
        !          3184: 
        !          3185:        if (register_for_events)
        !          3186:        {
        !          3187:                struct sockaddr_nl addr;
        !          3188: 
        !          3189:                memset(&addr, 0, sizeof(addr));
        !          3190:                addr.nl_family = AF_NETLINK;
        !          3191: 
        !          3192:                /* create and bind RT socket for events (address/interface/route changes) */
        !          3193:                this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !          3194:                if (this->socket_events < 0)
        !          3195:                {
        !          3196:                        DBG1(DBG_KNL, "unable to create RT event socket: %s (%d)",
        !          3197:                                 strerror(errno), errno);
        !          3198:                        destroy(this);
        !          3199:                        return NULL;
        !          3200:                }
        !          3201:                addr.nl_groups = nl_group(RTNLGRP_IPV4_IFADDR) |
        !          3202:                                                 nl_group(RTNLGRP_IPV6_IFADDR) |
        !          3203:                                                 nl_group(RTNLGRP_LINK);
        !          3204:                if (this->process_route)
        !          3205:                {
        !          3206:                        addr.nl_groups |= nl_group(RTNLGRP_IPV4_ROUTE) |
        !          3207:                                                          nl_group(RTNLGRP_IPV6_ROUTE);
        !          3208:                }
        !          3209:                if (this->process_rules)
        !          3210:                {
        !          3211:                        addr.nl_groups |= nl_group(RTNLGRP_IPV4_RULE) |
        !          3212:                                                          nl_group(RTNLGRP_IPV6_RULE);
        !          3213:                }
        !          3214:                if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr)))
        !          3215:                {
        !          3216:                        DBG1(DBG_KNL, "unable to bind RT event socket: %s (%d)",
        !          3217:                                 strerror(errno), errno);
        !          3218:                        destroy(this);
        !          3219:                        return NULL;
        !          3220:                }
        !          3221: 
        !          3222:                lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ,
        !          3223:                                                  (watcher_cb_t)receive_events, this);
        !          3224:        }
        !          3225: 
        !          3226:        if (init_address_list(this) != SUCCESS)
        !          3227:        {
        !          3228:                DBG1(DBG_KNL, "unable to get interface list");
        !          3229:                destroy(this);
        !          3230:                return NULL;
        !          3231:        }
        !          3232: 
        !          3233:        if (this->routing_table)
        !          3234:        {
        !          3235:                if (manage_rule(this, RTM_NEWRULE, AF_INET, this->routing_table,
        !          3236:                                                this->routing_table_prio) != SUCCESS)
        !          3237:                {
        !          3238:                        DBG1(DBG_KNL, "unable to create IPv4 routing table rule");
        !          3239:                }
        !          3240:                if (manage_rule(this, RTM_NEWRULE, AF_INET6, this->routing_table,
        !          3241:                                                this->routing_table_prio) != SUCCESS)
        !          3242:                {
        !          3243:                        DBG1(DBG_KNL, "unable to create IPv6 routing table rule");
        !          3244:                }
        !          3245:        }
        !          3246: 
        !          3247:        return &this->public;
        !          3248: }

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