Browse Source

Leave IP addresses alone instead of deleting them from tap if they are not members of any of the networks under management.

Adam Ierymenko 11 years ago
parent
commit
f82c7006ea
3 changed files with 189 additions and 179 deletions
  1. 18 5
      node/EthernetTap.hpp
  2. 120 8
      node/InetAddress.cpp
  3. 51 166
      node/InetAddress.hpp

+ 18 - 5
node/EthernetTap.hpp

@@ -115,7 +115,8 @@ public:
 	/**
 	 * Set this tap's IP addresses to exactly this set of IPs
 	 *
-	 * New IPs are created, ones not in this list are removed.
+	 * New IPs are created. Any IP that overlaps with the network of an IP in
+	 * this list is removed, but other IPs are left intact.
 	 *
 	 * @param ips IP addresses with netmask in port field
 	 */
@@ -130,15 +131,27 @@ public:
 			if (i->isLinkLocal()) {
 				if (i->isV6())
 					haveV6LinkLocal = true;
-			} else if (!allIps.count(*i))
-				removeIP(*i);
+			} else if (!allIps.count(*i)) {
+				for(std::set<InetAddress>::const_iterator i2(allIps.begin());i2!=allIps.end();++i2) {
+					if (i->sameNetworkAs(*i2)) {
+						removeIP(*i);
+						break;
+					}
+				}
+			}
 		}
 		if (!haveV6LinkLocal)
 			addIP(InetAddress::makeIpv6LinkLocal(_mac));
 #else
 		for(std::set<InetAddress>::iterator i(myIps.begin());i!=myIps.end();++i) {
-			if ((!i->isLinkLocal())&&(!allIps.count(*i)))
-				removeIP(*i);
+			if ((!i->isLinkLocal())&&(!allIps.count(*i))) {
+				for(std::set<InetAddress>::const_iterator i2(allIps.begin());i2!=allIps.end();++i2) {
+					if (i->sameNetworkAs(*i2)) {
+						removeIP(*i);
+						break;
+					}
+				}
+			}
 		}
 #endif
 	}

+ 120 - 8
node/InetAddress.cpp

@@ -46,17 +46,51 @@ void InetAddress::set(const std::string &ip,unsigned int port)
 	memset(&_sa,0,sizeof(_sa));
 	if (ip.find(':') != std::string::npos) {
 		_sa.sin6.sin6_family = AF_INET6;
-		_sa.sin6.sin6_port = htons((uint16_t)port);
+		_sa.sin6.sin6_port = Utils::hton((uint16_t)port);
 		if (inet_pton(AF_INET6,ip.c_str(),(void *)&(_sa.sin6.sin6_addr.s6_addr)) <= 0)
 			_sa.saddr.sa_family = 0;
 	} else {
 		_sa.sin.sin_family = AF_INET;
-		_sa.sin.sin_port = htons((uint16_t)port);
+		_sa.sin.sin_port = Utils::hton((uint16_t)port);
 		if (inet_pton(AF_INET,ip.c_str(),(void *)&(_sa.sin.sin_addr.s_addr)) <= 0)
 			_sa.saddr.sa_family = 0;
 	}
 }
 
