CLOSE
Updated on 12 Aug, 202511 mins read 3 views

What it is?

FWPM_LAYER_STREAM_V4 is a Windows Filtering Platform (WFP) layer that sits between the transport layer (TCP) and the application layer for IPv4 TCP streams.

It delivers reassembled TCP data to our callout driver, so you see data in logical stream order, not raw IP packets.

Think of it like this:

Raw Packets (Transport Layer) → TCP Stream Assembly (Stream Layer) → Application

Your classify function at FWPM_LAYER_STREAM_V4 sees this assembled TCP data.

Key Properties

  • TCP only — No UDP. If you want UDP, there's no stream layer equivalent.
  • IPv4 only – The IPv6 equivalent is FWPM_LAYER_STREAM_V6
  • Bi-directional – You get both send and receive streams.
  • Reassembled – You don't need to worry about TCP fragmentation or reordering; WFP does that before you see the data.
  • Real-time – Data is passed to you as it flows; you can block, permit, or modify it before it reaches the app.

When it triggers

When your filter matches a TCP connection, your callout gets stream data notifications:

  • Outbound stream: Data going from the local process →network.
  • Inbound stream: Data coming from network → local process.

This means for HTTP:

  • Outbound → You can see the Get /file.zip HTTP/1.1 request
  • Inbound → You can see the HTTP headers and body (file content) in the server's response.

What you get in layerData

At this layer, layerData is a FWPS_STREAM_CALLOUT_IO_PACKET structure, not a NET_BUFFER_LIST like at lower layers.

It contains:

typedef struct FWPS_STREAM_CALLOUT_IO_PACKET_ {
    FWPS_STREAM_DATA* streamData;    // The actual TCP data
    SIZE_T countBytesEnforced;       // Bytes you have inspected/enforced
    SIZE_T countBytesRequired;       // Bytes you want before next classify call
    ...
} FWPS_STREAM_CALLOUT_IO_PACKET;

And inside FWPS_STREAM_DATA:

  • dataLength – Number of bytes available in the classify call.
  • flags – Direction (inbound/outbound), FIN flags, etc.
  • NET_BUFFER_LIST* netBufferListChain – The actual data buffer.

Example Data Flow

Say a client downloads example.zip over HTTP:

Client -> GET /example.zip HTTP/1.1\r\nHost: site.com\r\n...

Server -> HTTP/1.1 200 OK\r\nContent-Disposition: attachment; filename="example.zip"\r\n...
(binary file data)

At FWPM_LAYER_STREAM_V4:

  • First classify calls show the request headers (GET /example.zip…).
  • Later classify calls show the HTTP response headers.
  • Then the actual binary file chunks.

You can:

  • Inspect this data.
  • Log it.
  • Modify it (strip certain headers, inject banners, etc.).
  • Block it.

Pros & Cons

Pros:

  • Reassembled data – easier parsing.
  • Works well for application protocols like HTTP, SMTP, etc.
  • Can modify data in-flight.

Cons:

  • Performance impact – every byte goes through your callout.
  • Memory buffering – if you need to parse large messages, you may need to buffer them in your driver.
  • No HTTPS visibility – encrypted traffic is opaque unless you do main-in-the-middle TLS interception.
  • More complex than ALE layers, because, you handle partial data and session state.

Typical use cases

  • Intrusion detection/prevention (IDS/IPS).
  • HTTP content filtering.
  • DLP (Data Loss Prevention) for unencrypted traffic.
  • File download/upload logging.
  • Modifying protocol payloads.

How to hook it

In your driver:

  1. Register callout with FwpsCalloutRegister.
  2. Add callout to the engine (FwpmCalloutAdd) with .applicableLayer = FWPM_LAYER_STREAM_V4.
  3. Add filter to that layer pointing to your callout
  4. In CalloutClassifyFn, handle FWPS_STREAM_CALLOUT_IO_PACKET and parse streamData.

Leave a comment

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