kernel-pfroute: install and uninstall routes
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -765,18 +766,144 @@ METHOD(kernel_net_t, del_ip, status_t,
|
|||||||
return FAILED;
|
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,
|
METHOD(kernel_net_t, add_route, status_t,
|
||||||
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
|
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
|
||||||
host_t *gateway, host_t *src_ip, char *if_name)
|
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,
|
METHOD(kernel_net_t, del_route, status_t,
|
||||||
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
|
private_kernel_pfroute_net_t *this, chunk_t dst_net, u_int8_t prefixlen,
|
||||||
host_t *gateway, host_t *src_ip, char *if_name)
|
host_t *gateway, host_t *src_ip, char *if_name)
|
||||||
{
|
{
|
||||||
return FAILED;
|
return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user