123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ics/c-adding-an-application-rule-edge-traversal
- /********************************************************************
- Copyright (C) Microsoft. All Rights Reserved.
- Abstract:
- This C++ file includes sample code that adds a firewall rule with
- EdgeTraversalOptions (one of the EdgeTraversalOptions values).
- ********************************************************************/
- #include "pch.h"
- #include <windows.h>
- #include <stdio.h>
- #include <netfw.h>
- #include <strsafe.h>
- #pragma comment(lib, "ole32.lib")
- #pragma comment(lib, "oleaut32.lib")
- #define STRING_BUFFER_SIZE 500
- // Forward declarations
- HRESULT WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2);
- void WFCOMCleanup(INetFwPolicy2* pNetFwPolicy2);
- HRESULT RemoveFirewallRule(
- __in INetFwPolicy2* pNetFwPolicy2,
- __in LPWSTR exeName);
- HRESULT AddFirewallRuleWithEdgeTraversal(__in INetFwPolicy2* pNetFwPolicy2,
- __in bool in,
- __in LPWSTR exeName,
- __in LPWSTR exeFile);
- bool AddFirewallRule(bool add, LPWSTR exeName, LPWSTR exeFile)
- {
- bool result = false;
- HRESULT hrComInit = S_OK;
- HRESULT hr = S_OK;
- INetFwPolicy2* pNetFwPolicy2 = NULL;
- // Initialize COM.
- hrComInit = CoInitializeEx(
- 0,
- COINIT_APARTMENTTHREADED
- );
- // Ignore RPC_E_CHANGED_MODE; this just means that COM has already been
- // initialized with a different mode. Since we don't care what the mode is,
- // we'll just use the existing mode.
- if (hrComInit != RPC_E_CHANGED_MODE)
- {
- if (FAILED(hrComInit))
- {
- WcaLog(LOGMSG_STANDARD, "CoInitializeEx failed: 0x%08lx\n", hrComInit);
- goto Cleanup;
- }
- }
- // Retrieve INetFwPolicy2
- hr = WFCOMInitialize(&pNetFwPolicy2);
- if (FAILED(hr))
- {
- goto Cleanup;
- }
- if (add) {
- // Add firewall rule with EdgeTraversalOption=DeferApp (Windows7+) if available
- // else add with Edge=True (Vista and Server 2008).
- hr = AddFirewallRuleWithEdgeTraversal(pNetFwPolicy2, true, exeName, exeFile);
- hr = AddFirewallRuleWithEdgeTraversal(pNetFwPolicy2, false, exeName, exeFile);
- }
- else {
- hr = RemoveFirewallRule(pNetFwPolicy2, exeName);
- }
- result = SUCCEEDED(hr);
- Cleanup:
- // Release INetFwPolicy2
- WFCOMCleanup(pNetFwPolicy2);
- // Uninitialize COM.
- if (SUCCEEDED(hrComInit))
- {
- CoUninitialize();
- }
- return result;
- }
- BSTR MakeRuleName(__in LPWSTR exeName)
- {
- WCHAR pwszTemp[STRING_BUFFER_SIZE] = L"";
- HRESULT hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"%ls Service", exeName);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to compose a resource identifier string: 0x%08lx\n", hr);
- return NULL;
- }
- return SysAllocString(pwszTemp);
- }
- HRESULT RemoveFirewallRule(
- __in INetFwPolicy2* pNetFwPolicy2,
- __in LPWSTR exeName)
- {
- HRESULT hr = S_OK;
- INetFwRules* pNetFwRules = NULL;
- WCHAR pwszTemp[STRING_BUFFER_SIZE] = L"";
- BSTR RuleName = NULL;
- RuleName = MakeRuleName(exeName);
- if (NULL == RuleName)
- {
- WcaLog(LOGMSG_STANDARD, "\nERROR: Insufficient memory\n");
- goto Cleanup;
- }
- hr = pNetFwPolicy2->get_Rules(&pNetFwRules);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to retrieve firewall rules collection : 0x%08lx\n", hr);
- goto Cleanup;
- }
- // We need to "Remove()" twice, because both "in" and "out" rules are added?
- // There's no remarks for this case https://learn.microsoft.com/en-us/windows/win32/api/netfw/nf-netfw-inetfwrules-remove
- hr = pNetFwRules->Remove(RuleName);
- hr = pNetFwRules->Remove(RuleName);
- if (FAILED(hr)) {
- WcaLog(LOGMSG_STANDARD, "Failed to remove firewall rule \"%ls\" : 0x%08lx\n", exeName, hr);
- }
- else {
- WcaLog(LOGMSG_STANDARD, "Firewall rule \"%ls\" is removed\n", exeName);
- }
- Cleanup:
- SysFreeString(RuleName);
- if (pNetFwRules != NULL)
- {
- pNetFwRules->Release();
- }
- return hr;
- }
- // Add firewall rule with EdgeTraversalOption=DeferApp (Windows7+) if available
- // else add with Edge=True (Vista and Server 2008).
- HRESULT AddFirewallRuleWithEdgeTraversal(
- __in INetFwPolicy2* pNetFwPolicy2,
- __in bool in,
- __in LPWSTR exeName,
- __in LPWSTR exeFile)
- {
- HRESULT hr = S_OK;
- INetFwRules* pNetFwRules = NULL;
- INetFwRule* pNetFwRule = NULL;
- INetFwRule2* pNetFwRule2 = NULL;
- WCHAR pwszTemp[STRING_BUFFER_SIZE] = L"";
- BSTR RuleName = NULL;
- BSTR RuleGroupName = NULL;
- BSTR RuleDescription = NULL;
- BSTR RuleAppPath = NULL;
- long CurrentProfilesBitMask = 0;
- // For localization purposes, the rule name, description, and group can be
- // provided as indirect strings. These indirect strings can be defined in an rc file.
- // Examples of the indirect string definitions in the rc file -
- // 127 "EdgeTraversalOptions Sample Application"
- // 128 "Allow inbound TCP traffic to application EdgeTraversalOptions.exe"
- // 129 "Allow EdgeTraversalOptions.exe to receive inbound traffic for TCP protocol
- // from remote machines located within your network as well as from
- // the Internet (i.e from outside of your Edge device like Firewall or NAT"
- // Examples of using indirect strings -
- // hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"@EdgeTraversalOptions.exe,-128");
- RuleName = MakeRuleName(exeName);
- if (NULL == RuleName)
- {
- WcaLog(LOGMSG_STANDARD, "\nERROR: Insufficient memory\n");
- goto Cleanup;
- }
- // Examples of using indirect strings -
- // hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"@EdgeTraversalOptions.exe,-127");
- hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, exeName);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to compose a resource identifier string: 0x%08lx\n", hr);
- goto Cleanup;
- }
- RuleGroupName = SysAllocString(pwszTemp); // Used for grouping together multiple rules
- if (NULL == RuleGroupName)
- {
- WcaLog(LOGMSG_STANDARD, "\nERROR: Insufficient memory\n");
- goto Cleanup;
- }
- // Examples of using indirect strings -
- // hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"@EdgeTraversalOptions.exe,-129");
- hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"Allow %ls to receive \
- inbound traffic from remote machines located within your network as well as \
- from the Internet", exeName);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to compose a resource identifier string: 0x%08lx\n", hr);
- goto Cleanup;
- }
- RuleDescription = SysAllocString(pwszTemp);
- if (NULL == RuleDescription)
- {
- WcaLog(LOGMSG_STANDARD, "\nERROR: Insufficient memory\n");
- goto Cleanup;
- }
- RuleAppPath = SysAllocString(exeFile);
- if (NULL == RuleAppPath)
- {
- WcaLog(LOGMSG_STANDARD, "\nERROR: Insufficient memory\n");
- goto Cleanup;
- }
- hr = pNetFwPolicy2->get_Rules(&pNetFwRules);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to retrieve firewall rules collection : 0x%08lx\n", hr);
- goto Cleanup;
- }
- hr = CoCreateInstance(
- __uuidof(NetFwRule), //CLSID of the class whose object is to be created
- NULL,
- CLSCTX_INPROC_SERVER,
- __uuidof(INetFwRule), // Identifier of the Interface used for communicating with the object
- (void**)&pNetFwRule);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "CoCreateInstance for INetFwRule failed: 0x%08lx\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_Name(RuleName);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Name failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_Grouping(RuleGroupName);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Grouping failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_Description(RuleDescription);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Description failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- // If you want the rule to avoid public, you can refer to
- // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ics/c-adding-an-outbound-rule
- CurrentProfilesBitMask = NET_FW_PROFILE2_ALL;
- hr = pNetFwRule->put_Direction(in ? NET_FW_RULE_DIR_IN : NET_FW_RULE_DIR_OUT);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Direction failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_Action(NET_FW_ACTION_ALLOW);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Action failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_ApplicationName(RuleAppPath);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_ApplicationName failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- //hr = pNetFwRule->put_Protocol(6); // TCP
- //if (FAILED(hr))
- //{
- // WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Protocol failed with error: 0x %x.\n", hr);
- // goto Cleanup;
- //}
- hr = pNetFwRule->put_Profiles(CurrentProfilesBitMask);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Profiles failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_Enabled failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- if (in) {
- // Check if INetFwRule2 interface is available (i.e Windows7+)
- // If supported, then use EdgeTraversalOptions
- // Else use the EdgeTraversal boolean flag.
- if (SUCCEEDED(pNetFwRule->QueryInterface(__uuidof(INetFwRule2), (void**)&pNetFwRule2)))
- {
- hr = pNetFwRule2->put_EdgeTraversalOptions(NET_FW_EDGE_TRAVERSAL_TYPE_DEFER_TO_APP);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_EdgeTraversalOptions failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- }
- else
- {
- hr = pNetFwRule->put_EdgeTraversal(VARIANT_TRUE);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed INetFwRule::put_EdgeTraversal failed with error: 0x %x.\n", hr);
- goto Cleanup;
- }
- }
- }
- hr = pNetFwRules->Add(pNetFwRule);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "Failed to add firewall rule to the firewall rules collection : 0x%08lx\n", hr);
- goto Cleanup;
- }
- WcaLog(LOGMSG_STANDARD, "Successfully added firewall rule !\n");
- Cleanup:
- SysFreeString(RuleName);
- SysFreeString(RuleGroupName);
- SysFreeString(RuleDescription);
- SysFreeString(RuleAppPath);
- if (pNetFwRule2 != NULL)
- {
- pNetFwRule2->Release();
- }
- if (pNetFwRule != NULL)
- {
- pNetFwRule->Release();
- }
- if (pNetFwRules != NULL)
- {
- pNetFwRules->Release();
- }
- return hr;
- }
- // Instantiate INetFwPolicy2
- HRESULT WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2)
- {
- HRESULT hr = S_OK;
- hr = CoCreateInstance(
- __uuidof(NetFwPolicy2),
- NULL,
- CLSCTX_INPROC_SERVER,
- __uuidof(INetFwPolicy2),
- (void**)ppNetFwPolicy2);
- if (FAILED(hr))
- {
- WcaLog(LOGMSG_STANDARD, "CoCreateInstance for INetFwPolicy2 failed: 0x%08lx\n", hr);
- goto Cleanup;
- }
- Cleanup:
- return hr;
- }
- // Release INetFwPolicy2
- void WFCOMCleanup(INetFwPolicy2* pNetFwPolicy2)
- {
- // Release the INetFwPolicy2 object (Vista+)
- if (pNetFwPolicy2 != NULL)
- {
- pNetFwPolicy2->Release();
- }
- }
|