Why Per-Process Networking Still Doesn't Exist on Windows
Windows has one of the most mature networking stacks in the world. It supports:
- high-performance TCP/UDP
- modern VPN protocols
- virtual network adapters
- enterprise-grade routing policies
And yet, one thing is still missing at the system level: True per-process networking control. Not “proxy per app”. Not “VPN split tunneling by rules”. Not “firewall-based heuristics”. But deterministic, low-level, per-process routing at the packet level. This post explains why.
The illusion of per-process networking
At first glance, it looks like Windows already solves this. You have:
- Proxy settings (WinHTTP / WinINET)
- Firewall rules (Windows Filtering Platform)
- VPN split tunneling
- SOCKS proxies
- Application-level SDKs (Electron, browsers, etc.)
So it feels like: “Just configure rules per app.” But in practice, none of these operate at the same layer. They are fragmented across the stack:
| Layer | Mechanism | Scope |
|---|---|---|
| Application | HTTP proxy | Partial (HTTP only) |
| OS | Firewall (WFP) | Packet filtering, not routing ownership |
| Network | VPN (TUN/TAP) | System-wide routing |
| App SDK | Custom networking | Only inside that app |
No layer provides a unified answer to: “Which process owns this packet, and where should it go?”
The fundamental gap
The core issue is architectural: Windows networking is packet-centric, not process-centric. At the lowest level:
- The network stack sees packets
- Not “applications”
- Not “user intent”
- Not “workspace contexts”
Even though Windows internally tracks sockets per process, that mapping is not exposed as a routing primitive. You can ask:
- “Which process owns this socket?”
But you cannot say:
- “Route all traffic from this process into a different network stack.”
This is the missing abstraction.
Why this is hard
To support per-process networking properly, you need to solve three problems simultaneously:
Packet ↔ Process attribution (real-time)
You must reliably map: TCP/UDP packet → socket → PID → process tree
This is non-trivial because:- sockets are ephemeral
- ports are reused
- NAT and loopback obscure ownership
- WSL2/Docker add virtual layers
Routing without kernel-level control
Windows routing is designed around:- interface metrics
- IP tables
- global policies
Not: - per-process routing graphs
So you either: - modify packets in kernel space (WFP / drivers)
- or reconstruct routing logic in user space (with tradeoffs)
Multi-context coexistence
Modern workflows require:- multiple VPNs at the same time
- multiple client environments
- local dev stack + remote cloud access
But Windows assumes: One machine = one network context
This assumption no longer holds.
Why existing solutions don’t solve it
VPN clients (WireGuard, OpenVPN, corporate VPNs)
They operate at: network interface level
Meaning:
- all traffic goes through one tunnel
- split tunneling is coarse and IP-based
Not process-aware.
Proxies (system or app-level)
They operate at: application protocol level (HTTP/SOCKS)
Limitations:
- only certain apps respect proxy settings
- raw TCP/UDP traffic bypasses them
- no kernel-level enforcement
Firewall (WFP)
WFP can inspect packets and associate metadata. But:
- it is policy-driven, not routing-driven
- building complex per-process routing logic becomes extremely complex
- performance and maintainability degrade quickly
The uncomfortable truth
To this day: Windows does not provide a first-class abstraction for “process as a network routing entity”. Everything is either:
- too high-level (proxy)
- too low-level (packet filtering)
- or too global (VPN)
Nothing sits in the middle.
What this implies
If you want true per-process networking, you are forced into one of two directions:
Option A - Kernel-driven architecture
- WFP drivers
- virtual adapters
- packet interception
- complex state tracking
Powerful, but heavy and fragile.
Option B - User-space reconstruction
- capture traffic via virtual interfaces (e.g., Wintun)
- reconstruct socket ↔ process mapping
- maintain routing state in user space
More flexible, but requires careful engineering around:
- latency
- packet buffering
- correctness under concurrency
Why this matters now
This problem was not critical 10 years ago. But today:
- developers work across multiple client VPNs
- cloud-native workflows create overlapping networks
- local + remote environments coexist constantly
- security requirements isolate network contexts
The machine is no longer a single network unit. It is a collection of overlapping network identities.
Closing thought
Per-process networking doesn’t exist on Windows not because it is impossible. But because: The OS was designed before “multiple simultaneous network contexts per user process” became a normal requirement.
I’m currently exploring this space by building an application-aware networking layer for Windows, focusing on per-process routing and workspace isolation. I’ll share the architecture decisions, failures, and performance tradeoffs as the project evolves.
Comments
No comments yet. Start the discussion.