TDIPBLKH - TDI Port Blocking Filter Driver Sample

Copyright © 2005 Printing Communications Assoc., Inc. (PCAUSA). All rights reserved.

New: V2.02.06.15 - March, 2005.

Overview

The goal of this TDI filter sample is to illustrate how to use a TDI filter to selectively block inbound and outbound TCP connection attempts as well as inbound and outbound UDP datagrams.

This sample consists of these components:

bulletTDIPBlkH.sys - The TDI Port Blocking Filter Driver.
bulletPBlockMan.exe - This is a Win32 console application that builds example port blocking rules and passes them to the TDIPBLKH driver.
bulletPCATTCP.exe - A flexible TCP/UDP transmitter/receiver utility used to generate test traffic.

 

TDIPBLKH - The TDI Port Blocking Filter Driver

This driver is fairly simple and illustrates the basics of blocking TDI operations in a filter driver. The TDI filter driver is provided with an array of port blocking rules that it applies to selected TDI operations as they are encountered.

The driver includes the capability to block the following operations:

bulletOutbound TCP Connections - By filtering TDI_CONNECT requests.
bulletInbound TCP Connections - By filtering TDI_LISTEN requests and ClientEventConnect event callbacks.
bulletOutbound TDP Datagrams - By filtering TDI_SEND_DATAGRAM requests.
bulletInbound UDP Datagrams - By filtering TDI_RECEIVE_DATAGRAM requests and the ClientEventReceiveDatagram and the ClientEventChainedReceiveDatagram event callbacks.

These rules are based solely on the port number. The driver does not filter based on process information or on local or remote IP address. The driver does not illustrate techniques for interacting with the user to approve or disapprove traffic.

The driver filters only on \Device\Tcp and \Device\Udp. The driver does not currently filter on \Device\RawIp, so it is possible for traffic to bypass this filter if the raw sockets interface or RawIp device is used.

In addition, the driver does not currently filter IPv6 at all.

The driver was derived from the Build 615 TDI Local Port Monitoring driver (TDILpbkH). It could also have been derived from the TDI PassThru driver (TDIPassH); however, the author had been working most recently with TDILpbkH and was most comfortable working with it.

 

PBlockMan - The Port Blocking Manager Application

This Win32 console application is used to build and pass a buffer containing TDI port blocking rules to the driver.

Testing the TDI port blocking filter is done by running various combinations of TCP and UDP traffic to see if the specified redirection rules are followed. The PCAUSA TTCP application is used to generate TCP and UDP traffic for most tests.

 

PCATTCP - The TCP/UDP Traffic Generator

The primary application used for initial testing PCAUSA TDI filters is TTCP. TTCP is a flexible Winsock utility that includes the capability to exercise the most common Internet protocols:

bulletTCP Client (Transmitter)
bulletTCP Server (Receiver)
bulletUDP Client (Transmitter)
bulletUDP Server (Receiver)

TTCP tests can be configured using a command-line interface: 

bulletLength of buffers read from or written to the network.
bulletNumber of buffers to send.
bulletBuffer alignment and offset.
bulletSocket options, including: SO_SNDBUF, SO_RCVBUF, TCP_NODELAY.
bulletPort number.

PCATTCP is included in both executable and source form with the PCAUSA TDI samples.

 

Getting Familiar with the Rules

Blocking Rule for a Single Port

The port blocking rules for a single port are specified in a FW_PORT_RULE structure, defined in common.h. Each rule contains these two fields:

bulletm_Port - The port number in host byte order.
bulletm_Action - A bit field that defines the blocking action that the driver should perform on the port.

The actions that can be specified are defined by an enumeration and MACROs defined in common.h. They include:

bulletFW_BLOCK_TCP_INBOUND - Block all inbound connections on the specified port.
bulletFW_BLOCK_TCP_OUTBOUND - Block all outbound connections on the specified port.
bulletFW_BLOCK_UDP_INBOUND - Block all inbound datagrams on the specified port.
bulletFW_BLOCK_UDP_OUTBOUND - Block all outbound datagrams on the specified port.

 

Passing Port Blocking Rules to the Driver

