summaryrefslogtreecommitdiff
path: root/osdep
diff options
context:
space:
mode:
authorGrant Limberg <grant.limberg@zerotier.com>2018-05-25 14:18:06 -0700
committerGrant Limberg <grant.limberg@zerotier.com>2018-05-25 14:18:06 -0700
commitbe469f4dd034050ca95a953903b3170ace275b27 (patch)
tree862260cd1a1de6abc98fe00dc22e5d53e7a40d7c /osdep
parent7da4b0af15fe5ff48db75471a3b416bbf2a6b822 (diff)
downloadinfinitytier-be469f4dd034050ca95a953903b3170ace275b27.tar.gz
infinitytier-be469f4dd034050ca95a953903b3170ace275b27.zip
add/remove routes via rtnetlink
Diffstat (limited to 'osdep')
-rw-r--r--osdep/LinuxNetLink.cpp896
-rw-r--r--osdep/LinuxNetLink.hpp28
-rw-r--r--osdep/ManagedRoute.cpp41
3 files changed, 570 insertions, 395 deletions
diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp
index 062144dc..6251cb10 100644
--- a/osdep/LinuxNetLink.cpp
+++ b/osdep/LinuxNetLink.cpp
@@ -30,408 +30,608 @@
namespace ZeroTier {
+struct nl_route_req {
+ struct nlmsghdr nl;
+ struct rtmsg rt;
+ char buf[8192];
+};
+
+struct nl_if_req {
+ struct nlmsghdr nl;
+ struct ifinfomsg ifa;
+ char buf[8192];
+};
+
LinuxNetLink::LinuxNetLink()
- : _t()
- , _running(false)
- , _routes_ipv4()
- , _routes_ipv6()
- , _seq(0)
- , _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
- , _la({0})
+ : _t()
+ , _running(false)
+ , _routes_ipv4()
+ , _routes_ipv6()
+ , _seq(0)
+ , _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
+ , _la({0})
{
- // 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|RTMGRP_NOTIFY;
- 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();
+ // 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|RTMGRP_NOTIFY;
+ 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();
+ Thread::sleep(10);
+ fprintf(stderr, "Requesting Interface List\n");
+ _requestInterfaceList();
}
LinuxNetLink::~LinuxNetLink()
{
- _running = false;
- Thread::join(_t);
+ _running = false;
+ Thread::join(_t);
- ::close(_fd);
+ ::close(_fd);
}
void LinuxNetLink::threadMain() throw()
{
- char buf[8192];
- char *p = NULL;
- struct nlmsghdr *nlp;
- int nll = 0;
- int rtn = 0;
- p = buf;
-
- 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(nlp, nll);
- 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(nlp, nll);
- p = buf;
- nll = 0;
- }
- else {
- Thread::sleep(100);
- continue;
- }
- }
+ char buf[8192];
+ char *p = NULL;
+ struct nlmsghdr *nlp;
+ int nll = 0;
+ int rtn = 0;
+ p = buf;
+
+ 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(nlp, nll);
+ 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(nlp, nll);
+ p = buf;
+ nll = 0;
+ }
+ else {
+ Thread::sleep(100);
+ continue;
+ }
+ }
}
void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll)
{
- for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll))
- {
- switch(nlp->nlmsg_type)
- {
- case RTM_NEWLINK:
- _linkAdded(nlp);
- break;
- case RTM_DELLINK:
- _linkDeleted(nlp);
- break;
- case RTM_NEWADDR:
- _ipAddressAdded(nlp);
- break;
- case RTM_DELADDR:
- _ipAddressDeleted(nlp);
- break;
- case RTM_NEWROUTE:
- _routeAdded(nlp);
- break;
- case RTM_DELROUTE:
- _routeDeleted(nlp);
- break;
- default:
- fprintf(stderr, "ignore msgtype %d...\n", nlp->nlmsg_type);
- }
- }
+ for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll))
+ {
+ switch(nlp->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ _linkAdded(nlp);
+ break;
+ case RTM_DELLINK:
+ _linkDeleted(nlp);
+ break;
+ case RTM_NEWADDR:
+ _ipAddressAdded(nlp);
+ break;
+ case RTM_DELADDR:
+ _ipAddressDeleted(nlp);
+ break;
+ case RTM_NEWROUTE:
+ _routeAdded(nlp);
+ break;
+ case RTM_DELROUTE:
+ _routeDeleted(nlp);
+ break;
+ default:
+ fprintf(stderr, "ignore msgtype %d...\n", nlp->nlmsg_type);
+ }
+ }
}
void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp)
{
- struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
- int 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);
+ struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
+ int 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(struct nlmsghdr *nlp)
{
- struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
- int 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);
+ struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);
+ int 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(struct nlmsghdr *nlp)
{
- char dsts[40] = {0};
- char gws[40] = {0};
- char ifs[16] = {0};
- char ms[24] = {0};
-
- struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
- int 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);
+ char dsts[40] = {0};
+ char gws[40] = {0};
+ char ifs[16] = {0};
+ char ms[24] = {0};
+
+ struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
+ int 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(struct nlmsghdr *nlp)
{
- char dsts[40] = {0};
- char gws[40] = {0};
- char ifs[16] = {0};
- char ms[24] = {0};
-
- struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
- int 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);
+ char dsts[40] = {0};
+ char gws[40] = {0};
+ char ifs[16] = {0};
+ char ms[24] = {0};
+
+ struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);
+ int 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(struct nlmsghdr *nlp)
{
- char mac[20] = {0};
- unsigned int mtu = 0;
- char ifname[40] = {0};
-
- struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
- int 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);
+ char mac[18] = {0};
+ unsigned int mtu = 0;
+ char ifname[IFNAMSIZ] = {0};
+
+ struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
+ int 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;
+ }
+ }
+
+ struct iface_entry &entry = _interfaces[ifip->ifi_index];
+ entry.index = ifip->ifi_index;
+ memcpy(entry.ifacename, ifname, sizeof(ifname));
+ memcpy(entry.mac, mac, sizeof(mac));
+ entry.mtu = mtu;
+
+ fprintf(stderr, "Link Added: %s mac: %s, mtu: %d\n", ifname, mac, mtu);
}
void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
{
- char mac[20] = {0};
- unsigned int mtu = 0;
- char ifname[40] = {0};
-
- struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
- struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
- int 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);
+ char mac[18] = {0};
+ unsigned int mtu = 0;
+ char ifname[40] = {0};
+
+ struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
+ struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
+ int 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);
+ if(_interfaces.contains(ifip->ifi_index)) {
+ _interfaces.erase(ifip->ifi_index);
+ }
}
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.nl.nlmsg_pid = 0;
- req.nl.nlmsg_seq = ++_seq;
- req.rt.rtm_family = AF_INET;
- req.rt.rtm_table = RT_TABLE_MAIN;
-
- struct sockaddr_nl pa;
- bzero(&pa, sizeof(pa));
- pa.nl_family = AF_NETLINK;
-
- struct msghdr msg;
- bzero(&msg, sizeof(msg));
- msg.msg_name = (void*)&pa;
- msg.msg_namelen = sizeof(pa);
-
- struct iovec iov;
- bzero(&iov, sizeof(iov));
- iov.iov_base = (void*)&req.nl;
- iov.iov_len = req.nl.nlmsg_len;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- sendmsg(_fd, &msg, 0);
+ struct nl_route_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.nl.nlmsg_pid = 0;
+ req.nl.nlmsg_seq = ++_seq;
+ req.rt.rtm_family = AF_INET;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+
+ struct sockaddr_nl pa;
+ bzero(&pa, sizeof(pa));
+ pa.nl_family = AF_NETLINK;
+
+ struct msghdr msg;
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (void*)&pa;
+ msg.msg_namelen = sizeof(pa);
+
+ struct iovec iov;
+ bzero(&iov, sizeof(iov));
+ iov.iov_base = (void*)&req.nl;
+ iov.iov_len = req.nl.nlmsg_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ 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.nl.nlmsg_pid = 0;
- req.nl.nlmsg_seq = ++_seq;
- req.rt.rtm_family = AF_INET6;
- req.rt.rtm_table = RT_TABLE_MAIN;
-
- struct sockaddr_nl pa;
- bzero(&pa, sizeof(pa));
- pa.nl_family = AF_NETLINK;
-
- struct msghdr msg;
- bzero(&msg, sizeof(msg));
- msg.msg_name = (void*)&pa;
- msg.msg_namelen = sizeof(pa);
-
- struct iovec iov;
- bzero(&iov, sizeof(iov));
- iov.iov_base = (void*)&req.nl;
- iov.iov_len = req.nl.nlmsg_len;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
-
- while((sendmsg(_fd, &msg, 0)) == -1) {
- fprintf(stderr, "ipv6 waiting...");
- Thread::sleep(100);
- }
+ struct nl_route_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.nl.nlmsg_pid = 0;
+ req.nl.nlmsg_seq = ++_seq;
+ req.rt.rtm_family = AF_INET6;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+
+ struct sockaddr_nl pa;
+ bzero(&pa, sizeof(pa));
+ pa.nl_family = AF_NETLINK;
+
+ struct msghdr msg;
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (void*)&pa;
+ msg.msg_namelen = sizeof(pa);
+
+ struct iovec iov;
+ bzero(&iov, sizeof(iov));
+ iov.iov_base = (void*)&req.nl;
+ iov.iov_len = req.nl.nlmsg_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ sendmsg(_fd, &msg, 0);
}
-void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName)
+void LinuxNetLink::_requestInterfaceList()
{
+ struct nl_if_req req;
+ bzero(&req, sizeof(req));
+ req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req.nl.nlmsg_type = RTM_GETLINK;
+ req.nl.nlmsg_pid = 0;
+ req.nl.nlmsg_seq = ++_seq;
+ req.ifa.ifi_family = AF_UNSPEC;
+
+ struct sockaddr_nl pa;
+ bzero(&pa, sizeof(pa));
+ pa.nl_family = AF_NETLINK;
+
+ struct msghdr msg;
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (void*)&pa;
+ msg.msg_namelen = sizeof(pa);
+
+ struct iovec iov;
+ bzero(&iov, sizeof(iov));
+ iov.iov_base = (void*)&req.nl;
+ iov.iov_len = req.nl.nlmsg_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ sendmsg(_fd, &msg, 0);
+}
+void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName)
+{
+ int rtl = sizeof(struct rtmsg);
+ struct nl_route_req req;
+ bzero(&req, sizeof(req));
+
+ struct rtattr *rtap = (struct rtattr *)req.buf;
+ rtap->rta_type = RTA_DST;
+ if (target.isV4()) {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in_addr);
+ memcpy((void*)((char*)rtap+sizeof(struct rtattr)), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));
+ } else {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in6_addr);
+ memcpy((void*)((char*)rtap+sizeof(struct rtattr)), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));
+ }
+ rtl += rtap->rta_len;
+
+ int interface_index = -1;
+ if (ifaceName != NULL) {
+ Hashtable<int, iface_entry>::Iterator iter(_interfaces);
+ int *k = NULL;
+ iface_entry *v = NULL;
+ while(iter.next(k, v)) {
+ if(strcmp(ifaceName, v->ifacename) == 0) {
+ interface_index = v->index;
+ break;
+ }
+ }
+ if (interface_index != -1) {
+ rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len);
+ rtap->rta_type = RTA_OIF;
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(int);
+ memcpy(((char*)rtap)+sizeof(rtattr), &interface_index, sizeof(int));
+ rtl += rtap->rta_len;
+ }
+ }
+
+ if(via) {
+ rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);
+ rtap->rta_type = RTA_GATEWAY;
+ if(via.isV4()) {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in_addr);
+ memcpy((char*)rtap+sizeof(struct rtattr), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));
+ } else {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in6_addr);
+ memcpy((char*)rtap+sizeof(struct rtattr), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));
+ }
+ rtl += rtap->rta_len;
+ }
+
+ req.nl.nlmsg_len = NLMSG_LENGTH(rtl);
+ req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+ req.nl.nlmsg_type = RTM_NEWROUTE;
+ req.nl.nlmsg_pid = 0;
+ req.nl.nlmsg_seq = ++_seq;
+ req.rt.rtm_family = target.ss_family;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+ req.rt.rtm_protocol = RTPROT_STATIC;
+ req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.rt.rtm_type = RTN_UNICAST;
+ req.rt.rtm_dst_len = target.netmaskBits();
+
+ struct sockaddr_nl pa;
+ bzero(&pa, sizeof(pa));
+ pa.nl_family = AF_NETLINK;
+
+ struct msghdr msg;
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (void*)&pa;
+ msg.msg_namelen = sizeof(pa);
+
+ struct iovec iov;
+ bzero(&iov, sizeof(iov));
+ iov.iov_base = (void*)&req.nl;
+ iov.iov_len = req.nl.nlmsg_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ sendmsg(_fd, &msg, 0);
}
void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const char *ifaceName)
{
-
+ int rtl = sizeof(struct rtmsg);
+ struct nl_route_req req;
+ bzero(&req, sizeof(req));
+
+ struct rtattr *rtap = (struct rtattr *)req.buf;
+ rtap->rta_type = RTA_DST;
+ if (target.isV4()) {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in_addr);
+ memcpy((void*)((char*)rtap+sizeof(struct rtattr)), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));
+ } else {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in6_addr);
+ memcpy((void*)((char*)rtap+sizeof(struct rtattr)), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));
+ }
+ rtl += rtap->rta_len;
+
+ int interface_index = -1;
+ if (ifaceName != NULL) {
+ Hashtable<int, iface_entry>::Iterator iter(_interfaces);
+ int *k = NULL;
+ iface_entry *v = NULL;
+ while(iter.next(k, v)) {
+ if(strcmp(ifaceName, v->ifacename) == 0) {
+ interface_index = v->index;
+ break;
+ }
+ }
+ if (interface_index != -1) {
+ rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len);
+ rtap->rta_type = RTA_OIF;
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(int);
+ memcpy(((char*)rtap)+sizeof(rtattr), &interface_index, sizeof(int));
+ rtl += rtap->rta_len;
+ }
+ }
+
+ if(via) {
+ rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);
+ rtap->rta_type = RTA_GATEWAY;
+ if(via.isV4()) {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in_addr);
+ memcpy((char*)rtap+sizeof(struct rtattr), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));
+ } else {
+ rtap->rta_len = sizeof(struct rtattr)+sizeof(struct in6_addr);
+ memcpy((char*)rtap+sizeof(struct rtattr), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));
+ }
+ rtl += rtap->rta_len;
+ }
+
+ req.nl.nlmsg_len = NLMSG_LENGTH(rtl);
+ req.nl.nlmsg_flags = NLM_F_REQUEST;
+ req.nl.nlmsg_type = RTM_DELROUTE;
+ req.nl.nlmsg_pid = 0;
+ req.nl.nlmsg_seq = ++_seq;
+ req.rt.rtm_family = target.ss_family;
+ req.rt.rtm_table = RT_TABLE_MAIN;
+ req.rt.rtm_protocol = RTPROT_STATIC;
+ req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.rt.rtm_type = RTN_UNICAST;
+ req.rt.rtm_dst_len = target.netmaskBits();
+
+ struct sockaddr_nl pa;
+ bzero(&pa, sizeof(pa));
+ pa.nl_family = AF_NETLINK;
+
+ struct msghdr msg;
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (void*)&pa;
+ msg.msg_namelen = sizeof(pa);
+
+ struct iovec iov;
+ bzero(&iov, sizeof(iov));
+ iov.iov_base = (void*)&req.nl;
+ iov.iov_len = req.nl.nlmsg_len;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ sendmsg(_fd, &msg, 0);
}
void LinuxNetLink::addInterface(const char *iface, unsigned int mtu)
@@ -446,12 +646,12 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
RouteList LinuxNetLink::getIPV4Routes() const
{
- return _routes_ipv4;
+ return _routes_ipv4;
}
RouteList LinuxNetLink::getIPV6Routes() const
{
- return _routes_ipv6;
+ return _routes_ipv6;
}
} // namespace ZeroTier \ No newline at end of file
diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp
index 8ee42ee4..d0e83189 100644
--- a/osdep/LinuxNetLink.hpp
+++ b/osdep/LinuxNetLink.hpp
@@ -33,28 +33,23 @@
#include <asm/types.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
-
+#include <linux/if.h>
#include "../node/InetAddress.hpp"
#include "Thread.hpp"
+#include "../node/Hashtable.hpp"
namespace ZeroTier {
struct route_entry {
- InetAddress target;
- InetAddress via;
- const char *iface;
+ InetAddress target;
+ InetAddress via;
+ int if_index;
+ char iface[IFNAMSIZ];
};
-
typedef std::vector<route_entry> RouteList;
-struct nl_req {
- struct nlmsghdr nl;
- struct rtmsg rt;
- char buf[8192];
-};
-
/**
* Interface with Linux's RTNETLINK
*/
@@ -93,18 +88,27 @@ private:
void _ipAddressAdded(struct nlmsghdr *nlp);
void _ipAddressDeleted(struct nlmsghdr *nlp);
-
+ void _requestInterfaceList();
void _requestIPv4Routes();
void _requestIPv6Routes();
Thread _t;
bool _running;
+
RouteList _routes_ipv4;
RouteList _routes_ipv6;
uint32_t _seq;
+ struct iface_entry {
+ int index;
+ char ifacename[IFNAMSIZ];
+ char mac[18];
+ unsigned int mtu;
+ };
+ Hashtable<int, iface_entry> _interfaces;
+
// socket communication vars;
int _fd;
struct sockaddr_nl _la;
diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp
index 8d64fde3..fe7c6267 100644
--- a/osdep/ManagedRoute.cpp
+++ b/osdep/ManagedRoute.cpp
@@ -54,6 +54,7 @@
#include <asm/types.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
+#include "../osdep/LinuxNetLink.hpp"
#endif
#ifdef __BSD__
#include <net/if_dl.h>
@@ -284,44 +285,14 @@ static void _routeCmd(const char *op,const InetAddress &target,const InetAddress
#ifdef __LINUX__ // ----------------------------------------------------------
#define ZT_ROUTING_SUPPORT_FOUND 1
-static bool _hasRoute(const InetAddress &target, const InetAddress &via, const char *localInterface)
-{
- 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;
+ if ((strcmp(op, "add") == 0 || strcmp(op, "replace") == 0)) {
+ LinuxNetLink::getInstance().addRoute(target, via, localInterface);
+ } else if ((strcmp(op, "remove") == 0 || strcmp(op, "del") == 0)) {
+ LinuxNetLink::getInstance().delRoute(target, via, localInterface);
}
+ return;
char targetStr[64] = {0};
char viaStr[64] = {0};