@@ -562,7 +562,7 @@ 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, host_t *src)
|
private_kernel_iph_net_t *this, host_t *dest, int prefix, host_t *src)
|
||||||
{
|
{
|
||||||
MIB_IPFORWARD_ROW2 route;
|
MIB_IPFORWARD_ROW2 route;
|
||||||
SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
|
SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ static void add_exclude_route(private_kernel_libipsec_ipsec_t *this,
|
|||||||
{
|
{
|
||||||
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 = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
||||||
dst, NULL);
|
dst, -1, NULL);
|
||||||
if (gtw)
|
if (gtw)
|
||||||
{
|
{
|
||||||
char *if_name = NULL;
|
char *if_name = NULL;
|
||||||
@@ -445,7 +445,7 @@ 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 = hydra->kernel_interface->get_nexthop(
|
route->gateway = hydra->kernel_interface->get_nexthop(
|
||||||
hydra->kernel_interface, dst, src);
|
hydra->kernel_interface, dst, -1, src);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (policy->route)
|
if (policy->route)
|
||||||
|
|||||||
@@ -1348,7 +1348,7 @@ static bool manage_route(private_kernel_wfp_ipsec_t *this,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
||||||
remote, local);
|
remote, -1, local);
|
||||||
if (add)
|
if (add)
|
||||||
{
|
{
|
||||||
done = install_route(this, dst, mask, src, gtw);
|
done = install_route(this, dst, mask, src, gtw);
|
||||||
|
|||||||
@@ -302,13 +302,13 @@ 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, host_t *src)
|
private_kernel_interface_t *this, host_t *dest, int prefix, host_t *src)
|
||||||
{
|
{
|
||||||
if (!this->net)
|
if (!this->net)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return this->net->get_nexthop(this->net, dest, src);
|
return this->net->get_nexthop(this->net, dest, prefix, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(kernel_interface_t, get_interface, bool,
|
METHOD(kernel_interface_t, get_interface, bool,
|
||||||
|
|||||||
@@ -330,9 +330,12 @@ struct kernel_interface_t {
|
|||||||
* for the given source to dest.
|
* for the given source to dest.
|
||||||
*
|
*
|
||||||
* @param dest target destination address
|
* @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
|
||||||
* @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 *src);
|
host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest,
|
||||||
|
int prefix, host_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|||||||
@@ -86,10 +86,12 @@ struct kernel_net_t {
|
|||||||
* for the given source to dest.
|
* for the given source to dest.
|
||||||
*
|
*
|
||||||
* @param dest target destination address
|
* @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 src source address to check, or NULL
|
||||||
* @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, host_t *src);
|
host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest, int prefix,
|
||||||
|
host_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
|||||||
@@ -2135,9 +2135,20 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
|
|||||||
fwd->dst_ts, &route->src_ip, NULL) == SUCCESS)
|
fwd->dst_ts, &route->src_ip, NULL) == SUCCESS)
|
||||||
{
|
{
|
||||||
/* get the nexthop to src (src as we are in POLICY_FWD) */
|
/* get the nexthop to src (src as we are in POLICY_FWD) */
|
||||||
route->gateway = hydra->kernel_interface->get_nexthop(
|
if (!ipsec->src->is_anyaddr(ipsec->src))
|
||||||
|
{
|
||||||
|
route->gateway = hydra->kernel_interface->get_nexthop(
|
||||||
hydra->kernel_interface, ipsec->src,
|
hydra->kernel_interface, ipsec->src,
|
||||||
ipsec->dst);
|
-1, ipsec->dst);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* for shunt policies */
|
||||||
|
iface = xfrm2host(policy->sel.family, &policy->sel.saddr, 0);
|
||||||
|
route->gateway = hydra->kernel_interface->get_nexthop(
|
||||||
|
hydra->kernel_interface, iface,
|
||||||
|
policy->sel.prefixlen_s, route->src_ip);
|
||||||
|
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);
|
||||||
memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
|
memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len);
|
||||||
|
|
||||||
|
|||||||
@@ -1460,9 +1460,10 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if an address (chunk) addr is in subnet (net with net_len net bits)
|
* check if an address or net (addr with prefix net bits) is in
|
||||||
|
* subnet (net with net_len net bits)
|
||||||
*/
|
*/
|
||||||
static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len)
|
static bool addr_in_subnet(chunk_t addr, int prefix, chunk_t net, int net_len)
|
||||||
{
|
{
|
||||||
static const u_char mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
|
static const u_char mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
|
||||||
int byte = 0;
|
int byte = 0;
|
||||||
@@ -1471,7 +1472,7 @@ static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len)
|
|||||||
{ /* any address matches a /0 network */
|
{ /* any address matches a /0 network */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (addr.len != net.len || net_len > 8 * net.len )
|
if (addr.len != net.len || net_len > 8 * net.len || prefix < net_len)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1587,7 +1588,8 @@ static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route)
|
|||||||
* Get a route: If "nexthop", the nexthop is returned. source addr otherwise.
|
* Get a route: If "nexthop", the nexthop is returned. source addr otherwise.
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
bool nexthop, host_t *candidate, u_int recursion)
|
int prefix, bool nexthop, host_t *candidate,
|
||||||
|
u_int recursion)
|
||||||
{
|
{
|
||||||
netlink_buf_t request;
|
netlink_buf_t request;
|
||||||
struct nlmsghdr *hdr, *out, *current;
|
struct nlmsghdr *hdr, *out, *current;
|
||||||
@@ -1598,18 +1600,25 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
rt_entry_t *route = NULL, *best = NULL;
|
rt_entry_t *route = NULL, *best = NULL;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
host_t *addr = NULL;
|
host_t *addr = NULL;
|
||||||
|
bool match_net;
|
||||||
|
int family;
|
||||||
|
|
||||||
if (recursion > MAX_ROUTE_RECURSION)
|
if (recursion > MAX_ROUTE_RECURSION)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
chunk = dest->get_address(dest);
|
||||||
|
len = chunk.len * 8;
|
||||||
|
prefix = prefix < 0 ? len : min(prefix, len);
|
||||||
|
match_net = prefix != len;
|
||||||
|
|
||||||
memset(&request, 0, sizeof(request));
|
memset(&request, 0, sizeof(request));
|
||||||
|
|
||||||
|
family = dest->get_family(dest);
|
||||||
hdr = (struct nlmsghdr*)request;
|
hdr = (struct nlmsghdr*)request;
|
||||||
hdr->nlmsg_flags = NLM_F_REQUEST;
|
hdr->nlmsg_flags = NLM_F_REQUEST;
|
||||||
if (dest->get_family(dest) == AF_INET || this->rta_prefsrc_for_ipv6 ||
|
if (family == AF_INET || this->rta_prefsrc_for_ipv6 ||
|
||||||
this->routing_table)
|
this->routing_table || match_net)
|
||||||
{ /* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes.
|
{ /* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes.
|
||||||
* as we want to ignore routes with virtual IPs we cannot use DUMP
|
* as we want to ignore routes with virtual IPs we cannot use DUMP
|
||||||
* if these routes are not installed in a separate table */
|
* if these routes are not installed in a separate table */
|
||||||
@@ -1619,19 +1628,22 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
|
|
||||||
msg = (struct rtmsg*)NLMSG_DATA(hdr);
|
msg = (struct rtmsg*)NLMSG_DATA(hdr);
|
||||||
msg->rtm_family = dest->get_family(dest);
|
msg->rtm_family = family;
|
||||||
if (candidate)
|
if (candidate)
|
||||||
{
|
{
|
||||||
chunk = candidate->get_address(candidate);
|
chunk = candidate->get_address(candidate);
|
||||||
netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
|
netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
|
||||||
}
|
}
|
||||||
chunk = dest->get_address(dest);
|
if (!match_net)
|
||||||
netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
|
{
|
||||||
|
chunk = dest->get_address(dest);
|
||||||
|
netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
|
||||||
|
}
|
||||||
|
|
||||||
if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
|
if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
|
||||||
{
|
{
|
||||||
DBG2(DBG_KNL, "getting %s to reach %H failed",
|
DBG2(DBG_KNL, "getting %s to reach %H/%d failed",
|
||||||
nexthop ? "nexthop" : "address", dest);
|
nexthop ? "nexthop" : "address", dest, prefix);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
routes = linked_list_create();
|
routes = linked_list_create();
|
||||||
@@ -1666,7 +1678,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
{ /* interface is down */
|
{ /* interface is down */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!addr_in_subnet(chunk, route->dst, route->dst_len))
|
if (!addr_in_subnet(chunk, prefix, route->dst, route->dst_len))
|
||||||
{ /* route destination does not contain dest */
|
{ /* route destination does not contain dest */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1761,7 +1773,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
gtw = host_create_from_chunk(msg->rtm_family, route->gtw, 0);
|
gtw = host_create_from_chunk(msg->rtm_family, route->gtw, 0);
|
||||||
if (gtw && !gtw->ip_equals(gtw, dest))
|
if (gtw && !gtw->ip_equals(gtw, dest))
|
||||||
{
|
{
|
||||||
route->src_host = get_route(this, gtw, FALSE, candidate,
|
route->src_host = get_route(this, gtw, -1, FALSE, candidate,
|
||||||
recursion + 1);
|
recursion + 1);
|
||||||
}
|
}
|
||||||
DESTROY_IF(gtw);
|
DESTROY_IF(gtw);
|
||||||
@@ -1785,7 +1797,10 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
{
|
{
|
||||||
addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0);
|
addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0);
|
||||||
}
|
}
|
||||||
addr = addr ?: dest->clone(dest);
|
if (!addr && !match_net)
|
||||||
|
{ /* fallback to destination address */
|
||||||
|
addr = dest->clone(dest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1800,13 +1815,13 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
{
|
{
|
||||||
DBG2(DBG_KNL, "using %H as %s to reach %H", addr,
|
DBG2(DBG_KNL, "using %H as %s to reach %H/%d", addr,
|
||||||
nexthop ? "nexthop" : "address", dest);
|
nexthop ? "nexthop" : "address", dest, prefix);
|
||||||
}
|
}
|
||||||
else if (!recursion)
|
else if (!recursion)
|
||||||
{
|
{
|
||||||
DBG2(DBG_KNL, "no %s found to reach %H",
|
DBG2(DBG_KNL, "no %s found to reach %H/%d",
|
||||||
nexthop ? "nexthop" : "address", dest);
|
nexthop ? "nexthop" : "address", dest, prefix);
|
||||||
}
|
}
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
@@ -1814,13 +1829,13 @@ 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, FALSE, src, 0);
|
return get_route(this, dest, -1, FALSE, src, 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, host_t *src)
|
private_kernel_netlink_net_t *this, host_t *dest, int prefix, host_t *src)
|
||||||
{
|
{
|
||||||
return get_route(this, dest, TRUE, src, 0);
|
return get_route(this, dest, prefix, TRUE, src, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2112,7 +2112,7 @@ static void add_exclude_route(private_kernel_pfkey_ipsec_t *this,
|
|||||||
{
|
{
|
||||||
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 = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
|
||||||
dst, NULL);
|
dst, -1, NULL);
|
||||||
if (gtw)
|
if (gtw)
|
||||||
{
|
{
|
||||||
char *if_name = NULL;
|
char *if_name = NULL;
|
||||||
@@ -2224,7 +2224,7 @@ static bool install_route(private_kernel_pfkey_ipsec_t *this,
|
|||||||
.prefixlen = policy->src.mask,
|
.prefixlen = policy->src.mask,
|
||||||
.src_ip = host,
|
.src_ip = host,
|
||||||
.gateway = hydra->kernel_interface->get_nexthop(
|
.gateway = hydra->kernel_interface->get_nexthop(
|
||||||
hydra->kernel_interface, dst, src),
|
hydra->kernel_interface, dst, -1, src),
|
||||||
.dst_net = chunk_clone(policy->src.net->get_address(policy->src.net)),
|
.dst_net = chunk_clone(policy->src.net->get_address(policy->src.net)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1612,7 +1612,7 @@ 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, host_t *src)
|
private_kernel_pfroute_net_t *this, host_t *dest, int prefix, host_t *src)
|
||||||
{
|
{
|
||||||
return get_route(this, TRUE, dest, src);
|
return get_route(this, TRUE, dest, src);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user