A user-mode application passes port blocking rules to the driver by filling a buffer with an array of FW_PORT_RULE structures that have been sorted by qsort so the array elements are in ascending port number order. This is done so the driver can search the rule array using the bsearch facility. The buffer containing the rules includes the FW_PORT_RULE_BUFFER header that provides a sanity-checking prolog before the port blocking rule array.

The user-mode IpApi.c module provides a number of helper functions for building a FW_PORT_RULE_BUFFER and the FW_PORT_RULE array. These include:

bulletTdiPortBlocker_AllocateRuleBuffer - Allocates an empty FW_PORT_RULE_BUFFER.
bulletTdiPortBlocker_FreeRuleBuffer - Frees a FW_PORT_RULE_BUFFER.
bulletTdiPortBlocker_AddPortRule - Add a new port blocking rule to the buffer.

The AddPortRule function automatically performs the necessary qsort after adding a new rule to the buffer.

Here is an example of adding a port blocking rule to a FW_PORT_RULE_BUFFER:

pRuleBuffer = TdiPortBlocker_AddPortRule( pRuleBuffer, 5001, FW_BLOCK_TCP_INBOUND | FW_BLOCK_TCP_OUTBOUND );

This rule would block inbound and outbound connections on port 5001.

The user-mode IoApi.c module also provides functions that open a control handle to the TDIPBlkH driver and allows that application to control the driver:

bulletTdiPortBlocker_Startup -Mandatory first application call that initializes app-driver interface.
bulletTdiPortBlocker_Shutdown - Mandatory call at application exit to close app-driver interface.
bulletTdiPortBlocker_IsDriverLoaded - Returns TRUE if TDIPBlkH driver is loaded.
bulletTdiPortBlocker_SetBlockingRules - Passes a FW_PORT_RULE_BUFFER to the driver using DeviceIoControl on IOCTL_SET_BLOCKING_RULES.
bulletTdiPortBlocker_GetBlockingRules - Fetches the driver's FW_PORT_RULE_BUFFER using DeviceIoControl on IOCTL_GET_BLOCKING_RULES.
bulletTdiPortBlocker_EnableBlocking - Enable or disable port blocking busing DeviceIoControl on IOCTL_SET_BLOCKING_STATE.
bulletTdiPortBlocker_GetBlockingState - Fetch the current port blocking state using DeviceIoControl on IOCTL_GET_BLOCKING_STATE.
bulletTdiPortBlocker_ClearBlockingRules - Clears the driver's copy of the current blocking rules.

Note that each call to TdiPortBlocker_SetBlockingRules will completely replace any existing rules that the driver may been given previously. It is not necessary to clear existing rules before passing new ones to the driver.

The PBlockMan sample application provides a simple illustration of the use of these user-mode API helper functions.

 

Driver Implementation Overview

User-Mode Interface

The driver ioctl.c module provides handlers for the user-mode DeviceIoControl API described in previous paragraphs. These handlers actually work on two variables that are declared in tdiblock.c:

bulletg_bIsBlockingEnabled - A parameter that is TRUE if port blocking is enabled in the driver.
bulletg_pRuleBuffer - A pointer to the driver's copy of the current FW_PORT_RULE_BUFFER.

 

Port Blocking Support Routines

The key driver function related to port blocking is BLK_FindPortRuleAction implemented in tdiblock.c. This routine performs a bsearch on the rule buffer to return the action to be performed on a port.

There are other support routines implemented in tdiblock.c, including:

bulletBLK_GetLocalAddressFromConnectionObject
bulletBLK_GetRemoteAddressFromConnectionInfo
bulletBLK_GetLocalAddressFromAddressObject

 

Blocking TCP Connections

Outbound TCP Connections

For outbound traffic the driver determines the remote port address and then calls BLK_FilePortRuleAction for the remote port. If the action includes FW_BLOCK_TCP_OUTBOUND then the connect request is failed with status STATUS_REMOTE_NOT_LISTENING.

This blocking is done in the FLT_OnConnect routine in handlers.c

Inbound TCP Connections

For inbound traffic the driver determines the local port address and then calls BLK_FilePortRuleAction for the local port. If the action includes FW_BLOCK_TCP_INBOUND then the listen request is failed with status INVALID_CONNECTION.

This blocking is done in the FLT_OnListen routine in handlers.c

 

Blocking UDP Datagrams

