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.
This commit is contained in:
Tobias Brunner
2016-06-10 13:54:18 +02:00
parent 436f64d5bc
commit 99a57aa5ee
10 changed files with 42 additions and 21 deletions
+3 -2
View File
@@ -524,13 +524,14 @@ METHOD(kernel_interface_t, get_source_addr, host_t*,
} }
METHOD(kernel_interface_t, get_nexthop, 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) if (!this->net)
{ {
return NULL; 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, METHOD(kernel_interface_t, get_interface, bool,
+3 -1
View File
@@ -285,10 +285,12 @@ struct kernel_interface_t {
* @param dest target destination address * @param dest target destination address
* @param prefix prefix length if dest is a subnet, -1 for auto * @param prefix prefix length if dest is a subnet, -1 for auto
* @param src source address to check, or NULL * @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 * @return next hop address, NULL if unreachable
*/ */
host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest, 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 * Get the interface name of a local address. Interfaces that are down or
+5 -3
View File
@@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008-2016 Tobias Brunner
* Copyright (C) 2007 Martin Willi * 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 * 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 * 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 dest target destination address
* @param prefix prefix length if dest is a subnet, -1 for auto * @param prefix prefix length if dest is a subnet, -1 for auto
* @param src source address to check, or NULL * @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 * @return next hop address, NULL if unreachable
*/ */
host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest, int prefix, 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 * Get the interface name of a local address. Interfaces that are down or
@@ -562,7 +562,8 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
} }
METHOD(kernel_net_t, get_nexthop, 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; MIB_IPFORWARD_ROW2 route;
SOCKADDR_INET best, *sai_dst, *sai_src = NULL; 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 (!nexthop->is_anyaddr(nexthop))
{ {
if (iface)
{
*iface = NULL;
}
return nexthop; return nexthop;
} }
nexthop->destroy(nexthop); nexthop->destroy(nexthop);
@@ -308,7 +308,7 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this,
if (!route->exclude) if (!route->exclude)
{ {
DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); 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) if (gtw)
{ {
char *if_name = NULL; char *if_name = NULL;
@@ -434,7 +434,8 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this,
); );
#ifndef __linux__ #ifndef __linux__
/* on Linux we cant't install a gateway */ /* 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 #endif
if (policy->route) if (policy->route)
@@ -2320,14 +2320,14 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
if (!ipsec->src->is_anyaddr(ipsec->src)) if (!ipsec->src->is_anyaddr(ipsec->src))
{ {
route->gateway = charon->kernel->get_nexthop(charon->kernel, route->gateway = charon->kernel->get_nexthop(charon->kernel,
ipsec->src, -1, ipsec->dst); ipsec->src, -1, ipsec->dst, NULL);
} }
else else
{ /* for shunt policies */ { /* for shunt policies */
iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0); iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0);
route->gateway = charon->kernel->get_nexthop(charon->kernel, route->gateway = charon->kernel->get_nexthop(charon->kernel,
iface, policy->sel.prefixlen_s, iface, policy->sel.prefixlen_s,
route->src_ip); route->src_ip, NULL);
iface->destroy(iface); iface->destroy(iface);
} }
route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
@@ -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, static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
int prefix, bool nexthop, host_t *candidate, int prefix, bool nexthop, host_t *candidate,
u_int recursion) char **iface, u_int recursion)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *hdr, *out, *current; 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)) if (gtw && !gtw->ip_equals(gtw, dest))
{ {
route->src_host = get_route(this, gtw, -1, FALSE, candidate, route->src_host = get_route(this, gtw, -1, FALSE, candidate,
recursion + 1); iface, recursion + 1);
} }
DESTROY_IF(gtw); DESTROY_IF(gtw);
if (route->src_host) if (route->src_host)
@@ -1880,6 +1880,10 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
if (nexthop) if (nexthop)
{ /* nexthop lookup, return gateway if any */ { /* nexthop lookup, return gateway if any */
if (iface)
{
*iface = NULL;
}
if (best || routes->get_first(routes, (void**)&best) == SUCCESS) if (best || routes->get_first(routes, (void**)&best) == SUCCESS)
{ {
addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0); 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*, METHOD(kernel_net_t, get_source_addr, host_t*,
private_kernel_netlink_net_t *this, host_t *dest, host_t *src) 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*, 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);
} }
/** /**
@@ -2199,7 +2199,7 @@ static void add_exclude_route(private_kernel_pfkey_ipsec_t *this,
if (!route->exclude) if (!route->exclude)
{ {
DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src); 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) if (gtw)
{ {
char *if_name = NULL; char *if_name = NULL;
@@ -2315,7 +2315,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
if (!dst->is_anyaddr(dst)) if (!dst->is_anyaddr(dst))
{ {
route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, 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 /* 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 * 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 */ { /* for shunt policies */
route->gateway = charon->kernel->get_nexthop(charon->kernel, route->gateway = charon->kernel->get_nexthop(charon->kernel,
policy->src.net, policy->src.mask, 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 */ /* we don't have a source address, use the address we found */
src = route->src_ip; src = route->src_ip;
@@ -1684,8 +1684,13 @@ METHOD(kernel_net_t, get_source_addr, host_t*,
} }
METHOD(kernel_net_t, get_nexthop, 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); return get_route(this, TRUE, dest, src);
} }
@@ -1489,7 +1489,7 @@ static bool manage_route(private_kernel_wfp_ipsec_t *this,
dst->destroy(dst); dst->destroy(dst);
return FALSE; 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) if (add)
{ {
done = install_route(this, dst, mask, src, gtw); done = install_route(this, dst, mask, src, gtw);