+void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
+	throw()
+{
+	memset(&_sa,0,sizeof(_sa));
+	if (ipLen == 4) {
+		setV4();
+		memcpy(rawIpData(),ipBytes,4);
+		setPort(port);
+	} else if (ipLen == 16) {
+		setV6();
+		memcpy(rawIpData(),ipBytes,16);
+		setPort(port);
+	}
+}
+
+bool InetAddress::isLinkLocal() const
+	throw()
+{
+	if (_sa.saddr.sa_family == AF_INET)
+		return ((Utils::ntoh((uint32_t)_sa.sin.sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000);
+	else if (_sa.saddr.sa_family == AF_INET6) {
+		if (_sa.sin6.sin6_addr.s6_addr[0] != 0xfe) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[1] != 0x80) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[2] != 0x00) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[3] != 0x00) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[4] != 0x00) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[5] != 0x00) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[6] != 0x00) return false;
+		if (_sa.sin6.sin6_addr.s6_addr[7] != 0x00) return false;
+		return true;
+	}
+	return false;
+}
+
 std::string InetAddress::toString() const
 {
 	char buf[128],buf2[128];
@@ -103,7 +137,6 @@ void InetAddress::fromString(const std::string &ipSlashPort)
 std::string InetAddress::toIpString() const
 {
 	char buf[128];
-
 	switch(_sa.saddr.sa_family) {
 		case AF_INET:
 #ifdef __WINDOWS__
@@ -124,10 +157,64 @@ std::string InetAddress::toIpString() const
 #endif
 			break;
 	}
-
 	return std::string();
 }
 
+InetAddress InetAddress::netmask() const
+	throw()
+{
+	InetAddress r(*this);
+	switch(_sa.saddr.sa_family) {
+		case AF_INET:
+			r._sa.sin.sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+			break;
+		case AF_INET6: {
+			unsigned char *bf = (unsigned char *)r._sa.sin6.sin6_addr.s6_addr;
+			signed int bitsLeft = (signed int)netmaskBits();
+			for(unsigned int i=0;i<16;++i) {
+				if (bitsLeft > 0) {
+					bf[i] = (unsigned char)((bitsLeft >= 8) ? 0xff : (0xff << (8 - bitsLeft)));
+					bitsLeft -= 8;
+				} else bf[i] = (unsigned char)0;
+			}
+		}	break;
+	}
+	return r;
+}
+
+bool InetAddress::sameNetworkAs(const InetAddress &ipnet) const
+	throw()
+{
+	if (_sa.saddr.sa_family != ipnet._sa.saddr.sa_family)
+		return false;
+
+	unsigned int bits = netmaskBits();
+	if (bits != ipnet.netmaskBits())
+		return false;
+	if (!bits)
+		return true;
+	switch(_sa.saddr.sa_family) {
+		case AF_INET:
+			if (bits >= 32) bits = 32;
+			break;
+		case AF_INET6:
+			if (bits >= 128) bits = 128;
+			break;
+		default:
+			return false;
+	}
+
+	const uint8_t *a = (const uint8_t *)rawIpData();
+	const uint8_t *b = (const uint8_t *)ipnet.rawIpData();
+	while (bits >= 8) {
+		if (*(a++) != *(b++))
+			return false;
+		bits -= 8;
+	}
+	bits = 8 - bits;
+	return ((*a >> bits) == (*b >> bits));
+}
+
 bool InetAddress::operator==(const InetAddress &a) const
 	throw()
 {
@@ -151,19 +238,44 @@ bool InetAddress::operator<(const InetAddress &a) const
 		return true;
 	else if (_sa.saddr.sa_family == a._sa.saddr.sa_family) {
 		if (_sa.saddr.sa_family == AF_INET) {
-			unsigned long x = ntohl(_sa.sin.sin_addr.s_addr);
-			unsigned long y = ntohl(a._sa.sin.sin_addr.s_addr);
+			unsigned long x = Utils::ntoh((uint32_t)_sa.sin.sin_addr.s_addr);
+			unsigned long y = Utils::ntoh((uint32_t)a._sa.sin.sin_addr.s_addr);
 			if (x == y)
-				return (ntohs(_sa.sin.sin_port) < ntohs(a._sa.sin.sin_port));
+				return (Utils::ntoh((uint16_t)_sa.sin.sin_port) < Utils::ntoh((uint16_t)a._sa.sin.sin_port));
 			else return (x < y);
 		} else if (_sa.saddr.sa_family == AF_INET6) {
 			int cmp = (int)memcmp(_sa.sin6.sin6_addr.s6_addr,a._sa.sin6.sin6_addr.s6_addr,16);
 			if (cmp == 0)
-				return (ntohs(_sa.sin6.sin6_port) < ntohs(a._sa.sin6.sin6_port));
+				return (Utils::ntoh((uint16_t)_sa.sin6.sin6_port) < Utils::ntoh((uint16_t)a._sa.sin6.sin6_port));
 			else return (cmp < 0);
 		} else return (memcmp(&_sa,&a._sa,sizeof(_sa)) < 0);
 	}
 	return false;
 }
 
+InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
+	throw()
+{
+	InetAddress ip;
+	ip._sa.saddr.sa_family = AF_INET6;
+	ip._sa.sin6.sin6_addr.s6_addr[0] = 0xfe;
+	ip._sa.sin6.sin6_addr.s6_addr[1] = 0x80;
+	ip._sa.sin6.sin6_addr.s6_addr[2] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[3] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[4] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[5] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[6] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[7] = 0x00;
+	ip._sa.sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
+	ip._sa.sin6.sin6_addr.s6_addr[9] = mac[1];
+	ip._sa.sin6.sin6_addr.s6_addr[10] = mac[2];
+	ip._sa.sin6.sin6_addr.s6_addr[11] = 0xff;
+	ip._sa.sin6.sin6_addr.s6_addr[12] = 0xfe;
+	ip._sa.sin6.sin6_addr.s6_addr[13] = mac[3];
+	ip._sa.sin6.sin6_addr.s6_addr[14] = mac[4];
+	ip._sa.sin6.sin6_addr.s6_addr[15] = mac[5];
+	ip._sa.sin6.sin6_port = Utils::hton((uint16_t)64);
+	return ip;
+}
+
 } // namespace ZeroTier