Outbound UDP Datagrams

For outbound datagrams the driver determines the remote port address and then calls BLK_FilePortRuleAction for the remote port. If the action includes FW_BLOCK_UDP_OUTBOUND then the send datagram request is failed with status STATUS_INVALID_ADDRESS.

This blocking is done in the FLT_OnSendDatagram routine in handlers.c

 

Inbound UDP Datagrams

For inbound datagrams the driver determines the local port address and then calls BLK_FilePortRuleAction for the local port. If the action includes FW_BLOCK_UDP_INBOUND then the receive datagram request is failed with status STATUS_INVALID_ADDRESS.

This blocking is done in the FLT_OnReceiveDatagram routine in handlers.c

The driver also filters ClientEventReceiveDatagram and ClientEventChainedReceiveDatagram event handlers. The driver determines the local port address and then calls BLK_FilePortRuleAction for the local port. If the action includes FW_BLOCK_UDP_INBOUND then the receive datagram request is failed with status STATUS_DATA_NOT_ACCEPTED.

Event receive blocking is done in the FLT_OnEventReceiveDatagram and FLT_OnEventChainedReceiveDatagram routines in handlers.c

 

Derivation of TDI Port Blocking Driver

The TDI Port Blocking driver (TDIPBlkH) was derived from the Build 614 TDI Local Port Monitoring driver (TDILpbkH). It could also have been derived from the TDI PassThru driver (TDIPassH); however, the author had been working most recently with TDILpbkH and was most comfortable working with it.

The first step was to remove the logging function routines (those with "LF_" prefix) by deleting the tdilog.c and tdilog.h. New blocking functions (with "BLK_" prefix) are implemented in new module tdiblock.c and tdiblock.h.

It is worth pointing out that there is a difference in the prototypes and parameters of several request-filtering routines in handlers.c in the TDIPBlkH driver when compared to the same routines in the base TDILpbkH driver. The base TDIxyzH drivers did not include a mechanism for a request filter routine (such as FLT_OnConnect) to block or fail a request for the BeforeOriginal CallOrdercase. Basically, the bCallOriginal parameter was not provided to routines that needed to block a request. This missing parameter was added to the FLT_xyz functions needed to implement port blocking.

The missing bCallOriginal parameter was added to the FLT_xyz routines needed to implement the simple port blocking. To fail a request the FLT_xyz routine sets IoStatus to the desired failure status and clears the bCallOriginal parameter. Routines in filter.c that examine the bCallOriginal parameter will fail the request and call IoCompleteRequest with the failure status.

 

Filter Order Complications

It is important to understand that a TDI filter can only filter TDI address and connection objects (or "sockets") that it observes when they are created or opened. For example, if you start an application that listens on port 5001 and then start a TDI filter, then that filter cannot filter the listen request (because it has already occurred...).

This presents a special problem if it is necessary to redirect or block ports that are opened by the system very early in the startup process. Examples are ports 137, 138 and 139 opened by NetBIOS over TCP/IP (NetBT) or "NetBIOS-less" direct hosting of SMB over TCP/IP on port 445. If it is essential to redirect or block these ports then some fairly messy modifications to the driver load order registry settings must be made to insure that the TDI filter driver is loaded 1.) after TCP/IP is loaded but 2.) before NetBT opens ports. See the "Load Order Issues" topic in the TDI Samples Help File.

It is difficult to control the order that filters are processed. Windows anti-virus and firewall products often employ their own TDI filters.

You will have to test any product derived from this sample extensively to insure that it is compatible with possibly conflicting products.

 

 

 

 

PCAUSA Home · Privacy Statement · Products · Ordering · Support · Utilities · Resources
Mailing Lists  · PCAUSA Newsletter · PCAUSA Discussion List
 
Rawether for Windows and WinDis 32 are trademarks of Printing Communications Assoc., Inc. (PCAUSA)
Microsoft, MS, Windows, Windows 95, Windows 98, Windows Millennium, Windows 2000, and Win32 are registered trademarks and Visual C++ and Windows NT are trademarks of the Microsoft Corporation.
Send mail to webmaster@pcausa.com with questions or comments about this web site.
Copyright © 1996-2008 Printing Communications Assoc., Inc. (PCAUSA)
Last modified: December 31, 2007