summaryrefslogtreecommitdiffhomepage
path: root/wfpctl/src/extras
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2018-04-11 10:36:43 +0200
committerOdd Stranne <odd@mullvad.net>2018-04-11 10:36:43 +0200
commit1b97cdcd94e549decfe1d6081155c8efefe9b110 (patch)
tree66bc668bfe1868d925e32044373af83a3175bd2d /wfpctl/src/extras
parenta5f7cf5592003093caaa658516758fb3c45206d1 (diff)
parentf53d90c5d69e81b09eec67a406825c96ea19d072 (diff)
downloadmullvadvpn-1b97cdcd94e549decfe1d6081155c8efefe9b110.tar.xz
mullvadvpn-1b97cdcd94e549decfe1d6081155c8efefe9b110.zip
Merge branch 'migrate-wfpctl'
Diffstat (limited to 'wfpctl/src/extras')
-rw-r--r--wfpctl/src/extras/cli/cli.cpp173
-rw-r--r--wfpctl/src/extras/cli/cli.vcxproj230
-rw-r--r--wfpctl/src/extras/cli/cli.vcxproj.filters127
-rw-r--r--wfpctl/src/extras/cli/commands/icommand.h17
-rw-r--r--wfpctl/src/extras/cli/commands/list/events.cpp51
-rw-r--r--wfpctl/src/extras/cli/commands/list/events.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/filters.cpp51
-rw-r--r--wfpctl/src/extras/cli/commands/list/filters.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/layers.cpp51
-rw-r--r--wfpctl/src/extras/cli/commands/list/layers.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/providercontexts.cpp51
-rw-r--r--wfpctl/src/extras/cli/commands/list/providercontexts.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/providers.cpp48
-rw-r--r--wfpctl/src/extras/cli/commands/list/providers.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/sessions.cpp48
-rw-r--r--wfpctl/src/extras/cli/commands/list/sessions.h25
-rw-r--r--wfpctl/src/extras/cli/commands/list/sublayers.cpp51
-rw-r--r--wfpctl/src/extras/cli/commands/list/sublayers.h25
-rw-r--r--wfpctl/src/extras/cli/commands/monitor/m_events.cpp68
-rw-r--r--wfpctl/src/extras/cli/commands/monitor/m_events.h28
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/deinit.cpp35
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/deinit.h25
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/init.cpp54
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/init.h28
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/policy.cpp155
-rw-r--r--wfpctl/src/extras/cli/commands/wfpctl/policy.h34
-rw-r--r--wfpctl/src/extras/cli/filterengineprovider.h39
-rw-r--r--wfpctl/src/extras/cli/inlineformatter.h30
-rw-r--r--wfpctl/src/extras/cli/ipropertydecorator.h32
-rw-r--r--wfpctl/src/extras/cli/modules/imodule.h19
-rw-r--r--wfpctl/src/extras/cli/modules/list.h33
-rw-r--r--wfpctl/src/extras/cli/modules/module.cpp70
-rw-r--r--wfpctl/src/extras/cli/modules/module.h50
-rw-r--r--wfpctl/src/extras/cli/modules/monitor.h21
-rw-r--r--wfpctl/src/extras/cli/modules/wfpctl.h25
-rw-r--r--wfpctl/src/extras/cli/objectproperties.cpp709
-rw-r--r--wfpctl/src/extras/cli/objectproperties.h15
-rw-r--r--wfpctl/src/extras/cli/propertydecorator.cpp92
-rw-r--r--wfpctl/src/extras/cli/propertydecorator.h27
-rw-r--r--wfpctl/src/extras/cli/propertylist.h55
-rw-r--r--wfpctl/src/extras/cli/stdafx.cpp8
-rw-r--r--wfpctl/src/extras/cli/stdafx.h15
-rw-r--r--wfpctl/src/extras/cli/subcommanddispatcher.cpp27
-rw-r--r--wfpctl/src/extras/cli/subcommanddispatcher.h20
-rw-r--r--wfpctl/src/extras/cli/targetver.h12
-rw-r--r--wfpctl/src/extras/cli/util.cpp62
-rw-r--r--wfpctl/src/extras/cli/util.h20
47 files changed, 2881 insertions, 0 deletions
diff --git a/wfpctl/src/extras/cli/cli.cpp b/wfpctl/src/extras/cli/cli.cpp
new file mode 100644
index 0000000000..9595c24234
--- /dev/null
+++ b/wfpctl/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/wfpctl.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 wfpctl = std::make_unique<modules::Wfpctl>(OutputConsole);
+ g_modules.insert(std::make_pair(common::string::Lower(wfpctl->name()), std::move(wfpctl)));
+}
+
+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/wfpctl/src/extras/cli/cli.vcxproj b/wfpctl/src/extras/cli/cli.vcxproj
new file mode 100644
index 0000000000..86d6094f63
--- /dev/null
+++ b/wfpctl/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\</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>wfpctl.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\</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wfpctl.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\</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <LanguageStandard>stdcpplatest</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>wfpctl.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\</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>wfpctl.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\wfpctl\deinit.h" />
+ <ClInclude Include="commands\wfpctl\init.h" />
+ <ClInclude Include="commands\wfpctl\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\wfpctl.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\wfpctl\deinit.cpp" />
+ <ClCompile Include="commands\wfpctl\init.cpp" />
+ <ClCompile Include="commands\wfpctl\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/wfpctl/src/extras/cli/cli.vcxproj.filters b/wfpctl/src/extras/cli/cli.vcxproj.filters
new file mode 100644
index 0000000000..fabc1492f8
--- /dev/null
+++ b/wfpctl/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\wfpctl">
+ <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\wfpctl\policy.h">
+ <Filter>commands\wfpctl</Filter>
+ </ClInclude>
+ <ClInclude Include="subcommanddispatcher.h" />
+ <ClInclude Include="modules\wfpctl.h">
+ <Filter>modules</Filter>
+ </ClInclude>
+ <ClInclude Include="commands\wfpctl\init.h">
+ <Filter>commands\wfpctl</Filter>
+ </ClInclude>
+ <ClInclude Include="commands\wfpctl\deinit.h">
+ <Filter>commands\wfpctl</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\wfpctl\policy.cpp">
+ <Filter>commands\wfpctl</Filter>
+ </ClCompile>
+ <ClCompile Include="subcommanddispatcher.cpp" />
+ <ClCompile Include="commands\wfpctl\init.cpp">
+ <Filter>commands\wfpctl</Filter>
+ </ClCompile>
+ <ClCompile Include="commands\wfpctl\deinit.cpp">
+ <Filter>commands\wfpctl</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/wfpctl/src/extras/cli/commands/icommand.h b/wfpctl/src/extras/cli/commands/icommand.h
new file mode 100644
index 0000000000..a9503a205b
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/events.cpp b/wfpctl/src/extras/cli/commands/list/events.cpp
new file mode 100644
index 0000000000..4396eff980
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/events.h b/wfpctl/src/extras/cli/commands/list/events.h
new file mode 100644
index 0000000000..cc727712f0
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/filters.cpp b/wfpctl/src/extras/cli/commands/list/filters.cpp
new file mode 100644
index 0000000000..9c7917bf66
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/filters.h b/wfpctl/src/extras/cli/commands/list/filters.h
new file mode 100644
index 0000000000..4c0345f3b3
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/layers.cpp b/wfpctl/src/extras/cli/commands/list/layers.cpp
new file mode 100644
index 0000000000..3dc4368894
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/layers.h b/wfpctl/src/extras/cli/commands/list/layers.h
new file mode 100644
index 0000000000..92a62c58e0
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/providercontexts.cpp b/wfpctl/src/extras/cli/commands/list/providercontexts.cpp
new file mode 100644
index 0000000000..6612ce03dc
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/providercontexts.h b/wfpctl/src/extras/cli/commands/list/providercontexts.h
new file mode 100644
index 0000000000..b87886eac7
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/providers.cpp b/wfpctl/src/extras/cli/commands/list/providers.cpp
new file mode 100644
index 0000000000..a06318d74b
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/providers.h b/wfpctl/src/extras/cli/commands/list/providers.h
new file mode 100644
index 0000000000..2a09a88b67
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/sessions.cpp b/wfpctl/src/extras/cli/commands/list/sessions.cpp
new file mode 100644
index 0000000000..27000c903d
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/sessions.h b/wfpctl/src/extras/cli/commands/list/sessions.h
new file mode 100644
index 0000000000..b9d8f04ea2
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/sublayers.cpp b/wfpctl/src/extras/cli/commands/list/sublayers.cpp
new file mode 100644
index 0000000000..0c8a5f2f58
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/list/sublayers.h b/wfpctl/src/extras/cli/commands/list/sublayers.h
new file mode 100644
index 0000000000..e9b34bbd52
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/monitor/m_events.cpp b/wfpctl/src/extras/cli/commands/monitor/m_events.cpp
new file mode 100644
index 0000000000..294ae38e9c
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/monitor/m_events.h b/wfpctl/src/extras/cli/commands/monitor/m_events.h
new file mode 100644
index 0000000000..e8724129e8
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/commands/wfpctl/deinit.cpp b/wfpctl/src/extras/cli/commands/wfpctl/deinit.cpp
new file mode 100644
index 0000000000..fc5f5e0b2e
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/deinit.cpp
@@ -0,0 +1,35 @@
+#include "stdafx.h"
+#include "deinit.h"
+#include "wfpctl/wfpctl.h"
+
+namespace commands::wfpctl
+{
+
+Deinit::Deinit(MessageSink messageSink)
+ : m_messageSink(messageSink)
+{
+}
+
+std::wstring Deinit::name()
+{
+ return L"deinit";
+}
+
+std::wstring Deinit::description()
+{
+ return L"Deinitialize wfpctl; 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((Wfpctl_Deinitialize()
+ ? L"Deinitialization completed successfully."
+ : L"Deinitialization failed. See above for details, if any."));
+}
+
+}
diff --git a/wfpctl/src/extras/cli/commands/wfpctl/deinit.h b/wfpctl/src/extras/cli/commands/wfpctl/deinit.h
new file mode 100644
index 0000000000..f445566f02
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/deinit.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "cli/commands/icommand.h"
+#include "cli/util.h"
+
+namespace commands::wfpctl
+{
+
+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/wfpctl/src/extras/cli/commands/wfpctl/init.cpp b/wfpctl/src/extras/cli/commands/wfpctl/init.cpp
new file mode 100644
index 0000000000..eb569f55e7
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/init.cpp
@@ -0,0 +1,54 @@
+#include "stdafx.h"
+#include "init.h"
+#include "libcommon/string.h"
+
+namespace commands::wfpctl
+{
+
+Init::Init(MessageSink messageSink)
+ : m_messageSink(messageSink)
+{
+}
+
+std::wstring Init::name()
+{
+ return L"init";
+}
+
+std::wstring Init::description()
+{
+ return L"Initialize wfpctl; 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 = Wfpctl_Initialize(timeout, &Init::ErrorForwarder, this);
+
+ m_messageSink((success
+ ? L"Initialization completed successfully."
+ : L"Initialization failed. See above for details, if any."));
+}
+
+//static
+void WFPCTL_API Init::ErrorForwarder(const char *errorMessage, void *context)
+{
+ auto thiz = reinterpret_cast<Init *>(context);
+
+ thiz->m_messageSink(common::string::ToWide(errorMessage));
+}
+
+}
diff --git a/wfpctl/src/extras/cli/commands/wfpctl/init.h b/wfpctl/src/extras/cli/commands/wfpctl/init.h
new file mode 100644
index 0000000000..96686a2680
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/init.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "cli/commands/icommand.h"
+#include "cli/util.h"
+#include "wfpctl/wfpctl.h"
+
+namespace commands::wfpctl
+{
+
+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 WFPCTL_API ErrorForwarder(const char *errorMessage, void *context);
+};
+
+}
diff --git a/wfpctl/src/extras/cli/commands/wfpctl/policy.cpp b/wfpctl/src/extras/cli/commands/wfpctl/policy.cpp
new file mode 100644
index 0000000000..e323260e48
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/policy.cpp
@@ -0,0 +1,155 @@
+#include "stdafx.h"
+#include "policy.h"
+#include "libcommon/string.h"
+#include "wfpctl/wfpctl.h"
+#include <functional>
+
+namespace commands::wfpctl
+{
+
+namespace detail
+{
+
+WfpctlSettings CreateSettings(const std::wstring &dhcp, const std::wstring &lan)
+{
+ WfpctlSettings s;
+
+ s.permitDhcp = (0 == _wcsicmp(dhcp.c_str(), L"yes"));
+ s.permitLan = (0 == _wcsicmp(lan.c_str(), L"yes"));
+
+ return s;
+}
+
+WfpctlProtocol TranslateProtocol(const std::wstring &protocol)
+{
+ return (0 == _wcsicmp(protocol.c_str(), L"tcp") ? WfpctlProtocol::Tcp : WfpctlProtocol::Udp);
+}
+
+WfpctlRelay CreateRelay(const wchar_t *ip, const std::wstring &port, const std::wstring &protocol)
+{
+ WfpctlRelay 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"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 = Wfpctl_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 = Wfpctl_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::processReset()
+{
+ auto success = Wfpctl_Reset();
+
+ m_messageSink((success
+ ? L"Successfully reset policy."
+ : L"Failed to reset policy."));
+}
+
+}
diff --git a/wfpctl/src/extras/cli/commands/wfpctl/policy.h b/wfpctl/src/extras/cli/commands/wfpctl/policy.h
new file mode 100644
index 0000000000..28d966fa21
--- /dev/null
+++ b/wfpctl/src/extras/cli/commands/wfpctl/policy.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "cli/commands/icommand.h"
+#include "cli/util.h"
+#include "cli/subcommanddispatcher.h"
+#include "libcommon/string.h"
+
+namespace commands::wfpctl
+{
+
+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 processReset();
+};
+
+}
diff --git a/wfpctl/src/extras/cli/filterengineprovider.h b/wfpctl/src/extras/cli/filterengineprovider.h
new file mode 100644
index 0000000000..50382c7a6c
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/inlineformatter.h b/wfpctl/src/extras/cli/inlineformatter.h
new file mode 100644
index 0000000000..f00aa6d504
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/ipropertydecorator.h b/wfpctl/src/extras/cli/ipropertydecorator.h
new file mode 100644
index 0000000000..01a6021ba1
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/imodule.h b/wfpctl/src/extras/cli/modules/imodule.h
new file mode 100644
index 0000000000..82221f284f
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/list.h b/wfpctl/src/extras/cli/modules/list.h
new file mode 100644
index 0000000000..23751c2a26
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/module.cpp b/wfpctl/src/extras/cli/modules/module.cpp
new file mode 100644
index 0000000000..f66ae5a084
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/module.h b/wfpctl/src/extras/cli/modules/module.h
new file mode 100644
index 0000000000..45587ab7e5
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/monitor.h b/wfpctl/src/extras/cli/modules/monitor.h
new file mode 100644
index 0000000000..e227192e82
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/modules/wfpctl.h b/wfpctl/src/extras/cli/modules/wfpctl.h
new file mode 100644
index 0000000000..b690454e19
--- /dev/null
+++ b/wfpctl/src/extras/cli/modules/wfpctl.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "module.h"
+#include "cli/util.h"
+#include "cli/commands/wfpctl/init.h"
+#include "cli/commands/wfpctl/deinit.h"
+#include "cli/commands/wfpctl/policy.h"
+
+namespace modules
+{
+
+class Wfpctl : public Module
+{
+public:
+
+ Wfpctl(MessageSink messageSink)
+ : Module(L"wfpctl", L"Exercise functionality provided by \"wfpctl.dll\".")
+ {
+ addCommand(std::make_unique<commands::wfpctl::Init>(messageSink));
+ addCommand(std::make_unique<commands::wfpctl::Deinit>(messageSink));
+ addCommand(std::make_unique<commands::wfpctl::Policy>(messageSink));
+ }
+};
+
+}
diff --git a/wfpctl/src/extras/cli/objectproperties.cpp b/wfpctl/src/extras/cli/objectproperties.cpp
new file mode 100644
index 0000000000..8b7b5a9c04
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/objectproperties.h b/wfpctl/src/extras/cli/objectproperties.h
new file mode 100644
index 0000000000..a4f349f828
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/propertydecorator.cpp b/wfpctl/src/extras/cli/propertydecorator.cpp
new file mode 100644
index 0000000000..115c628c27
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/propertydecorator.h b/wfpctl/src/extras/cli/propertydecorator.h
new file mode 100644
index 0000000000..b021d275e1
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/propertylist.h b/wfpctl/src/extras/cli/propertylist.h
new file mode 100644
index 0000000000..b5d9d71499
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/stdafx.cpp b/wfpctl/src/extras/cli/stdafx.cpp
new file mode 100644
index 0000000000..62355160c9
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/stdafx.h b/wfpctl/src/extras/cli/stdafx.h
new file mode 100644
index 0000000000..b005a839de
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/subcommanddispatcher.cpp b/wfpctl/src/extras/cli/subcommanddispatcher.cpp
new file mode 100644
index 0000000000..4bb7868cd7
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/subcommanddispatcher.h b/wfpctl/src/extras/cli/subcommanddispatcher.h
new file mode 100644
index 0000000000..a480ec8104
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/targetver.h b/wfpctl/src/extras/cli/targetver.h
new file mode 100644
index 0000000000..ae4a5c032c
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/util.cpp b/wfpctl/src/extras/cli/util.cpp
new file mode 100644
index 0000000000..6181e68639
--- /dev/null
+++ b/wfpctl/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/wfpctl/src/extras/cli/util.h b/wfpctl/src/extras/cli/util.h
new file mode 100644
index 0000000000..3919e03422
--- /dev/null
+++ b/wfpctl/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);