diff options
| author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:44:41 +0000 |
|---|---|---|
| committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2008-12-05 16:44:41 +0000 |
| commit | 2db1ef4ac8928944958712923b9c89c263a337d2 (patch) | |
| tree | 700043d9d97b7e7ba344b448918728af0a8be8d1 /src/charon/plugins/kernel_netlink/kernel_netlink_net.c | |
| parent | 5dc75410286b0e3a16845b44dd696ba0f40df573 (diff) | |
| download | vyos-strongswan-2db1ef4ac8928944958712923b9c89c263a337d2.tar.gz vyos-strongswan-2db1ef4ac8928944958712923b9c89c263a337d2.zip | |
- Updated to new upstream.
Diffstat (limited to 'src/charon/plugins/kernel_netlink/kernel_netlink_net.c')
| -rw-r--r-- | src/charon/plugins/kernel_netlink/kernel_netlink_net.c | 269 |
1 files changed, 159 insertions, 110 deletions
diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c index d8bba9412..69a781c14 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_net.c @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: kernel_netlink_net.c 4391 2008-10-09 05:44:00Z andreas $ + * $Id: kernel_netlink_net.c 4660 2008-11-14 14:23:11Z martin $ */ #include <sys/socket.h> @@ -29,6 +29,7 @@ #include "kernel_netlink_shared.h" #include <daemon.h> +#include <utils/mutex.h> #include <utils/linked_list.h> #include <processing/jobs/callback_job.h> #include <processing/jobs/roam_job.h> @@ -116,12 +117,12 @@ struct private_kernel_netlink_net_t { /** * mutex to lock access to various lists */ - pthread_mutex_t mutex; + mutex_t *mutex; /** * condition variable to signal virtual IP add/removal */ - pthread_cond_t cond; + condvar_t *condvar; /** * Cached list of interfaces and its addresses (iface_entry_t) @@ -157,7 +158,7 @@ struct private_kernel_netlink_net_t { * priority of used routing table */ int routing_table_prio; - + /** * whether to react to RTM_NEWROUTE or RTM_DELROUTE events */ @@ -206,7 +207,7 @@ static int get_vip_refcount(private_kernel_netlink_net_t *this, host_t* ip) static void fire_roam_job(private_kernel_netlink_net_t *this, bool address) { struct timeval now; - + if (gettimeofday(&now, NULL) == 0) { if (timercmp(&now, &this->last_roam, >)) @@ -233,7 +234,7 @@ static void process_link(private_kernel_netlink_net_t *this, struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr)); struct rtattr *rta = IFLA_RTA(msg); size_t rtasize = IFLA_PAYLOAD (hdr); - iterator_t *iterator; + enumerator_t *enumerator; iface_entry_t *current, *entry = NULL; char *name = NULL; bool update = FALSE; @@ -253,6 +254,7 @@ static void process_link(private_kernel_netlink_net_t *this, name = "(unknown)"; } + this->mutex->lock(this->mutex); switch (hdr->nlmsg_type) { case RTM_NEWLINK: @@ -261,9 +263,8 @@ static void process_link(private_kernel_netlink_net_t *this, { /* ignore loopback interfaces */ break; } - iterator = this->ifaces->create_iterator_locked(this->ifaces, - &this->mutex); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, ¤t)) { if (current->ifindex == msg->ifi_index) { @@ -271,6 +272,7 @@ static void process_link(private_kernel_netlink_net_t *this, break; } } + enumerator->destroy(enumerator); if (!entry) { entry = malloc_thing(iface_entry_t); @@ -295,14 +297,12 @@ static void process_link(private_kernel_netlink_net_t *this, } } entry->flags = msg->ifi_flags; - iterator->destroy(iterator); break; } case RTM_DELLINK: { - iterator = this->ifaces->create_iterator_locked(this->ifaces, - &this->mutex); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, ¤t)) { if (current->ifindex == msg->ifi_index) { @@ -312,10 +312,11 @@ static void process_link(private_kernel_netlink_net_t *this, break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); break; } } + this->mutex->unlock(this->mutex); /* send an update to all IKE_SAs */ if (update && event) @@ -334,7 +335,7 @@ static void process_addr(private_kernel_netlink_net_t *this, struct rtattr *rta = IFA_RTA(msg); size_t rtasize = IFA_PAYLOAD (hdr); host_t *host = NULL; - iterator_t *ifaces, *addrs; + enumerator_t *ifaces, *addrs; iface_entry_t *iface; addr_entry_t *addr; chunk_t local = chunk_empty, address = chunk_empty; @@ -373,20 +374,21 @@ static void process_addr(private_kernel_netlink_net_t *this, return; } - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { if (iface->ifindex == msg->ifa_index) { - addrs = iface->addrs->create_iterator(iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, &addr)) { if (host->ip_equals(host, addr->ip)) { found = TRUE; if (hdr->nlmsg_type == RTM_DELADDR) { - addrs->remove(addrs); + iface->addrs->remove_at(iface->addrs, addrs); if (!addr->virtual) { changed = TRUE; @@ -430,6 +432,7 @@ static void process_addr(private_kernel_netlink_net_t *this, } } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); host->destroy(host); /* send an update to all IKE_SAs */ @@ -468,10 +471,12 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h } if (host) { + this->mutex->lock(this->mutex); if (!get_vip_refcount(this, host)) { /* ignore routes added for virtual IPs */ fire_roam_job(this, FALSE); } + this->mutex->unlock(this->mutex); host->destroy(host); } } @@ -522,12 +527,12 @@ static job_requeue_t receive_events(private_kernel_netlink_net_t *this) case RTM_NEWADDR: case RTM_DELADDR: process_addr(this, hdr, TRUE); - pthread_cond_broadcast(&this->cond); + this->condvar->broadcast(this->condvar); break; case RTM_NEWLINK: case RTM_DELLINK: process_link(this, hdr, TRUE); - pthread_cond_broadcast(&this->cond); + this->condvar->broadcast(this->condvar); break; case RTM_NEWROUTE: case RTM_DELROUTE: @@ -558,7 +563,7 @@ typedef struct { */ static void address_enumerator_destroy(address_enumerator_t *data) { - pthread_mutex_unlock(&data->this->mutex); + data->this->mutex->unlock(data->this->mutex); free(data); } @@ -612,7 +617,7 @@ static enumerator_t *create_address_enumerator(private_kernel_netlink_net_t *thi data->include_down_ifaces = include_down_ifaces; data->include_virtual_ips = include_virtual_ips; - pthread_mutex_lock(&this->mutex); + this->mutex->lock(this->mutex); return enumerator_create_nested( enumerator_create_filter(this->ifaces->create_enumerator(this->ifaces), (void*)filter_interfaces, data, NULL), @@ -624,18 +629,19 @@ static enumerator_t *create_address_enumerator(private_kernel_netlink_net_t *thi */ static char *get_interface_name(private_kernel_netlink_net_t *this, host_t* ip) { - iterator_t *ifaces, *addrs; + enumerator_t *ifaces, *addrs; iface_entry_t *iface; addr_entry_t *addr; char *name = NULL; DBG2(DBG_KNL, "getting interface name for %H", ip); - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { - addrs = iface->addrs->create_iterator(iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, &addr)) { if (ip->ip_equals(ip, addr->ip)) { @@ -650,6 +656,7 @@ static char *get_interface_name(private_kernel_netlink_net_t *this, host_t* ip) } } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); if (name) { @@ -667,14 +674,15 @@ static char *get_interface_name(private_kernel_netlink_net_t *this, host_t* ip) */ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) { - iterator_t *ifaces; + enumerator_t *ifaces; iface_entry_t *iface; int ifindex = 0; DBG2(DBG_KNL, "getting iface index for %s", name); - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { if (streq(name, iface->ifname)) { @@ -683,6 +691,7 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) } } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); if (ifindex == 0) { @@ -692,6 +701,28 @@ 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; + bool up = FALSE; + + 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) @@ -730,7 +761,7 @@ static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len) static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, bool nexthop, host_t *candidate) { - unsigned char request[NETLINK_BUFFER_SIZE]; + netlink_buf_t request; struct nlmsghdr *hdr, *out, *current; struct rtmsg *msg; chunk_t chunk; @@ -763,6 +794,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, DBG1(DBG_KNL, "getting address to %H failed", dest); return NULL; } + this->mutex->lock(this->mutex); current = out; while (NLMSG_OK(current, len)) { @@ -776,6 +808,9 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, size_t rtasize; chunk_t rta_gtw, rta_src, rta_dst; u_int32_t rta_oif = 0; + enumerator_t *ifaces, *addrs; + iface_entry_t *iface; + addr_entry_t *addr; rta_gtw = rta_src = rta_dst = chunk_empty; msg = (struct rtmsg*)(NLMSG_DATA(current)); @@ -803,79 +838,80 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, } rta = RTA_NEXT(rta, rtasize); } + if (rta_oif && !is_interface_up(this, rta_oif)) + { /* interface is down */ + goto next; + } + if (this->routing_table != 0 && + msg->rtm_table == this->routing_table) + { /* route is from our own ipsec routing table */ + goto next; + } + if (msg->rtm_dst_len <= best) + { /* not better than a previous one */ + goto next; + } + if (msg->rtm_dst_len != 0 && + (!rta_dst.ptr || + !addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len))) + { /* is not the default route and not contained in our dst */ + goto next; + } - /* apply the route if: - * - it is not from our own ipsec routing table - * - is better than a previous one - * - is the default route or - * - its destination net contains our destination - */ - if ((this->routing_table == 0 ||msg->rtm_table != this->routing_table) - && msg->rtm_dst_len > best - && (msg->rtm_dst_len == 0 || /* default route */ - (rta_dst.ptr && addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len)))) + best = msg->rtm_dst_len; + if (nexthop) { - iterator_t *ifaces, *addrs; - iface_entry_t *iface; - addr_entry_t *addr; - - best = msg->rtm_dst_len; - if (nexthop) - { - DESTROY_IF(gtw); - gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0); - } - else if (rta_src.ptr) - { + DESTROY_IF(gtw); + gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0); + goto next; + } + if (rta_src.ptr) + { + DESTROY_IF(src); + src = host_create_from_chunk(msg->rtm_family, rta_src, 0); + if (get_vip_refcount(this, src)) + { /* skip source address if it is installed by us */ DESTROY_IF(src); - src = host_create_from_chunk(msg->rtm_family, rta_src, 0); - if (get_vip_refcount(this, src)) - { /* skip source address if it is installed by us */ - DESTROY_IF(src); - src = NULL; - current = NLMSG_NEXT(current, len); - continue; - } + src = NULL; } - else + goto next; + } + /* no source addr, get one from the interfaces */ + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) + { + if (iface->ifindex == rta_oif && + iface->flags & IFF_UP) { - /* no source addr, get one from the interfaces */ - ifaces = this->ifaces->create_iterator_locked( - this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, &addr)) { - if (iface->ifindex == rta_oif) + chunk_t ip = addr->ip->get_address(addr->ip); + if ((msg->rtm_dst_len == 0 && + addr->ip->get_family(addr->ip) == + dest->get_family(dest)) || + addr_in_subnet(ip, rta_dst, msg->rtm_dst_len)) { - addrs = iface->addrs->create_iterator( - iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) - { - chunk_t ip = addr->ip->get_address(addr->ip); - if ((msg->rtm_dst_len == 0 && - addr->ip->get_family(addr->ip) == - dest->get_family(dest)) || - addr_in_subnet(ip, rta_dst, msg->rtm_dst_len)) - { - DESTROY_IF(src); - src = addr->ip->clone(addr->ip); - break; - } - } - addrs->destroy(addrs); + DESTROY_IF(src); + src = addr->ip->clone(addr->ip); + break; } } - ifaces->destroy(ifaces); + addrs->destroy(addrs); } } - /* FALL through */ + ifaces->destroy(ifaces); + goto next; } default: + next: current = NLMSG_NEXT(current, len); continue; } break; } free(out); + this->mutex->unlock(this->mutex); if (nexthop) { @@ -912,7 +948,7 @@ static host_t* get_nexthop(private_kernel_netlink_net_t *this, host_t *dest) static status_t manage_ipaddr(private_kernel_netlink_net_t *this, int nlmsg_type, int flags, int if_index, host_t *ip) { - unsigned char request[NETLINK_BUFFER_SIZE]; + netlink_buf_t request; struct nlmsghdr *hdr; struct ifaddrmsg *msg; chunk_t chunk; @@ -946,18 +982,19 @@ static status_t add_ip(private_kernel_netlink_net_t *this, { iface_entry_t *iface; addr_entry_t *addr; - iterator_t *addrs, *ifaces; + enumerator_t *addrs, *ifaces; int ifindex; DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip); - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { bool iface_found = FALSE; - addrs = iface->addrs->create_iterator(iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, &addr)) { if (iface_ip->ip_equals(iface_ip, addr->ip)) { @@ -970,6 +1007,7 @@ static status_t add_ip(private_kernel_netlink_net_t *this, virtual_ip, iface->ifname); addrs->destroy(addrs); ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); return SUCCESS; } } @@ -990,17 +1028,20 @@ static status_t add_ip(private_kernel_netlink_net_t *this, { while (get_vip_refcount(this, virtual_ip) == 0) { /* wait until address appears */ - pthread_cond_wait(&this->cond, &this->mutex); + this->condvar->wait(this->condvar, this->mutex); } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); return SUCCESS; } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip); return FAILED; } } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); DBG1(DBG_KNL, "interface address %H not found, unable to install" "virtual IP %H", iface_ip, virtual_ip); @@ -1014,17 +1055,18 @@ static status_t del_ip(private_kernel_netlink_net_t *this, host_t *virtual_ip) { iface_entry_t *iface; addr_entry_t *addr; - iterator_t *addrs, *ifaces; + enumerator_t *addrs, *ifaces; status_t status; int ifindex; DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip); - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { - addrs = iface->addrs->create_iterator(iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, &addr)) { if (virtual_ip->ip_equals(virtual_ip, addr->ip)) { @@ -1037,11 +1079,12 @@ static status_t del_ip(private_kernel_netlink_net_t *this, host_t *virtual_ip) { /* wait until the address is really gone */ while (get_vip_refcount(this, virtual_ip) > 0) { - pthread_cond_wait(&this->cond, &this->mutex); + this->condvar->wait(this->condvar, this->mutex); } } addrs->destroy(addrs); ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); return status; } else @@ -1052,12 +1095,14 @@ static status_t del_ip(private_kernel_netlink_net_t *this, host_t *virtual_ip) virtual_ip); addrs->destroy(addrs); ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); return SUCCESS; } } addrs->destroy(addrs); } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip); return FAILED; @@ -1071,7 +1116,7 @@ static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_ty int flags, chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) { - unsigned char request[NETLINK_BUFFER_SIZE]; + netlink_buf_t request; struct nlmsghdr *hdr; struct rtmsg *msg; int ifindex; @@ -1151,11 +1196,11 @@ status_t del_route(private_kernel_netlink_net_t *this, chunk_t dst_net, */ static status_t init_address_list(private_kernel_netlink_net_t *this) { - char request[NETLINK_BUFFER_SIZE]; + netlink_buf_t request; struct nlmsghdr *out, *current, *in; struct rtgenmsg *msg; size_t len; - iterator_t *ifaces, *addrs; + enumerator_t *ifaces, *addrs; iface_entry_t *iface; addr_entry_t *addr; @@ -1217,14 +1262,15 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) } free(out); - ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex); - while (ifaces->iterate(ifaces, (void**)&iface)) + this->mutex->lock(this->mutex); + ifaces = this->ifaces->create_enumerator(this->ifaces); + while (ifaces->enumerate(ifaces, &iface)) { if (iface->flags & IFF_UP) { DBG1(DBG_KNL, " %s", iface->ifname); - addrs = iface->addrs->create_iterator(iface->addrs, TRUE); - while (addrs->iterate(addrs, (void**)&addr)) + addrs = iface->addrs->create_enumerator(iface->addrs); + while (addrs->enumerate(addrs, (void**)&addr)) { DBG1(DBG_KNL, " %H", addr->ip); } @@ -1232,6 +1278,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) } } ifaces->destroy(ifaces); + this->mutex->unlock(this->mutex); return SUCCESS; } @@ -1241,7 +1288,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type, u_int32_t table, u_int32_t prio) { - unsigned char request[NETLINK_BUFFER_SIZE]; + netlink_buf_t request; struct nlmsghdr *hdr; struct rtmsg *msg; chunk_t chunk; @@ -1284,6 +1331,8 @@ static void destroy(private_kernel_netlink_net_t *this) close(this->socket_events); this->socket->destroy(this->socket); this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy); + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); free(this); } @@ -1308,8 +1357,8 @@ kernel_netlink_net_t *kernel_netlink_net_create() /* private members */ this->ifaces = linked_list_create(); - pthread_mutex_init(&this->mutex, NULL); - pthread_cond_init(&this->cond, NULL); + this->mutex = mutex_create(MUTEX_DEFAULT); + this->condvar = condvar_create(CONDVAR_DEFAULT); timerclear(&this->last_roam); this->routing_table = lib->settings->get_int(lib->settings, "charon.routing_table", IPSEC_ROUTING_TABLE); |
