Bläddra i källkod

Add a route DB to LinuxNetLink to make route sync robust.

Adam Ierymenko 4 år sedan
förälder
incheckning
a3875f9965
2 ändrade filer med 174 tillägg och 10 borttagningar
  1. 131 10
      osdep/LinuxNetLink.cpp
  2. 43 0
      osdep/LinuxNetLink.hpp

+ 131 - 10
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<Route> &rs = _routes[target];
+	for(std::set<Route>::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);

+ 43 - 0
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<Route> > _routes;
+	Mutex _routes_m;
+
 	struct iface_entry {
+		iface_entry()
+		{ memset(this,0,sizeof(iface_entry)); }
 		int index;
 		char ifacename[IFNAMSIZ];
 		char mac[18];