Use recursive source address lookup if we get a gateway only
This commit is contained in:
@@ -729,12 +729,15 @@ static bool addr_in_subnet(chunk_t addr, 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;
|
||||||
|
|
||||||
|
if (net_len == 0)
|
||||||
|
{ /* any address matches a /0 network */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
if (addr.len != net.len || net_len > 8 * net.len )
|
if (addr.len != net.len || net_len > 8 * net.len )
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan through all bytes in network order */
|
/* scan through all bytes in network order */
|
||||||
while (net_len > 0)
|
while (net_len > 0)
|
||||||
{
|
{
|
||||||
@@ -780,14 +783,13 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
|
|
||||||
msg = (struct rtmsg*)NLMSG_DATA(hdr);
|
msg = (struct rtmsg*)NLMSG_DATA(hdr);
|
||||||
msg->rtm_family = dest->get_family(dest);
|
msg->rtm_family = dest->get_family(dest);
|
||||||
|
|
||||||
chunk = dest->get_address(dest);
|
|
||||||
netlink_add_attribute(hdr, RTA_DST, chunk, sizeof(request));
|
|
||||||
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);
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
@@ -808,9 +810,7 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
size_t rtasize;
|
size_t rtasize;
|
||||||
chunk_t rta_gtw, rta_src, rta_dst;
|
chunk_t rta_gtw, rta_src, rta_dst;
|
||||||
u_int32_t rta_oif = 0;
|
u_int32_t rta_oif = 0;
|
||||||
enumerator_t *ifaces, *addrs;
|
host_t *new_src, *new_gtw;
|
||||||
iface_entry_t *iface;
|
|
||||||
addr_entry_t *addr;
|
|
||||||
|
|
||||||
rta_gtw = rta_src = rta_dst = chunk_empty;
|
rta_gtw = rta_src = rta_dst = chunk_empty;
|
||||||
msg = (struct rtmsg*)(NLMSG_DATA(current));
|
msg = (struct rtmsg*)(NLMSG_DATA(current));
|
||||||
@@ -838,8 +838,8 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
}
|
}
|
||||||
rta = RTA_NEXT(rta, rtasize);
|
rta = RTA_NEXT(rta, rtasize);
|
||||||
}
|
}
|
||||||
if (rta_oif && !is_interface_up(this, rta_oif))
|
if (msg->rtm_dst_len <= best)
|
||||||
{ /* interface is down */
|
{ /* not better than a previous one */
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
if (this->routing_table != 0 &&
|
if (this->routing_table != 0 &&
|
||||||
@@ -847,60 +847,55 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
|
|||||||
{ /* route is from our own ipsec routing table */
|
{ /* route is from our own ipsec routing table */
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
if (msg->rtm_dst_len <= best)
|
if (rta_oif && !is_interface_up(this, rta_oif))
|
||||||
{ /* not better than a previous one */
|
{ /* interface is down */
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
if (msg->rtm_dst_len != 0 &&
|
if (!addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len))
|
||||||
(!rta_dst.ptr ||
|
{ /* route destination does not contain dest */
|
||||||
!addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len)))
|
|
||||||
{ /* is not the default route and not contained in our dst */
|
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
best = msg->rtm_dst_len;
|
|
||||||
if (nexthop)
|
if (nexthop)
|
||||||
{
|
{
|
||||||
DESTROY_IF(gtw);
|
/* nexthop lookup, return gateway */
|
||||||
gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);
|
if (rta_gtw.ptr)
|
||||||
|
{
|
||||||
|
DESTROY_IF(gtw);
|
||||||
|
gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);
|
||||||
|
best = msg->rtm_dst_len;
|
||||||
|
}
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
if (rta_src.ptr)
|
if (rta_src.ptr)
|
||||||
{
|
{
|
||||||
DESTROY_IF(src);
|
/* got a source address */
|
||||||
src = host_create_from_chunk(msg->rtm_family, rta_src, 0);
|
new_src = host_create_from_chunk(msg->rtm_family, rta_src, 0);
|
||||||
if (get_vip_refcount(this, src))
|
if (get_vip_refcount(this, src))
|
||||||
{ /* skip source address if it is installed by us */
|
{ /* skip source address if it is installed by us */
|
||||||
|
new_src->destroy(new_src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
DESTROY_IF(src);
|
DESTROY_IF(src);
|
||||||
src = NULL;
|
src = new_src;
|
||||||
|
best = msg->rtm_dst_len;
|
||||||
}
|
}
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
/* no source addr, get one from the interfaces */
|
if (rta_gtw.ptr)
|
||||||
ifaces = this->ifaces->create_enumerator(this->ifaces);
|
{ /* no source, but a gateway. Lookup source to reach gtw. */
|
||||||
while (ifaces->enumerate(ifaces, &iface))
|
new_gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0);
|
||||||
{
|
new_src = get_route(this, new_gtw, FALSE, candidate);
|
||||||
if (iface->ifindex == rta_oif &&
|
new_gtw->destroy(new_gtw);
|
||||||
iface->flags & IFF_UP)
|
if (new_src)
|
||||||
{
|
{
|
||||||
addrs = iface->addrs->create_enumerator(iface->addrs);
|
DESTROY_IF(src);
|
||||||
while (addrs->enumerate(addrs, &addr))
|
src = new_src;
|
||||||
{
|
best = msg->rtm_dst_len;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
ifaces->destroy(ifaces);
|
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1367,7 +1362,7 @@ kernel_netlink_net_t *kernel_netlink_net_create()
|
|||||||
|
|
||||||
/* private members */
|
/* private members */
|
||||||
this->ifaces = linked_list_create();
|
this->ifaces = linked_list_create();
|
||||||
this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
|
this->mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
|
||||||
this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
|
this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
|
||||||
timerclear(&this->last_roam);
|
timerclear(&this->last_roam);
|
||||||
this->routing_table = lib->settings->get_int(lib->settings,
|
this->routing_table = lib->settings->get_int(lib->settings,
|
||||||
|
|||||||
Reference in New Issue
Block a user