METHOD(kernel_net_t, add_route, status_t,
private_android_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
return NOT_SUPPORTED;
}
METHOD(kernel_net_t, del_route, status_t,
private_android_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
return NOT_SUPPORTED;
}
METHOD(kernel_interface_t, add_route, status_t,
private_kernel_interface_t *this, chunk_t dst_net,
- uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
+ uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name,
+ bool pass)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->add_route(this->net, dst_net, prefixlen, gateway,
- src_ip, if_name);
+ src_ip, if_name, pass);
}
METHOD(kernel_interface_t, del_route, status_t,
private_kernel_interface_t *this, chunk_t dst_net,
- uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name)
+ uint8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name,
+ bool pass)
{
if (!this->net)
{
return NOT_SUPPORTED;
}
return this->net->del_route(this->net, dst_net, prefixlen, gateway,
- src_ip, if_name);
+ src_ip, if_name, pass);
}
METHOD(kernel_interface_t, bypass_socket, bool,
* @param gateway gateway for this route
* @param src_ip source ip of the route
* @param if_name name of the interface the route is bound to
+ * @param pass TRUE if route is installed for passthrough policy
* @return SUCCESS if operation completed
* ALREADY_DONE if the route already exists
*/
status_t (*add_route) (kernel_interface_t *this, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway, host_t *src_ip,
- char *if_name);
+ char *if_name, bool pass);
/**
* Delete a route.
* @param gateway gateway for this route
* @param src_ip source ip of the route
* @param if_name name of the interface the route is bound to
+ * @param pass TRUE if route was installed for passthrough policy
* @return SUCCESS if operation completed
*/
status_t (*del_route) (kernel_interface_t *this, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway, host_t *src_ip,
- char *if_name);
+ char *if_name, bool pass);
/**
* Set up a bypass policy for a given socket.
* @param gateway gateway for this route
* @param src_ip source ip of the route
* @param if_name name of the interface the route is bound to
+ * @param pass TRUE if route is installed for passthrough policy
* @return SUCCESS if operation completed
* ALREADY_DONE if the route already exists
*/
status_t (*add_route) (kernel_net_t *this, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway, host_t *src_ip,
- char *if_name);
+ char *if_name, bool pass);
/**
* Delete a route.
* @param gateway gateway for this route
* @param src_ip source ip of the route
* @param if_name name of the interface the route is bound to
+ * @param pass TRUE if route was installed for passthrough policy
* @return SUCCESS if operation completed
*/
status_t (*del_route) (kernel_net_t *this, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway, host_t *src_ip,
- char *if_name);
+ char *if_name, bool pass);
/**
* Destroy the implementation.
METHOD(kernel_net_t, add_route, status_t,
private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
- host_t *gateway, host_t *src, char *name)
+ host_t *gateway, host_t *src, char *name, bool pass)
{
return manage_route(this, TRUE, dst, prefixlen, gateway, name);
}
METHOD(kernel_net_t, del_route, status_t,
private_kernel_iph_net_t *this, chunk_t dst, uint8_t prefixlen,
- host_t *gateway, host_t *src, char *name)
+ host_t *gateway, host_t *src, char *name, bool pass)
{
return manage_route(this, FALSE, dst, prefixlen, gateway, name);
}
if (charon->kernel->get_interface(charon->kernel, src, &if_name) &&
charon->kernel->add_route(charon->kernel, dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
- gtw, src, if_name) == SUCCESS)
+ gtw, src, if_name, TRUE) == SUCCESS)
{
INIT(exclude,
.dst = dst->clone(dst),
charon->kernel->del_route(charon->kernel, dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
route->exclude->gtw, route->exclude->src,
- if_name) != SUCCESS)
+ if_name, TRUE) != SUCCESS)
{
DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst);
}
}
/* uninstall previously installed route */
if (charon->kernel->del_route(charon->kernel, old->dst_net,
- old->prefixlen, old->gateway,
- old->src_ip, old->if_name) != SUCCESS)
+ old->prefixlen, old->gateway, old->src_ip,
+ old->if_name, FALSE) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N", src_ts, dst_ts, policy_dir_names,
switch (charon->kernel->add_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ route->src_ip, route->if_name, FALSE))
{
case ALREADY_DONE:
/* route exists, do not uninstall */
route_entry_t *route = policy->route;
if (charon->kernel->del_route(charon->kernel, route->dst_net,
- route->prefixlen, route->gateway,
- route->src_ip, route->if_name) != SUCCESS)
+ route->prefixlen, route->gateway, route->src_ip,
+ route->if_name, FALSE) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with "
"policy %R === %R %N", id->src_ts, id->dst_ts,
charon->kernel->del_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
- route->src_ip, route->if_name);
+ route->src_ip, route->if_name, FALSE);
remove_exclude_route(this, route);
}
policy_entry_destroy(pol);
/** Destination net prefixlen */
uint8_t prefixlen;
+
+ /** Whether the route was installed for a passthrough policy */
+ bool pass;
};
/**
static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
{
if (a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
+ a->pass == b->pass &&
a->src_ip->ip_equals(a->src_ip, b->src_ip) &&
chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen)
{
INIT(route,
.prefixlen = policy->sel.prefixlen_d,
+ .pass = mapping->type == POLICY_PASS,
);
if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts,
/* uninstall previously installed route */
if (charon->kernel->del_route(charon->kernel, old->dst_net,
old->prefixlen, old->gateway,
- old->src_ip, old->if_name) != SUCCESS)
+ old->src_ip, old->if_name,
+ old->pass) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N", out->src_ts, out->dst_ts, policy_dir_names,
route->gateway, route->src_ip, route->if_name);
switch (charon->kernel->add_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ route->src_ip, route->if_name,
+ route->pass))
{
default:
DBG1(DBG_KNL, "unable to install source route for %H",
route_entry_t *route = current->route;
if (charon->kernel->del_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
- route->src_ip, route->if_name) != SUCCESS)
+ route->src_ip, route->if_name,
+ route->pass) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N%s", id->src_ts, id->dst_ts, policy_dir_names,
/** Destination net prefixlen */
uint8_t prefixlen;
+
+ /** Whether the route was installed for a passthrough policy */
+ bool pass;
};
/**
.gateway = this->gateway ? this->gateway->clone(this->gateway) : NULL,
.dst_net = chunk_clone(this->dst_net),
.prefixlen = this->prefixlen,
+ .pass = this->pass,
);
return route;
}
static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
{
if (a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
+ a->pass == b->pass &&
a->src_ip->ip_equals(a->src_ip, b->src_ip) &&
chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen)
{
static status_t manage_srcroute(private_kernel_netlink_net_t *this,
int nlmsg_type, int flags, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway,
- host_t *src_ip, char *if_name);
+ host_t *src_ip, char *if_name, bool pass);
/**
* Clear the queued network changes.
net_change_t *change, lookup = {
.if_name = route->if_name,
};
+ if (route->pass)
+ { /* no need to reinstall these, they don't reference interfaces */
+ continue;
+ }
/* check if a change for the outgoing interface is queued */
change = this->net_changes->get(this->net_changes, &lookup);
if (!change)
{
manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
route->dst_net, route->prefixlen, route->gateway,
- route->src_ip, route->if_name);
+ route->src_ip, route->if_name, route->pass);
}
}
enumerator->destroy(enumerator);
static status_t manage_srcroute(private_kernel_netlink_net_t *this,
int nlmsg_type, int flags, chunk_t dst_net,
uint8_t prefixlen, host_t *gateway,
- host_t *src_ip, char *if_name)
+ host_t *src_ip, char *if_name, bool pass)
{
netlink_buf_t request;
struct nlmsghdr *hdr;
half_net = chunk_alloca(dst_net.len);
memset(half_net.ptr, 0, half_net.len);
half_prefixlen = 1;
-
+ /* no throw routes in the main table */
status = manage_srcroute(this, nlmsg_type, flags, half_net,
- half_prefixlen, gateway, src_ip, if_name);
+ half_prefixlen, gateway, src_ip, if_name, FALSE);
half_net.ptr[0] |= 0x80;
status |= manage_srcroute(this, nlmsg_type, flags, half_net,
- half_prefixlen, gateway, src_ip, if_name);
+ half_prefixlen, gateway, src_ip, if_name, FALSE);
return status;
}
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
msg = NLMSG_DATA(hdr);
- msg->rtm_family = src_ip->get_family(src_ip);
+ msg->rtm_family = (dst_net.len == 4) ? AF_INET : AF_INET6;
msg->rtm_dst_len = prefixlen;
msg->rtm_protocol = RTPROT_STATIC;
- msg->rtm_type = RTN_UNICAST;
+ msg->rtm_type = pass ? RTN_THROW : RTN_UNICAST;
msg->rtm_scope = RT_SCOPE_UNIVERSE;
if (this->routing_table < 256)
#endif /* HAVE_RTA_TABLE */
}
netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request));
- chunk = src_ip->get_address(src_ip);
- netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
- if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
- {
- chunk = gateway->get_address(gateway);
- netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
- }
- ifindex = get_interface_index(this, if_name);
- chunk.ptr = (char*)&ifindex;
- chunk.len = sizeof(ifindex);
- netlink_add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
- if (this->mtu || this->mss)
+ /* only when installing regular routes do we need all the parameters,
+ * deletes are done by destination net (except if metrics are used, which
+ * we don't support), for throw routes we don't need any of them either */
+ if (nlmsg_type == RTM_NEWROUTE && !pass)
{
- chunk = chunk_alloca(RTA_LENGTH((sizeof(struct rtattr) +
- sizeof(uint32_t)) * 2));
- chunk.len = 0;
- rta = (struct rtattr*)chunk.ptr;
- if (this->mtu)
+ chunk = src_ip->get_address(src_ip);
+ netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
+ if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
{
- rta->rta_type = RTAX_MTU;
- rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
- memcpy(RTA_DATA(rta), &this->mtu, sizeof(uint32_t));
- chunk.len = rta->rta_len;
+ chunk = gateway->get_address(gateway);
+ netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
}
- if (this->mss)
+ ifindex = get_interface_index(this, if_name);
+ chunk.ptr = (char*)&ifindex;
+ chunk.len = sizeof(ifindex);
+ netlink_add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
+
+ if (this->mtu || this->mss)
{
- rta = (struct rtattr*)(chunk.ptr + RTA_ALIGN(chunk.len));
- rta->rta_type = RTAX_ADVMSS;
- rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
- memcpy(RTA_DATA(rta), &this->mss, sizeof(uint32_t));
- chunk.len = RTA_ALIGN(chunk.len) + rta->rta_len;
+ chunk = chunk_alloca(RTA_LENGTH((sizeof(struct rtattr) +
+ sizeof(uint32_t)) * 2));
+ chunk.len = 0;
+ rta = (struct rtattr*)chunk.ptr;
+ if (this->mtu)
+ {
+ rta->rta_type = RTAX_MTU;
+ rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
+ memcpy(RTA_DATA(rta), &this->mtu, sizeof(uint32_t));
+ chunk.len = rta->rta_len;
+ }
+ if (this->mss)
+ {
+ rta = (struct rtattr*)(chunk.ptr + RTA_ALIGN(chunk.len));
+ rta->rta_type = RTAX_ADVMSS;
+ rta->rta_len = RTA_LENGTH(sizeof(uint32_t));
+ memcpy(RTA_DATA(rta), &this->mss, sizeof(uint32_t));
+ chunk.len = RTA_ALIGN(chunk.len) + rta->rta_len;
+ }
+ netlink_add_attribute(hdr, RTA_METRICS, chunk, sizeof(request));
}
- netlink_add_attribute(hdr, RTA_METRICS, chunk, sizeof(request));
}
-
return this->socket->send_ack(this->socket, hdr);
}
METHOD(kernel_net_t, add_route, status_t,
private_kernel_netlink_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
status_t status;
route_entry_t *found;
.gateway = gateway,
.src_ip = src_ip,
.if_name = if_name,
+ .pass = pass,
},
.this = this,
};
+ if (!this->routing_table)
+ { /* treat these as regular routes if installing in the main table */
+ pass = lookup.route.pass = FALSE;
+ }
+
this->routes_lock->lock(this->routes_lock);
found = this->routes->get(this->routes, &lookup.route);
if (found)
else
{
status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
- dst_net, prefixlen, gateway, src_ip, if_name);
+ dst_net, prefixlen, gateway, src_ip, if_name,
+ pass);
}
if (status == SUCCESS)
{
METHOD(kernel_net_t, del_route, status_t,
private_kernel_netlink_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
status_t status;
route_entry_t *found;
.gateway = gateway,
.src_ip = src_ip,
.if_name = if_name,
+ .pass = pass,
},
.this = this,
};
+ if (!this->routing_table)
+ { /* treat these as regular routes if installing in the main table */
+ pass = lookup.route.pass = FALSE;
+ }
+
this->routes_lock->lock(this->routes_lock);
found = this->routes->remove(this->routes, &lookup.route);
if (!found)
{
status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
found->dst_net, found->prefixlen, found->gateway,
- found->src_ip, found->if_name);
+ found->src_ip, found->if_name, found->pass);
}
else
{
status = manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen,
- gateway, src_ip, if_name);
+ gateway, src_ip, if_name, pass);
}
this->routes_lock->unlock(this->routes_lock);
return status;
while (enumerator->enumerate(enumerator, NULL, (void**)&route))
{
manage_srcroute(this, RTM_DELROUTE, 0, route->dst_net, route->prefixlen,
- route->gateway, route->src_ip, route->if_name);
+ route->gateway, route->src_ip, route->if_name,
+ route->pass);
route_entry_destroy(route);
}
enumerator->destroy(enumerator);
charon->kernel->add_route(charon->kernel,
dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
- gtw, src, if_name) == SUCCESS)
+ gtw, src, if_name, FALSE) == SUCCESS)
{
INIT(exclude,
.dst = dst->clone(dst),
dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
route->exclude->gtw, route->exclude->src,
- if_name) != SUCCESS)
+ if_name, FALSE) != SUCCESS)
{
DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst);
}
}
/* uninstall previously installed route */
if (charon->kernel->del_route(charon->kernel, old->dst_net,
- old->prefixlen, old->gateway,
- old->src_ip, old->if_name) != SUCCESS)
+ old->prefixlen, old->gateway,
+ old->src_ip, old->if_name, FALSE) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N", out->src_ts, out->dst_ts,
switch (charon->kernel->add_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
- route->src_ip, route->if_name))
+ route->src_ip, route->if_name, FALSE))
{
case ALREADY_DONE:
/* route exists, do not uninstall */
{
route_entry_t *route = policy->route;
if (charon->kernel->del_route(charon->kernel, route->dst_net,
- route->prefixlen, route->gateway,
- route->src_ip, route->if_name) != SUCCESS)
+ route->prefixlen, route->gateway,
+ route->src_ip, route->if_name, FALSE) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with "
"policy %R === %R %N", id->src_ts, id->dst_ts,
METHOD(kernel_net_t, add_route, status_t,
private_kernel_pfroute_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
status_t status;
route_entry_t *found, route = {
METHOD(kernel_net_t, del_route, status_t,
private_kernel_pfroute_net_t *this, chunk_t dst_net, uint8_t prefixlen,
- host_t *gateway, host_t *src_ip, char *if_name)
+ host_t *gateway, host_t *src_ip, char *if_name, bool pass)
{
status_t status;
route_entry_t *found, route = {
if (charon->kernel->get_interface(charon->kernel, src, &name))
{
res = charon->kernel->del_route(charon->kernel,
- dst->get_address(dst), mask, gtw, src, name) == SUCCESS;
+ dst->get_address(dst), mask, gtw, src,
+ name, FALSE) == SUCCESS;
free(name);
}
route = this->routes->remove(this->routes, route);
{
if (charon->kernel->get_interface(charon->kernel, src, &name))
{
- if (charon->kernel->add_route(charon->kernel,
- dst->get_address(dst), mask, gtw, src, name) == SUCCESS)
+ if (charon->kernel->add_route(charon->kernel, dst->get_address(dst),
+ mask, gtw, src, name, FALSE) == SUCCESS)
{
INIT(route,
.dst = dst->clone(dst),