diff options
32 files changed, 1952 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index 400d25a55d..94c9d5c1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ flow-typed .DS_Store *.log dist-assets/relays.json -windows/winfw/bin/ +windows/**/bin/ **/.vs/ diff --git a/windows/windns/extras.sln b/windows/windns/extras.sln new file mode 100644 index 0000000000..ed1e71d4c2 --- /dev/null +++ b/windows/windns/extras.sln @@ -0,0 +1,56 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader", "src\extras\loader\loader.vcxproj", "{1476A8B9-4A9E-4358-8744-A350CB97E152}" + ProjectSection(ProjectDependencies) = postProject + {A5344205-FC37-4572-9C63-8564ECC410AC} = {A5344205-FC37-4572-9C63-8564ECC410AC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windns", "src\windns\windns.vcxproj", "{A5344205-FC37-4572-9C63-8564ECC410AC}" + ProjectSection(ProjectDependencies) = postProject + {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x64.ActiveCfg = Debug|x64 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x64.Build.0 = Debug|x64 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x86.ActiveCfg = Debug|Win32 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x86.Build.0 = Debug|Win32 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x64.ActiveCfg = Release|x64 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x64.Build.0 = Release|x64 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x86.ActiveCfg = Release|Win32 + {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x86.Build.0 = Release|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.ActiveCfg = Debug|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Build.0 = Debug|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.ActiveCfg = Debug|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Build.0 = Debug|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.ActiveCfg = Release|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Build.0 = Release|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.ActiveCfg = Release|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.Build.0 = Release|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.ActiveCfg = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.Build.0 = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.ActiveCfg = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.Build.0 = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.ActiveCfg = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.Build.0 = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.ActiveCfg = Release|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {16D5A833-BF2F-4049-A7E1-570B792F8148} + EndGlobalSection +EndGlobal diff --git a/windows/windns/src/extras/loader/loader.cpp b/windows/windns/src/extras/loader/loader.cpp new file mode 100644 index 0000000000..1f7b5a6f97 --- /dev/null +++ b/windows/windns/src/extras/loader/loader.cpp @@ -0,0 +1,120 @@ +#include "stdafx.h" +#include "windns/windns.h" +#include "libcommon/trace/trace.h" +#include "libcommon/trace/consoletracesink.h" +#include <iostream> +#include <conio.h> +#include <vector> +#include <windows.h> + +void WINDNS_API ErrorSink(const char *errorMessage, void *context) +{ + std::cout << "WINDNS Error: " << errorMessage << std::endl; +} + +void WINDNS_API ConfigSink(const void *configData, uint32_t dataLength, void *context) +{ + std::wcout << L"Updated config was delivered to WINDNS client code" << std::endl; + + auto f = CreateFileW(L"windns_recovery", GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr); + + if (INVALID_HANDLE_VALUE == f) + { + std::wcout << L"Failed to create recovery file" << std::endl; + return; + } + + if (FALSE == WriteFile(f, configData, dataLength, nullptr, nullptr)) + { + std::wcout << L"Failed to update recovery file" << std::endl; + } + + CloseHandle(f); +} + +void Recover() +{ + auto f = CreateFileW(L"windns_recovery", GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + + if (INVALID_HANDLE_VALUE == f) + { + std::wcout << L"Failed to open recovery file" << std::endl; + return; + } + + std::vector<uint8_t> data; + + data.resize(GetFileSize(f, nullptr)); + + if (FALSE == ReadFile(f, &data[0], static_cast<DWORD>(data.size()), nullptr, nullptr)) + { + std::wcout << L"Failed to read in recovery data" << std::endl; + CloseHandle(f); + + return; + } + + std::wcout << L"WinDns_Recover: " << WinDns_Recover(&data[0], static_cast<uint32_t>(data.size())) << std::endl; +} + +bool Ask(const std::wstring &question) +{ + std::wcout << question.c_str() << L" Y/N: "; + + auto answer = _getwch(); + + std::wcout << std::endl; + + if ('y' == answer || 'Y' == answer) + { + return true; + } + + return false; +} + +void WaitInput(const std::wstring &message) +{ + std::wcout << message.c_str() << std::endl; + _getwch(); +} + +int main() +{ + common::trace::Trace::RegisterSink(new common::trace::ConsoleTraceSink); + + if (Ask(L"Perform recovery?")) + { + Recover(); + return 0; + } + + std::wcout << L"WinDns_Initialize: " << WinDns_Initialize(ErrorSink, nullptr) << std::endl; + + const wchar_t *servers[] = + { + L"8.8.8.8" + }; + + std::wcout << L"WinDns_Set: " << WinDns_Set(servers, _countof(servers), ConfigSink, nullptr) << std::endl; + + WaitInput(L"Press a key to abort DNS monitoring + enforcing..."); + + if (Ask(L"Perform WinDns_Reset() before next WinDns_Set()?")) + { + std::wcout << L"WinDns_Reset: " << WinDns_Reset() << std::endl; + } + + std::wcout << L"WinDns_Set: " << WinDns_Set(servers, _countof(servers), ConfigSink, nullptr) << std::endl; + + WaitInput(L"Press a key to abort DNS monitoring + enforcing..."); + + if (Ask(L"Perform WinDns_Reset() before WinDns_Deinitialize()?")) + { + std::wcout << L"WinDns_Reset: " << WinDns_Reset() << std::endl; + } + + std::wcout << L"WinDns_Deinitialize: " << WinDns_Deinitialize() << std::endl; + + return 0; +}
\ No newline at end of file diff --git a/windows/windns/src/extras/loader/loader.vcxproj b/windows/windns/src/extras/loader/loader.vcxproj new file mode 100644 index 0000000000..7fdfe073c3 --- /dev/null +++ b/windows/windns/src/extras/loader/loader.vcxproj @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{1476A8B9-4A9E-4358-8744-A350CB97E152}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>loader</RootNamespace> + <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> + <LanguageStandard>stdcpplatest</LanguageStandard> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> + <LanguageStandard>stdcpplatest</LanguageStandard> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> + <LanguageStandard>stdcpplatest</LanguageStandard> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> + <LanguageStandard>stdcpplatest</LanguageStandard> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>windns.lib;libcommon.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="loader.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/windns/src/extras/loader/loader.vcxproj.filters b/windows/windns/src/extras/loader/loader.vcxproj.filters new file mode 100644 index 0000000000..e29869c50f --- /dev/null +++ b/windows/windns/src/extras/loader/loader.vcxproj.filters @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="loader.cpp" /> + <ClCompile Include="stdafx.cpp" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/windns/src/extras/loader/stdafx.cpp b/windows/windns/src/extras/loader/stdafx.cpp new file mode 100644 index 0000000000..e8a73894f3 --- /dev/null +++ b/windows/windns/src/extras/loader/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// dnstest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/windows/windns/src/extras/loader/stdafx.h b/windows/windns/src/extras/loader/stdafx.h new file mode 100644 index 0000000000..b005a839de --- /dev/null +++ b/windows/windns/src/extras/loader/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include <stdio.h> +#include <tchar.h> + + + +// TODO: reference additional headers your program requires here diff --git a/windows/windns/src/extras/loader/targetver.h b/windows/windns/src/extras/loader/targetver.h new file mode 100644 index 0000000000..87c0086de7 --- /dev/null +++ b/windows/windns/src/extras/loader/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <SDKDDKVer.h> diff --git a/windows/windns/src/windns/clientsinkinfo.h b/windows/windns/src/windns/clientsinkinfo.h new file mode 100644 index 0000000000..db42485d8e --- /dev/null +++ b/windows/windns/src/windns/clientsinkinfo.h @@ -0,0 +1,21 @@ +#pragma once + +#include "windns.h" + +struct ErrorSinkInfo +{ + WinDnsErrorSink sink; + void *context; +}; + +struct ConfigSinkInfo +{ + WinDnsConfigSink sink; + void *context; +}; + +struct ClientSinkInfo +{ + ErrorSinkInfo errorSinkInfo; + ConfigSinkInfo configSinkInfo; +}; diff --git a/windows/windns/src/windns/configmanager.cpp b/windows/windns/src/windns/configmanager.cpp new file mode 100644 index 0000000000..c9fdde1142 --- /dev/null +++ b/windows/windns/src/windns/configmanager.cpp @@ -0,0 +1,139 @@ +#include "stdafx.h" +#include "configmanager.h" +#include "libcommon/serialization/serializer.h" +#include "libcommon/trace/xtrace.h" +#include <utility> +#include <algorithm> + +ConfigManager::ConfigManager +( + const std::vector<std::wstring> &servers, + const ConfigSinkInfo &configSinkInfo +) + : m_servers(servers) + , m_configSinkInfo(configSinkInfo) +{ +} + +void ConfigManager::lock() +{ + m_mutex.lock(); +} + +void ConfigManager::unlock() +{ + m_mutex.unlock(); +} + +void ConfigManager::updateServers(const std::vector<std::wstring> &servers) +{ + XTRACE(L"Updating DNS server list"); + m_servers = servers; +} + +void ConfigManager::updateConfigSink(const ConfigSinkInfo &configSinkInfo) +{ + XTRACE(L"Updating config sink"); + m_configSinkInfo = configSinkInfo; +} + +const std::vector<std::wstring> &ConfigManager::getServers() const +{ + return m_servers; +} + +ConfigManager::UpdateStatus ConfigManager::updateConfig(const InterfaceConfig &previous, const InterfaceConfig &target) +{ + XTRACE(L"Interface configuration update for interface=", target.interfaceIndex()); + + // + // There are a few cases we need to deal with: + // + // 1/ An interface being offline and coming online. + // 2/ An external application changing the interface settings. + // 3/ Us changing the interface settings. + // a. On an interface the ConfigManager hasn't seen before. + // b. On an interface the ConfigManager already knows about. + // + + const auto configIndex = target.configIndex(); + auto iter = m_configs.find(configIndex); + + if (verifyServers(target)) + { + XTRACE(L"Update event was initiated by WINDNS or did not include DNS changes"); + + // + // If we haven't seen this config id before, it means the 'previous' instance + // is the original configuration on the system, and as such must be recorded. + // + if (m_configs.end() == iter) + { + XTRACE(L"Creating new interface configuration entry"); + m_configs.insert(std::make_pair(configIndex, previous)); + + exportConfigs(); + } + + return UpdateStatus::DnsApproved; + } + + // + // The update was not initiated by us so store the updated configuration. + // + if (m_configs.end() == iter) + { + XTRACE(L"Creating new interface configuration entry"); + m_configs.insert(std::make_pair(configIndex, target)); + } + else + { + XTRACE(L"Updating interface configuration entry"); + iter->second.updateServers(target); + } + + exportConfigs(); + + return UpdateStatus::DnsDeviates; +} + +bool ConfigManager::processConfigs(std::function<bool(const InterfaceConfig &)> configSink) +{ + for (auto it = m_configs.begin(); it != m_configs.end(); ++it) + { + if (false == configSink(it->second)) + { + return false; + } + } + + return true; +} + +bool ConfigManager::verifyServers(const InterfaceConfig &config) +{ + auto updatedServers = config.servers(); + + if (nullptr == updatedServers) + { + return false; + } + + return std::equal(m_servers.begin(), m_servers.end(), updatedServers->begin(), updatedServers->end()); +} + +void ConfigManager::exportConfigs() +{ + common::serialization::Serializer s; + + s << static_cast<uint32_t>(m_configs.size()); + + for (auto it = m_configs.begin(); it != m_configs.end(); ++it) + { + it->second.serialize(s); + } + + auto data = s.blob(); + + m_configSinkInfo.sink(&data[0], static_cast<uint32_t>(data.size()), m_configSinkInfo.context); +} diff --git a/windows/windns/src/windns/configmanager.h b/windows/windns/src/windns/configmanager.h new file mode 100644 index 0000000000..157f148901 --- /dev/null +++ b/windows/windns/src/windns/configmanager.h @@ -0,0 +1,115 @@ +#pragma once + +#include "interfaceconfig.h" +#include "clientsinkinfo.h" +#include <map> +#include <string> +#include <mutex> +#include <memory> +#include <functional> + +// +// The ConfigManager is engineered to track the "real" DNS configuration for an adapter. +// +// The situation is somewhat complicated, because a given system may have several adapters, which +// in turn may have several configurations? +// +// Every update for every configuration is recorded, bar the ones that correspond to us +// overriding the DNS settings. +// + +class ConfigManager +{ +public: + + struct Mutex + { + Mutex(const Mutex &) = delete; + Mutex &operator=(const Mutex &) = delete; + Mutex(Mutex &&) = delete; + Mutex &operator=(Mutex &&) = delete; + + Mutex(ConfigManager &manager) + : m_manager(manager) + { + m_manager.lock(); + } + + ~Mutex() + { + m_manager.unlock(); + } + + ConfigManager &m_manager; + }; + + // + // "servers" specifies the set of servers used when overriding settings. + // This enables filtering out the corresponding event. + // + ConfigManager + ( + const std::vector<std::wstring> &servers, + const ConfigSinkInfo &configSinkInfo + ); + + // + // The ConfigManager is shared between threads. + // Locking is managed externally for reasons of efficiency. + // + void lock(); + void unlock(); + + // + // Notify the ConfigManager that servers used when overriding DNS settings have changed. + // + void updateServers(const std::vector<std::wstring> &servers); + + // + // Update the callback used for persisting settings. + // + void updateConfigSink(const ConfigSinkInfo &configSinkInfo); + + // + // Get the current set of servers used for overriding DNS settings. + // + const std::vector<std::wstring> &getServers() const; + + // + // Notify the ConfigManager that a live configuration has been updated. + // + enum class UpdateStatus + { + DnsApproved, + DnsDeviates + }; + + UpdateStatus updateConfig(const InterfaceConfig &previous, const InterfaceConfig &target); + + // + // Enumerate recorded configs. + // + bool processConfigs(std::function<bool(const InterfaceConfig &)> configSink); + +private: + + std::mutex m_mutex; + + std::vector<std::wstring> m_servers; + ConfigSinkInfo m_configSinkInfo; + + // + // Organize configs based on their system assigned index. + // + std::map<uint32_t, InterfaceConfig> m_configs; + + // + // Check DNS server list to see if it matches what we're trying to enforce. + // + bool verifyServers(const InterfaceConfig &config); + + // + // Bundle the current config details and send them into the config sink. + // + void exportConfigs(); +}; diff --git a/windows/windns/src/windns/dllmain.cpp b/windows/windns/src/windns/dllmain.cpp new file mode 100644 index 0000000000..f11c65c519 --- /dev/null +++ b/windows/windns/src/windns/dllmain.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include <windows.h> + +BOOL APIENTRY DllMain(HMODULE, DWORD, LPVOID) +{ + // + // Avoid doing work in DllMain since the loader lock is held + // + + return TRUE; +} diff --git a/windows/windns/src/windns/interfaceconfig.cpp b/windows/windns/src/windns/interfaceconfig.cpp new file mode 100644 index 0000000000..74e912de89 --- /dev/null +++ b/windows/windns/src/windns/interfaceconfig.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "interfaceconfig.h" +#include "netconfighelpers.h" +#include "libcommon/com.h" +#include "libcommon/wmi/wmi.h" + +using namespace common; + +InterfaceConfig::InterfaceConfig(CComPtr<IWbemClassObject> instance) +{ + // + // V_xxx macros seem to require an l-value so access the correct field directly instead. + // + + m_configIndex = wmi::WmiGetPropertyAlways(instance, L"Index").ulVal; + + m_dhcp = wmi::WmiGetPropertyAlways(instance, L"DHCPEnabled").boolVal; + + m_interfaceIndex = wmi::WmiGetPropertyAlways(instance, L"InterfaceIndex").ulVal; + m_interfaceGuid = ComConvertString(wmi::WmiGetPropertyAlways(instance, L"SettingID").bstrVal); + + m_servers = nchelpers::GetDnsServers(instance); +} + +InterfaceConfig::InterfaceConfig(common::serialization::Deserializer &deserializer) +{ + common::serialization::Deserializer &d = deserializer; + + d >> m_configIndex; + d >> (uint8_t &)m_dhcp; + d >> m_interfaceIndex; + d >> m_interfaceGuid; + + bool serversAvailable; + + d >> (uint8_t &)serversAvailable; + + if (serversAvailable) + { + m_servers = std::make_shared<std::vector<std::wstring> >(); + d >> *m_servers; + } +} + +void InterfaceConfig::serialize(common::serialization::Serializer &serializer) const +{ + common::serialization::Serializer &s = serializer; + + s << m_configIndex; + s << (uint8_t)m_dhcp; + s << m_interfaceIndex; + s << m_interfaceGuid; + + // + // TODO: Encapsulate this inside a new type. + // + if (nullptr == m_servers.get()) + { + s << (uint8_t)0; + } + else + { + s << (uint8_t)1; + s << *m_servers; + } +} diff --git a/windows/windns/src/windns/interfaceconfig.h b/windows/windns/src/windns/interfaceconfig.h new file mode 100644 index 0000000000..e95296b7fb --- /dev/null +++ b/windows/windns/src/windns/interfaceconfig.h @@ -0,0 +1,62 @@ +#pragma once + +#include "types.h" +#include "libcommon/serialization/deserializer.h" +#include "libcommon/serialization/serializer.h" +#include <cstdint> +#include <string> +#include <vector> +#include <atlbase.h> +#include <wbemidl.h> + +class InterfaceConfig +{ +public: + + // instance = Win32_NetworkAdapterConfiguration. + explicit InterfaceConfig(CComPtr<IWbemClassObject> instance); + + explicit InterfaceConfig(common::serialization::Deserializer &deserializer); + void serialize(common::serialization::Serializer &serializer) const; + + void updateServers(const InterfaceConfig &rhs) + { + m_servers = rhs.m_servers; + } + + uint32_t configIndex() const + { + return m_configIndex; + } + + bool dhcp() const + { + return m_dhcp; + } + + uint32_t interfaceIndex() const + { + return m_interfaceIndex; + } + + const std::wstring &interfaceGuid() const + { + return m_interfaceGuid; + } + + const std::vector<std::wstring> *servers() const + { + return m_servers.get(); + } + +private: + + uint32_t m_configIndex; + + bool m_dhcp; + + uint32_t m_interfaceIndex; + std::wstring m_interfaceGuid; + + OptionalStringList m_servers; +}; diff --git a/windows/windns/src/windns/netconfigeventsink.cpp b/windows/windns/src/windns/netconfigeventsink.cpp new file mode 100644 index 0000000000..e4ef7ae1ce --- /dev/null +++ b/windows/windns/src/windns/netconfigeventsink.cpp @@ -0,0 +1,34 @@ +#include "stdafx.h" +#include "netconfigeventsink.h" +#include "windns/netconfighelpers.h" + +using namespace common; + +NetConfigEventSink::NetConfigEventSink(std::shared_ptr<wmi::IConnection> connection, std::shared_ptr<ConfigManager> configManager) + : m_connection(connection) + , m_configManager(configManager) +{ +} + +void NetConfigEventSink::update(CComPtr<IWbemClassObject> previous, CComPtr<IWbemClassObject> target) +{ + InterfaceConfig previousConfig(previous); + InterfaceConfig targetConfig(target); + + ConfigManager::Mutex mutex(*m_configManager); + + // + // This is OK because the config manager will reject updates + // that set our DNS servers. + // + if (ConfigManager::UpdateStatus::DnsApproved == m_configManager->updateConfig(previousConfig, targetConfig)) + { + return; + } + + // + // The update was initiated from an external source. + // Override current settings to enforce our selected DNS servers. + // + nchelpers::SetDnsServers(targetConfig.interfaceIndex(), m_configManager->getServers()); +} diff --git a/windows/windns/src/windns/netconfigeventsink.h b/windows/windns/src/windns/netconfigeventsink.h new file mode 100644 index 0000000000..342278c08c --- /dev/null +++ b/windows/windns/src/windns/netconfigeventsink.h @@ -0,0 +1,20 @@ +#pragma once + +#include "libcommon/wmi/ieventsink.h" +#include "libcommon/wmi/iconnection.h" +#include "windns/configmanager.h" +#include <memory> + +class NetConfigEventSink : public common::wmi::IModificationEventSink +{ +public: + + NetConfigEventSink(std::shared_ptr<common::wmi::IConnection> connection, std::shared_ptr<ConfigManager> configManager); + + void update(CComPtr<IWbemClassObject> previous, CComPtr<IWbemClassObject> target) override; + +private: + + std::shared_ptr<common::wmi::IConnection> m_connection; + std::shared_ptr<ConfigManager> m_configManager; +}; diff --git a/windows/windns/src/windns/netconfighelpers.cpp b/windows/windns/src/windns/netconfighelpers.cpp new file mode 100644 index 0000000000..65e38b06c3 --- /dev/null +++ b/windows/windns/src/windns/netconfighelpers.cpp @@ -0,0 +1,65 @@ +#include "stdafx.h" +#include "netconfighelpers.h" +#include "libcommon/com.h" +#include "libcommon/wmi/wmi.h" +#include "libcommon/trace/xtrace.h" +#include "netsh.h" + +using namespace common; + +namespace nchelpers +{ + +OptionalStringList GetDnsServers(CComPtr<IWbemClassObject> instance) +{ + OptionalStringList result; + + auto servers = wmi::WmiGetProperty(instance, L"DNSServerSearchOrder"); + + if (VT_EMPTY == V_VT(&servers) || VT_NULL == V_VT(&servers)) + { + return result; + } + + result = std::make_shared<std::vector<std::wstring> >( + ComConvertStringArray(V_ARRAY(&servers))); + + return result; +} + +uint32_t GetInterfaceIndex(CComPtr<IWbemClassObject> instance) +{ + return wmi::WmiGetPropertyAlways(instance, L"InterfaceIndex").ulVal; +} + +void SetDnsServers(uint32_t interfaceIndex, const std::vector<std::wstring> &servers) +{ + NetSh::SetIpv4PrimaryDns(interfaceIndex, servers[0]); + + if (servers.size() > 1) + { + NetSh::SetIpv4SecondaryDns(interfaceIndex, servers[1]); + } +} + +void RevertDnsServers(const InterfaceConfig &config) +{ + XTRACE("Reverting DNS configuration for interface with index=", config.interfaceIndex()); + + auto servers = config.servers(); + + if (config.dhcp() || nullptr == servers || 0 == servers->size()) + { + NetSh::SetIpv4Dhcp(config.interfaceIndex()); + return; + } + + NetSh::SetIpv4PrimaryDns(config.interfaceIndex(), (*servers)[0]); + + if (servers->size() > 1) + { + NetSh::SetIpv4SecondaryDns(config.interfaceIndex(), (*servers)[1]); + } +} + +} diff --git a/windows/windns/src/windns/netconfighelpers.h b/windows/windns/src/windns/netconfighelpers.h new file mode 100644 index 0000000000..fbfef34035 --- /dev/null +++ b/windows/windns/src/windns/netconfighelpers.h @@ -0,0 +1,24 @@ +#pragma once + +#include "types.h" +#include "interfaceconfig.h" +#include <string> +#include <vector> +#include <cstdint> +#include <atlbase.h> +#include <wbemidl.h> + +namespace nchelpers +{ + +// instance = Win32_NetworkAdapterConfiguration +OptionalStringList GetDnsServers(CComPtr<IWbemClassObject> instance); + +// instance = Win32_NetworkAdapterConfiguration +uint32_t GetInterfaceIndex(CComPtr<IWbemClassObject> instance); + +void SetDnsServers(uint32_t interfaceIndex, const std::vector<std::wstring> &servers); + +void RevertDnsServers(const InterfaceConfig &config); + +} diff --git a/windows/windns/src/windns/netsh.cpp b/windows/windns/src/windns/netsh.cpp new file mode 100644 index 0000000000..af65ace2a9 --- /dev/null +++ b/windows/windns/src/windns/netsh.cpp @@ -0,0 +1,159 @@ +#include "stdafx.h" +#include "netsh.h" +#include "libcommon/applicationrunner.h" +#include <sstream> +#include <stdexcept> + +namespace +{ + +void ValidateShellOut(common::ApplicationRunner &netsh) +{ + static const uint32_t TIMEOUT_TWO_SECONDS = 2000; + + DWORD returnCode; + + if (false == netsh.join(returnCode, TIMEOUT_TWO_SECONDS)) + { + throw std::runtime_error("'netsh' did not complete in a timely manner"); + } + + if (returnCode != 0) + { + std::stringstream ss; + + ss << "'netsh' failed the requested operation. Error: " << returnCode; + + throw std::runtime_error(ss.str()); + } +} + +} // anonymous namespace + +//static +void NetSh::SetIpv4PrimaryDns(uint32_t interfaceIndex, std::wstring server) +{ + // + // netsh interface ipv4 set dnsservers name="Ethernet 2" source=static address=8.8.8.8 validate=no + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv4 set dnsservers name=" + << interfaceIndex + << L" source=static address=" + << server + << L" validate=no"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} + +//static +void NetSh::SetIpv4SecondaryDns(uint32_t interfaceIndex, std::wstring server) +{ + // + // netsh interface ipv4 add dnsservers name="Ethernet 2" address=8.8.4.4 index=2 validate=no + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv4 add dnsservers name=" + << interfaceIndex + << L" address=" + << server + << L" index=2 validate=no"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} + +//static +void NetSh::SetIpv4Dhcp(uint32_t interfaceIndex) +{ + // + // netsh interface ipv4 set dnsservers name="Ethernet 2" source=dhcp + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv4 set dnsservers name=" + << interfaceIndex + << L" source=dhcp"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} + +//static +void NetSh::SetIpv6PrimaryDns(uint32_t interfaceIndex, std::wstring server) +{ + // + // netsh interface ipv6 set dnsservers name="Ethernet 2" source=static address=2001:4860:4860::8888 validate=no + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv6 set dnsservers name=" + << interfaceIndex + << L" source=static address=" + << server + << L" validate=no"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} + +//static +void NetSh::SetIpv6SecondaryDns(uint32_t interfaceIndex, std::wstring server) +{ + // + // netsh interface ipv6 add dnsservers name="Ethernet 2" address=2001:4860:4860::8844 index=2 validate=no + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv6 add dnsservers name=" + << interfaceIndex + << L"address =" + << server + << L" index=2 validate=no"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} + +//static +void NetSh::SetIpv6Dhcp(uint32_t interfaceIndex) +{ + // + // netsh interface ipv6 set dnsservers name="Ethernet 2" source=dhcp + // + // Note: we're specifying the interface by index instead. + // + + std::wstringstream ss; + + ss << L"interface ipv6 set dnsservers name=" + << interfaceIndex + << L" source=dhcp"; + + auto netsh = common::ApplicationRunner::StartWithoutConsole(L"netsh.exe", ss.str()); + + ValidateShellOut(*netsh); +} diff --git a/windows/windns/src/windns/netsh.h b/windows/windns/src/windns/netsh.h new file mode 100644 index 0000000000..d299cf6f87 --- /dev/null +++ b/windows/windns/src/windns/netsh.h @@ -0,0 +1,26 @@ +#pragma once + +#include <string> +#include <cstdint> + +class NetSh +{ +public: + + static void SetIpv4PrimaryDns(uint32_t interfaceIndex, std::wstring server); + + // + // Caveat: This sets the primary DNS server if there isn't already one. + // + static void SetIpv4SecondaryDns(uint32_t interfaceIndex, std::wstring server); + + static void SetIpv4Dhcp(uint32_t interfaceIndex); + + static void SetIpv6PrimaryDns(uint32_t interfaceIndex, std::wstring server); + static void SetIpv6SecondaryDns(uint32_t interfaceIndex, std::wstring server); + static void SetIpv6Dhcp(uint32_t interfaceIndex); + +private: + + NetSh(); +}; diff --git a/windows/windns/src/windns/stdafx.cpp b/windows/windns/src/windns/stdafx.cpp new file mode 100644 index 0000000000..689eb89a7e --- /dev/null +++ b/windows/windns/src/windns/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// windns.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/windows/windns/src/windns/stdafx.h b/windows/windns/src/windns/stdafx.h new file mode 100644 index 0000000000..6878f4de13 --- /dev/null +++ b/windows/windns/src/windns/stdafx.h @@ -0,0 +1,17 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include <windows.h> +#include <sstream> +#include <string> +#include <vector> +#include <stdexcept> +#include <cstdint> diff --git a/windows/windns/src/windns/targetver.h b/windows/windns/src/windns/targetver.h new file mode 100644 index 0000000000..ae4a5c032c --- /dev/null +++ b/windows/windns/src/windns/targetver.h @@ -0,0 +1,12 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <WinSDKVer.h> + +#define _WIN32_WINNT _WIN32_WINNT_WIN7 + +#include <SDKDDKVer.h> diff --git a/windows/windns/src/windns/types.h b/windows/windns/src/windns/types.h new file mode 100644 index 0000000000..d30d556c5d --- /dev/null +++ b/windows/windns/src/windns/types.h @@ -0,0 +1,7 @@ +#pragma once + +#include <string> +#include <vector> +#include <memory> + +using OptionalStringList = std::shared_ptr<std::vector<std::wstring> >; diff --git a/windows/windns/src/windns/windns.cpp b/windows/windns/src/windns/windns.cpp new file mode 100644 index 0000000000..48ad863dfa --- /dev/null +++ b/windows/windns/src/windns/windns.cpp @@ -0,0 +1,237 @@ +#include "stdafx.h" +#include "windns.h" +#include "windnscontext.h" +#include "clientsinkinfo.h" +#include "libcommon/serialization/deserializer.h" +#include "interfaceconfig.h" +#include "netconfighelpers.h" +#include <vector> +#include <string> + +namespace +{ + +WinDnsErrorSink g_ErrorSink = nullptr; +void *g_ErrorContext = nullptr; + +WinDnsContext *g_Context = nullptr; + +std::vector<std::wstring> MakeStringArray(const wchar_t **strings, uint32_t numStrings) +{ + std::vector<std::wstring> v; + + while (numStrings--) + { + v.emplace_back(*strings++); + } + + return v; +} + +} // anonymous namespace + +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Initialize( + WinDnsErrorSink errorSink, + void *errorContext +) +{ + if (nullptr != g_Context) + { + return false; + } + + g_ErrorSink = errorSink; + g_ErrorContext = errorContext; + + try + { + g_Context = new WinDnsContext; + } + catch (std::exception &err) + { + if (nullptr != g_ErrorSink) + { + g_ErrorSink(err.what(), g_ErrorContext); + } + + return false; + } + catch (...) + { + return false; + } + + return true; +} + +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Deinitialize( +) +{ + if (nullptr == g_Context) + { + return true; + } + + delete g_Context; + g_Context = nullptr; + + return true; +} + +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Set( + const wchar_t **servers, + uint32_t numServers, + WinDnsConfigSink configSink, + void *configContext +) +{ + if (nullptr == g_Context + || 0 == numServers + || nullptr == configSink) + { + return false; + } + + try + { + ClientSinkInfo sinkInfo; + + sinkInfo.errorSinkInfo = ErrorSinkInfo{ g_ErrorSink, g_ErrorContext }; + sinkInfo.configSinkInfo = ConfigSinkInfo{ configSink, configContext }; + + g_Context->set(MakeStringArray(servers, numServers), sinkInfo); + } + catch (std::exception &err) + { + if (nullptr != g_ErrorSink) + { + g_ErrorSink(err.what(), g_ErrorContext); + } + + return false; + } + catch (...) + { + return false; + } + + return true; +} + +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Reset( +) +{ + if (nullptr == g_Context) + { + return true; + } + + try + { + g_Context->reset(); + } + catch (std::exception &err) + { + if (nullptr != g_ErrorSink) + { + g_ErrorSink(err.what(), g_ErrorContext); + } + + return false; + } + catch (...) + { + return false; + } + + return true; +} + +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Recover( + const void *configData, + uint32_t dataLength +) +{ + std::vector<InterfaceConfig> configs; + + try + { + common::serialization::Deserializer d(reinterpret_cast<const uint8_t *>(configData), dataLength); + + auto numConfigs = d.decode<uint32_t>(); + + if (numConfigs > 50) + { + return false; + } + + configs.reserve(numConfigs); + + for (; numConfigs != 0; --numConfigs) + { + configs.emplace_back(InterfaceConfig(d)); + } + } + catch (std::exception &err) + { + if (nullptr != g_ErrorSink) + { + auto msg = std::string("Failed to deserialize recovery data: ").append(err.what()); + + g_ErrorSink(msg.c_str(), g_ErrorContext); + } + + return false; + } + catch (...) + { + return false; + } + + if (configs.empty()) + { + return true; + } + + bool success = true; + + for (const auto &config : configs) + { + try + { + nchelpers::RevertDnsServers(config); + } + catch (std::exception &err) + { + if (nullptr != g_ErrorSink) + { + auto msg = std::string("Failed to restore interface settings: ").append(err.what()); + + g_ErrorSink(msg.c_str(), g_ErrorContext); + } + + success = false; + } + catch (...) + { + success = false; + } + } + + return success; +} diff --git a/windows/windns/src/windns/windns.h b/windows/windns/src/windns/windns.h new file mode 100644 index 0000000000..734719ca80 --- /dev/null +++ b/windows/windns/src/windns/windns.h @@ -0,0 +1,107 @@ +#pragma once +#include <cstdint> + +// +// WINDNS public API +// + +#ifdef WINDNS_EXPORTS +#define WINDNS_LINKAGE __declspec(dllexport) +#else +#define WINDNS_LINKAGE __declspec(dllimport) +#endif + +#define WINDNS_API __stdcall + +/////////////////////////////////////////////////////////////////////////////// +// Functions +/////////////////////////////////////////////////////////////////////////////// + +typedef void (WINDNS_API *WinDnsErrorSink)(const char *errorMessage, void *context); +typedef void (WINDNS_API *WinDnsConfigSink)(const void *configData, uint32_t dataLength, void *context); + +// +// WinDns_Initialize: +// +// Call this function once at startup, to acquire resources etc. +// +// The OPTIONAL error callback is remembered and used to report exceptions that +// occur as a direct or indirect result of calling into WINDNS. +// +// (Recall that the monitoring provided by WINDNS is threaded.) +// +extern "C" +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Initialize( + WinDnsErrorSink errorSink, + void *errorContext +); + +// +// WinDns_Deinitialize: +// +// Call this function once before unloading WINDNS or exiting the process. +// +extern "C" +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Deinitialize( +); + +// +// WinDns_Set: +// +// Configure which DNS servers should be used and start enforcing these settings. +// +// The 'configSink' will receive periodic callbacks with updated config data +// until you call WinDns_Reset. +// +// You should persist the config data in preparation for an eventual recovery. +// +extern "C" +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Set( + const wchar_t **servers, + uint32_t numServers, + WinDnsConfigSink configSink, + void *configContext +); + +// +// Windns_Reset: +// +// Revert server settings to what they were before calling WinDns_Set. +// +// (Also taking into account external changes to DNS settings that have occurred +// during the period of enforcing specific settings.) +// +// It's safe to discard persisted config data once WinDns_Reset returns 'true'. +// +extern "C" +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Reset( +); + +// +// WinDns_Recover: +// +// Recover adapter configurations from a previously persisted state. +// +// This is useful if the machine has been abruptly powered off and +// WINDNS did not get a chance to restore settings. +// +extern "C" +WINDNS_LINKAGE +bool +WINDNS_API +WinDns_Recover( + const void *configData, + uint32_t dataLength +); diff --git a/windows/windns/src/windns/windns.vcxproj b/windows/windns/src/windns/windns.vcxproj new file mode 100644 index 0000000000..b495e10f0b --- /dev/null +++ b/windows/windns/src/windns/windns.vcxproj @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{A5344205-FC37-4572-9C63-8564ECC410AC}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>windns</RootNamespace> + <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;wbemuuid.lib;comsuppw.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="clientsinkinfo.h" /> + <ClInclude Include="configmanager.h" /> + <ClInclude Include="interfaceconfig.h" /> + <ClInclude Include="netconfigeventsink.h" /> + <ClInclude Include="netconfighelpers.h" /> + <ClInclude Include="netsh.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="types.h" /> + <ClInclude Include="windns.h" /> + <ClInclude Include="windnscontext.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="configmanager.cpp" /> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="interfaceconfig.cpp" /> + <ClCompile Include="netconfigeventsink.cpp" /> + <ClCompile Include="netconfighelpers.cpp" /> + <ClCompile Include="netsh.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="windns.cpp" /> + <ClCompile Include="windnscontext.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/windns/src/windns/windns.vcxproj.filters b/windows/windns/src/windns/windns.vcxproj.filters new file mode 100644 index 0000000000..07619150e9 --- /dev/null +++ b/windows/windns/src/windns/windns.vcxproj.filters @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="windns.h" /> + <ClInclude Include="windnscontext.h" /> + <ClInclude Include="configmanager.h" /> + <ClInclude Include="netconfigeventsink.h" /> + <ClInclude Include="netconfighelpers.h" /> + <ClInclude Include="clientsinkinfo.h" /> + <ClInclude Include="netsh.h" /> + <ClInclude Include="interfaceconfig.h" /> + <ClInclude Include="types.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="stdafx.cpp" /> + <ClCompile Include="windns.cpp" /> + <ClCompile Include="windnscontext.cpp" /> + <ClCompile Include="configmanager.cpp" /> + <ClCompile Include="netconfigeventsink.cpp" /> + <ClCompile Include="netconfighelpers.cpp" /> + <ClCompile Include="netsh.cpp" /> + <ClCompile Include="interfaceconfig.cpp" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/windns/src/windns/windnscontext.cpp b/windows/windns/src/windns/windnscontext.cpp new file mode 100644 index 0000000000..17265f0b65 --- /dev/null +++ b/windows/windns/src/windns/windnscontext.cpp @@ -0,0 +1,98 @@ +#include "stdafx.h" +#include "windnscontext.h" +#include "libcommon/wmi/connection.h" +#include "netconfigeventsink.h" +#include "netconfighelpers.h" + +using namespace common; + +WinDnsContext::WinDnsContext() +{ + m_connection = std::make_shared<wmi::Connection>(wmi::Connection::Namespace::Cimv2); +} + +WinDnsContext::~WinDnsContext() +{ + try + { + reset(); + } + catch (std::exception &err) + { + if (nullptr != m_sinkInfo.errorSinkInfo.sink) + { + m_sinkInfo.errorSinkInfo.sink(err.what(), m_sinkInfo.errorSinkInfo.context); + } + } + catch (...) + { + } +} + +void WinDnsContext::set(const std::vector<std::wstring> &servers, const ClientSinkInfo &sinkInfo) +{ + m_sinkInfo = sinkInfo; + + if (nullptr == m_notification) + { + m_configManager = std::make_shared<ConfigManager>(servers, m_sinkInfo.configSinkInfo); + + // + // Register interface configuration monitoring. + // + + auto eventSink = std::make_shared<NetConfigEventSink>(m_connection, m_configManager); + auto eventDispatcher = CComPtr<wmi::IEventDispatcher>(new wmi::ModificationEventDispatcher(eventSink)); + + m_notification = std::make_unique<wmi::Notification>(m_connection, eventDispatcher); + + m_notification->activate + ( + L"SELECT * " + L"FROM __InstanceModificationEvent " + L"WITHIN 1 " + L"WHERE TargetInstance ISA 'Win32_NetworkAdapterConfiguration'" + L"AND TargetInstance.IPEnabled = True" + ); + } + else + { + ConfigManager::Mutex mutex(*m_configManager); + + m_configManager->updateServers(servers); + m_configManager->updateConfigSink(m_sinkInfo.configSinkInfo); + } + + // + // Discover all active interfaces and apply our DNS settings. + // + + auto resultSet = m_connection->query(L"SELECT * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True"); + + while (resultSet.advance()) + { + nchelpers::SetDnsServers(nchelpers::GetInterfaceIndex(resultSet.result()), servers); + } +} + +void WinDnsContext::reset() +{ + if (nullptr == m_notification) + { + return; + } + + m_notification->deactivate(); + m_notification = nullptr; + + // + // Revert configs + // Safe to do without a mutex guarding the config manager + // + + m_configManager->processConfigs([&](const InterfaceConfig &config) + { + nchelpers::RevertDnsServers(config); + return true; + }); +} diff --git a/windows/windns/src/windns/windnscontext.h b/windows/windns/src/windns/windnscontext.h new file mode 100644 index 0000000000..c514153edd --- /dev/null +++ b/windows/windns/src/windns/windnscontext.h @@ -0,0 +1,28 @@ +#pragma once + +#include "windns.h" +#include "libcommon/wmi/connection.h" +#include "libcommon/wmi/notification.h" +#include "configmanager.h" +#include "clientsinkinfo.h" +#include <vector> +#include <string> +#include <memory> + +class WinDnsContext +{ +public: + + WinDnsContext(); + ~WinDnsContext(); + + void set(const std::vector<std::wstring> &servers, const ClientSinkInfo &sinkInfo); + void reset(); + +private: + + std::shared_ptr<common::wmi::Connection> m_connection; + std::shared_ptr<ConfigManager> m_configManager; + std::unique_ptr<common::wmi::Notification> m_notification; + ClientSinkInfo m_sinkInfo; +}; diff --git a/windows/windns/windns.sln b/windows/windns/windns.sln new file mode 100644 index 0000000000..5db77f1c6b --- /dev/null +++ b/windows/windns/windns.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windns", "src\windns\windns.vcxproj", "{A5344205-FC37-4572-9C63-8564ECC410AC}" + ProjectSection(ProjectDependencies) = postProject + {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.ActiveCfg = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.Build.0 = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.ActiveCfg = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.Build.0 = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.ActiveCfg = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.Build.0 = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.ActiveCfg = Release|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.Build.0 = Release|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.ActiveCfg = Debug|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Build.0 = Debug|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Deploy.0 = Debug|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.ActiveCfg = Debug|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Build.0 = Debug|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Deploy.0 = Debug|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.ActiveCfg = Release|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Build.0 = Release|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Deploy.0 = Release|x64 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.ActiveCfg = Release|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.Build.0 = Release|Win32 + {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A28F3793-15A7-4EE5-A899-373DF084D91F} + EndGlobalSection +EndGlobal diff --git a/windows/windows-libraries b/windows/windows-libraries -Subproject 75c07635f1430ccd9403da058d76e01435ec65a +Subproject af32131869f182d0c9a4af7a27cd7bc27d619e0 |
