diff options
-rw-r--r-- | ext/bin/devcon/README.txt | 7 | ||||
-rw-r--r-- | ext/bin/devcon/devcon_x64.exe | bin | 90456 -> 0 bytes | |||
-rw-r--r-- | ext/bin/devcon/devcon_x86.exe | bin | 86360 -> 0 bytes | |||
-rw-r--r-- | ext/installfiles/windows/ZeroTier One.aip | 47 | ||||
-rw-r--r-- | node/Network.cpp | 2 | ||||
-rw-r--r-- | node/Node.hpp | 3 | ||||
-rw-r--r-- | node/Peer.cpp | 6 | ||||
-rw-r--r-- | one.cpp | 50 | ||||
-rw-r--r-- | osdep/OSUtils.cpp | 4 | ||||
-rw-r--r-- | osdep/WindowsEthernetTap.cpp | 782 | ||||
-rw-r--r-- | osdep/WindowsEthernetTap.hpp | 49 | ||||
-rw-r--r-- | service/OneService.cpp | 13 | ||||
-rw-r--r-- | windows/ZeroTierOne/ZeroTierOne.vcxproj | 8 |
13 files changed, 613 insertions, 358 deletions
diff --git a/ext/bin/devcon/README.txt b/ext/bin/devcon/README.txt deleted file mode 100644 index 15cf1478..00000000 --- a/ext/bin/devcon/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -This is the Microsoft "devcon" utility, which as far as I know is -fair game to redistribute. It's packaged with OpenVPN and several -other things and also distributed in source code form as an example -program by Microsoft. - -It's called by zerotier-one.exe to automagically install and remove -instances of the tap device. diff --git a/ext/bin/devcon/devcon_x64.exe b/ext/bin/devcon/devcon_x64.exe Binary files differdeleted file mode 100644 index 5181aeb6..00000000 --- a/ext/bin/devcon/devcon_x64.exe +++ /dev/null diff --git a/ext/bin/devcon/devcon_x86.exe b/ext/bin/devcon/devcon_x86.exe Binary files differdeleted file mode 100644 index ce752b6e..00000000 --- a/ext/bin/devcon/devcon_x86.exe +++ /dev/null diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 8b26171c..6f98c32a 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -23,7 +23,7 @@ <ROW Property="CTRLS" Value="2"/> <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/> <ROW Property="Manufacturer" Value="ZeroTier, Inc."/> - <ROW Property="ProductCode" Value="1033:{04B3161E-427B-4C7D-B8FF-B38DE1DDC7F0} " Type="16"/> + <ROW Property="ProductCode" Value="1033:{6E2EC2C9-F3B2-474F-9176-54E029E0442F} " Type="16"/> <ROW Property="ProductLanguage" Value="1033"/> <ROW Property="ProductName" Value="ZeroTier One"/> <ROW Property="ProductVersion" Value="1.0.4" Type="32"/> @@ -62,8 +62,6 @@ <ROW Component="WdfCoinstaller01011.dll" ComponentId="{2E3DD7BE-00C0-44A1-ABA9-6F0468FC9EAA}" Directory_="x64_Dir" Attributes="256" Condition="VersionNT64" KeyPath="WdfCoinstaller01011.dll"/> <ROW Component="WdfCoinstaller01011.dll_1" ComponentId="{137E5A80-62C3-4B30-9900-131919675AC9}" Directory_="x86_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="WdfCoinstaller01011.dll_1"/> <ROW Component="ZeroTierOne.exe" ComponentId="{18B51525-77BF-4FD9-9C18-A10D4CFC25BA}" Directory_="APPDIR" Attributes="0" KeyPath="ZeroTierOne.exe"/> - <ROW Component="devcon_x64.exe" ComponentId="{0711ACF9-EEF5-48B0-95D7-8421B74AE314}" Directory_="One_Dir" Attributes="256" Condition="VersionNT64" KeyPath="devcon_x64.exe"/> - <ROW Component="devcon_x86.exe" ComponentId="{335F6945-AC5D-40DD-B671-C9BA9C304623}" Directory_="One_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="devcon_x86.exe"/> <ROW Component="index.html" ComponentId="{24AB46DC-56EA-4F3C-A8B7-95957509CDD1}" Directory_="ui_Dir" Attributes="0" KeyPath="index.html" Type="0"/> <ROW Component="networks.d" ComponentId="{EF54D0DF-889F-41DC-AF5C-4E7F96AB1C8B}" Directory_="networks.d_Dir" Attributes="0"/> <ROW Component="regid.201001.com.zerotier" ComponentId="{A39C80FC-6A8F-454F-9052-10DAC3C3B139}" Directory_="regid.201001.com.zerotier_Dir" Attributes="0"/> @@ -73,15 +71,13 @@ <ROW Component="zttap300.cat_1" ComponentId="{9F913E48-095B-4EA3-98DA-EDAB1593F3E3}" Directory_="x86_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zttap300.cat_3" Type="0"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent"> - <ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify ProductInformation WdfCoinstaller01011.dll WdfCoinstaller01011.dll_1 ZeroTierOne.exe devcon_x64.exe devcon_x86.exe index.html networks.d regid.201001.com.zerotier zerotierone_x64.exe zerotierone_x86.exe zttap300.cat zttap300.cat_1"/> + <ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="AI_CustomARPName AI_DisableModify ProductInformation WdfCoinstaller01011.dll WdfCoinstaller01011.dll_1 ZeroTierOne.exe index.html networks.d regid.201001.com.zerotier zerotierone_x64.exe zerotierone_x86.exe zttap300.cat zttap300.cat_1"/> <ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent"> <ROW File="WdfCoinstaller01011.dll" Component_="WdfCoinstaller01011.dll" FileName="WDFCOI~1.DLL|WdfCoinstaller01011.dll" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\WdfCoinstaller01011.dll" SelfReg="false" NextFile="WdfCoinstaller01011.dll_1"/> <ROW File="WdfCoinstaller01011.dll_1" Component_="WdfCoinstaller01011.dll_1" FileName="WDFCOI~1.DLL|WdfCoinstaller01011.dll" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\WdfCoinstaller01011.dll" SelfReg="false" NextFile="zttap300.cat_2"/> <ROW File="ZeroTierOne.exe" Component_="ZeroTierOne.exe" FileName="ZEROTI~1.EXE|ZeroTier One.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\win-ui-wrapper\ZeroTier One.exe" SelfReg="false" NextFile="WdfCoinstaller01011.dll"/> - <ROW File="devcon_x64.exe" Component_="devcon_x64.exe" FileName="DEVCON~1.EXE|devcon_x64.exe" Attributes="0" SourcePath="..\..\bin\devcon\devcon_x64.exe" SelfReg="false" NextFile="devcon_x86.exe"/> - <ROW File="devcon_x86.exe" Component_="devcon_x86.exe" FileName="DEVCON~2.EXE|devcon_x86.exe" Attributes="0" SourcePath="..\..\bin\devcon\devcon_x86.exe" SelfReg="false" NextFile="zerotierone_x86.exe"/> <ROW File="index.html" Component_="index.html" FileName="INDEX~1.HTM|index.html" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\index.html" SelfReg="false" NextFile="main.js"/> <ROW File="main.js" Component_="index.html" FileName="main.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\main.js" SelfReg="false" NextFile="react.min.js"/> <ROW File="react.min.js" Component_="index.html" FileName="REACTM~1.JS|react.min.js" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\ui\react.min.js" SelfReg="false" NextFile="simpleajax.min.js"/> @@ -105,8 +101,8 @@ <ATTRIBUTE name="Enable" value="false"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageComponent"> - <ROW ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Order="1" Options="108" InstallCondition="((NOT Installed) AND (VersionNT64))" RemoveCondition="((REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE) AND (VersionNT64))"/> - <ROW ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Order="2" Options="108" InstallCondition="((NOT Installed) AND (NOT VersionNT64))" RemoveCondition="((REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE) AND (NOT VersionNT64))"/> + <ROW ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Order="1" Options="108" InstallCondition="(VersionNT64)" RemoveCondition="((REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE) AND (VersionNT64))"/> + <ROW ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Order="2" Options="108" InstallCondition="(NOT VersionNT64)" RemoveCondition="((REMOVE="ALL") AND (NOT UPGRADINGPRODUCTCODE) AND (NOT VersionNT64))"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageFileComponent"> <ROW FileId="ZeroTierOne_NDIS6_x64.msi" ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Options="1" TargetPath="ZeroTierOne_NDIS6_x64.msi" Content="..\..\bin\tap-windows-ndis6\x64\ZeroTierOne_NDIS6_x64.msi"/> @@ -120,10 +116,7 @@ <ROW TimeStampUrl="http://timestamp.verisign.com/scripts/timstamp.dll" SignerDescription="ZeroTier One" DescriptionUrl="https://www.zerotier.com/" SignOptions="7" SignTool="0" Thumbprint="2ad023dc7aa92bf4265b33852a2ed2406d2bee86 Subject: ZeroTier Networks LLC Issuer: DigiCert High Assurance Code Signing CA-1 Valid from 04/24/2015 to 04/01/2016"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.FirewallExceptionComponent"> - <ROW FirewallException="ZeroTierOne" DisplayName="ZeroTier One (UDP_9993)" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="1" Profiles="7" Port="9993" Protocol="UDP"/> - <ROW FirewallException="ZeroTierOneService_x64" DisplayName="ZeroTier One (Service_x64)" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="((?zerotierone_x64.exe=2) AND ($zerotierone_x64.exe=3))" Profiles="7" AppPath="[#zerotierone_x64.exe]" Protocol="ANY"/> - <ROW FirewallException="ZeroTierOneService_x86" DisplayName="ZeroTier One (Service_x86)" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="((?zerotierone_x86.exe=2) AND ($zerotierone_x86.exe=3))" Profiles="7" AppPath="[#zerotierone_x86.exe]" Protocol="ANY"/> - <ROW FirewallException="ZeroTierOneTCP_9993" DisplayName="ZeroTier One (TCP_9993)" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="1" Profiles="7" Port="9993" Protocol="TCP"/> + <ROW FirewallException="ZeroTierOneUDP9993" DisplayName="ZeroTier One UDP/9993" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="1" Profiles="7" Port="9993" Protocol="UDP"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent"> <ROW Fragment="CommonUI.aip" Path="<AI_FRAGS>CommonUI.aip"/> @@ -202,16 +195,16 @@ <ROW Action="AI_CommitChainers" Type="11841" Source="chainersupport.dll" Target="CommitChainedPackages" WithoutSeq="true"/> <ROW Action="AI_DATA_SETTER" Type="51" Source="CustomActionData" Target="[~]"/> <ROW Action="AI_DATA_SETTER_1" Type="51" Source="CustomActionData" Target="[~]"/> + <ROW Action="AI_DATA_SETTER_2" Type="51" Source="CustomActionData" Target="[~]"/> <ROW Action="AI_DATA_SETTER_3" Type="51" Source="CustomActionData" Target="[~]"/> - <ROW Action="AI_DATA_SETTER_4" Type="51" Source="CustomActionData" Target="[~]"/> <ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/> <ROW Action="AI_DoRemoveExternalUIStub" Type="3585" Source="ExternalUICleaner.dll" Target="DoRemoveExternalUIStub" WithoutSeq="true"/> <ROW Action="AI_DpiContentScale" Type="1" Source="aicustact.dll" Target="DpiContentScale"/> <ROW Action="AI_FwConfig" Type="11265" Source="NetFirewall.dll" Target="OnFwConfig" WithoutSeq="true"/> - <ROW Action="AI_FwInstall" Type="1" Source="NetFirewall.dll" Target="OnFwInstall" AdditionalSeq="AI_DATA_SETTER_3"/> + <ROW Action="AI_FwInstall" Type="1" Source="NetFirewall.dll" Target="OnFwInstall" AdditionalSeq="AI_DATA_SETTER_2"/> <ROW Action="AI_FwRemove" Type="11265" Source="NetFirewall.dll" Target="OnFwRemove" WithoutSeq="true"/> <ROW Action="AI_FwRollback" Type="11521" Source="NetFirewall.dll" Target="OnFwRollback" WithoutSeq="true"/> - <ROW Action="AI_FwUninstall" Type="1" Source="NetFirewall.dll" Target="OnFwUninstall" AdditionalSeq="AI_DATA_SETTER_4"/> + <ROW Action="AI_FwUninstall" Type="1" Source="NetFirewall.dll" Target="OnFwUninstall" AdditionalSeq="AI_DATA_SETTER_3"/> <ROW Action="AI_GetArpIconPath" Type="1" Source="aicustact.dll" Target="GetArpIconPath"/> <ROW Action="AI_InstallModeCheck" Type="1" Source="aicustact.dll" Target="UpdateInstallMode" WithoutSeq="true"/> <ROW Action="AI_LaunchApp" Type="1" Source="aicustact.dll" Target="[#ZeroTierOne.exe]"/> @@ -234,10 +227,8 @@ <ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]" MultiBuildTarget="DefaultBuild:[ProgramFilesFolder]ZeroTier\One"/> <ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]" MultiBuildTarget="DefaultBuild:[ProgramMenuFolder]"/> <ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/> - <ROW Action="TapDeviceRemove32_NDIS5" Type="3154" Source="devcon_x86.exe" Target="remove zttap200"/> - <ROW Action="TapDeviceRemove32_NDIS6" Type="3154" Source="devcon_x86.exe" Target="remove zttap300"/> - <ROW Action="TapDeviceRemove64_NDIS5" Type="3154" Source="devcon_x64.exe" Target="remove zttap200"/> - <ROW Action="TapDeviceRemove64_NDIS6" Type="3154" Source="devcon_x64.exe" Target="remove zttap300"/> + <ROW Action="TapDeviceRemove32" Type="3154" Source="zerotierone_x86.exe" Target="-D"/> + <ROW Action="TapDeviceRemove64" Type="3154" Source="zerotierone_x64.exe" Target="-D"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiEmbeddedChainerComponent"> <ROW MsiEmbeddedChainer="msichainer.exe" Condition="VersionMsi >= "4.05"" CommandLine="[AI_CHAINER_CMD_LINE]" Source="msichainer.exe" Type="2"/> @@ -259,15 +250,13 @@ <ROW Action="InstallFinalize" Sequence="6596" SeqType="0" MsiKey="InstallFinalize"/> <ROW Action="AI_RemoveExternalUIStub" Condition="(REMOVE="ALL") AND ((VersionNT > 500) OR((VersionNT = 500) AND (ServicePackLevel >= 4)))" Sequence="1501"/> <ROW Action="AI_GetArpIconPath" Sequence="1401"/> - <ROW Action="TapDeviceRemove32_NDIS6" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1602"/> - <ROW Action="TapDeviceRemove64_NDIS6" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( VersionNT64 )" Sequence="1604"/> - <ROW Action="TapDeviceRemove32_NDIS5" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1601"/> - <ROW Action="TapDeviceRemove64_NDIS5" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( VersionNT64 )" Sequence="1603"/> + <ROW Action="TapDeviceRemove32" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1601"/> + <ROW Action="TapDeviceRemove64" Condition="( Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE ) AND ( VersionNT64 )" Sequence="1602"/> <ROW Action="AI_PrepareChainers" Condition="VersionMsi >= "4.05"" Sequence="5851"/> <ROW Action="AI_FwInstall" Condition="(VersionNT >= 501) AND (REMOVE <> "ALL")" Sequence="5802"/> - <ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT >= 501) AND (REMOVE <> "ALL")" Sequence="5801"/> + <ROW Action="AI_DATA_SETTER_2" Condition="(VersionNT >= 501) AND (REMOVE <> "ALL")" Sequence="5801"/> <ROW Action="AI_FwUninstall" Condition="(VersionNT >= 501) AND (REMOVE="ALL")" Sequence="1702"/> - <ROW Action="AI_DATA_SETTER_4" Condition="(VersionNT >= 501) AND (REMOVE="ALL")" Sequence="1701"/> + <ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT >= 501) AND (REMOVE="ALL")" Sequence="1701"/> </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent"> <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=""" Sequence="749"/> @@ -306,6 +295,14 @@ <ROW Registry="VersionMajor" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="VersionMajor" Value="#0" Component_="AI_CustomARPName"/> <ROW Registry="VersionMinor" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="VersionMinor" Value="#7" Component_="AI_CustomARPName"/> </COMPONENT> + <COMPONENT cid="caphyon.advinst.msicomp.MsiRemoveFileComponent"> + <ROW FileKey="devcon.log" Component_="ProductInformation" FileName="devcon.log" DirProperty="One_Dir" InstallMode="3"/> + <ROW FileKey="devcon_x64.exe" Component_="ProductInformation" FileName="devcon_x64.exe" DirProperty="One_Dir" InstallMode="3"/> + <ROW FileKey="devcon_x86.exe" Component_="ProductInformation" FileName="devcon_x86.exe" DirProperty="One_Dir" InstallMode="3"/> + <ROW FileKey="node.log" Component_="ProductInformation" FileName="node.log" DirProperty="One_Dir" InstallMode="3"/> + <ROW FileKey="node.log.old" Component_="ProductInformation" FileName="node.log.old" DirProperty="One_Dir" InstallMode="3"/> + <ROW FileKey="roottopology" Component_="ProductInformation" FileName="root-topology" DirProperty="One_Dir" InstallMode="3"/> + </COMPONENT> <COMPONENT cid="caphyon.advinst.msicomp.MsiServCtrlComponent"> <ROW ServiceControl="zerotierone_x64.exe" Name="ZeroTierOneService" Event="163" Wait="1" Component_="zerotierone_x64.exe"/> <ROW ServiceControl="zerotierone_x86.exe" Name="ZeroTierOneService" Event="163" Wait="1" Component_="zerotierone_x86.exe"/> diff --git a/node/Network.cpp b/node/Network.cpp index 549219d7..39042fab 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -533,7 +533,7 @@ public: inline void operator()(Topology &t,const SharedPtr<Peer> &p) { - if ( ( (p->hasActiveDirectPath(_now)) && (_network->_isAllowed(p->address())) ) || (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ) { + if ( ( (p->hasActiveDirectPath(_now)) && ( (_network->_isAllowed(p->address())) || (p->address() == _network->controller()) ) ) || (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ) { Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); for(std::vector<MulticastGroup>::iterator mg(_allMulticastGroups.begin());mg!=_allMulticastGroups.end();++mg) { diff --git a/node/Node.hpp b/node/Node.hpp index 0e966aa6..2a283eab 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -248,9 +248,6 @@ private: ZT1_VirtualNetworkConfigFunction _virtualNetworkConfigFunction; ZT1_EventCallback _eventCallback; - //Dictionary _localConfig; // persisted as local.conf - //Mutex _localConfig_m; - std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks; Mutex _networks_m; diff --git a/node/Peer.cpp b/node/Peer.cpp index 3cf0ec4e..c27afa8f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -133,7 +133,7 @@ void Peer::received( Packet outp(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); const std::vector< SharedPtr<Network> > networks(RR->node->allNetworks()); for(std::vector< SharedPtr<Network> >::const_iterator n(networks.begin());n!=networks.end();++n) { - if ( (isRoot) || ((*n)->isAllowed(_id.address())) ) { + if ( (isRoot) || ((*n)->isAllowed(_id.address())) || (_id.address() == (*n)->controller()) ) { const std::vector<MulticastGroup> mgs((*n)->allMulticastGroups()); for(std::vector<MulticastGroup>::const_iterator mg(mgs.begin());mg!=mgs.end();++mg) { if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) { @@ -211,7 +211,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &at void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) { RemotePath *const bestPath = getBestPath(now); - if ((bestPath)&&(bestPath->active(now))) { + if (bestPath) { if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str()); attemptToContactAt(RR,bestPath->address(),now); @@ -239,7 +239,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ ps.push_back(','); ps.append(p->address().toString()); } - TRACE("pushing %u direct paths (local interface addresses) to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str()); + TRACE("pushing %u direct paths to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str()); } #endif @@ -42,6 +42,7 @@ #include <lmcons.h> #include <newdev.h> #include <atlbase.h> +#include "osdep/WindowsEthernetTap.hpp" #include "windows/ZeroTierOne/ServiceInstaller.h" #include "windows/ZeroTierOne/ServiceBase.h" #include "windows/ZeroTierOne/ZeroTierOneService.h" @@ -765,8 +766,6 @@ static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType) return FALSE; } -// Pokes a hole in the Windows firewall (advfirewall) for the running program -/* -- now done by Advanced Installer static void _winPokeAHole() { char myPath[MAX_PATH]; @@ -778,7 +777,7 @@ static void _winPokeAHole() startupInfo.cb = sizeof(startupInfo); memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall delete rule name=\"ZeroTier One\" program=\"") + myPath + "\"").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall delete rule name=\"ZeroTier One\" program=\"") + myPath + "\"").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); @@ -787,7 +786,7 @@ static void _winPokeAHole() startupInfo.cb = sizeof(startupInfo); memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=in action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=in action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); @@ -796,14 +795,13 @@ static void _winPokeAHole() startupInfo.cb = sizeof(startupInfo); memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=out action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=out action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } } } -*/ // Returns true if this is running as the local administrator static BOOL IsCurrentUserLocalAdministrator(void) @@ -906,7 +904,7 @@ static void printHelp(const char *cn,FILE *out) fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S); std::string updateUrl(OneService::autoUpdateUrl()); if (updateUrl.length()) - fprintf(out,"Automatic update enabled:"ZT_EOL_S" %s"ZT_EOL_S""ZT_EOL_S,updateUrl.c_str()); + fprintf(out,"Automatic updates enabled:"ZT_EOL_S" %s"ZT_EOL_S" (all updates are securely authenticated by 256-bit ECDSA signature)"ZT_EOL_S""ZT_EOL_S,updateUrl.c_str()); fprintf(out,"Usage: %s [-switches] [home directory]"ZT_EOL_S""ZT_EOL_S,cn); fprintf(out,"Available switches:"ZT_EOL_S); fprintf(out," -h - Display this help"ZT_EOL_S); @@ -914,17 +912,20 @@ static void printHelp(const char *cn,FILE *out) fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S); fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993)"ZT_EOL_S); //fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S); + #ifdef __UNIX_LIKE__ fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S); #endif // __UNIX_LIKE__ - fprintf(out," -i - Generate and manage identities (zerotier-idtool)"ZT_EOL_S); - fprintf(out," -q - Query API (zerotier-cli)"ZT_EOL_S); + #ifdef __WINDOWS__ fprintf(out," -C - Run from command line instead of as service (Windows)"ZT_EOL_S); fprintf(out," -I - Install Windows service (Windows)"ZT_EOL_S); fprintf(out," -R - Uninstall Windows service (Windows)"ZT_EOL_S); - fprintf(out," -D - Load tap driver into system driver store (Windows)"ZT_EOL_S); + fprintf(out," -D - Remove all instances of Windows tap device (Windows)"ZT_EOL_S); #endif // __WINDOWS__ + + fprintf(out," -i - Generate and manage identities (zerotier-idtool)"ZT_EOL_S); + fprintf(out," -q - Query API (zerotier-cli)"ZT_EOL_S); } #ifdef __WINDOWS__ @@ -1059,26 +1060,15 @@ int main(int argc,char **argv) return 0; } break; -#if 0 - case 'D': { // Install Windows driver (since PNPUTIL.EXE seems to be weirdly unreliable) - std::string pathToInf; -#ifdef _WIN64 - pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x64\\zttap200.inf"; -#else - pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x86\\zttap200.inf"; -#endif - printf("Installing ZeroTier One virtual Ethernet port driver."ZT_EOL_S""ZT_EOL_S"NOTE: If you don't see a confirmation window to allow driver installation,"ZT_EOL_S"check to make sure it didn't appear under the installer."ZT_EOL_S); - BOOL needReboot = FALSE; - if (DiInstallDriverA(NULL,pathToInf.c_str(),DIIRFLAG_FORCE_INF,&needReboot)) { - printf("%s: driver successfully installed from %s"ZT_EOL_S,argv[0],pathToInf.c_str()); - return 0; - } else { - printf("%s: failed installing %s: %d"ZT_EOL_S,argv[0],pathToInf.c_str(),(int)GetLastError()); + case 'D': { + std::string err = WindowsEthernetTap::destroyAllPersistentTapDevices(); + if (err.length() > 0) { + fprintf(stderr,"%s: unable to uninstall one or more persistent tap devices: %s"ZT_EOL_S,argv[0],err.c_str()); return 3; } + return 0; } break; #endif // __WINDOWS__ -#endif case 'h': case '?': @@ -1134,6 +1124,10 @@ int main(int argc,char **argv) #endif // __UNIX_LIKE__ #ifdef __WINDOWS__ + // Uninstall legacy tap devices. New devices will automatically be installed and configured + // when tap instances are created. + WindowsEthernetTap::destroyAllLegacyPersistentTapDevices(); + if (winRunFromCommandLine) { // Running in "interactive" mode (mostly for debugging) if (IsCurrentUserLocalAdministrator() != TRUE) { @@ -1142,13 +1136,13 @@ int main(int argc,char **argv) return 1; } } else { - //_winPokeAHole(); + _winPokeAHole(); } SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE); // continues on to ordinary command line execution code below... } else { // Running from service manager - //_winPokeAHole(); + _winPokeAHole(); ZeroTierOneService zt1Service; if (CServiceBase::Run(zt1Service) == TRUE) { return 0; diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 0ff7bfc4..45fbf100 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -125,7 +125,7 @@ void OSUtils::lockDownFile(const char *path,bool isDir) startupInfo.cb = sizeof(startupInfo); memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); @@ -134,7 +134,7 @@ void OSUtils::lockDownFile(const char *path,bool isDir) startupInfo.cb = sizeof(startupInfo); memset(&startupInfo,0,sizeof(STARTUPINFOA)); memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { + if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { WaitForSingleObject(processInfo.hProcess,INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index b2d3ed8b..c6b434e1 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -32,6 +32,7 @@ #include <WinSock2.h> #include <Windows.h> #include <tchar.h> +#include <malloc.h> #include <winreg.h> #include <wchar.h> #include <ws2ipdef.h> @@ -42,6 +43,9 @@ #include <atlbase.h> #include <netlistmgr.h> #include <nldef.h> +#include <SetupAPI.h> +#include <newdev.h> +#include <cfgmgr32.h> #include <iostream> #include <set> @@ -55,15 +59,28 @@ #include "..\windows\TapDriver6\tap-windows.h" -// ff:ff:ff:ff:ff:ff with no ADI -//static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - +// Create a fake unused default route to force detection of network type on networks without gateways #define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE +// Function signatures of dynamically loaded functions, from newdev.h, setupapi.h, and cfgmgr32.h +typedef BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesA_t)(_In_opt_ HWND hwndParent,_In_ LPCSTR HardwareId,_In_ LPCSTR FullInfPath,_In_ DWORD InstallFlags,_Out_opt_ PBOOL bRebootRequired); +typedef BOOL (WINAPI *SetupDiGetINFClassA_t)(_In_ PCSTR InfName,_Out_ LPGUID ClassGuid,_Out_writes_(ClassNameSize) PSTR ClassName,_In_ DWORD ClassNameSize,_Out_opt_ PDWORD RequiredSize); +typedef HDEVINFO (WINAPI *SetupDiCreateDeviceInfoList_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ HWND hwndParent); +typedef BOOL (WINAPI *SetupDiCreateDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceName,_In_ CONST GUID *ClassGuid,_In_opt_ PCSTR DeviceDescription,_In_opt_ HWND hwndParent,_In_ DWORD CreationFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL (WINAPI *SetupDiSetDeviceRegistryPropertyA_t)(_In_ HDEVINFO DeviceInfoSet,_Inout_ PSP_DEVINFO_DATA DeviceInfoData,_In_ DWORD Property,_In_reads_bytes_opt_(PropertyBufferSize) CONST BYTE *PropertyBuffer,_In_ DWORD PropertyBufferSize); +typedef BOOL (WINAPI *SetupDiCallClassInstaller_t)(_In_ DI_FUNCTION InstallFunction,_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL (WINAPI *SetupDiDestroyDeviceInfoList_t)(_In_ HDEVINFO DeviceInfoSet); +typedef HDEVINFO (WINAPI *SetupDiGetClassDevsExA_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ PCSTR Enumerator,_In_opt_ HWND hwndParent,_In_ DWORD Flags,_In_opt_ HDEVINFO DeviceInfoSet,_In_opt_ PCSTR MachineName,_Reserved_ PVOID Reserved); +typedef BOOL (WINAPI *SetupDiOpenDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceInstanceId,_In_opt_ HWND hwndParent,_In_ DWORD OpenFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL (WINAPI *SetupDiEnumDeviceInfo_t)(_In_ HDEVINFO DeviceInfoSet,_In_ DWORD MemberIndex,_Out_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL (WINAPI *SetupDiSetClassInstallParamsA_t)(_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData,_In_reads_bytes_opt_(ClassInstallParamsSize) PSP_CLASSINSTALL_HEADER ClassInstallParams,_In_ DWORD ClassInstallParamsSize); +typedef CONFIGRET (WINAPI *CM_Get_Device_ID_ExA_t)(_In_ DEVINST dnDevInst,_Out_writes_(BufferLen) PSTR Buffer,_In_ ULONG BufferLen,_In_ ULONG ulFlags,_In_opt_ HMACHINE hMachine); + namespace ZeroTier { namespace { +// Static/singleton class that when initialized loads a bunch of environment information and a few dynamically loaded DLLs class WindowsEthernetTapEnv { public: @@ -71,29 +88,364 @@ public: { #ifdef _WIN64 is64Bit = TRUE; - devcon = "\\devcon_x64.exe"; - tapDriverNdis5 = "\\tap-windows\\x64\\zttap200.inf"; - tapDriverNdis6 = "\\tap-windows\\x64\\zttap300.inf"; + tapDriverPath = "\\tap-windows\\x64\\zttap300.inf"; #else is64Bit = FALSE; IsWow64Process(GetCurrentProcess(),&is64Bit); - devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe"); - tapDriverNdis5 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf"); - tapDriverNdis6 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap300.inf" : "\\tap-windows\\x86\\zttap300.inf"); + if (is64Bit) { + fprintf(stderr,"FATAL: you must use the 64-bit ZeroTier One service on 64-bit Windows systems\r\n"); + _exit(1); + } + tapDriverPath = "\\tap-windows\\x86\\zttap300.inf"; #endif + tapDriverName = "zttap300"; + + setupApiMod = LoadLibraryA("setupapi.dll"); + if (!setupApiMod) { + fprintf(stderr,"FATAL: unable to dynamically load setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiGetINFClassA = (SetupDiGetINFClassA_t)GetProcAddress(setupApiMod,"SetupDiGetINFClassA"))) { + fprintf(stderr,"FATAL: SetupDiGetINFClassA not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiCreateDeviceInfoList = (SetupDiCreateDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoList"))) { + fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoList not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiCreateDeviceInfoA = (SetupDiCreateDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoA"))) { + fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoA not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiSetDeviceRegistryPropertyA = (SetupDiSetDeviceRegistryPropertyA_t)GetProcAddress(setupApiMod,"SetupDiSetDeviceRegistryPropertyA"))) { + fprintf(stderr,"FATAL: SetupDiSetDeviceRegistryPropertyA not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiCallClassInstaller = (SetupDiCallClassInstaller_t)GetProcAddress(setupApiMod,"SetupDiCallClassInstaller"))) { + fprintf(stderr,"FATAL: SetupDiCallClassInstaller not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiDestroyDeviceInfoList"))) { + fprintf(stderr,"FATAL: SetupDiDestroyDeviceInfoList not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiGetClassDevsExA = (SetupDiGetClassDevsExA_t)GetProcAddress(setupApiMod,"SetupDiGetClassDevsExA"))) { + fprintf(stderr,"FATAL: SetupDiGetClassDevsExA not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiOpenDeviceInfoA = (SetupDiOpenDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiOpenDeviceInfoA"))) { + fprintf(stderr,"FATAL: SetupDiOpenDeviceInfoA not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfo_t)GetProcAddress(setupApiMod,"SetupDiEnumDeviceInfo"))) { + fprintf(stderr,"FATAL: SetupDiEnumDeviceInfo not found in setupapi.dll\r\n"); + _exit(1); + } + if (!(this->SetupDiSetClassInstallParamsA = (SetupDiSetClassInstallParamsA_t)GetProcAddress(setupApiMod,"SetupDiSetClassInstallParamsA"))) { + fprintf(stderr,"FATAL: SetupDiSetClassInstallParamsA not found in setupapi.dll\r\n"); + _exit(1); + } + + newDevMod = LoadLibraryA("newdev.dll"); + if (!newDevMod) { + fprintf(stderr,"FATAL: unable to dynamically load newdev.dll\r\n"); + _exit(1); + } + if (!(this->UpdateDriverForPlugAndPlayDevicesA = (UpdateDriverForPlugAndPlayDevicesA_t)GetProcAddress(newDevMod,"UpdateDriverForPlugAndPlayDevicesA"))) { + fprintf(stderr,"FATAL: UpdateDriverForPlugAndPlayDevicesA not found in newdev.dll\r\n"); + _exit(1); + } + + cfgMgrMod = LoadLibraryA("cfgmgr32.dll"); + if (!cfgMgrMod) { + fprintf(stderr,"FATAL: unable to dynamically load cfgmgr32.dll\r\n"); + _exit(1); + } + if (!(this->CM_Get_Device_ID_ExA = (CM_Get_Device_ID_ExA_t)GetProcAddress(cfgMgrMod,"CM_Get_Device_ID_ExA"))) { + fprintf(stderr,"FATAL: CM_Get_Device_ID_ExA not found in cfgmgr32.dll\r\n"); + _exit(1); + } } - BOOL is64Bit; - const char *devcon; - const char *tapDriverNdis5; - const char *tapDriverNdis6; + + BOOL is64Bit; // is the system 64-bit, regardless of whether this binary is or not + std::string tapDriverPath; + std::string tapDriverName; + + UpdateDriverForPlugAndPlayDevicesA_t UpdateDriverForPlugAndPlayDevicesA; + + SetupDiGetINFClassA_t SetupDiGetINFClassA; + SetupDiCreateDeviceInfoList_t SetupDiCreateDeviceInfoList; + SetupDiCreateDeviceInfoA_t SetupDiCreateDeviceInfoA; + SetupDiSetDeviceRegistryPropertyA_t SetupDiSetDeviceRegistryPropertyA; + SetupDiCallClassInstaller_t SetupDiCallClassInstaller; + SetupDiDestroyDeviceInfoList_t SetupDiDestroyDeviceInfoList; + SetupDiGetClassDevsExA_t SetupDiGetClassDevsExA; + SetupDiOpenDeviceInfoA_t SetupDiOpenDeviceInfoA; + SetupDiEnumDeviceInfo_t SetupDiEnumDeviceInfo; + SetupDiSetClassInstallParamsA_t SetupDiSetClassInstallParamsA; + + CM_Get_Device_ID_ExA_t CM_Get_Device_ID_ExA; + +private: + HMODULE setupApiMod; + HMODULE newDevMod; + HMODULE cfgMgrMod; }; static const WindowsEthernetTapEnv WINENV; // Only create or delete devices one at a time static Mutex _systemTapInitLock; +// Only perform installation or uninstallation options one at a time +static Mutex _systemDeviceManagementLock; + } // anonymous namespace +std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf) +{ + Mutex::Lock _l(_systemDeviceManagementLock); + + GUID classGuid; + char className[4096]; + if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) { + return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file"); + } + + HDEVINFO deviceInfoSet = WINENV.SetupDiCreateDeviceInfoList(&classGuid,(HWND)0); + if (deviceInfoSet == INVALID_HANDLE_VALUE) { + return std::string("SetupDiCreateDeviceInfoList() failed"); + } + + SP_DEVINFO_DATA deviceInfoData; + memset(&deviceInfoData,0,sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + if (!WINENV.SetupDiCreateDeviceInfoA(deviceInfoSet,className,&classGuid,(PCSTR)0,(HWND)0,DICD_GENERATE_ID,&deviceInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiCreateDeviceInfoA() failed"); + } + + if (!WINENV.SetupDiSetDeviceRegistryPropertyA(deviceInfoSet,&deviceInfoData,SPDRP_HARDWAREID,(const BYTE *)WINENV.tapDriverName.c_str(),(DWORD)(WINENV.tapDriverName.length() + 1))) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiSetDeviceRegistryPropertyA() failed"); + } + + if (!WINENV.SetupDiCallClassInstaller(DIF_REGISTERDEVICE,deviceInfoSet,&deviceInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed"); + } + + // HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts + // with a 1s delay between each attempt. + bool driverInstalled = false; + for(int retryCounter=0;retryCounter<60;++retryCounter) { + BOOL rebootRequired = FALSE; + if (WINENV.UpdateDriverForPlugAndPlayDevicesA((HWND)0,WINENV.tapDriverName.c_str(),pathToInf,INSTALLFLAG_FORCE|INSTALLFLAG_NONINTERACTIVE,&rebootRequired)) { + driverInstalled = true; + break; + } else Sleep(1000); + } + if (!driverInstalled) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts)"); + } + + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + + return std::string(); +} + +std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices() +{ + char subkeyName[4096]; + char subkeyClass[4096]; + char data[4096]; + + std::set<std::string> instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) + return std::string("Could not open registry key"); + + for(DWORD subkeyIndex=0;;++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + + if ((!strnicmp(data,"zttap",5))&&(WINENV.tapDriverName != data)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data,dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } else break; // end of list or failure + } + + RegCloseKey(nwAdapters); + } + + std::string errlist; + for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { + std::string err = deletePersistentTapDevice(iidp->c_str()); + if (err.length() > 0) { + if (errlist.length() > 0) + errlist.push_back(','); + errlist.append(err); + } + } + return errlist; +} + +std::string WindowsEthernetTap::destroyAllPersistentTapDevices() +{ + char subkeyName[4096]; + char subkeyClass[4096]; + char data[4096]; + + std::set<std::string> instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) + return std::string("Could not open registry key"); + + for(DWORD subkeyIndex=0;;++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + + if (!strnicmp(data,"zttap",5)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data,dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } else break; // end of list or failure + } + + RegCloseKey(nwAdapters); + } + + std::string errlist; + for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { + std::string err = deletePersistentTapDevice(iidp->c_str()); + if (err.length() > 0) { + if (errlist.length() > 0) + errlist.push_back(','); + errlist.append(err); + } + } + return errlist; +} + +std::string WindowsEthernetTap::deletePersistentTapDevice(const char *instanceId) +{ + char iid[256]; + SP_REMOVEDEVICE_PARAMS rmdParams; + + memset(&rmdParams,0,sizeof(rmdParams)); + rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; + rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; + rmdParams.HwProfile = 0; + + Mutex::Lock _l(_systemDeviceManagementLock); + + HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); + if (devInfo == INVALID_HANDLE_VALUE) + return std::string("SetupDiGetClassDevsExA() failed"); + WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); + + SP_DEVINFO_DATA devInfoData; + memset(&devInfoData,0,sizeof(devInfoData)); + devInfoData.cbSize = sizeof(devInfoData); + for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { + if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { + if (!WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams))) { + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("SetupDiSetClassInstallParams() failed"); + } + + if (!WINENV.SetupDiCallClassInstaller(DIF_REMOVE,devInfo,&devInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("SetupDiCallClassInstaller(DIF_REMOVE) failed"); + } + + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string(); + } + } + + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("instance ID not found"); +} + +bool WindowsEthernetTap::setPersistentTapDeviceState(const char *instanceId,bool enabled) +{ + char iid[256]; + SP_PROPCHANGE_PARAMS params; + + Mutex::Lock _l(_systemDeviceManagementLock); + + HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); + if (devInfo == INVALID_HANDLE_VALUE) + return false; + WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); + + SP_DEVINFO_DATA devInfoData; + memset(&devInfoData,0,sizeof(devInfoData)); + devInfoData.cbSize = sizeof(devInfoData); + for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { + if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { + memset(¶ms,0,sizeof(params)); + params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; + params.Scope = DICS_FLAG_GLOBAL; + params.HwProfile = 0; + + WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); + WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); + + memset(¶ms,0,sizeof(params)); + params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; + params.Scope = DICS_FLAG_CONFIGSPECIFIC; + params.HwProfile = 0; + + WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); + WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); + + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return true; + } + } + + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return false; +} + WindowsEthernetTap::WindowsEthernetTap( const char *hp, const MAC &mac, @@ -118,35 +470,20 @@ WindowsEthernetTap::WindowsEthernetTap( char subkeyClass[4096]; char data[4096]; char tag[24]; + std::string mySubkeyName; if (mtu > 2800) throw std::runtime_error("MTU too large for Windows tap"); - Mutex::Lock _l(_systemTapInitLock); + // We "tag" registry entries with the network ID to identify persistent devices + Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); - // Use NDIS5 if it's installed, since we don't want to switch out the driver on - // pre-existing installs (yet). We won't ship NDIS5 anymore so new installs will - // use NDIS6. - std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis5); - const char *tapDriverName = "zttap200"; - if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { - tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis6; - tapDriverName = "zttap300"; - if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) { - throw std::runtime_error("no tap driver available: cannot find zttap300.inf (NDIS6) or zttap200.inf (NDIS5) under home path"); - } - } + Mutex::Lock _l(_systemTapInitLock); HKEY nwAdapters; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) throw std::runtime_error("unable to open registry key for network adapter enumeration"); - std::set<std::string> existingDeviceInstances; - std::string mySubkeyName; - - // We "tag" registry entries with the network ID to identify persistent devices - Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); - // Look for the tap instance that corresponds with this network for(DWORD subkeyIndex=0;;++subkeyIndex) { DWORD type; @@ -158,15 +495,14 @@ WindowsEthernetTap::WindowsEthernetTap( type = 0; dataLen = sizeof(data); if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strnicmp(data,"zttap",5)) { + data[dataLen] = (char)0; + + if (WINENV.tapDriverName == data) { std::string instanceId; type = 0; dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) instanceId.assign(data,dataLen); - existingDeviceInstances.insert(instanceId); - } std::string instanceIdPath; type = 0; @@ -196,74 +532,61 @@ WindowsEthernetTap::WindowsEthernetTap( // If there is no device, try to create one bool creatingNewDevice = (_netCfgInstanceId.length() == 0); if (creatingNewDevice) { - // Log devcon output to a file - HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (devconLog != INVALID_HANDLE_VALUE) - SetFilePointer(devconLog,0,0,FILE_END); - - // Execute devcon to create a new tap device - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - SetFilePointer(devconLog,0,0,FILE_END); - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + tapDriverPath + "\" " + tapDriverName).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - RegCloseKey(nwAdapters); - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - throw std::runtime_error(std::string("unable to find or execute devcon at ") + WINENV.devcon); - } - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - - // Scan for the new instance by simply looking for taps that weren't originally there... - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strnicmp(data,"zttap",5)) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - if (existingDeviceInstances.count(std::string(data,dataLen)) == 0) { - RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1)); - _netCfgInstanceId.assign(data,dataLen); + for(int getNewAttemptCounter=0;getNewAttemptCounter<2;++getNewAttemptCounter) { + for(DWORD subkeyIndex=0;;++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + + if (WINENV.tapDriverName == data) { + type = 0; + dataLen = sizeof(data); + if ((RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) != ERROR_SUCCESS)||(dataLen <= 0)) { type = 0; dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - _deviceInstanceId.assign(data,dataLen); - mySubkeyName = subkeyName; + if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { + RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1)); - // 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,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); - RegCloseKey(tcpIpInterfaces); - } + _netCfgInstanceId.assign(data,dataLen); - break; // found it! + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) + _deviceInstanceId.assign(data,dataLen); + + mySubkeyName = subkeyName; + + // Disable DHCP by default on new 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,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); + RegCloseKey(tcpIpInterfaces); + } + + break; // found an unused zttap device + } } } } - } - } else break; // no more keys or error occurred + } else break; // no more keys or error occurred + } + + if (_netCfgInstanceId.length() > 0) { + break; // found an unused zttap device + } else { + // no unused zttap devices, so create one + std::string errm = addNewPersistentTapDevice((std::string(_pathToHelpers) + WINENV.tapDriverPath).c_str()); + if (errm.length() > 0) + throw std::runtime_error(std::string("unable to create new device instance: ")+errm); + } } } @@ -281,6 +604,7 @@ WindowsEthernetTap::WindowsEthernetTap( RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); if (creatingNewDevice) { + // Set EnableDHCP to 0 by default on new devices tmp = 0; RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); } @@ -291,7 +615,7 @@ WindowsEthernetTap::WindowsEthernetTap( } { - char nobraces[128]; + char nobraces[128]; // strip braces from GUID before converting it, because Windows const char *nbtmp1 = _netCfgInstanceId.c_str(); char *nbtmp2 = nobraces; while (*nbtmp1) { @@ -304,17 +628,15 @@ WindowsEthernetTap::WindowsEthernetTap( throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)"); } - // Look up interface LUID... why are there (at least) four fucking ways to refer to a network device in Windows? + // Get the LUID, which is one of like four fucking ways to refer to a network device in Windows if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR) throw std::runtime_error("unable to convert device interface GUID to LUID"); - // Certain functions can now work (e.g. ips()) _initialized = true; if (friendlyName) setFriendlyName(friendlyName); - // Start background thread that actually performs I/O _injectSemaphore = CreateSemaphore(NULL,0,1,NULL); _thread = Thread::start(this); } @@ -325,7 +647,7 @@ WindowsEthernetTap::~WindowsEthernetTap() ReleaseSemaphore(_injectSemaphore,1,NULL); Thread::join(_thread); CloseHandle(_injectSemaphore); - _disableTapDevice(); + setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); } void WindowsEthernetTap::setEnabled(bool en) @@ -340,63 +662,28 @@ bool WindowsEthernetTap::enabled() const bool WindowsEthernetTap::addIp(const InetAddress &ip) { - if (!_initialized) - return false; if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? return false; - - std::vector<InetAddress> haveIps(ips()); - - try { - // Add IP to interface at the netlink level if not already assigned. - if (!std::binary_search(haveIps.begin(),haveIps.end(),ip)) { - 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(); - if (ipr.OnLinkPrefixLength >= 32) - return false; - } else if (ip.isV6()) { - ipr.Address.Ipv6.sin6_family = AF_INET6; - memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,ip.rawIpData(),16); - ipr.OnLinkPrefixLength = ip.port(); - if (ipr.OnLinkPrefixLength >= 128) - return false; - } else return false; - - ipr.PrefixOrigin = IpPrefixOriginManual; - ipr.SuffixOrigin = IpSuffixOriginManual; - ipr.ValidLifetime = 0xffffffff; - ipr.PreferredLifetime = 0xffffffff; - - ipr.InterfaceLuid = _deviceLuid; - ipr.InterfaceIndex = _getDeviceIndex(); - - if (CreateUnicastIpAddressEntry(&ipr) != NO_ERROR) - return false; - } - - std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress")); - if (std::find(regIps.begin(),regIps.end(),ip.toIpString()) == regIps.end()) { - std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); - regIps.push_back(ip.toIpString()); - regSubnetMasks.push_back(ip.netmask().toIpString()); - _setRegistryIPv4Value("IPAddress",regIps); - _setRegistryIPv4Value("SubnetMask",regSubnetMasks); - } - } catch ( ... ) { - return false; - } + Mutex::Lock _l(_assignedIps_m); + if (std::find(_assignedIps.begin(),_assignedIps.end(),ip) != _assignedIps.end()) + return true; + _assignedIps.push_back(ip); + _syncIps(); return true; } bool WindowsEthernetTap::removeIp(const InetAddress &ip) { + { + Mutex::Lock _l(_assignedIps_m); + std::vector<InetAddress>::iterator aip(std::find(_assignedIps.begin(),_assignedIps.end(),ip)); + if (aip != _assignedIps.end()) + _assignedIps.erase(aip); + } + if (!_initialized) return false; + try { MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0; if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) { @@ -572,13 +859,18 @@ void WindowsEthernetTap::threadMain() try { while (_run) { - _enableTapDevice(); + // Because Windows + setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); + Sleep(500); + setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); + Sleep(500); + setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); + Sleep(500); + setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); Sleep(500); _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL); if (_tap == INVALID_HANDLE_VALUE) { - _disableTapDevice(); - _enableTapDevice(); Sleep(1000); continue; } @@ -668,6 +960,12 @@ void WindowsEthernetTap::threadMain() } #endif + // Assign or re-assign any should-be-assigned IPs in case we have restarted + { + Mutex::Lock _l(_assignedIps_m); + _syncIps(); + } + memset(&tapOvlRead,0,sizeof(tapOvlRead)); tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); memset(&tapOvlWrite,0,sizeof(tapOvlWrite)); @@ -761,131 +1059,6 @@ void WindowsEthernetTap::threadMain() } catch ( ... ) {} // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw } -void WindowsEthernetTap::destroyAllPersistentTapDevices(const char *pathToHelpers) -{ - char subkeyName[4096]; - char subkeyClass[4096]; - char data[4096]; - - std::set<std::string> instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return; - - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strnicmp(data,"zttap",5)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } - - RegCloseKey(nwAdapters); - } - - for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) - deletePersistentTapDevice(pathToHelpers,iidp->c_str()); -} - -void WindowsEthernetTap::deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId) -{ - HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - SetFilePointer(devconLog,0,0,FILE_END); - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); -} - -bool WindowsEthernetTap::_disableTapDevice() -{ - HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (devconLog != INVALID_HANDLE_VALUE) - SetFilePointer(devconLog,0,0,FILE_END); - - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" disable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - return false; - } - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - - return true; -} - -bool WindowsEthernetTap::_enableTapDevice() -{ - HANDLE devconLog = CreateFileA((_pathToHelpers + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); - if (devconLog != INVALID_HANDLE_VALUE) - SetFilePointer(devconLog,0,0,FILE_END); - - STARTUPINFOA startupInfo; - startupInfo.cb = sizeof(startupInfo); - if (devconLog != INVALID_HANDLE_VALUE) { - startupInfo.hStdOutput = devconLog; - startupInfo.hStdError = devconLog; - } - PROCESS_INFORMATION processInfo; - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" enable @" + _deviceInstanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) { - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - return false; - } - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - - if (devconLog != INVALID_HANDLE_VALUE) - CloseHandle(devconLog); - - return true; -} - NET_IFINDEX WindowsEthernetTap::_getDeviceIndex() { MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0; @@ -956,4 +1129,55 @@ void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vec } } +void WindowsEthernetTap::_syncIps() +{ + // assumes _assignedIps_m is locked + + if (!_initialized) + return; + + std::vector<InetAddress> haveIps(ips()); + + for(std::vector<InetAddress>::const_iterator aip(_assignedIps.begin());aip!=_assignedIps.end();++aip) { + if (std::find(haveIps.begin(),haveIps.end(),*aip) == haveIps.end()) { + MIB_UNICASTIPADDRESS_ROW ipr; + + InitializeUnicastIpAddressEntry(&ipr); + if (aip->isV4()) { + ipr.Address.Ipv4.sin_family = AF_INET; + ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)aip->rawIpData()); + ipr.OnLinkPrefixLength = aip->netmaskBits(); + if (ipr.OnLinkPrefixLength >= 32) + continue; + } else if (aip->isV6()) { + ipr.Address.Ipv6.sin6_family = AF_INET6; + memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,aip->rawIpData(),16); + ipr.OnLinkPrefixLength = aip->netmaskBits(); + if (ipr.OnLinkPrefixLength >= 128) + continue; + } else continue; + + ipr.PrefixOrigin = IpPrefixOriginManual; + ipr.SuffixOrigin = IpSuffixOriginManual; + ipr.ValidLifetime = 0xffffffff; + ipr.PreferredLifetime = 0xffffffff; + + ipr.InterfaceLuid = _deviceLuid; + ipr.InterfaceIndex = _getDeviceIndex(); + + CreateUnicastIpAddressEntry(&ipr); + } + + std::string ipStr(aip->toString()); + std::vector<std::string> regIps(_getRegistryIPv4Value("IPAddress")); + if (std::find(regIps.begin(),regIps.end(),ipStr) == regIps.end()) { + std::vector<std::string> regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); + regIps.push_back(ipStr); + regSubnetMasks.push_back(aip->netmask().toIpString()); + _setRegistryIPv4Value("IPAddress",regIps); + _setRegistryIPv4Value("SubnetMask",regSubnetMasks); + } + } +} + } // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 944b53f3..dd60c0bf 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -41,6 +41,7 @@ #include "../node/Mutex.hpp" #include "../node/Array.hpp" #include "../node/MulticastGroup.hpp" +#include "../node/InetAddress.hpp" #include "../osdep/Thread.hpp" namespace ZeroTier { @@ -48,6 +49,45 @@ namespace ZeroTier { class WindowsEthernetTap { public: + /** + * Installs a new instance of the ZT tap driver + * + * @param pathToInf Path to zttap driver .inf file + * @return Empty string on success, otherwise an error message + */ + static std::string addNewPersistentTapDevice(const char *pathToInf); + + /** + * Uninstalls all persistent tap devices that have legacy drivers + * + * @return Empty string on success, otherwise an error message + */ + static std::string destroyAllLegacyPersistentTapDevices(); + + /** + * Uninstalls all persistent tap devices on the system + * + * @return Empty string on success, otherwise an error message + */ + static std::string destroyAllPersistentTapDevices(); + + /** + * Uninstall a specific persistent tap device by instance ID + * + * @param instanceId Device instance ID + * @return Empty string on success, otherwise an error message + */ + static std::string deletePersistentTapDevice(const char *instanceId); + + /** + * Disable a persistent tap device by instance ID + * + * @param instanceId Device instance ID + * @param enabled Enable device? + * @return True if device was found and disabled + */ + static bool setPersistentTapDeviceState(const char *instanceId,bool enabled); + WindowsEthernetTap( const char *hp, const MAC &mac, @@ -77,15 +117,11 @@ public: void threadMain() throw(); - static void destroyAllPersistentTapDevices(const char *pathToHelpers); - static void deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId); - private: - bool _disableTapDevice(); - bool _enableTapDevice(); NET_IFINDEX _getDeviceIndex(); // throws on failure std::vector<std::string> _getRegistryIPv4Value(const char *regKey); void _setRegistryIPv4Value(const char *regKey,const std::vector<std::string> &value); + void _syncIps(); void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; @@ -101,6 +137,9 @@ private: std::string _netCfgInstanceId; std::string _deviceInstanceId; + std::vector<InetAddress> _assignedIps; // IPs assigned with addIp + Mutex _assignedIps_m; + std::vector<MulticastGroup> _multicastGroups; std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending; diff --git a/service/OneService.cpp b/service/OneService.cpp index 06e37a45..670d5641 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -943,6 +943,17 @@ public: friendlyName, StapFrameHandler, (void *)this))).first; + } catch (std::exception &exc) { +#ifdef __WINDOWS__ + FILE *tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S"port_error_log.txt").c_str(),"a"); + if (tapFailLog) { + fprintf(tapFailLog,"%.16llx: %s"ZT_EOL_S,(unsigned long long)nwid,exc.what()); + fclose(tapFailLog); + } +#else + fprintf(stderr,"ERROR: unable to configure virtual network port: %s"ZT_EOL_S,exc.what()); +#endif + return -999; } catch ( ... ) { return -999; // tap init failed } @@ -982,7 +993,7 @@ public: _tapAssignedIps.erase(nwid); #ifdef __WINDOWS__ if ((op == ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY)&&(winInstanceId.length() > 0)) - WindowsEthernetTap::deletePersistentTapDevice(_homePath.c_str(),winInstanceId.c_str()); + WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); #endif } break; diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 14bf7c3e..0a43a6f6 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -217,7 +217,7 @@ </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> @@ -232,7 +232,7 @@ </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> @@ -257,7 +257,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> @@ -282,7 +282,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>$(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> </ItemDefinitionGroup> |