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:
1. 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
2. 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)
3. 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.
Top comments (0)