+ 51 - 166
node/InetAddress.hpp

@@ -77,53 +77,14 @@ public:
 	 */
 	static const InetAddress LO6;
 
-	InetAddress()
-		throw()
-	{
-		memset(&_sa,0,sizeof(_sa));
-	}
-
-	InetAddress(const InetAddress &a)
-		throw()
-	{
-		memcpy(&_sa,&a._sa,sizeof(_sa));
-	}
-
-	InetAddress(const struct sockaddr *sa)
-		throw()
-	{
-		this->set(sa);
-	}
-
-	InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port)
-		throw()
-	{
-		this->set(ipBytes,ipLen,port);
-	}
-
-	InetAddress(const uint32_t ipv4,unsigned int port)
-		throw()
-	{
-		this->set(&ipv4,4,port);
-	}
-
-	InetAddress(const std::string &ip,unsigned int port)
-		throw()
-	{
-		this->set(ip,port);
-	}
-
-	InetAddress(const std::string &ipSlashPort)
-		throw()
-	{
-		this->fromString(ipSlashPort);
-	}
-
-	InetAddress(const char *ipSlashPort)
-		throw()
-	{
-		this->fromString(std::string(ipSlashPort));
-	}
+	InetAddress() throw() { memset(&_sa,0,sizeof(_sa)); }
+	InetAddress(const InetAddress &a) throw() { memcpy(&_sa,&a._sa,sizeof(_sa)); }
+	InetAddress(const struct sockaddr *sa) throw() { this->set(sa); }
+	InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) throw() { this->set(ipBytes,ipLen,port); }
+	InetAddress(const uint32_t ipv4,unsigned int port) throw() { this->set(&ipv4,4,port); }
+	InetAddress(const std::string &ip,unsigned int port) throw() { this->set(ip,port); }
+	InetAddress(const std::string &ipSlashPort) throw() { this->fromString(ipSlashPort); }
+	InetAddress(const char *ipSlashPort) throw() { this->fromString(std::string(ipSlashPort)); }
 
 	inline InetAddress &operator=(const InetAddress &a)
 		throw()
@@ -141,15 +102,9 @@ public:
 		throw()
 	{
 		switch(sa->sa_family) {
-			case AF_INET:
-				memcpy(&_sa.sin,sa,sizeof(struct sockaddr_in));
-				break;
-			case AF_INET6:
-				memcpy(&_sa.sin6,sa,sizeof(struct sockaddr_in6));
-				break;
-			default:
-				_sa.saddr.sa_family = 0;
-				break;
+			case AF_INET: memcpy(&_sa.sin,sa,sizeof(struct sockaddr_in)); break;
+			case AF_INET6: memcpy(&_sa.sin6,sa,sizeof(struct sockaddr_in6)); break;
+			default: memset(&_sa,0,sizeof(_sa)); break;
 		}
 	}
 
@@ -169,20 +124,8 @@ public:
 	 * @param ipLen Length of IP address: 4 or 16
 	 * @param port Port number or 0 for none
 	 */
