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, ¤t))
! 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>