From c24d16e62eb6db70ff8aa8777156a938d1b7b2c0 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Thu, 24 May 2018 15:22:11 -0700 Subject: 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. --- osdep/ManagedRoute.cpp | 163 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 14 deletions(-) (limited to 'osdep/ManagedRoute.cpp') diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index d7c80704..8d64fde3 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -48,6 +48,13 @@ #include #include #include +#ifdef __LINUX__ +#include +#include +#include +#include +#include +#endif #ifdef __BSD__ #include #include @@ -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 (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(localInterface); + 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); + // 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])) { - ::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); + 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(localInterface); + route.rt_flags = RTF_UP; } - ::_exit(-1); } + + 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__ // -------------------------------------------------------- -- cgit v1.2.3