Browse Source

Fix for GitHub issue #36 on OSX... results in a duplicate entry for IPv6 link-local but seems okay... need to test on OSX 10.6 though.

Adam Ierymenko 11 years ago
parent
commit
64231aa3f0
3 changed files with 102 additions and 21 deletions
  1. 66 20
      node/EthernetTap.cpp
  2. 6 1
      node/EthernetTap.hpp
  3. 30 0
      node/InetAddress.hpp

+ 66 - 20
node/EthernetTap.cpp

@@ -68,8 +68,7 @@ static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC
 #define ZT_UNIX_IP_COMMAND 1
 #define ZT_UNIX_IP_COMMAND 1
 #define ZT_UNIX_IFCONFIG_COMMAND 2
 #define ZT_UNIX_IFCONFIG_COMMAND 2
 #define ZT_MAC_KEXTLOAD_COMMAND 3
 #define ZT_MAC_KEXTLOAD_COMMAND 3
-#define ZT_MAC_IPCONFIG_COMMAND 4
-#define ZT_MAC_KEXTUNLOAD_COMMAND 5
+#define ZT_MAC_KEXTUNLOAD_COMMAND 4
 
 
 // Finds external commands on startup
 // Finds external commands on startup
 class _CommandFinder
 class _CommandFinder
@@ -83,7 +82,6 @@ public:
 #endif
 #endif
 #ifdef __APPLE__
 #ifdef __APPLE__
 		_findCmd(ZT_MAC_KEXTLOAD_COMMAND,"kextload");
 		_findCmd(ZT_MAC_KEXTLOAD_COMMAND,"kextload");
-		_findCmd(ZT_MAC_IPCONFIG_COMMAND,"ipconfig");
 		_findCmd(ZT_MAC_KEXTUNLOAD_COMMAND,"kextunload");
 		_findCmd(ZT_MAC_KEXTUNLOAD_COMMAND,"kextunload");
 #endif
 #endif
 	}
 	}
@@ -135,17 +133,80 @@ static const _CommandFinder UNIX_COMMANDS;
 #endif // __LINUX__
 #endif // __LINUX__
 
 
 #ifdef __APPLE__
 #ifdef __APPLE__
+
 #include <sys/cdefs.h>
 #include <sys/cdefs.h>
 #include <sys/uio.h>
 #include <sys/uio.h>
 #include <sys/param.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <sys/sysctl.h>
+#include <sys/ioctl.h>
 #include <net/route.h>
 #include <net/route.h>
 #include <net/if.h>
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_dl.h>
+#include <net/if_media.h>
+struct prf_ra { // stupid OSX compile fix... in6_var defines this in a struct which namespaces it for C++
+	u_char onlink : 1;
+	u_char autonomous : 1;
+	u_char reserved : 6;
+} prf_ra;
+#include <netinet6/in6_var.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
 #include <ifaddrs.h>
 #include <ifaddrs.h>
 
 
+// These are KERNEL_PRIVATE... why?
+#ifndef SIOCAUTOCONF_START
+#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq)    /* accept rtadvd on this interface */
+#endif
+#ifndef SIOCAUTOCONF_STOP
+#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq)    /* stop accepting rtadv for this interface */
+#endif
+
 static volatile int EthernetTap_instances = 0;
 static volatile int EthernetTap_instances = 0;
 static ZeroTier::Mutex EthernetTap_instances_m;
 static ZeroTier::Mutex EthernetTap_instances_m;
