aboutsummaryrefslogtreecommitdiffstats
path: root/src/libhydra/plugins/kernel_netlink
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-09-14 16:43:08 +0200
committerTobias Brunner <tobias@strongswan.org>2012-09-21 18:16:26 +0200
commit940e1b0f66dc04b0853414c1f4c45fa3f6e33bdd (patch)
tree230fbd0a377abcb5592036b8b30ed3341e412d6e /src/libhydra/plugins/kernel_netlink
parent645d7a5ef32b03d137d21b2dc73fdb6d528d65dc (diff)
downloadstrongswan-940e1b0f66dc04b0853414c1f4c45fa3f6e33bdd.tar.bz2
strongswan-940e1b0f66dc04b0853414c1f4c45fa3f6e33bdd.tar.xz
Filter ignored interfaces in kernel interfaces (for events, address enumeration, etc.)
Diffstat (limited to 'src/libhydra/plugins/kernel_netlink')
-rw-r--r--src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c118
1 files changed, 79 insertions, 39 deletions
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
index 2180b9008..09a850667 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c
@@ -110,6 +110,9 @@ struct iface_entry_t {
/** list of addresses as host_t */
linked_list_t *addrs;
+
+ /** TRUE if usable by config */
+ bool usable;
};
/**
@@ -121,6 +124,22 @@ static void iface_entry_destroy(iface_entry_t *this)
free(this);
}
+/**
+ * find an interface entry by index
+ */
+static bool iface_entry_by_index(iface_entry_t *this, int *ifindex)
+{
+ return this->ifindex == *ifindex;
+}
+
+/**
+ * check if an interface is up and usable
+ */
+static inline bool iface_entry_up_and_usable(iface_entry_t *iface)
+{
+ return iface->usable && (iface->flags & IFF_UP) == IFF_UP;
+}
+
typedef struct route_entry_t route_entry_t;
/**
@@ -486,6 +505,10 @@ static host_t *get_interface_address(private_kernel_netlink_net_t *this,
{
if (iface->ifindex == ifindex)
{
+ if (!iface->usable)
+ { /* ignore interfaces excluded by config */
+ break;
+ }
addrs = iface->addrs->create_enumerator(iface->addrs);
while (addrs->enumerate(addrs, &addr))
{
@@ -558,6 +581,22 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address)
}
/**
+ * check if an interface with a given index is up and usable
+ */
+static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this,
+ int index)
+{
+ iface_entry_t *iface;
+
+ if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index,
+ (void**)&iface, &index) == SUCCESS)
+ {
+ return iface_entry_up_and_usable(iface);
+ }
+ return FALSE;
+}
+
+/**
* process RTM_NEWLINK/RTM_DELLINK from kernel
*/
static void process_link(private_kernel_netlink_net_t *this,
@@ -606,12 +645,14 @@ static void process_link(private_kernel_netlink_net_t *this,
entry = malloc_thing(iface_entry_t);
entry->ifindex = msg->ifi_index;
entry->flags = 0;
+ entry->usable = hydra->kernel_interface->is_interface_usable(
+ hydra->kernel_interface, name);
entry->addrs = linked_list_create();
this->ifaces->insert_last(this->ifaces, entry);
}
strncpy(entry->ifname, name, IFNAMSIZ);
entry->ifname[IFNAMSIZ-1] = '\0';
- if (event)
+ if (event && entry->usable)
{
if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
{
@@ -634,7 +675,7 @@ static void process_link(private_kernel_netlink_net_t *this,
{
if (current->ifindex == msg->ifi_index)
{
- if (event)
+ if (event && current->usable)
{
update = TRUE;
DBG1(DBG_KNL, "interface %s deleted", current->ifname);
@@ -727,7 +768,7 @@ static void process_addr(private_kernel_netlink_net_t *this,
if (hdr->nlmsg_type == RTM_DELADDR)
{
iface->addrs->remove_at(iface->addrs, addrs);
- if (!addr->virtual)
+ if (!addr->virtual && iface->usable)
{
changed = TRUE;
DBG1(DBG_KNL, "%H disappeared from %s",
@@ -757,7 +798,7 @@ static void process_addr(private_kernel_netlink_net_t *this,
addr->scope = msg->ifa_scope;
iface->addrs->insert_last(iface->addrs, addr);
- if (event)
+ if (event && iface->usable)
{
DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
}
@@ -767,6 +808,10 @@ static void process_addr(private_kernel_netlink_net_t *this,
{
update = TRUE;
}
+ if (!iface->usable)
+ { /* ignore events for interfaces excluded by config */
+ update = changed = FALSE;
+ }
break;
}
}
@@ -830,20 +875,26 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h
}
rta = RTA_NEXT(rta, rtasize);
}
+ this->mutex->lock(this->mutex);
+ if (rta_oif && !is_interface_up_and_usable(this, rta_oif))
+ { /* ignore route changes for interfaces that are ignored or down */
+ this->mutex->unlock(this->mutex);
+ DESTROY_IF(host);
+ return;
+ }
if (!host && rta_oif)
{
host = get_interface_address(this, rta_oif, msg->rtm_family, NULL);
}
if (host)
{
- this->mutex->lock(this->mutex);
if (!get_vip_refcount(this, host))
{ /* ignore routes added for virtual IPs */
fire_roam_event(this, FALSE);
}
- this->mutex->unlock(this->mutex);
host->destroy(host);
}
+ this->mutex->unlock(this->mutex);
}
/**
@@ -970,6 +1021,10 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface,
static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in,
iface_entry_t** out)
{
+ if (!(*in)->usable)
+ { /* skip interfaces excluded by config */
+ return FALSE;
+ }
if (!data->include_loopback && ((*in)->flags & IFF_LOOPBACK))
{ /* ignore loopback devices */
return FALSE;
@@ -1007,7 +1062,7 @@ METHOD(kernel_net_t, get_interface_name, bool,
enumerator_t *ifaces, *addrs;
iface_entry_t *iface;
addr_entry_t *addr;
- bool found = FALSE;
+ bool found = FALSE, ignored = FALSE;
if (ip->is_anyaddr(ip))
{
@@ -1024,6 +1079,11 @@ METHOD(kernel_net_t, get_interface_name, bool,
if (ip->ip_equals(ip, addr->ip))
{
found = TRUE;
+ if (!iface->usable)
+ {
+ ignored = TRUE;
+ break;
+ }
if (name)
{
*name = strdup(iface->ifname);
@@ -1040,15 +1100,18 @@ METHOD(kernel_net_t, get_interface_name, bool,
ifaces->destroy(ifaces);
this->mutex->unlock(this->mutex);
- if (!found)
- {
- DBG2(DBG_KNL, "%H is not a local address", ip);
- }
- else if (name)
+ if (!ignored)
{
- DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
+ if (!found)
+ {
+ DBG2(DBG_KNL, "%H is not a local address", ip);
+ }
+ else if (name)
+ {
+ DBG2(DBG_KNL, "%H is on interface %s", ip, *name);
+ }
}
- return found;
+ return found && !ignored;
}
/**
@@ -1083,29 +1146,6 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
}
/**
- * Check if an interface with a given index is up
- */
-static bool is_interface_up(private_kernel_netlink_net_t *this, int index)
-{
- enumerator_t *ifaces;
- iface_entry_t *iface;
- /* default to TRUE for interface we do not monitor (e.g. lo) */
- bool up = TRUE;
-
- ifaces = this->ifaces->create_enumerator(this->ifaces);
- while (ifaces->enumerate(ifaces, &iface))
- {
- if (iface->ifindex == index)
- {
- up = iface->flags & IFF_UP;
- break;
- }
- }
- ifaces->destroy(ifaces);
- return up;
-}
-
-/**
* check if an address (chunk) addr is in subnet (net with net_len net bits)
*/
static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len)
@@ -1303,7 +1343,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
{ /* route is from our own ipsec routing table */
continue;
}
- if (route->oif && !is_interface_up(this, route->oif))
+ if (route->oif && !is_interface_up_and_usable(this, route->oif))
{ /* interface is down */
continue;
}
@@ -1830,7 +1870,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this)
ifaces = this->ifaces->create_enumerator(this->ifaces);
while (ifaces->enumerate(ifaces, &iface))
{
- if (iface->flags & IFF_UP)
+ if (iface_entry_up_and_usable(iface))
{
DBG2(DBG_KNL, " %s", iface->ifname);
addrs = iface->addrs->create_enumerator(iface->addrs);