CLOSE
Updated on 04 Aug, 202517 mins read 8 views

What is the goal?

We want to block all outgoing TCP connections to a specific IP address, say 23.57.74.170 (www.example.com). That means:

  • No application (browser, command-line tool, service) on the system should be able to initiate a TCP connection to this IP.
  • The block should apply system-wide and at the kernel level, ensuring reliability and security.

Where can we implement this in the Windows network stack?

Windows provides multiple entry points for filtering network traffic including:

LayerDescriptionDirection
Application Layer (ALE)Controls connection authorizationsBoth
Transport LayerWorks on raw TCP/UDP packetsBoth
Network LayerWorks on raw IP packetsBoth

For this case, the best place to implement this filter is:

FWPM_LAYER_ALE_AUTH_CONNECT_V4

This layer fires just before a TCP connection is allowed to proceed from the system. It allows us to intercept and block outbound TCP connections right when an app tries to initiate them.

Why this layer?

Here's why ALE_AUTH_CONNECT_V4 is ideal for our use case:

ReasonExplanation
Direction-awareWe can filter outgoing traffic only.
Pre-connectionIt evaluates traffic before a socket connects, saving system resources.
Process-awareWe can (optionally) tie rules to specific apps or users.
Reliable and early interceptionIt guarantees filtering before the connection is handed off to the transport layer.

What are we going to build?

We will use the Windows Filtering Platform (WFP) APIs to:

  1. Open a session with the filtering engine.
  2. Register a provider (identity for our filters).
  3. Register a sublayer (a group for our filters).
  4. Add a filter that:
    1. Applies to outbound TCP connections,
    2. Matches destination IP address 23.57.74.170
    3. Blocks this connection.

Before Implementation

Open the cmd and run the following command:

curl -H "Host: www.example.com" http://23.57.74.170

It should show some output.

After building the program and running it, we should not show that output.

Code Example – Blocking Outbound TCP to a Specific IP

Create a New Console Application in Visual Studio

  • Open Visual Studio
  • Go to File > New > Project > Console Application
  • Name it something like WfpBlockIP
  • Select C or C++ depending on your preference

Step 1: Add Required Headers and Libraries

Add these headers at the top of your .c or .cpp file:

#include <windows.h>
#include <fwpmu.h>
#include <initguid.h>
#include <winsock2.h>
#include <stdio.h>

Link these libraries:

#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "ws2_32.lib")

Step 2: Define Unique GUIDs for our Provider and Sublayer

DEFINE_GUID(GUID_SAMPLE_PROVIDER, 
0xaabbccdd, 0x1122, 0x3344, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc);

DEFINE_GUID(GUID_SAMPLE_SUBLAYER, 
0xddccbbaa, 0x2211, 0x4433, 0x66, 0x55, 0x88, 0x77, 0xaa, 0x99, 0xcc, 0xbb);

These uniquely identify our filtering components.

Step 3: Open a Session with the WFP Filtering Engine

HANDLE engineHandle = NULL;
DWORD result = FwpmEngineOpen(NULL, RPC_C_AUTHN_WINNT, NULL, NULL, &engineHandle);

Always check the result.

Step 4: Add a Provider (Identity)

FWPM_PROVIDER provider = {0};
provider.providerKey = GUID_SAMPLE_PROVIDER;
provider.displayData.name = L"Sample Provider";
provider.displayData.description = L"Demo provider for blocking IP";

FwpmProviderAdd(engineHandle, &provider, NULL);

The provider identifies you to the WFP system. Optional, but a good practice.

Step 5: Add a Sublayer (Group of Filters)

FWPM_SUBLAYER sublayer = {0};
sublayer.subLayerKey = GUID_SAMPLE_SUBLAYER;
sublayer.displayData.name = L"Sample Sublayer";
sublayer.displayData.description = L"Filters managed by sample provider";
sublayer.providerKey = &GUID_SAMPLE_PROVIDER;
sublayer.weight = 0x100;

FwpmSubLayerAdd(engineHandle, &sublayer, NULL);

You must add a sublayer for your filter to exist under

Step 6: Definer the Filter Condition

Convert the target IP address to network byte order using inet_addr:

UINT32 ip = inet_addr("23.57.74.170");

Define the Condition:

FWPM_FILTER_CONDITION condition = {0};
condition.fieldKey = FWPM_CONDITION_IP_REMOTE_ADDRESS;
condition.matchType = FWP_MATCH_EQUAL;
condition.conditionValue.type = FWP_UINT32;
condition.conditionValue.uint32 = ip;

This condition matches any packet destined to 192.168.1.100

Step 7: Define and Add the Filter

FWPM_FILTER filter = {0};
filter.displayData.name = L"Block TCP to 192.168.1.100";
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
filter.subLayerKey = GUID_SAMPLE_SUBLAYER;
filter.weight.type = FWP_EMPTY; // Use default priority
filter.numFilterConditions = 1;
filter.filterCondition = &condition;
filter.action.type = FWP_ACTION_BLOCK;
filter.flags = FWPM_FILTER_FLAG_PERSISTENT; // Keep after reboot (optional)

Now add it:

result = FwpmFilterAdd(engineHandle, &filter, NULL, NULL);
if (result == ERROR_SUCCESS) {
    printf("Filter added: TCP to 23.57.74.170 is now blocked.\n");
} else {
    printf("Failed to add filter: %lu\n", result);
}

Step 8: Close the Engine Handle

FwpmEngineClose(engineHandle);

Always clean up when done.

Step 9: Test Your Filter

Try accessing the target IP:

curl http://192.168.1.100

You should see a connection error.

Leave a comment

Your email address will not be published. Required fields are marked *