+
+static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts)
+{
+	struct in6_ndireq nd;
+	struct in6_ifreq ifr;
+
+	int s = socket(AF_INET6,SOCK_DGRAM,0);
+	if (s <= 0)
+		return false;
+
+	memset(&nd,0,sizeof(nd));
+	strncpy(nd.ifname,ifname,sizeof(nd.ifname));
+
+	if (ioctl(s,SIOCGIFINFO_IN6,&nd)) {
+		close(s);
+		return false;
+	}
+
+	unsigned long oldFlags = (unsigned long)nd.ndi.flags;
+
+	if (performNUD)
+		nd.ndi.flags |= ND6_IFF_PERFORMNUD;
+	else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
+
+	if (oldFlags != (unsigned long)nd.ndi.flags) {
+		if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) {
+			close(s);
+			return false;
+		}
+	}
+
+	memset(&ifr,0,sizeof(ifr));
+	strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name));
+	if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) {
+		close(s);
+		return false;
+	}
+
+	close(s);
+	return true;
+}
+
 #endif // __APPLE__
 #endif // __APPLE__
 
 
 namespace ZeroTier {
 namespace ZeroTier {
@@ -336,6 +397,8 @@ EthernetTap::EthernetTap(
 		}
 		}
 	}
 	}
 
 
+	_setIpv6Stuff(_dev,true,false);
+
 	::pipe(_shutdownSignalPipe);
 	::pipe(_shutdownSignalPipe);
 
 
 	_thread = Thread::start(this);
 	_thread = Thread::start(this);
@@ -376,23 +439,6 @@ EthernetTap::~EthernetTap()
 #endif // __APPLE__
 #endif // __APPLE__
 }
 }
 
 
-/*
-void EthernetTap::whack()
-{
-	const char *ipconfig = UNIX_COMMANDS[ZT_MAC_IPCONFIG_COMMAND];
-	if (ipconfig) {
-		long cpid = (long)vfork();
-		if (cpid == 0) {
-			execl(ipconfig,ipconfig,"set",_dev,"AUTOMATIC-V6",(const char *)0);
-			_exit(-1);
-		} else if (cpid > 0) {
-			int exitcode = -1;
-			waitpid(cpid,&exitcode,0);
-		}
-	}
-}
-*/
-
 void EthernetTap::setDisplayName(const char *dn)
 void EthernetTap::setDisplayName(const char *dn)
 {
 {
 }
 }

+ 6 - 1
node/EthernetTap.hpp

@@ -148,10 +148,15 @@ public:
 		for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i)
 		for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i)
 			addIP(*i);
 			addIP(*i);
 		std::set<InetAddress> myIps(ips());
 		std::set<InetAddress> myIps(ips());
+		bool haveV6LinkLocal = false;
 		for(std::set<InetAddress>::iterator i(myIps.begin());i!=myIps.end();++i) {
 		for(std::set<InetAddress>::iterator i(myIps.begin());i!=myIps.end();++i) {
-			if (!allIps.count(*i))
+			if ((i->isV6())&&(i->isLinkLocal()))
+				haveV6LinkLocal = true;
+			else if (!allIps.count(*i))
 				removeIP(*i);
 				removeIP(*i);
 		}
 		}
+		if (!haveV6LinkLocal)
+			addIP(InetAddress::makeIpv6LinkLocal(_mac));
 	}
 	}
 
 
 	/**
 	/**

+ 30 - 0
node/InetAddress.hpp

@@ -36,6 +36,7 @@
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
+#include "MAC.hpp"
 
 
 #ifdef __WINDOWS__
 #ifdef __WINDOWS__
 #include <WinSock2.h>
 #include <WinSock2.h>
@@ -387,6 +388,35 @@ public:
 		_sa.saddr.sa_family = 0;
 		_sa.saddr.sa_family = 0;
 	}
 	}
 
 
+	/**
+	 * @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.data[0] & 0xfd;
+		ip._sa.sin6.sin6_addr.s6_addr[9] = mac.data[1];
+		ip._sa.sin6.sin6_addr.s6_addr[10] = mac.data[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.data[3];
+		ip._sa.sin6.sin6_addr.s6_addr[14] = mac.data[4];
+		ip._sa.sin6.sin6_addr.s6_addr[15] = mac.data[5];
+		ip._sa.sin6.sin6_port = Utils::hton((uint16_t)64);
+		return ip;
+	}
+
 private:
 private:
 	union {
 	union {
 		struct sockaddr saddr;
 		struct sockaddr saddr;