Why My Windows Transparent Proxy Failed on Wi-Fi (and Worked on Ethernet)

Source: Dev.to | Jan 21, 2026 (UTC)

TL;DR:

My transparent proxy was architecturally correct, fully implemented, and thoroughly tested — yet it silently failed on Wi-Fi. The reason wasn’t a bug, a missing flag, or bad code. It was a Windows + Wi-Fi driver boundary that user-mode tools like WinDivert simply cannot cross.

This article documents the journey, the dead ends, the hard evidence, and the final, correct conclusion.

Background

I was building a transparent TCP proxy on Windows using:

  • Rust
  • WinDivert (user-mode packet capture/injection)
  • SOCKS5 upstream
  • Full DNAT / SNAT redirection
  • No explicit proxy configuration on the client

The goal was simple:

Intercept outbound TCP connections (ports 80/443), transparently redirect them to a local proxy, and forward traffic upstream — without breaking applications or TCP semantics.

This is a solved problem on Linux (iptables + REDIRECT).
On Windows, it’s much harder.

Phase 1: The Wrong Idea (Packet Forging)

The initial design attempted to:

  1. Intercept outbound SYN packets
  2. Drop them
  3. Forge a SYN-ACK pretending to be the real server
  4. Maintain a user-space TCP state machine
  5. Relay data via SOCKS5

On paper, everything worked:

  • Correct TCP flags
  • Correct SEQ/ACK numbers
  • Correct IP + TCP checksums
  • Verified hex dumps
  • Passing unit tests

Reality:
Windows silently dropped every forged SYN-ACK.

No ACK.
No handshake.
No error.

Root Cause

Windows enforces TCP anti-spoofing below WinDivert.

User-mode code cannot inject packets claiming to originate from external IPs and expect the TCP stack to accept them.

This is not configurable.
No WinDivert layer fixes this.
Not Impostor, not REFLECT, not FORWARD.

Conclusion:
Forging TCP peers in user mode on Windows is architecturally impossible.

Phase 2: The Correct Architecture (Redirection)

After discarding packet forging entirely, I implemented the only correct approach:

Transparent Redirection (DNAT / SNAT)

  1. Intercept outbound SYN
  2. Record original destination (dst_ip, dst_port)
  3. Rewrite destination → LOCAL_IP:8899
  4. Flip packet direction to INBOUND
  5. Let Windows complete a real TCP handshake
  6. Proxy connects upstream via SOCKS5
  7. Rewrite source on return packets back to original server
  8. Flip direction to OUTBOUND
  9. Clean up mappings on FIN/RST

Key rules:

  • No forged packets
  • No custom TCP state machine
  • Windows owns TCP semantics

This is how all real transparent proxies work on Windows.

Everything Was Correct — Yet Nothing Worked

Even with the correct architecture:

  • curl hung
  • No outbound SYN visible
  • WinDivert captured only inbound packets
  • Outbound=1 never appeared
  • NETWORK_FORWARD layer captured nothing
  • Filters were correct
  • Injection logic was correct

At this point, the usual suspects were gone.

The Critical Discovery: Wi-Fi Fast-Path

The system used an Intel Wi-Fi adapter.

After exhaustive testing:

  • WinDivert never saw outbound TCP packets
  • Even with filter "tcp"
  • Even after disabling all configurable offloads
  • Even after restarting the adapter
  • Even at different WinDivert layers

PowerShell confirmed it:

Get-NetAdapterAdvancedProperty -Name "Wi-Fi"

Enter fullscreen mode

Exit fullscreen mode

Only WoWLAN offloads existed.
No TCP offload toggles.
No segmentation controls.

What This Means

On this Wi-Fi adapter:

Inbound packets still appear — because they must traverse the receive path.

This is a driver + firmware fast-path, not a bug.

Why Ethernet Works (and Wi-Fi Doesn’t)

Ethernet drivers typically:

Wi-Fi drivers often:

This is why:

Final Resolution

I chose the most pragmatic and correct next step:

USB-to-Ethernet Adapter

This isn’t a workaround — it’s crossing a known platform boundary.

On Ethernet:

Key Takeaways

1. You cannot forge TCP peers on Windows in user mode

Anti-spoofing is enforced below WinDivert.

2. Transparent proxies must use redirection, not forgery

Let the OS own TCP.

3. WinDivert is correct — but limited by NIC drivers

Especially on Wi-Fi.

4. Absence of packets can be a hardware truth, not a bug

Empirical testing matters more than assumptions.

5. Ethernet validates architecture; Wi-Fi dictates tooling

User mode vs kernel mode is not a preference — it’s a requirement.

When Do You Need WFP?

Only if:

Otherwise:

Closing

This project did not fail.

It reached a correct architectural conclusion, backed by:

Sometimes the hardest bugs aren’t bugs at all — they’re boundaries.

If this saves you weeks of chasing ghosts, it did its job.

For further actions, you may consider blocking this person and/or reporting abuse

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Читайте також