summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@zerotier.com>2014-01-23 14:15:00 -0800
committerAdam Ierymenko <adam.ierymenko@zerotier.com>2014-01-23 14:15:00 -0800
commit2f37ea842fc15790406d770a487725e70c1aa98c (patch)
treea1199a556d8b25c1da11dbff880605ef6ee354d6
parent9232ba1da05a6f4f884d7d5d5d644ec3ca6dad33 (diff)
downloadinfinitytier-2f37ea842fc15790406d770a487725e70c1aa98c.tar.gz
infinitytier-2f37ea842fc15790406d770a487725e70c1aa98c.zip
Couple of Windows fixes, get rid of ips()/allIps() distinction in EthernetTap. (Will need to be fixed on Unix now... later.)
-rw-r--r--node/EthernetTap.cpp130
-rw-r--r--node/EthernetTap.hpp20
-rw-r--r--node/InetAddress.hpp48
3 files changed, 135 insertions, 63 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp
index 5ae537a9..47355cbc 100644
--- a/node/EthernetTap.cpp
+++ b/node/EthernetTap.cpp
@@ -1089,6 +1089,15 @@ EthernetTap::EthernetTap(
if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
_myDeviceInstanceIdPath.assign(data,dataLen);
mySubkeyName = subkeyName;
+
+ // Disable DHCP by default on newly created devices
+ HKEY tcpIpInterfaces;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
+ DWORD enable = 0;
+ RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
+ RegCloseKey(tcpIpInterfaces);
+ }
+
subkeyIndex = -1; // break outer loop
}
}
@@ -1133,14 +1142,6 @@ EthernetTap::EthernetTap(
throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)");
}
- // Disable DHCP -- this might get changed if/when DHCP is supported
- HKEY tcpIpInterfaces;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
- DWORD enable = 0;
- RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable));
- RegCloseKey(tcpIpInterfaces);
- }
-
// Disable and enable interface to ensure registry settings take effect
{
STARTUPINFOA startupInfo;
@@ -1241,40 +1242,70 @@ void EthernetTap::setDisplayName(const char *dn)
bool EthernetTap::addIP(const InetAddress &ip)
{
- Mutex::Lock _l(_ips_m);
-
- if (_ips.count(ip))
- return true;
-
- if (!ip.port())
+ if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT?
return false;
- try {
- std::pair<NET_LUID,NET_IFINDEX> ifidx = _findAdapterByGuid(_deviceGuid);
- MIB_UNICASTIPADDRESS_ROW ipr;
-
- InitializeUnicastIpAddressEntry(&ipr);
- if (ip.isV4()) {
- ipr.Address.Ipv4.sin_family = AF_INET;
- ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)ip.rawIpData());
- ipr.OnLinkPrefixLength = ip.port();
- } else if (ip.isV6()) {
- } else return false;
-
- ipr.PrefixOrigin = IpPrefixOriginManual;
- ipr.SuffixOrigin = IpSuffixOriginManual;
- ipr.ValidLifetime = 0xffffffff;
- ipr.PreferredLifetime = 0xffffffff;
+ std::set<InetAddress> haveIps(ips());
- ipr.InterfaceLuid = ifidx.first;
- ipr.InterfaceIndex = ifidx.second;
-
- if (CreateUnicastIpAddressEntry(&ipr) == NO_ERROR) {
- _ips.insert(ip);
- return true;
+ try {
+ // Add IP to interface at the netlink level if not already assigned.
+ if (!haveIps.count(ip)) {
+ std::pair<NET_LUID,NET_IFINDEX> ifidx = _findAdapterByGuid(_deviceGuid);
+ MIB_UNICASTIPADDRESS_ROW ipr;
+
+ InitializeUnicastIpAddressEntry(&ipr);
+ if (ip.isV4()) {
+ ipr.Address.Ipv4.sin_family = AF_INET;
+ ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)ip.rawIpData());
+ ipr.OnLinkPrefixLength = ip.port();
+ } else if (ip.isV6()) {
+ // TODO
+ } else return false;
+
+ ipr.PrefixOrigin = IpPrefixOriginManual;
+ ipr.SuffixOrigin = IpSuffixOriginManual;
+ ipr.ValidLifetime = 0xffffffff;
+ ipr.PreferredLifetime = 0xffffffff;
+
+ ipr.InterfaceLuid = ifidx.first;
+ ipr.InterfaceIndex = ifidx.second;
+
+ if (CreateUnicastIpAddressEntry(&ipr) == NO_ERROR) {
+ haveIps.insert(ip);
+ } else {
+ LOG("unable to add IP address %s to interface %s: %d",ip.toString().c_str(),deviceName().c_str(),(int)GetLastError());
+ return false;
+ }
}
- } catch ( ... ) {}
+ // Update registry to contain all non-link-local IPs for this interface
+ std::string regMultiIps,regMultiNetmasks;
+ for(std::set<InetAddress>::const_iterator i(haveIps.begin());i!=haveIps.end();++i) {
+ if (!i->isLinkLocal()) {
+ regMultiIps.append(i->toIpString());
+ regMultiIps.push_back((char)0);
+ regMultiNetmasks.append(i->netmask().toIpString());
+ regMultiNetmasks.push_back((char)0);
+ }
+ }
+ HKEY tcpIpInterfaces;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) {
+ if (regMultiIps.length()) {
+ regMultiIps.push_back((char)0);
+ regMultiNetmasks.push_back((char)0);
+ RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"IPAddress",REG_MULTI_SZ,regMultiIps.data(),(DWORD)regMultiIps.length());
+ RegSetKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"SubnetMask",REG_MULTI_SZ,regMultiNetmasks.data(),(DWORD)regMultiNetmasks.length());
+ } else {
+ RegDeleteKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"IPAddress");
+ RegDeleteKeyValueA(tcpIpInterfaces,_myDeviceInstanceId.c_str(),"SubnetMask");
+ }
+ }
+ RegCloseKey(tcpIpInterfaces);
+ } catch (std::exception &exc) {
+ LOG("unexpected exception adding IP address to %s: %s",ip.toString().c_str(),deviceName().c_str(),exc.what());
+ } catch ( ... ) {
+ LOG("unexpected exception adding IP address %s to %s: unknown exception",ip.toString().c_str(),deviceName().c_str());
+ }
return false;
}
@@ -1283,7 +1314,6 @@ bool EthernetTap::removeIP(const InetAddress &ip)
try {
MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
std::pair<NET_LUID,NET_IFINDEX> ifidx = _findAdapterByGuid(_deviceGuid);
-
if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) {
for(DWORD i=0;i<ipt->NumEntries;++i) {
if ((ipt->Table[i].InterfaceLuid.Value == ifidx.first.Value)&&(ipt->Table[i].InterfaceIndex == ifidx.second)) {
@@ -1294,26 +1324,26 @@ bool EthernetTap::removeIP(const InetAddress &ip)
break;
case AF_INET6:
addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength);
+ if (addr.isLinkLocal())
+ continue; // can't remove link-local IPv6 addresses
break;
}
if (addr == ip) {
DeleteUnicastIpAddressEntry(&(ipt->Table[i]));
FreeMibTable(ipt);
- Mutex::Lock _l(_ips_m);
- _ips.erase(ip);
return true;
}
}
}
- FreeMibTable(&ipt);
+ FreeMibTable((PVOID)ipt);
}
} catch ( ... ) {}
return false;
}
-std::set<InetAddress> EthernetTap::allIps() const
+std::set<InetAddress> EthernetTap::ips() const
{
- static const InetAddress ifLoopback("fe80::1",64);
+ static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
std::set<InetAddress> addrs;
try {
@@ -1324,12 +1354,14 @@ std::set<InetAddress> EthernetTap::allIps() const
for(DWORD i=0;i<ipt->NumEntries;++i) {
if ((ipt->Table[i].InterfaceLuid.Value == ifidx.first.Value)&&(ipt->Table[i].InterfaceIndex == ifidx.second)) {
switch(ipt->Table[i].Address.si_family) {
- case AF_INET:
- addrs.insert(InetAddress(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength));
- break;
+ case AF_INET: {
+ InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength);
+ if (ip != InetAddress::LO4)
+ addrs.insert(ip);
+ } break;
case AF_INET6: {
InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength);
- if (ip != ifLoopback) // don't include fe80::1
+ if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6))
addrs.insert(ip);
} break;
}
@@ -1372,8 +1404,8 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
// Ensure that groups are added for each IP... this handles the MAC:ADI
// groups that are created from IPv4 addresses. Some of these may end
// up being duplicates of what the IOCTL returns but that's okay since
- // the set will filter these.
- std::set<InetAddress> ipaddrs(allIps());
+ // the set<> will filter that.
+ std::set<InetAddress> ipaddrs(ips());
for(std::set<InetAddress>::const_iterator i(ipaddrs.begin());i!=ipaddrs.end();++i)
newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp
index 3d91261b..dd3654d4 100644
--- a/node/EthernetTap.hpp
+++ b/node/EthernetTap.hpp
@@ -129,24 +129,17 @@ public:
/**
* Remove an IP from this interface
*
+ * Link-local IP addresses may not be able to be removed, depending on platform and type.
+ *
* @param ip IP and netmask (netmask stored in port field)
* @return True if IP removed successfully
*/
bool removeIP(const InetAddress &ip);
/**
- * @return Set of IP addresses / netmasks
- */
- inline std::set<InetAddress> ips() const
- {
- Mutex::Lock _l(_ips_m);
- return _ips;
- }
-
- /**
- * @return Set of IP addresses / netmasks included any we did not assign, link-local, etc.
+ * @return All IP addresses (V4 and V6) assigned to this interface (including link-local)
*/
- std::set<InetAddress> allIps() const;
+ std::set<InetAddress> ips() const;
/**
* Set this tap's IP addresses to exactly this set of IPs
@@ -208,15 +201,14 @@ private:
const RuntimeEnvironment *_r;
- std::set<InetAddress> _ips;
- Mutex _ips_m;
-
void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
void *_arg;
Thread _thread;
#ifdef __UNIX_LIKE__
+ std::set<InetAddress> _ips;
+ Mutex _ips_m;
char _dev[16];
int _fd;
int _shutdownSignalPipe[2];
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index d90574e5..49729017 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -35,6 +35,7 @@
#include <string>
#include "Constants.hpp"
+#include "Utils.hpp"
#ifdef __WINDOWS__
#include <WinSock2.h>
@@ -189,6 +190,28 @@ public:
}
/**
+ * @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;
+ }
+
+ /**
* @return ASCII IP/port format representation
*/
std::string toString() const;
@@ -234,6 +257,31 @@ public:
}
/**
+ * 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;
+ }
+
+ /**
* @return True if this is an IPv4 address
*/
inline bool isV4() const throw() { return (_sa.saddr.sa_family == AF_INET); }