diff options
author | Grant Limberg <grant.limberg@zerotier.com> | 2018-05-24 15:22:11 -0700 |
---|---|---|
committer | Grant Limberg <grant.limberg@zerotier.com> | 2018-05-24 15:22:11 -0700 |
commit | c24d16e62eb6db70ff8aa8777156a938d1b7b2c0 (patch) | |
tree | ed1d3805867c4b1aba616a813c48e49687eaf595 /osdep | |
parent | c0efba79c70ee537813efd333302dc588668cbce (diff) | |
download | infinitytier-c24d16e62eb6db70ff8aa8777156a938d1b7b2c0.tar.gz infinitytier-c24d16e62eb6db70ff8aa8777156a938d1b7b2c0.zip |
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.
Diffstat (limited to 'osdep')
-rw-r--r-- | osdep/LinuxNetLink.cpp | 476 | ||||
-rw-r--r-- | osdep/LinuxNetLink.hpp | 133 | ||||
-rw-r--r-- | osdep/ManagedRoute.cpp | 163 |
3 files changed, 758 insertions, 14 deletions
diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp new file mode 100644 index 00000000..308f0f8a --- /dev/null +++ b/osdep/LinuxNetLink.cpp @@ -0,0 +1,476 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#include "LinuxNetLink.hpp" + +#include <unistd.h> + +namespace ZeroTier { + +LinuxNetLink::LinuxNetLink() + : _t() + , _running(false) + , _routes_ipv4() + , _routes_ipv6() + , _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) + , _la({0}) + , _pa({0}) + , _msg({0}) + , _iov({0}) + , _rtn(0) + , _nlp(NULL) + , _nll(0) + , _rtp(NULL) + , _rtl(0) + , _rtap(NULL) + , _ifip(NULL) + , _ifil(0) + , _ifap(NULL) + , _ifal(0) +{ + memset(_buf, 0, sizeof(_buf)); + + // set socket timeout to 1 sec so we're not permablocking recv() calls + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if(setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) { + fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); + } + + _la.nl_family = AF_NETLINK; + _la.nl_pid = getpid(); + _la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE; + if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) { + fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno)); + ::exit(1); + } + + _running = true; + _t = Thread::start(this); + + fprintf(stderr, "Requesting IPV4 Routes\n"); + _requestIPv4Routes(); + Thread::sleep(10); + fprintf(stderr, "Requesting IPV6 Routes\n"); + _requestIPv6Routes(); +} + +LinuxNetLink::~LinuxNetLink() +{ + _running = false; + Thread::join(_t); + + ::close(_fd); +} + +void LinuxNetLink::threadMain() throw() +{ + char *p; + p = _buf; + _nll = 0; + + while(_running) { + _rtn = recv(_fd, p, sizeof(_buf) - _nll, 0); + + if (_rtn > 0) { + _nlp = (struct nlmsghdr *) p; + + if(_nlp->nlmsg_type == NLMSG_ERROR && (_nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) { + fprintf(stderr, "NLMSG_ERROR\n"); + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(_nlp); + if (err->error != 0) { + fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error))); + } + p = _buf; + _nll = 0; + continue; + } + + if (_nlp->nlmsg_type == NLMSG_NOOP) { + fprintf(stderr, "noop\n"); + continue; + } + + if( (_nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (_nlp->nlmsg_type == NLMSG_DONE)) + { + if (_nlp->nlmsg_type == NLMSG_DONE) { + _processMessage(); + p = _buf; + _nll = 0; + continue; + } + p += _rtn; + _nll += _rtn; + } + + if (_nlp->nlmsg_type == NLMSG_OVERRUN) { + fprintf(stderr, "NLMSG_OVERRUN: Data lost\n"); + p = _buf; + _nll = 0; + continue; + } + + _nll += _rtn; + + _processMessage(); + p = _buf; + _nll = 0; + } + else { + Thread::sleep(100); + continue; + } + } +} + +void LinuxNetLink::_processMessage() +{ + for(_nlp = (struct nlmsghdr *)_buf; NLMSG_OK(_nlp, _nll); _nlp=NLMSG_NEXT(_nlp, _nll)) + { + switch(_nlp->nlmsg_type) + { + case RTM_NEWLINK: + _linkAdded(); + break; + case RTM_DELLINK: + _linkDeleted(); + break; + case RTM_GETLINK: + fprintf(stderr, "Get Link\n"); + break; + case RTM_SETLINK: + fprintf(stderr, "Set Link\n"); + break; + case RTM_NEWADDR: + _ipAddressAdded(); + break; + case RTM_DELADDR: + _ipAddressDeleted(); + break; + case RTM_GETADDR: + fprintf(stderr, "Get IP Address\n"); + break; + case RTM_NEWROUTE: + _routeAdded(); + break; + case RTM_DELROUTE: + _routeDeleted(); + break; + case RTM_GETROUTE: + break; + default: + fprintf(stderr, "ignore msgtype %d...\n", _nlp->nlmsg_type); + } + } + _nlp = NULL; + _nll = 0; + _rtp = NULL; + _rtl = 0; + _ifip = NULL; + _ifil = 0; + _ifap = NULL; + _ifal = 0; +} + +void LinuxNetLink::_ipAddressAdded() +{ + _ifap = (struct ifaddrmsg *)NLMSG_DATA(_nlp); + _rtap = (struct rtattr *)IFA_RTA(_ifap); + _ifal = IFA_PAYLOAD(_nlp); + + char addr[40] = {0}; + char local[40] = {0}; + char label[40] = {0}; + char bcast[40] = {0}; + + for(;RTA_OK(_rtap, _ifal); _rtap=RTA_NEXT(_rtap,_ifal)) + { + switch(_rtap->rta_type) { + case IFA_ADDRESS: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), addr, 40); + break; + case IFA_LOCAL: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), local, 40); + break; + case IFA_LABEL: + memcpy(label, RTA_DATA(_rtap), 40); + break; + case IFA_BROADCAST: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), bcast, 40); + break; + } + } + + fprintf(stderr, "Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); +} + +void LinuxNetLink::_ipAddressDeleted() +{ + _ifap = (struct ifaddrmsg *)NLMSG_DATA(_nlp); + _rtap = (struct rtattr *)IFA_RTA(_ifap); + _ifal = IFA_PAYLOAD(_nlp); + + char addr[40] = {0}; + char local[40] = {0}; + char label[40] = {0}; + char bcast[40] = {0}; + + for(;RTA_OK(_rtap, _ifal); _rtap=RTA_NEXT(_rtap,_ifal)) + { + switch(_rtap->rta_type) { + case IFA_ADDRESS: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), addr, 40); + break; + case IFA_LOCAL: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), local, 40); + break; + case IFA_LABEL: + memcpy(label, RTA_DATA(_rtap), 40); + break; + case IFA_BROADCAST: + inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), bcast, 40); + break; + } + } + + fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); +} + +void LinuxNetLink::_routeAdded() +{ + char dsts[40] = {0}; + char gws[40] = {0}; + char ifs[16] = {0}; + char ms[24] = {0}; + + _rtp = (struct rtmsg *) NLMSG_DATA(_nlp); + + _rtap = (struct rtattr *)RTM_RTA(_rtp); + _rtl = RTM_PAYLOAD(_nlp); + for(;RTA_OK(_rtap, _rtl); _rtap=RTA_NEXT(_rtap, _rtl)) + { + switch(_rtap->rta_type) + { + case RTA_DST: + inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), dsts, _rtp->rtm_family == AF_INET ? 24 : 40); + break; + case RTA_GATEWAY: + inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), gws, _rtp->rtm_family == AF_INET ? 24 : 40); + break; + case RTA_OIF: + sprintf(ifs, "%d", *((int*)RTA_DATA(_rtap))); + break; + } + } + sprintf(ms, "%d", _rtp->rtm_dst_len); + + fprintf(stderr, "Route Added: dst %s/%s gw %s if %s\n", dsts, ms, gws, ifs); +} + +void LinuxNetLink::_routeDeleted() +{ + char dsts[40] = {0}; + char gws[40] = {0}; + char ifs[16] = {0}; + char ms[24] = {0}; + + _rtp = (struct rtmsg *) NLMSG_DATA(_nlp); + + _rtap = (struct rtattr *)RTM_RTA(_rtp); + _rtl = RTM_PAYLOAD(_nlp); + for(;RTA_OK(_rtap, _rtl); _rtap=RTA_NEXT(_rtap, _rtl)) + { + switch(_rtap->rta_type) + { + case RTA_DST: + inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), dsts, _rtp->rtm_family == AF_INET ? 24 : 40); + break; + case RTA_GATEWAY: + inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), gws, _rtp->rtm_family == AF_INET ? 24 : 40); + break; + case RTA_OIF: + sprintf(ifs, "%d", *((int*)RTA_DATA(_rtap))); + break; + } + } + sprintf(ms, "%d", _rtp->rtm_dst_len); + + fprintf(stderr, "Route Deleted: dst %s/%s gw %s if %s\n", dsts, ms, gws, ifs); +} + +void LinuxNetLink::_linkAdded() +{ + char mac[20] = {0}; + unsigned int mtu = 0; + char ifname[40] = {0}; + + _ifip = (struct ifinfomsg *)NLMSG_DATA(_nlp); + _rtap = (struct rtattr *)IFLA_RTA(_ifip); + _ifil = RTM_PAYLOAD(_nlp); + + const char *ptr; + unsigned char *ptr2; + for(;RTA_OK(_rtap, _ifil);_rtap=RTA_NEXT(_rtap, _ifil)) + { + switch(_rtap->rta_type) { + case IFLA_ADDRESS: + ptr2 = (unsigned char*)RTA_DATA(_rtap); + snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x", + ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]); + break; + case IFLA_IFNAME: + ptr = (const char*)RTA_DATA(_rtap); + memcpy(ifname, ptr, strlen(ptr)); + break; + case IFLA_MTU: + memcpy(&mtu, RTA_DATA(_rtap), sizeof(unsigned int)); + break; + } + } + + fprintf(stderr, "Link Added: %s mac: %s, mtu: %d\n", ifname, mac, mtu); +} + +void LinuxNetLink::_linkDeleted() +{ + char mac[20] = {0}; + unsigned int mtu = 0; + char ifname[40] = {0}; + + _ifip = (struct ifinfomsg *)NLMSG_DATA(_nlp); + _rtap = (struct rtattr *)IFLA_RTA(_ifip); + _ifil = RTM_PAYLOAD(_nlp); + + const char *ptr; + unsigned char *ptr2; + for(;RTA_OK(_rtap, _ifil);_rtap=RTA_NEXT(_rtap, _ifil)) + { + switch(_rtap->rta_type) { + case IFLA_ADDRESS: + ptr2 = (unsigned char*)RTA_DATA(_rtap); + snprintf(mac, 20, "%02x:%02x:%02x:%02x:%02x:%02x", + ptr2[0], ptr2[1], ptr2[2], ptr2[3], ptr2[4], ptr2[5]); + break; + case IFLA_IFNAME: + ptr = (const char*)RTA_DATA(_rtap); + memcpy(ifname, ptr, strlen(ptr)); + break; + case IFLA_MTU: + memcpy(&mtu, RTA_DATA(_rtap), sizeof(unsigned int)); + break; + } + } + + fprintf(stderr, "Link Deleted: %s mac: %s, mtu: %d\n", ifname, mac, mtu); +} + +void LinuxNetLink::_requestIPv4Routes() +{ + struct nl_req req; + bzero(&req, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nl.nlmsg_type = RTM_GETROUTE; + req.rt.rtm_family = AF_INET; + req.rt.rtm_table = RT_TABLE_MAIN; + + + bzero(&_pa, sizeof(_pa)); + _pa.nl_family = AF_NETLINK; + + bzero(&_msg, sizeof(_msg)); + _msg.msg_name = (void*)&_pa; + _msg.msg_namelen = sizeof(_pa); + + _iov.iov_base = (void*)&req.nl; + _iov.iov_len = req.nl.nlmsg_len; + _msg.msg_iov = &_iov; + _msg.msg_iovlen = 1; + + _rtn = sendmsg(_fd, &_msg, 0); +} + +void LinuxNetLink::_requestIPv6Routes() +{ + struct nl_req req; + bzero(&req, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nl.nlmsg_type = RTM_GETROUTE; + req.rt.rtm_family = AF_INET6; + req.rt.rtm_table = RT_TABLE_MAIN; + + + bzero(&_pa, sizeof(_pa)); + _pa.nl_family = AF_NETLINK; + + bzero(&_msg, sizeof(_msg)); + _msg.msg_name = (void*)&_pa; + _msg.msg_namelen = sizeof(_pa); + + _iov.iov_base = (void*)&req.nl; + _iov.iov_len = req.nl.nlmsg_len; + _msg.msg_iov = &_iov; + _msg.msg_iovlen = 1; + + while((_rtn = sendmsg(_fd, &_msg, 0)) == -1) { + fprintf(stderr, "ipv6 waiting..."); + Thread::sleep(100); + } +} + +void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName) +{ + +} + +void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName) +{ + +} + +void LinuxNetLink::addInterface(const char *iface) +{ + +} + +void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface) +{ + +} + +RouteList LinuxNetLink::getIPV4Routes() const +{ + return _routes_ipv4; +} + +RouteList LinuxNetLink::getIPV6Routes() const +{ + return _routes_ipv6; +} + +} // namespace ZeroTier
\ No newline at end of file diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp new file mode 100644 index 00000000..519bb435 --- /dev/null +++ b/osdep/LinuxNetLink.hpp @@ -0,0 +1,133 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. + */ + +#ifndef ZT_LINUX_NETLINK_HPP +#define ZT_LINUX_NETLINK_HPP + +#include <vector> + +#include <bits/sockaddr.h> +#include <asm/types.h> +#include <linux/rtnetlink.h> +#include <sys/socket.h> + + +#include "../node/InetAddress.hpp" +#include "Thread.hpp" + + +namespace ZeroTier { + +struct route_entry { + InetAddress target; + InetAddress via; + const char *iface; +}; + +typedef std::vector<route_entry> RouteList; + +struct nl_req { + struct nlmsghdr nl; + struct rtmsg rt; + char buf[8192]; +}; + +/** + * Interface with Linux's RTNETLINK + */ +class LinuxNetLink +{ +private: + LinuxNetLink(); + ~LinuxNetLink(); + +public: + static LinuxNetLink& getInstance() + { + static LinuxNetLink instance; + return instance; + } + + LinuxNetLink(LinuxNetLink const&) = delete; + void operator=(LinuxNetLink const&) = delete; + + void addRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName); + void delRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName); + RouteList getIPV4Routes() const; + RouteList getIPV6Routes() const; + + void addInterface(const char *iface); + + void addAddress(const InetAddress &addr, const char *iface); + + void threadMain() throw(); +private: + void _processMessage(); + void _routeAdded(); + void _routeDeleted(); + void _linkAdded(); + void _linkDeleted(); + void _ipAddressAdded(); + void _ipAddressDeleted(); + + + void _requestIPv4Routes(); + void _requestIPv6Routes(); + + + Thread _t; + bool _running; + RouteList _routes_ipv4; + RouteList _routes_ipv6; + + // socket communication vars; + int _fd; + struct sockaddr_nl _la; + struct sockaddr_nl _pa; + struct msghdr _msg; + struct iovec _iov; + int _rtn; + char _buf[8192]; + + // RTNETLINK message pointers & lengths + // used for processing messages + struct nlmsghdr *_nlp; + int _nll; + + struct rtmsg *_rtp; + int _rtl; + struct rtattr *_rtap; + + struct ifinfomsg *_ifip; + int _ifil; + + struct ifaddrmsg *_ifap; + int _ifal; +}; + +} + +#endif // ZT_LINUX_NETLINK_HPPS
\ No newline at end of file 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 <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 (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) { - ::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<char*>(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__ // -------------------------------------------------------- |