-	inline void set(const void *ipBytes,unsigned int ipLen,unsigned int port)
-		throw()
-	{
-		_sa.saddr.sa_family = 0;
-		if (ipLen == 4) {
-			setV4();
-			memcpy(rawIpData(),ipBytes,4);
-			setPort(port);
-		} else if (ipLen == 16) {
-			setV6();
-			memcpy(rawIpData(),ipBytes,16);
-			setPort(port);
-		}
-	}
+	void set(const void *ipBytes,unsigned int ipLen,unsigned int port)
+		throw();
 
 	/**
 	 * Set the port component
@@ -193,32 +136,16 @@ public:
 		throw()
 	{
 		if (_sa.saddr.sa_family == AF_INET)
-			_sa.sin.sin_port = htons((uint16_t)port);
+			_sa.sin.sin_port = Utils::hton((uint16_t)port);
 		else if (_sa.saddr.sa_family == AF_INET6)
-			_sa.sin6.sin6_port = htons((uint16_t)port);
+			_sa.sin6.sin6_port = Utils::hton((uint16_t)port);
 	}
 
 	/**
 	 * @return True if this is a link-local IP address
 	 */
-	inline bool isLinkLocal() const
-		throw()
-	{
-		if (_sa.saddr.sa_family == AF_INET)
-			return ((Utils::ntoh((uint32_t)_sa.sin.sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000);
-		else if (_sa.saddr.sa_family == AF_INET6) {
-			if (_sa.sin6.sin6_addr.s6_addr[0] != 0xfe) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[1] != 0x80) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[2] != 0x00) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[3] != 0x00) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[4] != 0x00) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[5] != 0x00) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[6] != 0x00) return false;
-			if (_sa.sin6.sin6_addr.s6_addr[7] != 0x00) return false;
-			return true;
-		}
-		return false;
-	}
+	bool isLinkLocal() const
+		throw();
 
 	/**
 	 * @return ASCII IP/port format representation
@@ -242,12 +169,10 @@ public:
 		throw()
 	{
 		switch(_sa.saddr.sa_family) {
-			case AF_INET:
-				return ntohs(_sa.sin.sin_port);
-			case AF_INET6:
-				return ntohs(_sa.sin6.sin6_port);
+			case AF_INET: return Utils::ntoh((uint16_t)_sa.sin.sin_port);
+			case AF_INET6: return Utils::ntoh((uint16_t)_sa.sin6.sin6_port);
+			default: return 0;
 		}
-		return 0;
 	}
 
 	/**
@@ -259,36 +184,13 @@ public:
 	 *
 	 * @return Netmask bits
 	 */
-	inline unsigned int netmaskBits() const
-		throw()
-	{
-		return port();
-	}
+	inline unsigned int netmaskBits() const throw() { return port(); }
 
 	/**
 	 * Construct a full netmask as an InetAddress
 	 */
-	inline InetAddress netmask() const
-		throw()
-	{
-		InetAddress r(*this);
-		switch(_sa.saddr.sa_family) {
-			case AF_INET:
-				r._sa.sin.sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
-				break;
-			case AF_INET6: {
-				unsigned char *bf = (unsigned char *)r._sa.sin6.sin6_addr.s6_addr;
-				signed int bitsLeft = (signed int)netmaskBits();
-				for(unsigned int i=0;i<16;++i) {
-					if (bitsLeft > 0) {
-						bf[i] = (unsigned char)((bitsLeft >= 8) ? 0xff : (0xff << (8 - bitsLeft)));
-						bitsLeft -= 8;
-					} else bf[i] = (unsigned char)0;
-				}
-			}	break;
-		}
-		return r;
-	}
+	InetAddress netmask() const
+		throw();
 
 	/**
 	 * @return True if this is an IPv4 address
@@ -327,17 +229,17 @@ public:
 	inline unsigned int saddrLen() const
 		throw()
 	{
-		return (isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
+		switch(_sa.saddr.sa_family) {
+			case AF_INET: return sizeof(struct sockaddr_in);
+			case AF_INET6: return sizeof(struct sockaddr_in6);
+			default: return 0;
+		}
 	}
 
 	/**
 	 * @return Combined length of internal structure, room for either V4 or V6
 	 */
