Added support for IPv6 source route installation

This commit is contained in:
Martin Willi
2009-11-26 10:31:00 +01:00
parent 387a6e6c32
commit 5be75c2cb1
2 changed files with 44 additions and 17 deletions
@@ -260,7 +260,7 @@ static void route_entry_destroy(route_entry_t *this)
{ {
free(this->if_name); free(this->if_name);
this->src_ip->destroy(this->src_ip); this->src_ip->destroy(this->src_ip);
this->gateway->destroy(this->gateway); DESTROY_IF(this->gateway);
chunk_free(&this->dst_net); chunk_free(&this->dst_net);
free(this); free(this);
} }
@@ -1661,24 +1661,34 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
* - we are NOT updating a policy * - we are NOT updating a policy
* - this is a forward policy (to just get one for each child) * - this is a forward policy (to just get one for each child)
* - we are in tunnel mode * - we are in tunnel mode
* - we are not using IPv6 (does not work correctly yet!)
* - routing is not disabled via strongswan.conf * - routing is not disabled via strongswan.conf
*/ */
if (policy->route == NULL && direction == POLICY_FWD && if (policy->route == NULL && direction == POLICY_FWD &&
mode != MODE_TRANSPORT && src->get_family(src) != AF_INET6 && mode != MODE_TRANSPORT && this->install_routes)
this->install_routes)
{ {
route_entry_t *route = malloc_thing(route_entry_t); route_entry_t *route = malloc_thing(route_entry_t);
if (charon->kernel_interface->get_address_by_ts(charon->kernel_interface, if (charon->kernel_interface->get_address_by_ts(charon->kernel_interface,
dst_ts, &route->src_ip) == SUCCESS) dst_ts, &route->src_ip) == SUCCESS)
{ {
/* get the nexthop to src (src as we are in POLICY_FWD).*/ if (policy->sel.family == AF_INET)
route->gateway = charon->kernel_interface->get_nexthop( {
/* get the nexthop to src (src as we are in POLICY_FWD).*/
route->gateway = charon->kernel_interface->get_nexthop(
charon->kernel_interface, src); charon->kernel_interface, src);
route->if_name = charon->kernel_interface->get_interface( /* for IPv4, the route is installed on the outgoing interface */
charon->kernel_interface, dst); route->if_name = charon->kernel_interface->get_interface(
route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); charon->kernel_interface, dst);
route->dst_net = chunk_alloc(4);
}
else
{
route->gateway = NULL;
/* for IPv6, it is on the interface with our source address */
route->if_name = charon->kernel_interface->get_interface(
charon->kernel_interface, route->src_ip);
route->dst_net = chunk_alloc(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);
route->prefixlen = policy->sel.prefixlen_s; route->prefixlen = policy->sel.prefixlen_s;
@@ -769,7 +769,14 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest,
memset(&request, 0, sizeof(request)); memset(&request, 0, sizeof(request));
hdr = (struct nlmsghdr*)request; hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ROOT; hdr->nlmsg_flags = NLM_F_REQUEST;
if (dest->get_family(dest) == AF_INET)
{
/* We dump all addresses for IPv4, as we want to ignore IPsec specific
* routes installed by us. But the kernel does not return source
* addresses in a IPv6 dump, so fall back to get() for v6 routes. */
hdr->nlmsg_flags |= NLM_F_ROOT | NLM_F_DUMP;
}
hdr->nlmsg_type = RTM_GETROUTE; hdr->nlmsg_type = RTM_GETROUTE;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
@@ -1157,8 +1164,11 @@ static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_ty
netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request)); netlink_add_attribute(hdr, RTA_DST, dst_net, sizeof(request));
chunk = src_ip->get_address(src_ip); chunk = src_ip->get_address(src_ip);
netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request)); netlink_add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
chunk = gateway->get_address(gateway); if (gateway && gateway->get_family(gateway) == src_ip->get_family(src_ip))
netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request)); {
chunk = gateway->get_address(gateway);
netlink_add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
}
ifindex = get_interface_index(this, if_name); ifindex = get_interface_index(this, if_name);
chunk.ptr = (char*)&ifindex; chunk.ptr = (char*)&ifindex;
chunk.len = sizeof(ifindex); chunk.len = sizeof(ifindex);
@@ -1282,7 +1292,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this)
* create or delete a rule to use our routing table * create or delete a rule to use our routing table
*/ */
static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type, static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
u_int32_t table, u_int32_t prio) int family, u_int32_t table, u_int32_t prio)
{ {
netlink_buf_t request; netlink_buf_t request;
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
@@ -1301,7 +1311,7 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type,
msg = (struct rtmsg*)NLMSG_DATA(hdr); msg = (struct rtmsg*)NLMSG_DATA(hdr);
msg->rtm_table = table; msg->rtm_table = table;
msg->rtm_family = AF_INET; msg->rtm_family = family;
msg->rtm_protocol = RTPROT_BOOT; msg->rtm_protocol = RTPROT_BOOT;
msg->rtm_scope = RT_SCOPE_UNIVERSE; msg->rtm_scope = RT_SCOPE_UNIVERSE;
msg->rtm_type = RTN_UNICAST; msg->rtm_type = RTN_UNICAST;
@@ -1319,7 +1329,9 @@ static void destroy(private_kernel_netlink_net_t *this)
{ {
if (this->routing_table) if (this->routing_table)
{ {
manage_rule(this, RTM_DELRULE, this->routing_table, manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table,
this->routing_table_prio);
manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table,
this->routing_table_prio); this->routing_table_prio);
} }
@@ -1394,10 +1406,15 @@ kernel_netlink_net_t *kernel_netlink_net_create()
if (this->routing_table) if (this->routing_table)
{ {
if (manage_rule(this, RTM_NEWRULE, this->routing_table, if (manage_rule(this, RTM_NEWRULE, AF_INET, this->routing_table,
this->routing_table_prio) != SUCCESS) this->routing_table_prio) != SUCCESS)
{ {
DBG1(DBG_KNL, "unable to create routing table rule"); DBG1(DBG_KNL, "unable to create IPv4 routing table rule");
}
if (manage_rule(this, RTM_NEWRULE, AF_INET6, this->routing_table,
this->routing_table_prio) != SUCCESS)
{
DBG1(DBG_KNL, "unable to create IPv6 routing table rule");
} }
} }