WFP redirection to local proxy using app id and remote ip filter

Hi everyone,

I'm relatively new to Windows driver development, so please feel free to correct me if I’m misunderstanding something.

I'm currently working on building a split-tunneling mechanism using WFP, where I aim to redirect traffic based on both the AppId and specific remote IP ranges.

My implementation is inspired by well know VPN software, like ProtonVPN or PIA.

The redirection is done with:
INETADDR_SET_ADDRESS((PSOCKADDR)&sockAddrStorage, &(addr.S_un.S_un_b.s_b1));

What works so far:
I’m able to successfully redirect all UDP and TCP traffic from Microsoft Edge to go through my local proxy interface. That part is functioning as expected.

The issue:
I would like to refine the redirection to only apply when both:

  • the AppId matches (e.g., Edge or another process), and
  • the remote IP is in a specific list or prefix range.

However, as far as I can tell, ALE_BIND_REDIRECT does not provide access to the remote IP during classification. This makes sense per Microsoft’s documentation and the WFPSampler sample, which states:

For non-TCP, this setting will not be enforced being that local redirection of this tuple is only available during bind time. and ideally redirection should be performed using ALE_BIND_REDIRECT instead.

The ALE_BIND_REDIRECT is the only place I can change the local address and port (it is, by default, 0.0.0.0:0). Even if after UDP packets goes through ALE_CONNECT_REDIRECT, it does not work.

So while UDP redirection works correctly at the bind layer, I am unable to make a redirection decision based on the destination address, meaning all traffic from that AppId gets redirected unconditionally.

So, is there any way to conditionally redirect UDP and TCP traffic in WFP based on both AppId and remote IP, while still respecting the early binding behavior required for UDP?

Any insight would be greatly appreciated. Thanks in advance!

Best regards,
Chris

Presumably you are changing the local address to that of the VPN adapter so that the system routes traffic out it?

Personally, I would use ALE_CONNECT_REDIRECT to redirect all outbound flows (tcp+udp) into a user mode service. From there your usermode service can conditionally bind to the VPN adapter when it is establishing the upstream connection.

You could also conditionally redirect into your usermode service based on your criteria if you really want to be out of the way of traffic you don't care about.

Jason

Hi Jason,

Thanks for your reply.

Yes, my intent is indeed to redirect traffic to the VPN adapter based on some conditions (such as app ID and remote IP). I already attempted to use only ALE_CONNECT_REDIRECT with a callout driver to reroute all outbound TCP and UDP traffic.

However, from what I’ve seen in Microsoft's documentation and my own testing, redirection at the "CONNECT_REDIRECT" layer doesn't seem to work for UDP flows. Specifically, the INETADDR_SET_ADDRESS function does not appear to take effect for UDP traffic, since, as per the documentation: "for non-TCP, this setting will not be enforced as local redirection of this tuple is only available during bind time." So the only way to redirect UDP traffic is done using ALE_BIND_REDIRECT.

I’m a bit unclear about how I would perform full redirection entirely from user-mode. From what I understand, WFP user-mode APIs allow me to add filters and block, permit or call a classify function on a driver, but not to actually redirect the traffic, unless I'm missing something. Are you suggesting using user-mode to inject a proxy or socket-layer relay?

Thanks again for the insight!

BR,
Chris

for non-TCP, this setting will not be enforced as local redirection of this tuple is only available during bind time

Where is this quote from? It is (or was) definately possible to redirect UDP flows are ALE_CONNECT_REDIRECT.

Specifically, the INETADDR_SET_ADDRESS function does not appear to take effect for UDP traffic.

It definately will, given the correct inputs.

So the only way to redirect UDP traffic is done using ALE_BIND_REDIRECT.

You can redirect UDP at the packet layers, DATAGRAM_DATA and IP. If memory serves me correctly DATAGRAMD_DATA is preferred to IP due to better compatibility with IPSEC tunnels.

I’m a bit unclear about how I would perform full redirection entirely from user-mode.

Your user application listens on some ports. Your kernel driver redirects all/relevant traffic to those ports. Your user application proxies to the destination.

Jason

Hi Jason,

Thanks again for the clarification.

The statement I quoted: "for non-TCP, this setting will not be enforced as local redirection of this tuple is only available during bind time" is from Microsoft's own Windows-driver-samples repository. I can’t include links in posts here, but the exact path on GitHub is:

network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp,
specifically inside the PerformProxyConnectRedirection function.

Even in that sample, Microsoft uses INETADDR_SET_ADDRESS for redirection. However, in my tests, although the UDP flow clearly goes through the ALE_CONNECT_REDIRECT layer (I confirmed it via debug logs), the redirection doesn’t happen — the destination IP remains unchanged. I'm not sure if I'm missing something in the callout or providing incorrect parameters, but the behavior matches what the comment suggests.

You can redirect UDP at the packet layers, DATAGRAM_DATA and IP.
Yes, I was under the impression that redirecting outside the ALE_REDIRECT layers (e.g., at DATAGRAM_DATA or IPPACKET) was not a good practice. But maybe that's just a recommendation rather than a strict rule?

Thanks again for taking the time to reply!

— Chris

The comments you are referencing only apply to the manipulation of the source address and port. The solution I proposed (forwarding the traffic to a usermode application) would be manipulating the destination address and port to point to your application, before proxying onwards.

Sounds like you can either:

  • Keep the manipulation of source address for TCP & redirect UDP to the usermode application by manipulating the dest address
  • Send both to usermode by altering dest address
  • Tweak outbound src/dst addresses @ DATAGRAM_DATA for UDP

Each have their own pro's & cons.

But maybe that's just a recommendation rather than a strict rule?

My understanding is it's primarily a performance thing; When altering dest addresses for UDP flows @ CONNECT_REDIRECT you are doing it once for the entire stream and the system maintains this for all flows. When you do it at DATAGRAM_DATA you are doing it on a per packet basis.

Jason

Hi Jason,

Than you for your answer.

I will try as suggested, and will keep you informed!

Chris