From 99a57aa5ee15affa9e38595d90971031977e34be Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 11 Mar 2016 18:54:31 +0100 Subject: [PATCH] kernel-net: Let get_nexthop() return an optional interface name The returned name should be the interface over which the destination address/net is reachable. --- src/libcharon/kernel/kernel_interface.c | 5 +++-- src/libcharon/kernel/kernel_interface.h | 4 +++- src/libcharon/kernel/kernel_net.h | 8 +++++--- src/libcharon/plugins/kernel_iph/kernel_iph_net.c | 7 ++++++- .../kernel_libipsec/kernel_libipsec_ipsec.c | 5 +++-- .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 4 ++-- .../plugins/kernel_netlink/kernel_netlink_net.c | 15 ++++++++++----- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 6 +++--- .../plugins/kernel_pfroute/kernel_pfroute_net.c | 7 ++++++- .../plugins/kernel_wfp/kernel_wfp_ipsec.c | 2 +- 10 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index 0a0081c22..7b39a020c 100644 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -524,13 +524,14 @@ METHOD(kernel_interface_t, get_source_addr, host_t*, } METHOD(kernel_interface_t, get_nexthop, host_t*, - private_kernel_interface_t *this, host_t *dest, int prefix, host_t *src) + private_kernel_interface_t *this, host_t *dest, int prefix, host_t *src, + char **iface) { if (!this->net) { return NULL; } - return this->net->get_nexthop(this->net, dest, prefix, src); + return this->net->get_nexthop(this->net, dest, prefix, src, iface); } METHOD(kernel_interface_t, get_interface, bool, diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index 50f6d9829..225b40932 100644 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -285,10 +285,12 @@ struct kernel_interface_t { * @param dest target destination address * @param prefix prefix length if dest is a subnet, -1 for auto * @param src source address to check, or NULL + * @param[out] iface allocated name of the interface to reach dest, if + * available (optional) * @return next hop address, NULL if unreachable */ host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest, - int prefix, host_t *src); + int prefix, host_t *src, char **iface); /** * Get the interface name of a local address. Interfaces that are down or diff --git a/src/libcharon/kernel/kernel_net.h b/src/libcharon/kernel/kernel_net.h index 4f3063deb..1d78d6edd 100644 --- a/src/libcharon/kernel/kernel_net.h +++ b/src/libcharon/kernel/kernel_net.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2008-2012 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -88,10 +88,12 @@ struct kernel_net_t { * @param dest target destination address * @param prefix prefix length if dest is a subnet, -1 for auto * @param src source address to check, or NULL + * @param[out] iface allocated name of the interface to reach dest, if + * available (optional) * @return next hop address, NULL if unreachable */ host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest, int prefix, - host_t *src); + host_t *src, char **iface); /** * Get the interface name of a local address. Interfaces that are down or diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c index 3633213f3..efeb98045 100644 --- a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c +++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c @@ -562,7 +562,8 @@ METHOD(kernel_net_t, get_source_addr, host_t*, } METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src) + private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src, + char **iface) { MIB_IPFORWARD_ROW2 route; SOCKADDR_INET best, *sai_dst, *sai_src = NULL; @@ -592,6 +593,10 @@ METHOD(kernel_net_t, get_nexthop, host_t*, { if (!nexthop->is_anyaddr(nexthop)) { + if (iface) + { + *iface = NULL; + } return nexthop; } nexthop->destroy(nexthop); diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index f1340320a..77e37e249 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -308,7 +308,7 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this, if (!route->exclude) { DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); - gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL); + gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL, NULL); if (gtw) { char *if_name = NULL; @@ -434,7 +434,8 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this, ); #ifndef __linux__ /* on Linux we cant't install a gateway */ - route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, src); + route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, src, + NULL); #endif if (policy->route) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index e78e13e40..be0756d6f 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -2320,14 +2320,14 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, if (!ipsec->src->is_anyaddr(ipsec->src)) { route->gateway = charon->kernel->get_nexthop(charon->kernel, - ipsec->src, -1, ipsec->dst); + ipsec->src, -1, ipsec->dst, NULL); } else { /* for shunt policies */ iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0); route->gateway = charon->kernel->get_nexthop(charon->kernel, iface, policy->sel.prefixlen_s, - route->src_ip); + route->src_ip, NULL); iface->destroy(iface); } route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c index bde0e775d..e9308690f 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c @@ -1659,7 +1659,7 @@ static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route) */ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, int prefix, bool nexthop, host_t *candidate, - u_int recursion) + char **iface, u_int recursion) { netlink_buf_t request; struct nlmsghdr *hdr, *out, *current; @@ -1861,7 +1861,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, if (gtw && !gtw->ip_equals(gtw, dest)) { route->src_host = get_route(this, gtw, -1, FALSE, candidate, - recursion + 1); + iface, recursion + 1); } DESTROY_IF(gtw); if (route->src_host) @@ -1880,6 +1880,10 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, if (nexthop) { /* nexthop lookup, return gateway if any */ + if (iface) + { + *iface = NULL; + } if (best || routes->get_first(routes, (void**)&best) == SUCCESS) { addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0); @@ -1916,13 +1920,14 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, METHOD(kernel_net_t, get_source_addr, host_t*, private_kernel_netlink_net_t *this, host_t *dest, host_t *src) { - return get_route(this, dest, -1, FALSE, src, 0); + return get_route(this, dest, -1, FALSE, src, NULL, 0); } METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_netlink_net_t *this, host_t *dest, int prefix, host_t *src) + private_kernel_netlink_net_t *this, host_t *dest, int prefix, host_t *src, + char **iface) { - return get_route(this, dest, prefix, TRUE, src, 0); + return get_route(this, dest, prefix, TRUE, src, iface, 0); } /** diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index a0fd42995..d54a96eb5 100644 --- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -2199,7 +2199,7 @@ static void add_exclude_route(private_kernel_pfkey_ipsec_t *this, if (!route->exclude) { DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); - gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL); + gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL, NULL); if (gtw) { char *if_name = NULL; @@ -2315,7 +2315,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this, if (!dst->is_anyaddr(dst)) { route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, - src); + src, NULL); /* if the IP is virtual, we install the route over the interface it has * been installed on. Otherwise we use the interface we use for IKE, as @@ -2329,7 +2329,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this, { /* for shunt policies */ route->gateway = charon->kernel->get_nexthop(charon->kernel, policy->src.net, policy->src.mask, - route->src_ip); + route->src_ip, NULL); /* we don't have a source address, use the address we found */ src = route->src_ip; diff --git a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c index 5ab39bbfe..b2b6d9758 100644 --- a/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -1684,8 +1684,13 @@ METHOD(kernel_net_t, get_source_addr, host_t*, } METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_pfroute_net_t *this, host_t *dest, int prefix, host_t *src) + private_kernel_pfroute_net_t *this, host_t *dest, int prefix, host_t *src, + char **iface) { + if (iface) + { + *iface = NULL; + } return get_route(this, TRUE, dest, src); } diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c index c12d38430..6ad26b72f 100644 --- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c +++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c @@ -1489,7 +1489,7 @@ static bool manage_route(private_kernel_wfp_ipsec_t *this, dst->destroy(dst); return FALSE; } - gtw = charon->kernel->get_nexthop(charon->kernel, remote, -1, local); + gtw = charon->kernel->get_nexthop(charon->kernel, remote, -1, local, NULL); if (add) { done = install_route(this, dst, mask, src, gtw);