From a3875f996551c2d6d815254566f9b29565e6f71f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 13 Nov 2020 21:55:31 -0500 Subject: [PATCH] Add a route DB to LinuxNetLink to make route sync robust. --- osdep/LinuxNetLink.cpp | 141 ++++++++++++++++++++++++++++++++++++++--- osdep/LinuxNetLink.hpp | 43 +++++++++++++ 2 files changed, 174 insertions(+), 10 deletions(-) diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp index e101b407d..f9defdcb3 100644 --- a/osdep/LinuxNetLink.cpp +++ b/osdep/LinuxNetLink.cpp @@ -280,7 +280,6 @@ void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp) void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp) { -#ifdef ZT_NETLINK_TRACE char dsts[40] = {0}; char gws[40] = {0}; char srcs[40] = {0}; @@ -291,33 +290,84 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp) struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); int rtl = RTM_PAYLOAD(nlp); + Route r; + bool wecare = false; + 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); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_SRC: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, rtp->rtm_family == AF_INET ? 24: 40); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_GATEWAY: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, rtp->rtm_family == AF_INET ? 24 : 40); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_OIF: + switch(rtp->rtm_family) { + case AF_INET: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + case AF_INET6: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + } sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); break; } } - sprintf(ms, "%d", rtp->rtm_dst_len); + if (wecare) { + Mutex::Lock rl(_routes_m); + _routes[target].insert(r); + } + +#ifdef ZT_NETLINK_TRACE + sprintf(ms, "%d", rtp->rtm_dst_len); fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); #endif } void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp) { -#ifdef ZT_NETLINK_TRACE char dsts[40] = {0}; char gws[40] = {0}; char srcs[40] = {0}; @@ -328,26 +378,78 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp) struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); int rtl = RTM_PAYLOAD(nlp); + Route r; + bool wecare = false; + 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); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_SRC: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, rtp->rtm_family == AF_INET ? 24 : 40); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_GATEWAY: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, rtp->rtm_family == AF_INET ? 24 : 40); + switch(rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } break; case RTA_OIF: + switch(rtp->rtm_family) { + case AF_INET: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + case AF_INET6: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + } sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); break; } } - sprintf(ms, "%d", rtp->rtm_dst_len); + if (wecare) { + Mutex::Lock rl(_routes_m); + _routes[target].erase(r); + } + +#ifdef ZT_NETLINK_TRACE + sprintf(ms, "%d", rtp->rtm_dst_len); fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); #endif } @@ -1040,6 +1142,25 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) close(fd); } +bool LinuxNetLink::routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) +{ + Mutex::Lock rl(_routes_m); + const std::set &rs = _routes[target]; + for(std::set::const_iterator ri(rs.begin());ri!=rs.end();++ri) { + if ((ri->via == via)&&(ri->src == src)) { + if (ifname) { + Mutex::Lock ifl(_if_m); + const iface_entry *ife = _interfaces.get(rs->ifidx); + if ((ife)&&(!strncmp(ife->ifacename,ifname,IFNAMSIZ))) + return true; + } else { + return true; + } + } + } + return false; +} + int LinuxNetLink::_indexForInterface(const char *iface) { Mutex::Lock l(_if_m); diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp index c6c4be00a..7f49fd2ed 100644 --- a/osdep/LinuxNetLink.hpp +++ b/osdep/LinuxNetLink.hpp @@ -45,6 +45,41 @@ private: ~LinuxNetLink(); public: + struct Route { + InetAddress target; + InetAddress via; + InetAddress src; + int ifidx; + + inline bool operator==(const Route &r) const + { return ((target == r.target)&&(via == r.via)&&(src == r.src)&&(ifidx == r.ifidx)); } + inline bool operator!=(const Route &r) const + { return (!(*this == r)); } + inline bool operator<(const Route &r) const + { + if (target < r.target) { + return true; + } else if (target == r.target) { + if (via < r.via) { + return true; + } else if (via == r.via) { + if (src < r.src) { + return true; + } else if (src == r.src) { + return (ifidx < r.ifidx); + } + } + } + return false; + } + inline bool operator>(const Route &r) const + { return (r < *this); } + inline bool operator<=(const Route &r) const + { return !(r < *this); } + inline bool operator>=(const Route &r) const + { return !(*this < r); } + }; + static LinuxNetLink& getInstance() { static LinuxNetLink instance; @@ -60,7 +95,10 @@ public: void addAddress(const InetAddress &addr, const char *iface); void removeAddress(const InetAddress &addr, const char *iface); + bool routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname); + void threadMain() throw(); + private: int _doRecv(int fd); @@ -85,7 +123,12 @@ private: uint32_t _seq; + std::map< InetAddress,std::set > _routes; + Mutex _routes_m; + struct iface_entry { + iface_entry() + { memset(this,0,sizeof(iface_entry)); } int index; char ifacename[IFNAMSIZ]; char mac[18];