diff --git a/.gitignore b/.gitignore index 49733d1f0..c80615527 100755 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /zerotier-cli /zerotier-selftest /zerotier +/nltest # OS-created garbage files from various platforms .DS_Store diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp index 308f0f8ad..062144dcb 100644 --- a/osdep/LinuxNetLink.cpp +++ b/osdep/LinuxNetLink.cpp @@ -35,23 +35,10 @@ LinuxNetLink::LinuxNetLink() , _running(false) , _routes_ipv4() , _routes_ipv6() + , _seq(0) , _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; @@ -63,7 +50,7 @@ LinuxNetLink::LinuxNetLink() _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; + _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); @@ -89,56 +76,59 @@ LinuxNetLink::~LinuxNetLink() void LinuxNetLink::threadMain() throw() { - char *p; - p = _buf; - _nll = 0; + 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); + rtn = recv(_fd, p, sizeof(buf) - nll, 0); - if (_rtn > 0) { - _nlp = (struct nlmsghdr *) p; + if (rtn > 0) { + nlp = (struct nlmsghdr *)p; - if(_nlp->nlmsg_type == NLMSG_ERROR && (_nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) { + 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); + 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; + p = buf; + nll = 0; continue; } - if (_nlp->nlmsg_type == NLMSG_NOOP) { + 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_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE)) { - if (_nlp->nlmsg_type == NLMSG_DONE) { - _processMessage(); - p = _buf; - _nll = 0; + if (nlp->nlmsg_type == NLMSG_DONE) { + _processMessage(nlp, nll); + p = buf; + nll = 0; continue; } - p += _rtn; - _nll += _rtn; + p += rtn; + nll += rtn; } - if (_nlp->nlmsg_type == NLMSG_OVERRUN) { + if (nlp->nlmsg_type == NLMSG_OVERRUN) { fprintf(stderr, "NLMSG_OVERRUN: Data lost\n"); - p = _buf; - _nll = 0; + p = buf; + nll = 0; continue; } - _nll += _rtn; + nll += rtn; - _processMessage(); - p = _buf; - _nll = 0; + _processMessage(nlp, nll); + p = buf; + nll = 0; } else { Thread::sleep(100); @@ -147,80 +137,61 @@ void LinuxNetLink::threadMain() throw() } } -void LinuxNetLink::_processMessage() +void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll) { - for(_nlp = (struct nlmsghdr *)_buf; NLMSG_OK(_nlp, _nll); _nlp=NLMSG_NEXT(_nlp, _nll)) + for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll)) { - switch(_nlp->nlmsg_type) + switch(nlp->nlmsg_type) { case RTM_NEWLINK: - _linkAdded(); + _linkAdded(nlp); break; case RTM_DELLINK: - _linkDeleted(); - break; - case RTM_GETLINK: - fprintf(stderr, "Get Link\n"); - break; - case RTM_SETLINK: - fprintf(stderr, "Set Link\n"); + _linkDeleted(nlp); break; case RTM_NEWADDR: - _ipAddressAdded(); + _ipAddressAdded(nlp); break; case RTM_DELADDR: - _ipAddressDeleted(); - break; - case RTM_GETADDR: - fprintf(stderr, "Get IP Address\n"); + _ipAddressDeleted(nlp); break; case RTM_NEWROUTE: - _routeAdded(); + _routeAdded(nlp); break; case RTM_DELROUTE: - _routeDeleted(); - break; - case RTM_GETROUTE: + _routeDeleted(nlp); break; default: - fprintf(stderr, "ignore msgtype %d...\n", _nlp->nlmsg_type); + 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() +void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp) { - _ifap = (struct ifaddrmsg *)NLMSG_DATA(_nlp); - _rtap = (struct rtattr *)IFA_RTA(_ifap); - _ifal = IFA_PAYLOAD(_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)) + for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) { - switch(_rtap->rta_type) { + switch(rtap->rta_type) { case IFA_ADDRESS: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), addr, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); break; case IFA_LOCAL: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), local, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); break; case IFA_LABEL: - memcpy(label, RTA_DATA(_rtap), 40); + memcpy(label, RTA_DATA(rtap), 40); break; case IFA_BROADCAST: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), bcast, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); break; } } @@ -228,31 +199,31 @@ void LinuxNetLink::_ipAddressAdded() fprintf(stderr, "Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); } -void LinuxNetLink::_ipAddressDeleted() +void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp) { - _ifap = (struct ifaddrmsg *)NLMSG_DATA(_nlp); - _rtap = (struct rtattr *)IFA_RTA(_ifap); - _ifal = IFA_PAYLOAD(_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)) + for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) { - switch(_rtap->rta_type) { + switch(rtap->rta_type) { case IFA_ADDRESS: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), addr, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); break; case IFA_LOCAL: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), local, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); break; case IFA_LABEL: - memcpy(label, RTA_DATA(_rtap), 40); + memcpy(label, RTA_DATA(rtap), 40); break; case IFA_BROADCAST: - inet_ntop(_ifap->ifa_family, RTA_DATA(_rtap), bcast, 40); + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); break; } } @@ -260,94 +231,94 @@ void LinuxNetLink::_ipAddressDeleted() fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); } -void LinuxNetLink::_routeAdded() +void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp) { char dsts[40] = {0}; char gws[40] = {0}; char ifs[16] = {0}; char ms[24] = {0}; - _rtp = (struct rtmsg *) NLMSG_DATA(_nlp); + struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp); + struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); + int rtl = RTM_PAYLOAD(nlp); - _rtap = (struct rtattr *)RTM_RTA(_rtp); - _rtl = RTM_PAYLOAD(_nlp); - for(;RTA_OK(_rtap, _rtl); _rtap=RTA_NEXT(_rtap, _rtl)) + for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) { - switch(_rtap->rta_type) + switch(rtap->rta_type) { case RTA_DST: - inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), dsts, _rtp->rtm_family == AF_INET ? 24 : 40); + 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); + 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))); + sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); break; } } - sprintf(ms, "%d", _rtp->rtm_dst_len); + 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() +void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp) { char dsts[40] = {0}; char gws[40] = {0}; char ifs[16] = {0}; char ms[24] = {0}; - _rtp = (struct rtmsg *) NLMSG_DATA(_nlp); + struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp); + struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); + int rtl = RTM_PAYLOAD(nlp); - _rtap = (struct rtattr *)RTM_RTA(_rtp); - _rtl = RTM_PAYLOAD(_nlp); - for(;RTA_OK(_rtap, _rtl); _rtap=RTA_NEXT(_rtap, _rtl)) + for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) { - switch(_rtap->rta_type) + switch(rtap->rta_type) { case RTA_DST: - inet_ntop(_rtp->rtm_family, RTA_DATA(_rtap), dsts, _rtp->rtm_family == AF_INET ? 24 : 40); + 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); + 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))); + sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); break; } } - sprintf(ms, "%d", _rtp->rtm_dst_len); + 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() +void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp) { 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); + 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)) + for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil)) { - switch(_rtap->rta_type) { + switch(rtap->rta_type) { case IFLA_ADDRESS: - ptr2 = (unsigned char*)RTA_DATA(_rtap); + 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); + ptr = (const char*)RTA_DATA(rtap); memcpy(ifname, ptr, strlen(ptr)); break; case IFLA_MTU: - memcpy(&mtu, RTA_DATA(_rtap), sizeof(unsigned int)); + memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); break; } } @@ -355,32 +326,32 @@ void LinuxNetLink::_linkAdded() fprintf(stderr, "Link Added: %s mac: %s, mtu: %d\n", ifname, mac, mtu); } -void LinuxNetLink::_linkDeleted() +void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp) { 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); + 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)) + for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil)) { - switch(_rtap->rta_type) { + switch(rtap->rta_type) { case IFLA_ADDRESS: - ptr2 = (unsigned char*)RTA_DATA(_rtap); + 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); + ptr = (const char*)RTA_DATA(rtap); memcpy(ifname, ptr, strlen(ptr)); break; case IFLA_MTU: - memcpy(&mtu, RTA_DATA(_rtap), sizeof(unsigned int)); + memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); break; } } @@ -395,23 +366,28 @@ void LinuxNetLink::_requestIPv4Routes() 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; - 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); - 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; - _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); + sendmsg(_fd, &msg, 0); } void LinuxNetLink::_requestIPv6Routes() @@ -421,23 +397,28 @@ void LinuxNetLink::_requestIPv6Routes() 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; - 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); - 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; - _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) { + while((sendmsg(_fd, &msg, 0)) == -1) { fprintf(stderr, "ipv6 waiting..."); Thread::sleep(100); } @@ -453,7 +434,7 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c } -void LinuxNetLink::addInterface(const char *iface) +void LinuxNetLink::addInterface(const char *iface, unsigned int mtu) { } diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp index 519bb435c..8ee42ee4f 100644 --- a/osdep/LinuxNetLink.hpp +++ b/osdep/LinuxNetLink.hpp @@ -79,19 +79,19 @@ public: RouteList getIPV4Routes() const; RouteList getIPV6Routes() const; - void addInterface(const char *iface); + void addInterface(const char *iface, unsigned int mtu); 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 _processMessage(struct nlmsghdr *nlp, int nll); + void _routeAdded(struct nlmsghdr *nlp); + void _routeDeleted(struct nlmsghdr *nlp); + void _linkAdded(struct nlmsghdr *nlp); + void _linkDeleted(struct nlmsghdr *nlp); + void _ipAddressAdded(struct nlmsghdr *nlp); + void _ipAddressDeleted(struct nlmsghdr *nlp); void _requestIPv4Routes(); @@ -103,29 +103,11 @@ private: RouteList _routes_ipv4; RouteList _routes_ipv6; + uint32_t _seq; + // 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; }; }