-	inline unsigned int saddrSpaceLen() const
-		throw()
-	{
-		return sizeof(_sa);
-	}
+	inline unsigned int saddrSpaceLen() const throw() { return sizeof(_sa); }
 
 	/**
 	 * @return Raw sockaddr_in structure (valid if IPv4)
@@ -356,7 +258,7 @@ public:
 	inline const void *rawIpData() const throw() { return ((_sa.saddr.sa_family == AF_INET) ? (void *)(&(_sa.sin.sin_addr.s_addr)) : (void *)_sa.sin6.sin6_addr.s6_addr); }
 
 	/**
-	 * Compare only the IP portions of addresses, ignoring port
+	 * Compare only the IP portions of addresses, ignoring port/netmask
 	 *
 	 * @param a Address to compare
 	 * @return True if both addresses are of the same (valid) type and their IPs match
@@ -375,55 +277,38 @@ public:
 		return false;
 	}
 
-	bool operator==(const InetAddress &a) const throw();
-	inline bool operator!=(const InetAddress &a) const throw() { return !(*this == a); }
-	bool operator<(const InetAddress &a) const throw();
-	inline bool operator>(const InetAddress &a) const throw() { return (a < *this); }
-	inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); }
-	inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); }
-
 	/**
-	 * @return True if address family is non-zero
+	 * Compare IP/netmask with another IP/netmask
+	 *
+	 * @param ipnet IP/netmask to compare with
+	 * @return True if [netmask] bits match
 	 */
-	inline operator bool() const throw() { return ((_sa.saddr.sa_family == AF_INET)||(_sa.saddr.sa_family == AF_INET6)); }
+	bool sameNetworkAs(const InetAddress &ipnet) const
+		throw();
 
 	/**
 	 * Set to null/zero
 	 */
-	inline void zero()
-		throw()
-	{
-		_sa.saddr.sa_family = 0;
-	}
+	inline void zero() throw() { memset(&_sa,0,sizeof(_sa)); }
+
+	/**
+	 * @return True if address family is non-zero
+	 */
+	inline operator bool() const throw() { return ((_sa.saddr.sa_family == AF_INET)||(_sa.saddr.sa_family == AF_INET6)); }
+
+	bool operator==(const InetAddress &a) const throw();
+	inline bool operator!=(const InetAddress &a) const throw() { return !(*this == a); }
+	bool operator<(const InetAddress &a) const throw();
+	inline bool operator>(const InetAddress &a) const throw() { return (a < *this); }
+	inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); }
+	inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); }
 
 	/**
 	 * @param mac MAC address seed
 	 * @return IPv6 link-local address
 	 */
-	static inline InetAddress makeIpv6LinkLocal(const MAC &mac)
-		throw()
-	{
-		InetAddress ip;
-		ip._sa.saddr.sa_family = AF_INET6;
-		ip._sa.sin6.sin6_addr.s6_addr[0] = 0xfe;
-		ip._sa.sin6.sin6_addr.s6_addr[1] = 0x80;
-		ip._sa.sin6.sin6_addr.s6_addr[2] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[3] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[4] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[5] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[6] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[7] = 0x00;
-		ip._sa.sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
-		ip._sa.sin6.sin6_addr.s6_addr[9] = mac[1];
-		ip._sa.sin6.sin6_addr.s6_addr[10] = mac[2];
-		ip._sa.sin6.sin6_addr.s6_addr[11] = 0xff;
-		ip._sa.sin6.sin6_addr.s6_addr[12] = 0xfe;
-		ip._sa.sin6.sin6_addr.s6_addr[13] = mac[3];
-		ip._sa.sin6.sin6_addr.s6_addr[14] = mac[4];
-		ip._sa.sin6.sin6_addr.s6_addr[15] = mac[5];
-		ip._sa.sin6.sin6_port = Utils::hton((uint16_t)64);
-		return ip;
-	}
+	static InetAddress makeIpv6LinkLocal(const MAC &mac)
+		throw();
 
 private:
 	union {