diff options
| author | Odd Stranne <odd@mullvad.net> | 2018-05-25 11:22:01 +0200 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2018-05-25 11:22:01 +0200 |
| commit | 32e1bd67dd67652c89762a327e44ba3d47780c48 (patch) | |
| tree | f0ae4de1b7d5703a500209f876d35530f3dcb9fc /windows/winfw/src/extras/cli | |
| parent | 835342bcd9ccffc092825b1c96077f6af1eb9878 (diff) | |
| download | mullvadvpn-32e1bd67dd67652c89762a327e44ba3d47780c48.tar.xz mullvadvpn-32e1bd67dd67652c89762a327e44ba3d47780c48.zip | |
Move wfpctl -> windows/winfw
Diffstat (limited to 'windows/winfw/src/extras/cli')
47 files changed, 2897 insertions, 0 deletions
diff --git a/windows/winfw/src/extras/cli/cli.cpp b/windows/winfw/src/extras/cli/cli.cpp new file mode 100644 index 0000000000..a1758df8ee --- /dev/null +++ b/windows/winfw/src/extras/cli/cli.cpp @@ -0,0 +1,173 @@ +// cli.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "util.h" +#include "filterengineprovider.h" +#include "modules/imodule.h" +#include "modules/list.h" +#include "modules/monitor.h" +#include "modules/winfw.h" +#include "libcommon/string.h" +#include <iostream> +#include <conio.h> + +// Should set key comparison operator to compare lowercase strings but meh. +std::map<std::wstring, std::unique_ptr<modules::IModule> > g_modules; + +void OutputConsole(const std::wstring &str) +{ + std::wcout << str.c_str() << std::endl; +} + +void InitializeFilterEngine() +{ + FilterEngineProvider::Instance().set(std::move(wfp::FilterEngine::DynamicSession())); +} + +void InitializeModules() +{ + auto list = std::make_unique<modules::List>(OutputConsole); + g_modules.insert(std::make_pair(common::string::Lower(list->name()), std::move(list))); + + auto monitor = std::make_unique<modules::Monitor>(OutputConsole); + g_modules.insert(std::make_pair(common::string::Lower(monitor->name()), std::move(monitor))); + + auto winfw = std::make_unique<modules::WinFw>(OutputConsole); + g_modules.insert(std::make_pair(common::string::Lower(winfw->name()), std::move(winfw))); +} + +void ProcessHelp(const std::wstring &request) +{ + auto tokens = common::string::Tokenize(request, L" "); + + if (tokens.empty()) + { + std::wcout << L"Unable to interpret request." << std::endl; + return; + } + + if (tokens.size() == 1) + { + PropertyList list; + + for (auto &module : g_modules) + { + list.add(common::string::Lower(module.second->name()), module.second->description()); + } + + list.add(L"help", L"List available modules."); + list.add(L"help /module/", L"Show module specific help."); + list.add(L"reset", L"Reset the Filter Engine session."); + list.add(L"quit", L"Exit the application."); + + PrettyPrintOptions options; + + options.indent = 0; + options.useSeparator = false; + + PrettyPrintProperties(OutputConsole, options, list); + + return; + } + + if (tokens.size() != 2) + { + std::wcout << L"Unable to interpret request." << std::endl; + return; + } + + auto wanted = common::string::Lower(tokens[1]); + auto found = g_modules.find(wanted); + + if (found == g_modules.end()) + { + std::wcout << L"No such module: " << wanted << L"." << std::endl; + return; + } + + auto moduleCommands = found->second->commands(); + + PrettyPrintOptions options; + + options.indent = 0; + options.useSeparator = false; + + PrettyPrintProperties(OutputConsole, options, moduleCommands); +} + +void ProcessRequest(const std::wstring &request) +{ + auto tokens = common::string::Tokenize(request, L" "); + + if (tokens.empty()) + { + std::wcout << L"Unable to interpret request." << std::endl; + return; + } + + auto wanted = common::string::Lower(tokens[0]); + auto found = g_modules.find(wanted); + + if (found == g_modules.end()) + { + std::wcout << L"No such module: " << wanted << L"." << std::endl; + return; + } + + tokens.erase(tokens.begin()); + + found->second->handleRequest(tokens); +} + +int main(int, wchar_t **) +{ + InitializeFilterEngine(); + InitializeModules(); + + for (;;) + { + std::wcout << L"wfp> "; + + std::wstring request; + std::getline(std::wcin, request); + + if (0 == _wcsicmp(request.c_str(), L"quit")) + { + break; + } + + if (0 == _wcsicmp(request.c_str(), L"reset")) + { + InitializeFilterEngine(); + std::wcout << std::endl; + + continue; + } + + if (0 == _wcsnicmp(request.c_str(), L"help", 4)) + { + ProcessHelp(request); + std::wcout << std::endl; + + continue; + } + + try + { + ProcessRequest(request); + } + catch (std::exception &error) + { + std::cout << "Error: " << error.what() << std::endl; + } + catch (...) + { + std::cout << "Unknown error, caught exception!" << std::endl; + } + + std::wcout << std::endl; + } + + return 0; +} diff --git a/windows/winfw/src/extras/cli/cli.vcxproj b/windows/winfw/src/extras/cli/cli.vcxproj new file mode 100644 index 0000000000..93ade5ea56 --- /dev/null +++ b/windows/winfw/src/extras/cli/cli.vcxproj @@ -0,0 +1,230 @@ +<?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>{242A58CA-8E54-4170-A8C5-6F91CC4F7DB2}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>cli</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|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> + </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> + <IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)..\..\..\..\libwfp\src\;$(ProjectDir)..\..\..\..\windows-libraries\src\</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>winfw.lib;libcommon.lib;libwfp.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> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)..\..\..\..\libwfp\src\;$(ProjectDir)..\..\..\..\windows-libraries\src\</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winfw.lib;libcommon.lib;libwfp.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;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)..\..\..\..\libwfp\src\;$(ProjectDir)..\..\..\..\windows-libraries\src\</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>winfw.lib;libcommon.lib;libwfp.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> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + </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;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)..\..\..\..\libwfp\src\;$(ProjectDir)..\..\..\..\windows-libraries\src\</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winfw.lib;libcommon.lib;libwfp.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="commands\icommand.h" /> + <ClInclude Include="commands\list\events.h" /> + <ClInclude Include="commands\list\filters.h" /> + <ClInclude Include="commands\list\layers.h" /> + <ClInclude Include="commands\list\providercontexts.h" /> + <ClInclude Include="commands\list\providers.h" /> + <ClInclude Include="commands\list\sessions.h" /> + <ClInclude Include="commands\list\sublayers.h" /> + <ClInclude Include="commands\monitor\m_events.h" /> + <ClInclude Include="commands\winfw\deinit.h" /> + <ClInclude Include="commands\winfw\init.h" /> + <ClInclude Include="commands\winfw\policy.h" /> + <ClInclude Include="filterengineprovider.h" /> + <ClInclude Include="inlineformatter.h" /> + <ClInclude Include="ipropertydecorator.h" /> + <ClInclude Include="modules\imodule.h" /> + <ClInclude Include="modules\list.h" /> + <ClInclude Include="modules\module.h" /> + <ClInclude Include="modules\monitor.h" /> + <ClInclude Include="modules\winfw.h" /> + <ClInclude Include="objectproperties.h" /> + <ClInclude Include="propertydecorator.h" /> + <ClInclude Include="propertylist.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="subcommanddispatcher.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="util.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="cli.cpp" /> + <ClCompile Include="commands\list\events.cpp" /> + <ClCompile Include="commands\list\filters.cpp" /> + <ClCompile Include="commands\list\layers.cpp" /> + <ClCompile Include="commands\list\providercontexts.cpp" /> + <ClCompile Include="commands\list\providers.cpp" /> + <ClCompile Include="commands\list\sessions.cpp" /> + <ClCompile Include="commands\list\sublayers.cpp" /> + <ClCompile Include="commands\monitor\m_events.cpp" /> + <ClCompile Include="commands\winfw\deinit.cpp" /> + <ClCompile Include="commands\winfw\init.cpp" /> + <ClCompile Include="commands\winfw\policy.cpp" /> + <ClCompile Include="modules\module.cpp" /> + <ClCompile Include="objectproperties.cpp" /> + <ClCompile Include="propertydecorator.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> + </ClCompile> + <ClCompile Include="subcommanddispatcher.cpp" /> + <ClCompile Include="util.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/winfw/src/extras/cli/cli.vcxproj.filters b/windows/winfw/src/extras/cli/cli.vcxproj.filters new file mode 100644 index 0000000000..4f737b5a67 --- /dev/null +++ b/windows/winfw/src/extras/cli/cli.vcxproj.filters @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="commands"> + <UniqueIdentifier>{da097053-def0-4a93-a7a3-b62cc761ac4c}</UniqueIdentifier> + </Filter> + <Filter Include="commands\list"> + <UniqueIdentifier>{25335122-c3ac-492b-bec2-827f73a5269f}</UniqueIdentifier> + </Filter> + <Filter Include="modules"> + <UniqueIdentifier>{e88bc8bf-763d-4c21-b558-18c18c3d01aa}</UniqueIdentifier> + </Filter> + <Filter Include="commands\monitor"> + <UniqueIdentifier>{ff50eaf3-6e11-41ad-bae9-24427a025d33}</UniqueIdentifier> + </Filter> + <Filter Include="commands\winfw"> + <UniqueIdentifier>{571487f4-437d-4ad1-a409-f2b143f6803e}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClInclude Include="modules\imodule.h"> + <Filter>modules</Filter> + </ClInclude> + <ClInclude Include="modules\list.h"> + <Filter>modules</Filter> + </ClInclude> + <ClInclude Include="commands\icommand.h"> + <Filter>commands</Filter> + </ClInclude> + <ClInclude Include="commands\list\sessions.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="modules\module.h"> + <Filter>modules</Filter> + </ClInclude> + <ClInclude Include="commands\list\providers.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="commands\list\events.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="commands\list\filters.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="commands\list\layers.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="commands\list\providercontexts.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="commands\list\sublayers.h"> + <Filter>commands\list</Filter> + </ClInclude> + <ClInclude Include="filterengineprovider.h" /> + <ClInclude Include="inlineformatter.h" /> + <ClInclude Include="objectproperties.h" /> + <ClInclude Include="propertylist.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="util.h" /> + <ClInclude Include="modules\monitor.h"> + <Filter>modules</Filter> + </ClInclude> + <ClInclude Include="commands\monitor\m_events.h"> + <Filter>commands\monitor</Filter> + </ClInclude> + <ClInclude Include="ipropertydecorator.h" /> + <ClInclude Include="propertydecorator.h" /> + <ClInclude Include="commands\winfw\policy.h"> + <Filter>commands\winfw</Filter> + </ClInclude> + <ClInclude Include="subcommanddispatcher.h" /> + <ClInclude Include="modules\winfw.h"> + <Filter>modules</Filter> + </ClInclude> + <ClInclude Include="commands\winfw\init.h"> + <Filter>commands\winfw</Filter> + </ClInclude> + <ClInclude Include="commands\winfw\deinit.h"> + <Filter>commands\winfw</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="commands\list\sessions.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="modules\module.cpp"> + <Filter>modules</Filter> + </ClCompile> + <ClCompile Include="commands\list\providers.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="commands\list\events.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="commands\list\filters.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="commands\list\layers.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="commands\list\providercontexts.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="commands\list\sublayers.cpp"> + <Filter>commands\list</Filter> + </ClCompile> + <ClCompile Include="cli.cpp" /> + <ClCompile Include="objectproperties.cpp" /> + <ClCompile Include="stdafx.cpp" /> + <ClCompile Include="util.cpp" /> + <ClCompile Include="commands\monitor\m_events.cpp"> + <Filter>commands\monitor</Filter> + </ClCompile> + <ClCompile Include="propertydecorator.cpp" /> + <ClCompile Include="commands\winfw\policy.cpp"> + <Filter>commands\winfw</Filter> + </ClCompile> + <ClCompile Include="subcommanddispatcher.cpp" /> + <ClCompile Include="commands\winfw\init.cpp"> + <Filter>commands\winfw</Filter> + </ClCompile> + <ClCompile Include="commands\winfw\deinit.cpp"> + <Filter>commands\winfw</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/winfw/src/extras/cli/commands/icommand.h b/windows/winfw/src/extras/cli/commands/icommand.h new file mode 100644 index 0000000000..a9503a205b --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/icommand.h @@ -0,0 +1,17 @@ +#pragma once + +#include <string> +#include <vector> + +namespace commands +{ + +struct ICommand +{ + virtual std::wstring name() = 0; + virtual std::wstring description() = 0; + + virtual void handleRequest(const std::vector<std::wstring> &arguments) = 0; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/events.cpp b/windows/winfw/src/extras/cli/commands/list/events.cpp new file mode 100644 index 0000000000..4396eff980 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/events.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "events.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "cli/propertydecorator.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Events::Events(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Events::name() +{ + return L"events"; + +} + +std::wstring Events::description() +{ + return L"Provides a listing of all recent events in the system."; +} + +void Events::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + wfp::ObjectEnumerator::Events(*FilterEngineProvider::Instance().get(), [&](const FWPM_NET_EVENT0 &event) + { + m_messageSink(L"Event"); + + PrettyPrintProperties(m_messageSink, options, EventProperties(event, &decorator)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/events.h b/windows/winfw/src/extras/cli/commands/list/events.h new file mode 100644 index 0000000000..cc727712f0 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/events.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Events : public ICommand +{ +public: + + Events(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/filters.cpp b/windows/winfw/src/extras/cli/commands/list/filters.cpp new file mode 100644 index 0000000000..9c7917bf66 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/filters.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "filters.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "cli/propertydecorator.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Filters::Filters(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Filters::name() +{ + return L"filters"; + +} + +std::wstring Filters::description() +{ + return L"Provides a listing of all filters in the system."; +} + +void Filters::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + wfp::ObjectEnumerator::Filters(*FilterEngineProvider::Instance().get(), [&](const FWPM_FILTER0 &filter) + { + m_messageSink(L"Filter"); + + PrettyPrintProperties(m_messageSink, options, FilterProperties(filter, &decorator)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/filters.h b/windows/winfw/src/extras/cli/commands/list/filters.h new file mode 100644 index 0000000000..4c0345f3b3 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/filters.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Filters : public ICommand +{ +public: + + Filters(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/layers.cpp b/windows/winfw/src/extras/cli/commands/list/layers.cpp new file mode 100644 index 0000000000..3dc4368894 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/layers.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "layers.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "cli/propertydecorator.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Layers::Layers(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Layers::name() +{ + return L"layers"; + +} + +std::wstring Layers::description() +{ + return L"Provides a listing of all layers in the system."; +} + +void Layers::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + wfp::ObjectEnumerator::Layers(*FilterEngineProvider::Instance().get(), [&](const FWPM_LAYER0 &layer) + { + m_messageSink(L"Layer"); + + PrettyPrintProperties(m_messageSink, options, LayerProperties(layer, &decorator)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/layers.h b/windows/winfw/src/extras/cli/commands/list/layers.h new file mode 100644 index 0000000000..92a62c58e0 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/layers.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Layers : public ICommand +{ +public: + + Layers(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/providercontexts.cpp b/windows/winfw/src/extras/cli/commands/list/providercontexts.cpp new file mode 100644 index 0000000000..6612ce03dc --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/providercontexts.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "providercontexts.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "cli/propertydecorator.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +ProviderContexts::ProviderContexts(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring ProviderContexts::name() +{ + return L"providercontexts"; + +} + +std::wstring ProviderContexts::description() +{ + return L"Provides a listing of all provider contexts in the system."; +} + +void ProviderContexts::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + wfp::ObjectEnumerator::ProviderContexts(*FilterEngineProvider::Instance().get(), [&](const FWPM_PROVIDER_CONTEXT0 &context) + { + m_messageSink(L"Provider context"); + + PrettyPrintProperties(m_messageSink, options, ProviderContextProperties(context, &decorator)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/providercontexts.h b/windows/winfw/src/extras/cli/commands/list/providercontexts.h new file mode 100644 index 0000000000..b87886eac7 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/providercontexts.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class ProviderContexts : public ICommand +{ +public: + + ProviderContexts(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/providers.cpp b/windows/winfw/src/extras/cli/commands/list/providers.cpp new file mode 100644 index 0000000000..a06318d74b --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/providers.cpp @@ -0,0 +1,48 @@ +#include "stdafx.h" +#include "providers.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Providers::Providers(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Providers::name() +{ + return L"providers"; + +} + +std::wstring Providers::description() +{ + return L"Provides a listing of all providers in the system."; +} + +void Providers::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + wfp::ObjectEnumerator::Providers(*FilterEngineProvider::Instance().get(), [&](const FWPM_PROVIDER0 &provider) + { + m_messageSink(L"Provider"); + + PrettyPrintProperties(m_messageSink, options, ProviderProperties(provider)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/providers.h b/windows/winfw/src/extras/cli/commands/list/providers.h new file mode 100644 index 0000000000..2a09a88b67 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/providers.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Providers : public ICommand +{ +public: + + Providers(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/sessions.cpp b/windows/winfw/src/extras/cli/commands/list/sessions.cpp new file mode 100644 index 0000000000..27000c903d --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/sessions.cpp @@ -0,0 +1,48 @@ +#include "stdafx.h" +#include "sessions.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Sessions::Sessions(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Sessions::name() +{ + return L"sessions"; + +} + +std::wstring Sessions::description() +{ + return L"Provides a listing of all active sessions in the system."; +} + +void Sessions::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + wfp::ObjectEnumerator::Sessions(*FilterEngineProvider::Instance().get(), [&](const FWPM_SESSION0 &session) + { + m_messageSink(L"Session"); + + PrettyPrintProperties(m_messageSink, options, SessionProperties(session)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/sessions.h b/windows/winfw/src/extras/cli/commands/list/sessions.h new file mode 100644 index 0000000000..b9d8f04ea2 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/sessions.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Sessions : public ICommand +{ +public: + + Sessions(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/list/sublayers.cpp b/windows/winfw/src/extras/cli/commands/list/sublayers.cpp new file mode 100644 index 0000000000..0c8a5f2f58 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/sublayers.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "sublayers.h" +#include "cli/objectproperties.h" +#include "cli/filterengineprovider.h" +#include "cli/propertydecorator.h" +#include "libwfp/objectenumerator.h" + +namespace commands::list +{ + +Sublayers::Sublayers(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Sublayers::name() +{ + return L"sublayers"; + +} + +std::wstring Sublayers::description() +{ + return L"Provides a listing of all sublayers in the system."; +} + +void Sublayers::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + wfp::ObjectEnumerator::Sublayers(*FilterEngineProvider::Instance().get(), [&](const FWPM_SUBLAYER0 &sublayer) + { + m_messageSink(L"Sublayer"); + + PrettyPrintProperties(m_messageSink, options, SublayerProperties(sublayer, &decorator)); + + return true; + }); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/list/sublayers.h b/windows/winfw/src/extras/cli/commands/list/sublayers.h new file mode 100644 index 0000000000..e9b34bbd52 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/list/sublayers.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::list +{ + +class Sublayers : public ICommand +{ +public: + + Sublayers(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/monitor/m_events.cpp b/windows/winfw/src/extras/cli/commands/monitor/m_events.cpp new file mode 100644 index 0000000000..294ae38e9c --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/monitor/m_events.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "m_events.h" +#include "cli/objectproperties.h" +#include "cli/propertydecorator.h" +#include "cli/filterengineprovider.h" +#include "libwfp/objectmonitor.h" +#include <conio.h> + +namespace commands::monitor +{ + +Events::Events(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Events::name() +{ + return L"events"; + +} + +std::wstring Events::description() +{ + return L"Provides monitoring of drop/allow events."; +} + +void Events::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Unsupported argument(s). Cannot complete request."); + } + + wfp::ObjectMonitor objectMonitor(FilterEngineProvider::Instance().get()); + + objectMonitor.monitorEvents(std::bind(&Events::eventCallback, this, std::placeholders::_1)); + + m_messageSink(L"Successfully enabled monitor. Press any key to abort monitoring."); + + // + // This assumes we're in a console environment, but the alternative is to have + // the command (this class) communicate to the outside world that we're in + // a monitoring state. + // + // Hence, this is sufficient for now. + // + + _getwch(); + + objectMonitor.monitorEventsStop(); +} + +void Events::eventCallback(const FWPM_NET_EVENT1 &event) +{ + m_messageSink(L"Event"); + + PrettyPrintOptions options; + + options.indent = 2; + options.useSeparator = true; + + PropertyDecorator decorator(FilterEngineProvider::Instance().get()); + + PrettyPrintProperties(m_messageSink, options, EventProperties(event, &decorator)); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/monitor/m_events.h b/windows/winfw/src/extras/cli/commands/monitor/m_events.h new file mode 100644 index 0000000000..e8724129e8 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/monitor/m_events.h @@ -0,0 +1,28 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" +#include <memory> + +namespace commands::monitor +{ + +class Events : public ICommand +{ +public: + + Events(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; + + void eventCallback(const FWPM_NET_EVENT1 &event); +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/deinit.cpp b/windows/winfw/src/extras/cli/commands/winfw/deinit.cpp new file mode 100644 index 0000000000..d0fc5cfffb --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/deinit.cpp @@ -0,0 +1,35 @@ +#include "stdafx.h" +#include "deinit.h" +#include "winfw/winfw.h" + +namespace commands::winfw +{ + +Deinit::Deinit(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Deinit::name() +{ + return L"deinit"; +} + +std::wstring Deinit::description() +{ + return L"Deinitialize winfw; Destroy session and all associated objects"; +} + +void Deinit::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (false == arguments.empty()) + { + throw std::runtime_error("Invalid argument(s). Cannot complete request."); + } + + m_messageSink((WinFw_Deinitialize() + ? L"Deinitialization completed successfully." + : L"Deinitialization failed. See above for details, if any.")); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/deinit.h b/windows/winfw/src/extras/cli/commands/winfw/deinit.h new file mode 100644 index 0000000000..2395f381de --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/deinit.h @@ -0,0 +1,25 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" + +namespace commands::winfw +{ + +class Deinit : public ICommand +{ +public: + + Deinit(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/init.cpp b/windows/winfw/src/extras/cli/commands/winfw/init.cpp new file mode 100644 index 0000000000..6236027725 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/init.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "init.h" +#include "libcommon/string.h" + +namespace commands::winfw +{ + +Init::Init(MessageSink messageSink) + : m_messageSink(messageSink) +{ +} + +std::wstring Init::name() +{ + return L"init"; +} + +std::wstring Init::description() +{ + return L"Initialize winfw; Create session and fundamental objects"; +} + +void Init::handleRequest(const std::vector<std::wstring> &arguments) +{ + uint32_t timeout = 0; + + if (false == arguments.empty()) + { + auto keyvalue = common::string::SplitKeyValuePairs(arguments); + + if (keyvalue.empty() || 0 != keyvalue.begin()->first.compare(L"timeout")) + { + throw std::runtime_error("Invalid argument. Cannot complete request."); + } + + timeout = wcstoul(keyvalue.begin()->second.c_str(), nullptr, 10); + } + + auto success = WinFw_Initialize(timeout, &Init::ErrorForwarder, this); + + m_messageSink((success + ? L"Initialization completed successfully." + : L"Initialization failed. See above for details, if any.")); +} + +//static +void WINFW_API Init::ErrorForwarder(const char *errorMessage, void *context) +{ + auto thiz = reinterpret_cast<Init *>(context); + + thiz->m_messageSink(common::string::ToWide(errorMessage)); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/init.h b/windows/winfw/src/extras/cli/commands/winfw/init.h new file mode 100644 index 0000000000..f3589535bf --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/init.h @@ -0,0 +1,28 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" +#include "winfw/winfw.h" + +namespace commands::winfw +{ + +class Init : public ICommand +{ +public: + + Init(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; + + static void WINFW_API ErrorForwarder(const char *errorMessage, void *context); +}; + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/policy.cpp b/windows/winfw/src/extras/cli/commands/winfw/policy.cpp new file mode 100644 index 0000000000..04906332aa --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/policy.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "policy.h" +#include "libcommon/string.h" +#include "winfw/winfw.h" +#include <functional> + +namespace commands::winfw +{ + +namespace detail +{ + +WinFwSettings CreateSettings(const std::wstring &dhcp, const std::wstring &lan) +{ + WinFwSettings s; + + s.permitDhcp = (0 == _wcsicmp(dhcp.c_str(), L"yes")); + s.permitLan = (0 == _wcsicmp(lan.c_str(), L"yes")); + + return s; +} + +WinFwProtocol TranslateProtocol(const std::wstring &protocol) +{ + return (0 == _wcsicmp(protocol.c_str(), L"tcp") ? WinFwProtocol::Tcp : WinFwProtocol::Udp); +} + +WinFwRelay CreateRelay(const wchar_t *ip, const std::wstring &port, const std::wstring &protocol) +{ + WinFwRelay r; + + r.ip = ip; + r.port = common::string::LexicalCast<uint16_t>(port); + r.protocol = TranslateProtocol(protocol); + + return r; +} + +} // namespace detail + +Policy::Policy(MessageSink messageSink) + : m_messageSink(messageSink) +{ + m_dispatcher.addSubcommand + ( + L"connecting", + std::bind(&Policy::processConnecting, this, std::placeholders::_1) + ); + + m_dispatcher.addSubcommand + ( + L"connected", + std::bind(&Policy::processConnected, this, std::placeholders::_1) + ); + + m_dispatcher.addSubcommand + ( + L"netblocked", + std::bind(&Policy::processNetBlocked, this) + ); + + m_dispatcher.addSubcommand + ( + L"reset", + std::bind(&Policy::processReset, this) + ); +} + +std::wstring Policy::name() +{ + return L"policy"; +} + +std::wstring Policy::description() +{ + return L"Activate and reset policies."; +} + +void Policy::handleRequest(const std::vector<std::wstring> &arguments) +{ + if (arguments.empty()) + { + throw std::runtime_error("Missing subcommand. Cannot complete request."); + } + + auto subcommand = arguments[0]; + + auto actualArguments(arguments); + actualArguments.erase(actualArguments.begin()); + + m_dispatcher.dispatch(subcommand, actualArguments); +} + +void Policy::processConnecting(const KeyValuePairs &arguments) +{ + auto settings = detail::CreateSettings + ( + GetArgumentValue(arguments, L"dhcp"), + GetArgumentValue(arguments, L"lan") + ); + + auto r = GetArgumentValue(arguments, L"relay"); + + auto relay = detail::CreateRelay + ( + r.c_str(), + GetArgumentValue(arguments, L"port"), + GetArgumentValue(arguments, L"protocol") + ); + + auto success = WinFw_ApplyPolicyConnecting + ( + settings, + relay + ); + + m_messageSink((success + ? L"Successfully applied policy." + : L"Failed to apply policy.")); +} + +void Policy::processConnected(const KeyValuePairs &arguments) +{ + auto settings = detail::CreateSettings + ( + GetArgumentValue(arguments, L"dhcp"), + GetArgumentValue(arguments, L"lan") + ); + + auto r = GetArgumentValue(arguments, L"relay"); + + auto relay = detail::CreateRelay + ( + r.c_str(), + GetArgumentValue(arguments, L"port"), + GetArgumentValue(arguments, L"protocol") + ); + + auto success = WinFw_ApplyPolicyConnected + ( + settings, + relay, + GetArgumentValue(arguments, L"tunnel").c_str(), + GetArgumentValue(arguments, L"dns").c_str() + ); + + m_messageSink((success + ? L"Successfully applied policy." + : L"Failed to apply policy.")); +} + +void Policy::processNetBlocked() +{ + auto success = WinFw_ApplyPolicyNetBlocked(); + + m_messageSink((success + ? L"Successfully applied policy." + : L"Failed to apply policy.")); +} + +void Policy::processReset() +{ + auto success = WinFw_Reset(); + + m_messageSink((success + ? L"Successfully reset policy." + : L"Failed to reset policy.")); +} + +} diff --git a/windows/winfw/src/extras/cli/commands/winfw/policy.h b/windows/winfw/src/extras/cli/commands/winfw/policy.h new file mode 100644 index 0000000000..5d4d15e6b1 --- /dev/null +++ b/windows/winfw/src/extras/cli/commands/winfw/policy.h @@ -0,0 +1,35 @@ +#pragma once + +#include "cli/commands/icommand.h" +#include "cli/util.h" +#include "cli/subcommanddispatcher.h" +#include "libcommon/string.h" + +namespace commands::winfw +{ + +class Policy : public ICommand +{ +public: + + Policy(MessageSink messageSink); + + std::wstring name() override; + std::wstring description() override; + + void handleRequest(const std::vector<std::wstring> &arguments) override; + +private: + + MessageSink m_messageSink; + SubcommandDispatcher m_dispatcher; + + using KeyValuePairs = common::string::KeyValuePairs; + + void processConnecting(const KeyValuePairs &arguments); + void processConnected(const KeyValuePairs &arguments); + void processNetBlocked(); + void processReset(); +}; + +} diff --git a/windows/winfw/src/extras/cli/filterengineprovider.h b/windows/winfw/src/extras/cli/filterengineprovider.h new file mode 100644 index 0000000000..50382c7a6c --- /dev/null +++ b/windows/winfw/src/extras/cli/filterengineprovider.h @@ -0,0 +1,39 @@ +#pragma once + +#include "libwfp/filterengine.h" +#include <memory> + +class FilterEngineProvider +{ + FilterEngineProvider() + { + } + +public: + + static FilterEngineProvider &Instance() + { + static FilterEngineProvider provider; + return provider; + } + + std::shared_ptr<wfp::FilterEngine> get() + { + return m_engine; + } + + // + // naive set(), good for now + // + void set(std::shared_ptr<wfp::FilterEngine> engine) + { + m_engine = engine; + } + +private: + + FilterEngineProvider(const FilterEngineProvider &); + FilterEngineProvider &operator=(const FilterEngineProvider &); + + std::shared_ptr<wfp::FilterEngine> m_engine; +}; diff --git a/windows/winfw/src/extras/cli/inlineformatter.h b/windows/winfw/src/extras/cli/inlineformatter.h new file mode 100644 index 0000000000..f00aa6d504 --- /dev/null +++ b/windows/winfw/src/extras/cli/inlineformatter.h @@ -0,0 +1,30 @@ +#pragma once + +#include <sstream> +#include <utility> + +class InlineFormatter +{ +public: + + template<typename T> + InlineFormatter &operator<<(const T &t) + { + m_ss << t; + return *this; + } + + std::wstring str() + { + auto s = m_ss.str(); + + m_ss.str(L""); + m_ss.clear(); + + return s; + } + +private: + + std::wstringstream m_ss; +}; diff --git a/windows/winfw/src/extras/cli/ipropertydecorator.h b/windows/winfw/src/extras/cli/ipropertydecorator.h new file mode 100644 index 0000000000..01a6021ba1 --- /dev/null +++ b/windows/winfw/src/extras/cli/ipropertydecorator.h @@ -0,0 +1,32 @@ +#pragma once + +// +// These methods should be used during property extraction in order to translate +// identifiers (references) into something more meaningful. +// +// Ideally we would nest a PropertyList inside a PropertyList, but that's a rather +// large update since each element in the PropertyList would need to be wrapped. +// If such an update is made one day, be sure to also add a "group" element so +// we can have better structuring within a PropertyList +// + +#include <windows.h> +#include <string> + +struct IPropertyDecorator +{ + // + // These methods should return a short string that adds + // value for human operators/analysts. + // + + virtual std::wstring FilterDecoration(UINT64 id) = 0; + virtual std::wstring LayerDecoration(UINT16 id) = 0; + virtual std::wstring LayerDecoration(const GUID &key) = 0; + virtual std::wstring ProviderDecoration(const GUID &key) = 0; + virtual std::wstring SublayerDecoration(const GUID &key) = 0; + + virtual ~IPropertyDecorator() = 0 + { + } +}; diff --git a/windows/winfw/src/extras/cli/modules/imodule.h b/windows/winfw/src/extras/cli/modules/imodule.h new file mode 100644 index 0000000000..82221f284f --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/imodule.h @@ -0,0 +1,19 @@ +#pragma once + +#include "cli/propertylist.h" +#include <string> +#include <vector> + +namespace modules +{ + +struct IModule +{ + virtual std::wstring name() = 0; + virtual std::wstring description() = 0; + virtual PropertyList commands() = 0; + + virtual void handleRequest(const std::vector<std::wstring> &request) = 0; +}; + +} diff --git a/windows/winfw/src/extras/cli/modules/list.h b/windows/winfw/src/extras/cli/modules/list.h new file mode 100644 index 0000000000..23751c2a26 --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/list.h @@ -0,0 +1,33 @@ +#pragma once + +#include "module.h" +#include "cli/util.h" +#include "cli/commands/list/sessions.h" +#include "cli/commands/list/providers.h" +#include "cli/commands/list/events.h" +#include "cli/commands/list/filters.h" +#include "cli/commands/list/layers.h" +#include "cli/commands/list/providercontexts.h" +#include "cli/commands/list/sublayers.h" + +namespace modules +{ + +class List : public Module +{ +public: + + List(MessageSink messageSink) + : Module(L"list", L"List various objects in the WFP universe.") + { + addCommand(std::make_unique<commands::list::Sessions>(messageSink)); + addCommand(std::make_unique<commands::list::Providers>(messageSink)); + addCommand(std::make_unique<commands::list::Events>(messageSink)); + addCommand(std::make_unique<commands::list::Filters>(messageSink)); + addCommand(std::make_unique<commands::list::Layers>(messageSink)); + addCommand(std::make_unique<commands::list::ProviderContexts>(messageSink)); + addCommand(std::make_unique<commands::list::Sublayers>(messageSink)); + } +}; + +} diff --git a/windows/winfw/src/extras/cli/modules/module.cpp b/windows/winfw/src/extras/cli/modules/module.cpp new file mode 100644 index 0000000000..f66ae5a084 --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/module.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "module.h" +#include "cli/util.h" +#include "libcommon/string.h" +#include <sstream> +#include <utility> + +namespace modules +{ + +PropertyList Module::commands() +{ + PropertyList c; + + for (auto &command : m_commands) + { + c.add(common::string::Lower(command.second->name()), command.second->description()); + } + + return c; +} + +void Module::handleRequest(const std::vector<std::wstring> &request) +{ + // + // The request has the form of: + // + // [0] command + // [1] arg1 + // [2] arg2 + // ... + // + + if (request.empty()) + { + std::wstringstream ss; + + ss << L"Command missing. Try 'help " << m_name << "'."; + + throw std::runtime_error(common::string::ToAnsi(ss.str())); + } + + auto wanted = common::string::Lower(request[0]); + auto found = m_commands.find(wanted); + + if (found == m_commands.end()) + { + std::wstringstream ss; + + ss << L"Module '" << m_name << "' doesn't support the command '" << request[0] << "'."; + + throw std::runtime_error(common::string::ToAnsi(ss.str())); + } + + auto args = request; + + args.erase(args.begin()); + + found->second->handleRequest(args); +} + +void Module::addCommand(std::unique_ptr<commands::ICommand> command) +{ + m_commands.insert(std::make_pair( + common::string::Lower(command->name()), + std::move(command) + )); +} + +} diff --git a/windows/winfw/src/extras/cli/modules/module.h b/windows/winfw/src/extras/cli/modules/module.h new file mode 100644 index 0000000000..45587ab7e5 --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/module.h @@ -0,0 +1,50 @@ +#pragma once + +#include "imodule.h" +#include "cli/commands/icommand.h" +#include <map> +#include <memory> + +namespace modules +{ + +class Module : public IModule +{ +public: + + Module(const std::wstring &name, const std::wstring &description) + : m_name(name) + , m_description(description) + { + } + + std::wstring name() override + { + return m_name; + } + + std::wstring description() override + { + return m_description; + } + + // Collect name and description from commands. + PropertyList commands() override; + + // Identify requested command and dispatch to it. + void handleRequest(const std::vector<std::wstring> &request) override; + + void addCommand(std::unique_ptr<commands::ICommand> command); + +private: + + Module(const Module &); + Module &operator=(const Module &); + + std::wstring m_name; + std::wstring m_description; + + std::map<std::wstring, std::unique_ptr<commands::ICommand> > m_commands; +}; + +} diff --git a/windows/winfw/src/extras/cli/modules/monitor.h b/windows/winfw/src/extras/cli/modules/monitor.h new file mode 100644 index 0000000000..e227192e82 --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/monitor.h @@ -0,0 +1,21 @@ +#pragma once + +#include "module.h" +#include "cli/util.h" +#include "cli/commands/monitor/m_events.h" + +namespace modules +{ + +class Monitor : public Module +{ +public: + + Monitor(MessageSink messageSink) + : Module(L"monitor", L"Real-time monitoring of events and object creation/deletion in WFP.") + { + addCommand(std::make_unique<commands::monitor::Events>(messageSink)); + } +}; + +} diff --git a/windows/winfw/src/extras/cli/modules/winfw.h b/windows/winfw/src/extras/cli/modules/winfw.h new file mode 100644 index 0000000000..33d5621fe9 --- /dev/null +++ b/windows/winfw/src/extras/cli/modules/winfw.h @@ -0,0 +1,25 @@ +#pragma once + +#include "module.h" +#include "cli/util.h" +#include "cli/commands/winfw/init.h" +#include "cli/commands/winfw/deinit.h" +#include "cli/commands/winfw/policy.h" + +namespace modules +{ + +class WinFw : public Module +{ +public: + + WinFw(MessageSink messageSink) + : Module(L"winfw", L"Exercise functionality provided by \"winfw.dll\".") + { + addCommand(std::make_unique<commands::winfw::Init>(messageSink)); + addCommand(std::make_unique<commands::winfw::Deinit>(messageSink)); + addCommand(std::make_unique<commands::winfw::Policy>(messageSink)); + } +}; + +} diff --git a/windows/winfw/src/extras/cli/objectproperties.cpp b/windows/winfw/src/extras/cli/objectproperties.cpp new file mode 100644 index 0000000000..8b7b5a9c04 --- /dev/null +++ b/windows/winfw/src/extras/cli/objectproperties.cpp @@ -0,0 +1,709 @@ +#include "stdafx.h" +#include "objectproperties.h" +#include "inlineformatter.h" +#include "propertylist.h" +#include "libcommon/string.h" +#include <string> +#include <utility> +#include <vector> +#include <cwchar> + +// Add missing constants +// These are documented in MSDN but not defined in any header? +#define FWP_DIRECTION_IN 0x00003900L +#define FWP_DIRECTION_OUT 0x00003901L +#define FWP_DIRECTION_FORWARD 0x00003902L + +namespace detail +{ + +std::wstring SessionFlags(UINT32 flags) +{ + std::vector<std::pair<UINT32, std::wstring> > definitions = + { + std::make_pair(FWPM_SESSION_FLAG_DYNAMIC, L"FWPM_SESSION_FLAG_DYNAMIC"), + std::make_pair(FWPM_SESSION_FLAG_RESERVED, L"FWPM_SESSION_FLAG_RESERVED") + }; + + return common::string::FormatFlags(definitions, flags); +} + +std::wstring ProviderFlags(UINT32 flags) +{ + std::vector<std::pair<UINT32, std::wstring> > definitions = + { + std::make_pair(FWPM_PROVIDER_FLAG_PERSISTENT, L"FWPM_PROVIDER_FLAG_PERSISTENT"), + std::make_pair(FWPM_PROVIDER_FLAG_DISABLED, L"FWPM_PROVIDER_FLAG_DISABLED") + }; + + return common::string::FormatFlags(definitions, flags); +} + +std::wstring FormatIpProtocol(UINT8 protocol) +{ + switch (protocol) + { + case 0: return L"IPPROTO_HOPOPTS"; + case 1: return L"IPPROTO_ICMP"; + case 2: return L"IPPROTO_IGMP"; + case 3: return L"IPPROTO_GGP"; + case 4: return L"IPPROTO_IPV4"; + case 5: return L"IPPROTO_ST"; + case 6: return L"IPPROTO_TCP"; + case 7: return L"IPPROTO_CBT"; + case 8: return L"IPPROTO_EGP"; + case 9: return L"IPPROTO_IGP"; + case 12: return L"IPPROTO_PUP"; + case 17: return L"IPPROTO_UDP"; + case 22: return L"IPPROTO_IDP"; + case 27: return L"IPPROTO_RDP"; + case 41: return L"IPPROTO_IPV6"; + case 43: return L"IPPROTO_ROUTING"; + case 44: return L"IPPROTO_FRAGMENT"; + case 50: return L"IPPROTO_ESP"; + case 51: return L"IPPROTO_AH"; + case 58: return L"IPPROTO_ICMPV6"; + case 59: return L"IPPROTO_NONE"; + case 60: return L"IPPROTO_DSTOPTS"; + case 77: return L"IPPROTO_ND"; + case 78: return L"IPPROTO_ICLFXBM"; + case 103: return L"IPPROTO_PIM"; + case 113: return L"IPPROTO_PGM"; + case 115: return L"IPPROTO_L2TP"; + case 132: return L"IPPROTO_SCTP"; + case 255: return L"IPPROTO_RAW"; + default: return L"Unknown"; + }; +} + +std::wstring FilterFlags(UINT32 flags) +{ + std::vector<std::pair<UINT32, std::wstring> > definitions = + { + std::make_pair(FWPM_FILTER_FLAG_PERSISTENT, L"FWPM_FILTER_FLAG_PERSISTENT"), + std::make_pair(FWPM_FILTER_FLAG_BOOTTIME, L"FWPM_FILTER_FLAG_BOOTTIME"), + std::make_pair(FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT, L"FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT"), + std::make_pair(FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED, L"FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED"), + std::make_pair(FWPM_FILTER_FLAG_DISABLED, L"FWPM_FILTER_FLAG_DISABLED"), + std::make_pair(FWPM_FILTER_FLAG_INDEXED, L"FWPM_FILTER_FLAG_INDEXED") + }; + + return common::string::FormatFlags(definitions, flags); +} + +std::wstring LayerFlags(UINT32 flags) +{ + std::vector<std::pair<UINT32, std::wstring> > definitions = + { + std::make_pair(FWPM_LAYER_FLAG_KERNEL, L"FWPM_LAYER_FLAG_KERNEL"), + std::make_pair(FWPM_LAYER_FLAG_BUILTIN, L"FWPM_LAYER_FLAG_BUILTIN"), + std::make_pair(FWPM_LAYER_FLAG_CLASSIFY_MOSTLY, L"FWPM_LAYER_FLAG_CLASSIFY_MOSTLY"), + std::make_pair(FWPM_LAYER_FLAG_BUFFERED, L"FWPM_LAYER_FLAG_BUFFERED") + }; + + return common::string::FormatFlags(definitions, flags); +} + +std::wstring ProviderContextType(FWPM_PROVIDER_CONTEXT_TYPE type) +{ + switch (type) + { + case FWPM_IPSEC_KEYING_CONTEXT: return L"FWPM_IPSEC_KEYING_CONTEXT"; + case FWPM_IPSEC_IKE_QM_TRANSPORT_CONTEXT: return L"FWPM_IPSEC_IKE_QM_TRANSPORT_CONTEXT"; + case FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT: return L"FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT"; + case FWPM_IPSEC_AUTHIP_QM_TRANSPORT_CONTEXT: return L"FWPM_IPSEC_AUTHIP_QM_TRANSPORT_CONTEXT"; + case FWPM_IPSEC_AUTHIP_QM_TUNNEL_CONTEXT: return L"FWPM_IPSEC_AUTHIP_QM_TUNNEL_CONTEXT"; + case FWPM_IPSEC_IKE_MM_CONTEXT: return L"FWPM_IPSEC_IKE_MM_CONTEXT"; + case FWPM_IPSEC_AUTHIP_MM_CONTEXT: return L"FWPM_IPSEC_AUTHIP_MM_CONTEXT"; + case FWPM_CLASSIFY_OPTIONS_CONTEXT: return L"FWPM_CLASSIFY_OPTIONS_CONTEXT"; + case FWPM_GENERAL_CONTEXT: return L"FWPM_GENERAL_CONTEXT"; + case FWPM_IPSEC_IKEV2_QM_TUNNEL_CONTEXT: return L"FWPM_IPSEC_IKEV2_QM_TUNNEL_CONTEXT"; + case FWPM_IPSEC_IKEV2_MM_CONTEXT: return L"FWPM_IPSEC_IKEV2_MM_CONTEXT"; + case FWPM_IPSEC_DOSP_CONTEXT: return L"FWPM_IPSEC_DOSP_CONTEXT"; + case FWPM_IPSEC_IKEV2_QM_TRANSPORT_CONTEXT: return L"FWPM_IPSEC_IKEV2_QM_TRANSPORT_CONTEXT"; + default: return L"[Unknown]"; + } +} + +std::wstring Direction(UINT32 direction) +{ + switch (direction) + { + case FWP_DIRECTION_IN: return L"In"; + case FWP_DIRECTION_OUT: return L"Out"; + case FWP_DIRECTION_FORWARD: return L"Forward"; + default: return L"[Unknown]"; + } +} + +std::wstring FilterDecoration(IPropertyDecorator *decorator, UINT64 id) +{ + if (nullptr == decorator) + { + return L""; + } + + return (InlineFormatter() << L" " << decorator->FilterDecoration(id)).str(); +} + +std::wstring LayerDecoration(IPropertyDecorator *decorator, UINT16 id) +{ + if (nullptr == decorator) + { + return L""; + } + + return (InlineFormatter() << L" " << decorator->LayerDecoration(id)).str(); +} + +std::wstring LayerDecoration(IPropertyDecorator *decorator, const GUID &key) +{ + if (nullptr == decorator) + { + return L""; + } + + return (InlineFormatter() << L" " << decorator->LayerDecoration(key)).str(); +} + +std::wstring ProviderDecoration(IPropertyDecorator *decorator, const GUID &key) +{ + if (nullptr == decorator) + { + return L""; + } + + return (InlineFormatter() << L" " << decorator->ProviderDecoration(key)).str(); +} + +std::wstring SublayerDecoration(IPropertyDecorator *decorator, const GUID &key) +{ + if (nullptr == decorator) + { + return L""; + } + + return (InlineFormatter() << L" " << decorator->SublayerDecoration(key)).str(); +} + +void AddStringProperty(PropertyList &props, const wchar_t *name, const wchar_t *value) +{ + if (nullptr == value || 0 == wcslen(value)) + { + return; + } + + props.add(name, value); +} + +// This won't work because sometimes 0 is a valid flag value +//template<typename T> +//void AddFlagProperty(PropertyList &props, const std::wstring &name, T value, std::function<std::wstring(T)> formatter> + +} // namespace detail + +PropertyList SessionProperties(const FWPM_SESSION0 &session) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(session.sessionKey)); + detail::AddStringProperty(props, L"name", session.displayData.name); + detail::AddStringProperty(props, L"description", session.displayData.description); + + props.add(L"flags", (f << session.flags << L" = " << detail::SessionFlags(session.flags)).str()); + props.add(L"wait timeout", (f << session.txnWaitTimeoutInMSec).str()); + props.add(L"sid", common::string::FormatSid(*session.sid)); + props.add(L"username", session.username); + props.add(L"kernel", (session.kernelMode ? L"true" : L"false")); + + return props; +} + +PropertyList ProviderProperties(const FWPM_PROVIDER0 &provider) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(provider.providerKey)); + detail::AddStringProperty(props, L"name", provider.displayData.name); + detail::AddStringProperty(props, L"description", provider.displayData.description); + + props.add(L"flags", (f << provider.flags << L" = " << detail::ProviderFlags(provider.flags)).str()); + + if (0 != provider.providerData.size) + { + props.add(L"provider data", (f << L"Present (" << provider.providerData.size << L" bytes)").str()); + } + + detail::AddStringProperty(props, L"service name", provider.serviceName); + + return props; +} + +PropertyList EventProperties(const FWPM_NET_EVENT0 &event, IPropertyDecorator *decorator) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"timestamp", common::string::FormatTime(event.header.timeStamp)); + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET)) + { + props.add(L"protocol", detail::FormatIpProtocol(event.header.ipProtocol)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_VERSION_SET) + && 0 != (event.header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET)) + { + if (event.header.ipVersion == FWP_IP_VERSION_V4) + { + props.add(L"local addr", common::string::FormatIpv4(event.header.localAddrV4)); + } + else + { + props.add(L"local addr", common::string::FormatIpv6(event.header.localAddrV6.byteArray16)); + } + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_VERSION_SET) + && 0 != (event.header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET)) + { + if (event.header.ipVersion == FWP_IP_VERSION_V4) + { + props.add(L"remote addr", common::string::FormatIpv4(event.header.remoteAddrV4)); + } + else + { + props.add(L"remote addr", common::string::FormatIpv6(event.header.remoteAddrV6.byteArray16)); + } + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)) + { + props.add(L"local port", (f << event.header.localPort).str()); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_REMOTE_PORT_SET)) + { + props.add(L"remote port", (f << event.header.remotePort).str()); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_APP_ID_SET)) + { + auto begin = reinterpret_cast<wchar_t *>(event.header.appId.data); + auto end = begin + (event.header.appId.size / sizeof(wchar_t)); + + props.add(L"app id", std::wstring(begin, end)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_USER_ID_SET)) + { + props.add(L"user id", common::string::FormatSid(*event.header.userId)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_SCOPE_ID_SET)) + { + props.add(L"IPv6 scope id", (f << event.header.scopeId).str()); + } + + switch (event.type) + { + case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE: + { + props.add(L"type", L"IKEEXT_MM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE: + { + props.add(L"type", L"IKEEXT_QM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE: + { + props.add(L"type", L"IKEEXT_EM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP: + { + props.add(L"type", L"CLASSIFY_DROP"); + + props.add(L"filter id", (f << event.classifyDrop->filterId + << detail::FilterDecoration(decorator, event.classifyDrop->filterId)).str()); + + props.add(L"layer id", (f << event.classifyDrop->layerId + << detail::LayerDecoration(decorator, event.classifyDrop->layerId)).str()); + + break; + } + case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP: + { + props.add(L"type", L"IPSEC_KERNEL_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP: + { + props.add(L"type", L"IPSEC_DOSP_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_ALLOW: + { + props.add(L"type", L"CLASSIFY_ALLOW"); + break; + } + case FWPM_NET_EVENT_TYPE_CAPABILITY_DROP: + { + props.add(L"type", L"CAPABILITY_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_CAPABILITY_ALLOW: + { + props.add(L"type", L"CAPABILITY_ALLOW"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP_MAC: + { + props.add(L"type", L"CLASSIFY_DROP_MAC"); + break; + } + default: + { + props.add(L"type", L"Unknown"); + } + }; + + return props; +} + +PropertyList EventProperties(const FWPM_NET_EVENT1 &event, IPropertyDecorator *decorator) +{ + // + // TODO-MAYBE: Restructure code to operate on individual elements of the structure + // then use upcasting and a single implementation for extracting the basic information. + // + + PropertyList props; + InlineFormatter f; + + props.add(L"timestamp", common::string::FormatTime(event.header.timeStamp)); + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET)) + { + props.add(L"protocol", detail::FormatIpProtocol(event.header.ipProtocol)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_VERSION_SET) + && 0 != (event.header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET)) + { + if (event.header.ipVersion == FWP_IP_VERSION_V4) + { + props.add(L"local addr", common::string::FormatIpv4(event.header.localAddrV4)); + } + else + { + props.add(L"local addr", common::string::FormatIpv6(event.header.localAddrV6.byteArray16)); + } + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_IP_VERSION_SET) + && 0 != (event.header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET)) + { + if (event.header.ipVersion == FWP_IP_VERSION_V4) + { + props.add(L"remote addr", common::string::FormatIpv4(event.header.remoteAddrV4)); + } + else + { + props.add(L"remote addr", common::string::FormatIpv6(event.header.remoteAddrV6.byteArray16)); + } + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)) + { + props.add(L"local port", (f << event.header.localPort).str()); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_REMOTE_PORT_SET)) + { + props.add(L"remote port", (f << event.header.remotePort).str()); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_APP_ID_SET)) + { + auto begin = reinterpret_cast<wchar_t *>(event.header.appId.data); + auto end = begin + (event.header.appId.size / sizeof(wchar_t)); + + props.add(L"app id", std::wstring(begin, end)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_USER_ID_SET)) + { + props.add(L"user id", common::string::FormatSid(*event.header.userId)); + } + + if (0 != (event.header.flags & FWPM_NET_EVENT_FLAG_SCOPE_ID_SET)) + { + props.add(L"IPv6 scope id", (f << event.header.scopeId).str()); + } + + switch (event.type) + { + case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE: + { + props.add(L"type", L"IKEEXT_MM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE: + { + props.add(L"type", L"IKEEXT_QM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE: + { + props.add(L"type", L"IKEEXT_EM_FAILURE"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP: + { + props.add(L"type", L"CLASSIFY_DROP"); + + props.add(L"filter id", (f << event.classifyDrop->filterId + << detail::FilterDecoration(decorator, event.classifyDrop->filterId)).str()); + + props.add(L"layer id", (f << event.classifyDrop->layerId + << detail::LayerDecoration(decorator, event.classifyDrop->layerId)).str()); + + props.add(L"direction", detail::Direction(event.classifyDrop->msFwpDirection)); + + if (1 == event.classifyDrop->isLoopback) + { + props.add(L"loopback", L"True"); + } + + break; + } + case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP: + { + props.add(L"type", L"IPSEC_KERNEL_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP: + { + props.add(L"type", L"IPSEC_DOSP_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_ALLOW: + { + props.add(L"type", L"CLASSIFY_ALLOW"); + break; + } + case FWPM_NET_EVENT_TYPE_CAPABILITY_DROP: + { + props.add(L"type", L"CAPABILITY_DROP"); + break; + } + case FWPM_NET_EVENT_TYPE_CAPABILITY_ALLOW: + { + props.add(L"type", L"CAPABILITY_ALLOW"); + break; + } + case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP_MAC: + { + props.add(L"type", L"CLASSIFY_DROP_MAC"); + break; + } + default: + { + props.add(L"type", L"Unknown"); + } + }; + + return props; +} + +PropertyList FilterProperties(const FWPM_FILTER0 &filter, IPropertyDecorator *decorator) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(filter.filterKey)); + detail::AddStringProperty(props, L"name", filter.displayData.name); + detail::AddStringProperty(props, L"description", filter.displayData.description); + + props.add(L"flags", (f << filter.flags << L" = " << detail::FilterFlags(filter.flags)).str()); + + if (nullptr != filter.providerKey) + { + props.add(L"provider key", (f << common::string::FormatGuid(*filter.providerKey) + << detail::ProviderDecoration(decorator, *filter.providerKey)).str()); + } + + if (0 != filter.providerData.size) + { + props.add(L"provider data", (f << L"Present (" << filter.providerData.size << L" bytes)").str()); + } + + props.add(L"layer key", (f << common::string::FormatGuid(filter.layerKey) + << detail::LayerDecoration(decorator, filter.layerKey)).str()); + + props.add(L"sublayer key", (f << common::string::FormatGuid(filter.subLayerKey) + << detail::SublayerDecoration(decorator, filter.subLayerKey)).str()); + + if (FWP_UINT64 == filter.weight.type) + { + props.add(L"weight", (f << *filter.weight.uint64 << L" (exact)").str()); + } + else if (FWP_UINT8 == filter.weight.type) + { + props.add(L"weight", (f << filter.weight.uint8 << L" (relative 0-15)").str()); + } + else + { + props.add(L"weight", L"Automatic"); + } + + props.add(L"num conditions", (f << filter.numFilterConditions).str()); + props.add(L"conditions", L"TODO"); + + if (FWP_ACTION_BLOCK == filter.action.type) + { + props.add(L"action", L"Block"); + props.add(L"filter type", common::string::FormatGuid(filter.action.filterType)); + } + else if (FWP_ACTION_PERMIT == filter.action.type) + { + props.add(L"action", L"Permit"); + props.add(L"filter type", common::string::FormatGuid(filter.action.filterType)); + } + else if (FWP_ACTION_CALLOUT_TERMINATING == filter.action.type) + { + props.add(L"action", L"Callout terminating"); + props.add(L"callout key", common::string::FormatGuid(filter.action.calloutKey)); + } + else if (FWP_ACTION_CALLOUT_INSPECTION == filter.action.type) + { + props.add(L"action", L"Callout inspection"); + props.add(L"callout key", common::string::FormatGuid(filter.action.calloutKey)); + } + else if (FWP_ACTION_CALLOUT_UNKNOWN == filter.action.type) + { + props.add(L"action", L"Callout unknown"); + props.add(L"callout key", common::string::FormatGuid(filter.action.calloutKey)); + } + + if (0 != (filter.flags & FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT)) + { + props.add(L"context", L"Provider context"); + } + else + { + props.add(L"context", L"Raw context"); + } + + props.add(L"filter id", (f << filter.filterId).str()); + + if (FWP_UINT64 == filter.effectiveWeight.type) + { + props.add(L"effective weight", (f << *filter.effectiveWeight.uint64 << L" (exact)").str()); + } + else if (FWP_UINT8 == filter.effectiveWeight.type) + { + props.add(L"effective weight", (f << filter.effectiveWeight.uint8 << L" (relative 0-15)").str()); + } + else + { + props.add(L"effective weight", L"Automatic"); + } + + return props; +} + +PropertyList LayerProperties(const FWPM_LAYER0 &layer, IPropertyDecorator *decorator) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(layer.layerKey)); + detail::AddStringProperty(props, L"name", layer.displayData.name); + detail::AddStringProperty(props, L"description", layer.displayData.description); + + props.add(L"flags", (f << layer.flags << L" = " << detail::LayerFlags(layer.flags)).str()); + props.add(L"num fields", (f << layer.numFields).str()); + props.add(L"field array", L"TODO"); + + props.add(L"default sublayer", (f << common::string::FormatGuid(layer.defaultSubLayerKey) + << detail::SublayerDecoration(decorator, layer.defaultSubLayerKey)).str()); + + props.add(L"layer id", (f << layer.layerId).str()); + + return props; +} + +PropertyList ProviderContextProperties(const FWPM_PROVIDER_CONTEXT0 &context, IPropertyDecorator *decorator) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(context.providerContextKey)); + detail::AddStringProperty(props, L"name", context.displayData.name); + detail::AddStringProperty(props, L"description", context.displayData.description); + + if (0 != (context.flags & FWPM_PROVIDER_CONTEXT_FLAG_PERSISTENT)) + { + props.add(L"flags", L"FWPM_PROVIDER_CONTEXT_FLAG_PERSISTENT"); + } + else + { + props.add(L"flags", (f << context.flags).str()); + } + + if (nullptr != context.providerKey) + { + props.add(L"provider key", (f << common::string::FormatGuid(*context.providerKey) + << detail::ProviderDecoration(decorator, *context.providerKey)).str()); + } + + if (0 != context.providerData.size) + { + props.add(L"provider data", (f << L"Present (" << context.providerData.size << L" bytes)").str()); + } + + props.add(L"context type", detail::ProviderContextType(context.type)); + props.add(L"id", (f << context.providerContextId).str()); + + return props; +} + +PropertyList SublayerProperties(const FWPM_SUBLAYER0 &sublayer, IPropertyDecorator *decorator) +{ + PropertyList props; + InlineFormatter f; + + props.add(L"key", common::string::FormatGuid(sublayer.subLayerKey)); + detail::AddStringProperty(props, L"name", sublayer.displayData.name); + detail::AddStringProperty(props, L"description", sublayer.displayData.description); + + if (0 != (sublayer.flags & FWPM_SUBLAYER_FLAG_PERSISTENT)) + { + props.add(L"flags", L"FWPM_SUBLAYER_FLAG_PERSISTENT"); + } + else + { + props.add(L"flags", (f << sublayer.flags).str()); + } + + if (nullptr != sublayer.providerKey) + { + props.add(L"provider key", (f << common::string::FormatGuid(*sublayer.providerKey) + << detail::ProviderDecoration(decorator, *sublayer.providerKey)).str()); + } + + if (0 != sublayer.providerData.size) + { + props.add(L"provider data", (f << L"Present (" << sublayer.providerData.size << L" bytes)").str()); + } + + props.add(L"weight", (f << sublayer.weight).str()); + + return props; +} diff --git a/windows/winfw/src/extras/cli/objectproperties.h b/windows/winfw/src/extras/cli/objectproperties.h new file mode 100644 index 0000000000..a4f349f828 --- /dev/null +++ b/windows/winfw/src/extras/cli/objectproperties.h @@ -0,0 +1,15 @@ +#pragma once + +#include "propertylist.h" +#include "ipropertydecorator.h" +#include <windows.h> +#include <fwpmu.h> + +PropertyList SessionProperties(const FWPM_SESSION0 &session); +PropertyList ProviderProperties(const FWPM_PROVIDER0 &provider); +PropertyList EventProperties(const FWPM_NET_EVENT0 &event, IPropertyDecorator *decorator = nullptr); +PropertyList EventProperties(const FWPM_NET_EVENT1 &event, IPropertyDecorator *decorator = nullptr); +PropertyList FilterProperties(const FWPM_FILTER0 &filter, IPropertyDecorator *decorator = nullptr); +PropertyList LayerProperties(const FWPM_LAYER0 &layer, IPropertyDecorator *decorator = nullptr); +PropertyList ProviderContextProperties(const FWPM_PROVIDER_CONTEXT0 &context, IPropertyDecorator *decorator = nullptr); +PropertyList SublayerProperties(const FWPM_SUBLAYER0 &sublayer, IPropertyDecorator *decorator = nullptr); diff --git a/windows/winfw/src/extras/cli/propertydecorator.cpp b/windows/winfw/src/extras/cli/propertydecorator.cpp new file mode 100644 index 0000000000..115c628c27 --- /dev/null +++ b/windows/winfw/src/extras/cli/propertydecorator.cpp @@ -0,0 +1,92 @@ +#include "stdafx.h" +#include "propertydecorator.h" +#include "libwfp/objectexplorer.h" +#include "libcommon/string.h" +#include "inlineformatter.h" +#include <cwchar> + +namespace detail +{ + +std::wstring Format(const wchar_t *in_name, const wchar_t *in_desc) +{ + auto haveName = (nullptr != in_name && 0 != wcslen(in_name)); + auto haveDesc = (nullptr != in_desc && 0 != wcslen(in_desc)); + + std::wstring name = (haveName ? in_name : L"n/a"); + std::wstring desc = (haveDesc ? common::string::Summary(in_desc, 50) : L"n/a"); + + return (InlineFormatter() << L"[" << name << L", " << desc << L"]").str(); +} + +} // namespace detail + +PropertyDecorator::PropertyDecorator(std::shared_ptr<wfp::FilterEngine> engine) + : m_engine(engine) +{ +} + +std::wstring PropertyDecorator::FilterDecoration(UINT64 id) +{ + std::wstring brief = L"[n/a]"; + + wfp::ObjectExplorer::GetFilter(*m_engine, id, [&brief](const FWPM_FILTER0 &filter) + { + brief = detail::Format(filter.displayData.name, filter.displayData.description); + return true; + }); + + return brief; +} + +std::wstring PropertyDecorator::LayerDecoration(UINT16 id) +{ + std::wstring brief = L"[n/a]"; + + wfp::ObjectExplorer::GetLayer(*m_engine, id, [&brief](const FWPM_LAYER0 &layer) + { + brief = detail::Format(layer.displayData.name, layer.displayData.description); + return true; + }); + + return brief; +} + +std::wstring PropertyDecorator::LayerDecoration(const GUID &key) +{ + std::wstring brief = L"[n/a]"; + + wfp::ObjectExplorer::GetLayer(*m_engine, key, [&brief](const FWPM_LAYER0 &layer) + { + brief = detail::Format(layer.displayData.name, layer.displayData.description); + return true; + }); + + return brief; +} + +std::wstring PropertyDecorator::ProviderDecoration(const GUID &key) +{ + std::wstring brief = L"[n/a]"; + + wfp::ObjectExplorer::GetProvider(*m_engine, key, [&brief](const FWPM_PROVIDER0 &provider) + { + brief = detail::Format(provider.displayData.name, provider.displayData.description); + return true; + }); + + return brief; +} + +std::wstring PropertyDecorator::SublayerDecoration(const GUID &key) +{ + std::wstring brief = L"[n/a]"; + + wfp::ObjectExplorer::GetSublayer(*m_engine, key, [&brief](const FWPM_SUBLAYER0 &sublayer) + { + brief = detail::Format(sublayer.displayData.name, sublayer.displayData.description); + return true; + }); + + return brief; +} diff --git a/windows/winfw/src/extras/cli/propertydecorator.h b/windows/winfw/src/extras/cli/propertydecorator.h new file mode 100644 index 0000000000..b021d275e1 --- /dev/null +++ b/windows/winfw/src/extras/cli/propertydecorator.h @@ -0,0 +1,27 @@ +#pragma once + +#include "ipropertydecorator.h" +#include "libwfp/filterengine.h" +#include <memory> + +class PropertyDecorator : public IPropertyDecorator +{ +public: + + PropertyDecorator(std::shared_ptr<wfp::FilterEngine> engine); + + // + // The format of the returned string: + // [name, first 50 chars of description] + // + + std::wstring FilterDecoration(UINT64 id) override; + std::wstring LayerDecoration(UINT16 id) override; + std::wstring LayerDecoration(const GUID &key) override; + std::wstring ProviderDecoration(const GUID &key) override; + std::wstring SublayerDecoration(const GUID &key) override; + +private: + + std::shared_ptr<wfp::FilterEngine> m_engine; +}; diff --git a/windows/winfw/src/extras/cli/propertylist.h b/windows/winfw/src/extras/cli/propertylist.h new file mode 100644 index 0000000000..b5d9d71499 --- /dev/null +++ b/windows/winfw/src/extras/cli/propertylist.h @@ -0,0 +1,55 @@ +#pragma once + +#include <string> +#include <utility> +#include <vector> + +class PropertyList +{ +public: + + struct Property + { + Property(const std::wstring &n, const std::wstring &v) + : name(n), value(v) + { + } + + Property(std::wstring &&n, std::wstring &&v) + : name(n), value(v) + { + } + + std::wstring name; + std::wstring value; + }; + + void add(const std::wstring &name, const std::wstring &value) + { + m_properties.emplace_back(name, value); + } + + void add(std::wstring &&name, std::wstring &&value) + { + m_properties.emplace_back(name, value); + } + + const std::vector<Property> &list() + { + return m_properties; + } + + std::vector<Property>::const_iterator begin() const + { + return m_properties.begin(); + } + + std::vector<Property>::const_iterator end() const + { + return m_properties.end(); + } + +private: + + std::vector<Property> m_properties; +}; diff --git a/windows/winfw/src/extras/cli/stdafx.cpp b/windows/winfw/src/extras/cli/stdafx.cpp new file mode 100644 index 0000000000..62355160c9 --- /dev/null +++ b/windows/winfw/src/extras/cli/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// cli.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/winfw/src/extras/cli/stdafx.h b/windows/winfw/src/extras/cli/stdafx.h new file mode 100644 index 0000000000..b005a839de --- /dev/null +++ b/windows/winfw/src/extras/cli/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/winfw/src/extras/cli/subcommanddispatcher.cpp b/windows/winfw/src/extras/cli/subcommanddispatcher.cpp new file mode 100644 index 0000000000..4bb7868cd7 --- /dev/null +++ b/windows/winfw/src/extras/cli/subcommanddispatcher.cpp @@ -0,0 +1,27 @@ +#include "stdafx.h" +#include "subcommanddispatcher.h" +#include "libcommon/string.h" +#include <sstream> +#include <stdexcept> +#include <utility> + +void SubcommandDispatcher::addSubcommand(const std::wstring &command, Handler handler) +{ + m_commands.insert(std::make_pair(command, handler)); +} + +void SubcommandDispatcher::dispatch(const std::wstring &command, const std::vector<std::wstring> &arguments) +{ + auto selectedCommand = m_commands.find(command); + + if (m_commands.end() == selectedCommand) + { + std::wstringstream ss; + + ss << L"Unsupported subcommand '" << command << "'. Cannot complete request."; + + throw std::runtime_error(common::string::ToAnsi(ss.str()).c_str()); + } + + selectedCommand->second(common::string::SplitKeyValuePairs(arguments)); +} diff --git a/windows/winfw/src/extras/cli/subcommanddispatcher.h b/windows/winfw/src/extras/cli/subcommanddispatcher.h new file mode 100644 index 0000000000..a480ec8104 --- /dev/null +++ b/windows/winfw/src/extras/cli/subcommanddispatcher.h @@ -0,0 +1,20 @@ +#pragma once + +#include "libcommon/string.h" +#include <functional> +#include <string> +#include <unordered_map> + +class SubcommandDispatcher +{ + typedef std::function<void(const common::string::KeyValuePairs &)> Handler; + +public: + + void addSubcommand(const std::wstring &command, Handler handler); + void dispatch(const std::wstring &command, const std::vector<std::wstring> &arguments); + +private: + + std::unordered_map<std::wstring, Handler> m_commands; +}; diff --git a/windows/winfw/src/extras/cli/targetver.h b/windows/winfw/src/extras/cli/targetver.h new file mode 100644 index 0000000000..ae4a5c032c --- /dev/null +++ b/windows/winfw/src/extras/cli/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/winfw/src/extras/cli/util.cpp b/windows/winfw/src/extras/cli/util.cpp new file mode 100644 index 0000000000..6181e68639 --- /dev/null +++ b/windows/winfw/src/extras/cli/util.cpp @@ -0,0 +1,62 @@ +#include "stdafx.h" +#include "util.h" +#include "inlineformatter.h" +#include "libcommon/string.h" +#include <string> + +void PrettyPrintProperties(MessageSink messageSink, PrettyPrintOptions options, const PropertyList &properties) +{ + size_t longestName = 0; + + for (auto &property : properties) + { + longestName = max(longestName, property.name.size()); + } + + // + // Format is: + // indent, name, [separator], tab, [tab, ...] + // + + const auto separator = std::wstring(options.useSeparator ? L":" : L""); + + auto insert = options.indent + longestName + separator.size(); + + if (0 == (insert % 8)) + { + insert += 8; + } + else + { + insert = ((insert / 8) + 1) * 8; + } + + std::wstring indenter(options.indent, L' '); + InlineFormatter f; + + for (auto &property : properties) + { + auto at = options.indent + property.name.size() + separator.size(); + auto distance = insert - at; + auto tabs = (0 == (distance % 8) ? distance / 8 : (distance / 8) + 1); + + messageSink((f << indenter << property.name << separator + << std::wstring(tabs, L'\t') << property.value).str()); + } +} + +std::wstring GetArgumentValue(const common::string::KeyValuePairs &arguments, const std::wstring &key) +{ + auto arg = arguments.find(key); + + if (arguments.end() == arg) + { + std::wstringstream ss; + + ss << L"Missing argument: '" << key << L"'"; + + throw std::runtime_error(common::string::ToAnsi(ss.str())); + } + + return arg->second; +} diff --git a/windows/winfw/src/extras/cli/util.h b/windows/winfw/src/extras/cli/util.h new file mode 100644 index 0000000000..3919e03422 --- /dev/null +++ b/windows/winfw/src/extras/cli/util.h @@ -0,0 +1,20 @@ +#pragma once + +#include <functional> +#include <memory> +#include <string> +#include "propertylist.h" +#include "libwfp/filterengine.h" +#include "libcommon/string.h" + +typedef std::function<void(const std::wstring &)> MessageSink; + +struct PrettyPrintOptions +{ + size_t indent; + bool useSeparator; +}; + +void PrettyPrintProperties(MessageSink, PrettyPrintOptions options, const PropertyList &properties); + +std::wstring GetArgumentValue(const common::string::KeyValuePairs &arguments, const std::wstring &key); |
