TUN Mode vs System Proxy: How Traffic Is Intercepted at Different Layers
Compare system proxy, which relies on apps reading proxy settings, with TUN mode, which intercepts all IP traffic through a virtual network adapter. Learn why CLI tools, games, and UDP apps behave differently and which mode fits each scenario.
The Bottom Line First
System proxy and TUN mode operate at different layers. System proxy is an application-layer convention: the OS writes the proxy address into settings, and apps have to read it and use it before traffic goes through the proxy. TUN mode is a network-layer takeover: mihomo creates a virtual network adapter, and the kernel routes matching IP packets into it. Apps don't know the proxy exists and can't bypass it.
In short: system proxy depends on app cooperation, TUN mode depends on kernel routing. That's exactly why CLI tools, games, and UDP traffic behave so differently between the two modes.
System Proxy: Only Works When Apps Read the Settings
When system proxy is enabled, Windows writes the address under Settings > Network & Internet > Proxy, and macOS writes the same info under System Settings > Network > Proxy. By default, mihomo listens on the mixed port at 127.0.0.1:7890, accepting both HTTP and SOCKS5 connections.
The key is the second step: apps must actively query the system for proxy settings and actually use that address to establish connections. This splits apps into four categories:
- Browsers and most Electron apps use the system network API, so they read the settings and system proxy works for them.
- Game engines often create sockets directly without checking system proxy, so they connect straight through.
- On Windows and macOS,
curl,wget, andgitdon't read system proxy by default; they only honor thehttp_proxy/https_proxyenvironment variables. - All UDP traffic: HTTP proxy only carries TCP; although SOCKS5 has the UDP ASSOCIATE extension, most apps never implement it.
So if "the proxy is on but curl in the terminal still connects directly," that's not a broken config — it's the boundary of how system proxy works. Here's the comparison:
| Traffic Type | System Proxy | TUN Mode |
|---|---|---|
| Browser HTTP/HTTPS | Intercepted | Intercepted |
| CLI curl / git / brew | Not intercepted (needs env vars) | Intercepted |
| Games & voice UDP | Not intercepted | Intercepted |
| QUIC / HTTP/3 | Not intercepted (browser falls back to TCP) | Intercepted |
| LAN device access | Unaffected | Needs LAN exclusions |
TUN Mode: Virtual Adapter Takes Over the IP Layer
TUN is a virtual network device provided by the kernel. When TUN is enabled, mihomo creates a virtual adapter — wintun on Windows, utun on macOS, tun on Linux — then modifies the routing table so IP packets destined for non-local addresses are sent to this adapter.
The traffic path changes accordingly:
- The app hands data to the kernel;
- The kernel routes it into the virtual adapter;
- mihomo reads the full IP packet in user space;
- It extracts TCP or UDP and matches it against the rules;
- The traffic is forwarded out through the node.
The interception happens at the network layer (L3), not the application layer (L7). mihomo doesn't care how apps send data; it only sees IP packets. Three direct consequences: apps have no idea they're being proxied; TCP and UDP are treated equally; and no matter what language or network library a process uses, it can't escape the routing table.
The costs are just as clear: creating a virtual adapter requires admin or root privileges, and since the routing table is modified, LAN and intranet access need extra allowances.
DNS is the other half of TUN mode that's easy to overlook. The dns-hijack setting in the TUN config intercepts all queries to port 53 and resolves them locally. Combined with enhanced-mode: fake-ip, domain resolution also goes through the proxy chain, preventing DNS leaks. Here's the default Clash Verge config as an example:
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://doh.pub/dns-query
Once enabled, resolving a domain that can't be reached directly returns a Fake-IP from the 198.18.0.0/16 range, while the real resolution is done by a remote DoH server — a quick visual check that TUN is actually working.
CLI, Games, and UDP: The Dividing Line Between the Two Modes
Command-Line Tools
With system proxy enabled, git clone, curl, brew, npm, and go install all connect directly. To cover them with system proxy, you need to export the environment variables manually:
export https_proxy=http://127.0.0.1:7890
export http_proxy=http://127.0.0.1:7890
export all_proxy=socks5://127.0.0.1:7890
Port 7890 is the mixed port shared by HTTP and SOCKS5, so the three lines above route git, curl, and npm through the same entry point. In TUN mode this step isn't needed; leftover environment variables can actually cause double proxying, so it's best to clear them.
Games and UDP
Game matchmaking, voice chat, and status sync rely heavily on UDP. System proxy doesn't carry UDP at the protocol level; even with SOCKS5 enabled, game clients won't implement UDP ASSOCIATE. That's why you get half-broken states like "can log in but can't find matches" or "voice keeps cutting out." TUN takes UDP packets into the virtual adapter as-is and forwards them by the rules, so behavior is close to a direct connection.
QUIC and HTTP/3
Chrome and Safari prefer QUIC (UDP/443) for sites that support HTTP/3. With system proxy, the browser detects that the proxy doesn't support UDP and automatically falls back to TCP; with TUN, QUIC traffic is intercepted directly and never downgraded.
Scenario Guide: Which Mode to Use When
| Scenario | Recommended Mode | Reason |
|---|---|---|
| Everyday web browsing | System Proxy | No admin rights needed, low resource usage |
| Development and CLI work | TUN Mode | Covers git / npm / curl in one shot |
| Games, voice, and video calls | TUN Mode | UDP must be handled at the network layer |
| Corporate intranet alongside proxy | System proxy + rules | LAN segments aren't intercepted, more controllable policies |
| Apps can't request admin privileges | System Proxy | TUN requires elevated privileges to create the adapter |
| Global packet capture and full testing | TUN Mode | One uniform path for all processes |
Checklist Before Switching
- Connectivity: verify with
curl -I https://www.gstatic.com/generate_204— don't use ping, because whether ICMP is intercepted depends on the node and stack and can't prove the proxy is working. - DNS: resolve a domain that can't be reached directly. A
198.18.x.xresponse means Fake-IP is active; a real IP means checkingdns-hijackandenhanced-mode. - LAN: printers, NAS devices, and router admin pages may be captured by TUN. Add
route-exclude-address: 192.168.0.0/16under thetunsection, or use rules to force direct connections. - Windows compatibility: if games or P2P can't connect, cycle through
stack: system→gvisor→mixedand test again. - Leftover env vars: in system proxy mode, run
env | grep -i proxyin the terminal; if anything remains,unsetit, otherwise CLI tools will keep using the old proxy.
A common mistake: enabling TUN and then also turning on system proxy. They don't stack — browser traffic just takes an extra detour into port 7890 and back out. In TUN mode, turn off the system proxy switch for the shortest path and cleaner troubleshooting.