kernel-pfroute: install and uninstall routes

This commit is contained in:
Martin Willi
2013-05-06 16:10:12 +02:00
parent 3a7f4b5c8d
commit 272bcac894
@@ -16,6 +16,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/route.h>
#include <unistd.h>
@@ -765,18 +766,144 @@ METHOD(kernel_net_t, del_ip, status_t,
return FAILED;
}
/**
* Append a sockaddr_in/in6 of given type to routing message
*/
static void add_rt_addr(struct rt_msghdr *hdr, int type, host_t *addr)
{
if (addr)
{
int len;
len = *addr->get_sockaddr_len(addr);
memcpy((char*)hdr + hdr->rtm_msglen, addr->get_sockaddr(addr), len);
hdr->rtm_msglen += len;
hdr->rtm_addrs |= type;
}
}
/**
* Append a subnet mask sockaddr using the given prefix to routing message
*/
static void add_rt_mask(struct rt_msghdr *hdr, int type, int family, int prefix)
{
host_t *mask;
mask = host_create_netmask(family, prefix);
if (mask)
{
add_rt_addr(hdr, type, mask);
mask->destroy(mask);
}
}
/**
* Append an interface name sockaddr_dl to routing message
*/
static void add_rt_ifname(struct rt_msghdr *hdr, int type, char *name)
{
struct sockaddr_dl sdl = {
.sdl_len = sizeof(struct sockaddr_dl),
.sdl_family = AF_LINK,
.sdl_nlen = strlen(name),
};
if (strlen(name) <= sizeof(sdl.sdl_data))
{
memcpy(sdl.sdl_data, name, sdl.sdl_nlen);
memcpy((char*)hdr + hdr->rtm_msglen, &sdl, sdl.sdl_len);
hdr->rtm_msglen += sdl.sdl_len;
hdr->rtm_addrs |= type;
}
}
/**
* Add or remove a route
*/
static status_t manage_route(private_kernel_pfroute_net_t *this, int op,
chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, char *if_name)
{
struct {
struct rt_msghdr hdr;
char buf[sizeof(struct sockaddr_storage) * RTAX_MAX];
} msg = {
.hdr = {
.rtm_version = RTM_VERSION,
.rtm_type = op,
.rtm_flags = RTF_UP | RTF_STATIC,
.rtm_pid = this->pid,
.rtm_seq = ++this->seq,
},
};
host_t *dst;
int type;
dst = host_create_from_chunk(AF_UNSPEC, dst_net, 0);
if (!dst)
{
return FAILED;
}
if ((dst->get_family(dst) == AF_INET && prefixlen == 32) ||
(dst->get_family(dst) == AF_INET6 && prefixlen == 128))
{
msg.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
}
msg.hdr.rtm_msglen = sizeof(struct rt_msghdr);
for (type = 0; type < RTAX_MAX; type++)
{
switch (type)
{
case RTAX_DST:
add_rt_addr(&msg.hdr, RTA_DST, dst);
break;
case RTAX_NETMASK:
if (!(msg.hdr.rtm_flags & RTF_HOST))
{
add_rt_mask(&msg.hdr, RTA_NETMASK,
dst->get_family(dst), prefixlen);
}
break;
case RTAX_GATEWAY:
/* interface name seems to replace gateway on OS X */
if (if_name)
{
add_rt_ifname(&msg.hdr, RTA_GATEWAY, if_name);
}
else if (gateway)
{
add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway);
}
break;
default:
break;
}
}
dst->destroy(dst);
if (send(this->socket, &msg, msg.hdr.rtm_msglen, 0) != msg.hdr.rtm_msglen)
{
DBG1(DBG_KNL, "%s PF_ROUTE route failed: %s",
op == RTM_ADD ? "adding" : "deleting", strerror(errno));
return FAILED;
}
return SUCCESS;
}
METHOD(kernel_net_t, add_route, status_t,
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name)
{
return FAILED;
return manage_route(this, RTM_ADD, dst_net, prefixlen, gateway, if_name);
}
METHOD(kernel_net_t, del_route, status_t,
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
host_t *gateway, host_t *src_ip, char *if_name)
{
return FAILED;
return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name);
}
/**