ManagedRoute uses ioctl to add/remove routes on Linux
Added LinuxNetLink to talk to the rtnetlink socket for adding interfaces, addresses routes. Not yet complete. Can currently monitor changes on the system.
This commit is contained in:
parent
c0efba79c7
commit
c24d16e62e
6 changed files with 783 additions and 19 deletions
|
@ -48,6 +48,13 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#ifdef __LINUX__
|
||||
#include <sys/ioctl.h>
|
||||
#include <bits/sockaddr.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef __BSD__
|
||||
#include <net/if_dl.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -277,27 +284,155 @@ static void _routeCmd(const char *op,const InetAddress &target,const InetAddress
|
|||
#ifdef __LINUX__ // ----------------------------------------------------------
|
||||
#define ZT_ROUTING_SUPPORT_FOUND 1
|
||||
|
||||
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *localInterface)
|
||||
static bool _hasRoute(const InetAddress &target, const InetAddress &via, const char *localInterface)
|
||||
{
|
||||
long p = (long)fork();
|
||||
if (p > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(p,&exitcode,0);
|
||||
} else if (p == 0) {
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
char ipbuf[64],ipbuf2[64];
|
||||
if (via) {
|
||||
::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
} else if ((localInterface)&&(localInterface[0])) {
|
||||
::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
}
|
||||
::_exit(-1);
|
||||
if (target.ss_family == AF_INET) {
|
||||
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
char *buf;
|
||||
int nll;
|
||||
struct rtmsg *rtp;
|
||||
int rtl;
|
||||
struct rtattr *rtap;
|
||||
|
||||
struct sockaddr_nl la;
|
||||
bzero(&la, sizeof(la));
|
||||
la.nl_family = AF_NETLINK;
|
||||
la.nl_pad = 0;
|
||||
la.nl_pid = (uint32_t)((ptrdiff_t)&target % getpid());
|
||||
la.nl_groups = 0;
|
||||
int rtn = bind(fd, (struct sockaddr*)&la, sizeof(la));
|
||||
|
||||
|
||||
|
||||
close(fd);
|
||||
return false;
|
||||
} else {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _routeCmd(const char *op, const InetAddress &target, const InetAddress &via, const char *localInterface)
|
||||
{
|
||||
bool hasRoute = _hasRoute(target, via, localInterface);
|
||||
if (hasRoute && (strcmp(op, "add") == 0 || strcmp(op, "replace") == 0)) {
|
||||
return;
|
||||
} else if (!hasRoute && (strcmp(op, "remove") == 0 || strcmp(op, "del") == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char targetStr[64] = {0};
|
||||
char viaStr[64] = {0};
|
||||
InetAddress nmsk = target.netmask();
|
||||
char nmskStr[64] = {0};
|
||||
fprintf(stderr, "Received Route Cmd: %s target: %s via: %s netmask: %s localInterface: %s\n", op, target.toString(targetStr), via.toString(viaStr), nmsk.toString(nmskStr), localInterface);
|
||||
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);;
|
||||
struct rtentry route = {0};
|
||||
|
||||
if (target.ss_family == AF_INET) {
|
||||
struct sockaddr_in *target_in = (struct sockaddr_in*)⌖
|
||||
struct sockaddr_in *via_in = (struct sockaddr_in*)&via;
|
||||
InetAddress netmask = target.netmask();
|
||||
struct sockaddr_in *netmask_in = (struct sockaddr_in*)&netmask;
|
||||
|
||||
struct sockaddr_in *addr = NULL;
|
||||
|
||||
// set target
|
||||
addr = (struct sockaddr_in *)&route.rt_dst;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr = target_in->sin_addr;
|
||||
|
||||
// set netmask
|
||||
addr = (struct sockaddr_in *)&route.rt_genmask;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr = netmask_in->sin_addr;
|
||||
|
||||
route.rt_dev = const_cast<char*>(localInterface);
|
||||
|
||||
if (via) {
|
||||
// set the gateway
|
||||
addr = (struct sockaddr_in *)&route.rt_gateway;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr = via_in->sin_addr;
|
||||
|
||||
route.rt_flags = RTF_UP | RTF_GATEWAY;
|
||||
} else if ((localInterface)&&(localInterface[0])) {
|
||||
route.rt_flags = RTF_UP;//| RTF_HOST;
|
||||
}
|
||||
}
|
||||
else if (target.ss_family == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *addr = NULL;
|
||||
|
||||
// set target
|
||||
addr = (struct sockaddr_in6 *)&route.rt_dst;
|
||||
addr->sin6_family = AF_INET6;
|
||||
memcpy(&addr->sin6_addr, &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));
|
||||
|
||||
//set netmask
|
||||
addr = (struct sockaddr_in6 *)&route.rt_genmask;
|
||||
addr->sin6_family = AF_INET6;
|
||||
InetAddress netmask = target.netmask();
|
||||
memcpy(&addr->sin6_addr, &((struct sockaddr_in6*)&netmask)->sin6_addr, sizeof(struct in6_addr));
|
||||
|
||||
if (via) {
|
||||
// set the gateway
|
||||
addr = (struct sockaddr_in6*)&route.rt_gateway;
|
||||
addr->sin6_family = AF_INET;
|
||||
memcpy(&addr->sin6_addr, &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));
|
||||
|
||||
route.rt_flags = RTF_UP | RTF_GATEWAY;
|
||||
} else if ((localInterface)&&(localInterface[0])) {
|
||||
route.rt_dev = const_cast<char*>(localInterface);
|
||||
route.rt_flags = RTF_UP;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long ctl = -1;
|
||||
if (strcmp(op, "add") == 0 || strcmp(op, "replace") == 0) {
|
||||
ctl = SIOCADDRT;
|
||||
} else if (strcmp(op, "remove") == 0 || strcmp(op, "del") == 0) {
|
||||
ctl = SIOCDELRT;
|
||||
} else {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ioctl(fd, ctl, &route)) {
|
||||
fprintf(stderr, "Error adding route: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
::exit(1);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *localInterface)
|
||||
// {
|
||||
// // long p = (long)fork();
|
||||
// // if (p > 0) {
|
||||
// // int exitcode = -1;
|
||||
// // ::waitpid(p,&exitcode,0);
|
||||
// // } else if (p == 0) {
|
||||
// // ::close(STDOUT_FILENO);
|
||||
// // ::close(STDERR_FILENO);
|
||||
// char ipbuf[64],ipbuf2[64];
|
||||
|
||||
|
||||
|
||||
// if (via) {
|
||||
// ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
// ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"via",via.toIpString(ipbuf2),(const char *)0);
|
||||
// } else if ((localInterface)&&(localInterface[0])) {
|
||||
// ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
// ::execl(ZT_LINUX_IP_COMMAND_2,ZT_LINUX_IP_COMMAND_2,(target.ss_family == AF_INET6) ? "-6" : "-4","route",op,target.toString(ipbuf),"dev",localInterface,(const char *)0);
|
||||
// }
|
||||
// // ::_exit(-1);
|
||||
// // }
|
||||
// }
|
||||
|
||||
#endif // __LINUX__ ----------------------------------------------------------
|
||||
|
||||
#ifdef __WINDOWS__ // --------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue