TUN 모드와 시스템 프록시의 작동 원리 비교: 트래픽은 어느 계층에서 가로채질까
시스템 프록시가 앱의 프록시 설정 읽기에 의존하는 방식과 TUN이 가상 네트워크 어댑터로 모든 IP 트래픽을 가로채는 방식을 비교합니다. 명령줄 도구, 게임, UDP 앱이 두 모드에서 다르게 동작하는 이유와 각각 적합한 사용 사례를 설명합니다.
결론부터 말하면
시스템 프록시와 TUN 모드는 서로 다른 계층에서 동작합니다. 시스템 프록시는 애플리케이션 계층의 약속입니다. 운영체제가 프록시 주소를 설정에 기록하면 앱이 직접 읽어야만 프록시를 거치게 됩니다. TUN 모드는 네트워크 계층에서 가로채는 방식입니다. mihomo가 가상 네트워크 어댑터를 만들면 커널이 조건에 맞는 IP 패킷을 전부 그 어댑터로 보내고, 앱은 프록시의 존재를 알지 못하며 우회할 수도 없습니다.
한마디로, 시스템 프록시는 앱의 협조가 필요하고 TUN 모드는 커널 라우팅에 의존합니다. 명령줄, 게임, UDP 환경에서 두 모드의 동작이 완전히 달라지는 이유가 바로 여기에 있습니다.
시스템 프록시: 앱이 직접 읽어야 프록시가 적용된다
시스템 프록시를 켜면 Windows는 [설정] → [네트워크 및 인터넷] → [프록시]에 주소를 기록하고, macOS는 [시스템 설정] → [네트워크] → [프록시]에 동일한 정보를 기록합니다. mihomo는 기본적으로 127.0.0.1:7890에서 혼합 포트를 열어 HTTP와 SOCKS5 연결을 동시에 받습니다.
핵심은 두 번째 단계입니다. 앱이 시스템에 프록시 설정을 직접 조회하고, 그 주소로 실제 연결을 맺어야 합니다. 그래서 다음과 같이 네 가지로 갈립니다.
- 브라우저와 대부분의 Electron 앱은 시스템 네트워크 API를 사용하므로 프록시를 읽으며, 시스템 프록시가 적용됩니다.
- 게임 엔진은 보통 소켓을 직접 생성하고 시스템 프록시를 확인하지 않아 그냥 직결됩니다.
curl,wget,git은 Windows와 macOS에서 기본적으로 시스템 프록시를 읽지 않고http_proxy/https_proxy환경 변수만 인식합니다.- 모든 UDP 트래픽: HTTP 프록시는 TCP만 처리합니다. SOCKS5에는 UDP ASSOCIATE 확장이 있지만 대부분의 앱은 이를 구현하지 않습니다.
그래서 "프록시를 켰는데 터미널에서 curl이 여전히 직결된다"고 해서 설정이 잘못된 것이 아니라 시스템 프록시의 구조적 한계입니다. 비교하면 다음과 같습니다.
| 트래픽 유형 | 시스템 프록시 | TUN 모드 |
|---|---|---|
| 브라우저 HTTP/HTTPS | 가로챔 | 가로챔 |
| 명령줄 curl / git / brew | 가로채지 않음(환경 변수 필요) | 가로챔 |
| 게임 및 음성 UDP | 가로채지 않음 | 가로챔 |
| QUIC / HTTP/3 | 가로채지 않음(브라우저는 TCP로 강등) | 가로챔 |
| LAN 장치 접근 | 영향 없음 | 내부 네트워크 대역 제외 필요 |
TUN 모드: 가상 네트워크 어댑터가 IP 계층을 가로챈다
TUN은 커널이 제공하는 가상 네트워크 장치입니다. mihomo가 TUN을 켜면 가상 네트워크 어댑터를 생성합니다. Windows는 wintun 드라이버, macOS는 utun, Linux는 tun을 사용합니다. 그다음 라우팅 테이블을 수정해 로컬 주소가 아닌 IP 패킷이 이 어댑터로 향하게 합니다.
이에 따라 트래픽 경로가 다음과 같이 바뀝니다.
- 앱이 데이터를 커널에 전달합니다.
- 커널이 라우팅 테이블에 따라 가상 네트워크 어댑터로 보냅니다.
- mihomo가 사용자 공간에서 완전한 IP 패킷을 읽습니다.
- TCP 또는 UDP를 해석해 규칙과 대조합니다.
- 노드를 통해 외부로 전달합니다.
가로채는 계층은 네트워크 계층(L3)이지 애플리케이션 계층(L7)이 아닙니다. mihomo는 앱이 데이터를 어떻게 보내는지 신경 쓰지 않고 IP 패킷만 바라봅니다. 그 결과는 세 가지입니다. 앱은 자신이 프록시되고 있다는 사실을 전혀 모릅니다. TCP와 UDP가 동등하게 처리됩니다. 어떤 프로세스가 어떤 언어나 네트워크 라이브러리를 쓰든 라우팅 테이블을 벗어날 수 없습니다.
대가도 분명합니다. 가상 네트워크 어댑터를 만들려면 관리자 또는 root 권한이 필요하고, 라우팅 테이블이 변경되므로 내부 네트워크와 LAN 접근을 위한 추가 허용이 필요합니다.
DNS는 TUN 모드에서 놓치기 쉬운 또 다른 절반입니다. TUN 설정의 dns-hijack은 53번 포트로 향하는 모든 쿼리를 로컬 해석으로 가로채고, enhanced-mode: fake-ip와 함께 사용하면 도메인 해석도 프록시 경로를 거쳐 DNS 누출을 방지합니다. Clash Verge 기본 설정을 예로 들면,
tun:
enable: true
stack: mixed
dns-hijack:
- any:53
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://doh.pub/dns-query
켜면 직결할 수 없는 도메인의 해석 결과로 198.18.0.0/16 대역의 Fake-IP가 반환되고, 실제 해석은 원격 DoH가 수행합니다. 이는 TUN이 실제로 작동하는지 확인할 수 있는 직관적인 신호입니다.
명령줄, 게임, UDP: 두 모드를 가르는 분수령
명령줄 도구
git clone, curl, brew, npm, go install은 시스템 프록시 모드에서 전부 직결됩니다. 시스템 프록시만 켜서는 이들을 커버할 수 없으므로 환경 변수를 직접 내보내야 합니다.
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
7890은 HTTP와 SOCKS5가 공용으로 쓰는 혼합 포트입니다. 위 세 줄이면 git, curl, npm이 같은 진입점을 사용합니다. TUN 모드에서는 이 단계가 필요 없고, 남아 있는 환경 변수는 오히려 이중 프록시를 유발하므로 지우는 것이 좋습니다.
게임과 UDP
게임 매칭, 음성, 상태 동기화는 UDP를 많이 사용합니다. 시스템 프록시는 프로토콜 수준에서 UDP를 처리하지 않습니다. SOCKS5를 켜도 게임 클라이언트가 UDP ASSOCIATE를 구현하지 않습니다. 그래서 "로그인은 되는데 매칭이 안 된다", "음성이 끊기고 이어지지 않는다" 같은 반쯤 망가진 상태가 흔히 발생합니다. TUN은 UDP 패킷을 그대로 가상 네트워크 어댑터로 받아 규칙에 따라 전달하므로 직결에 가까운 동작을 보여줍니다.
QUIC과 HTTP/3
Chrome과 Safari는 HTTP/3을 지원하는 사이트에서 QUIC(UDP/443)을 우선 시도합니다. 시스템 프록시에서는 브라우저가 프록시가 UDP를 지원하지 않음을 감지하고 자동으로 TCP로 강등합니다. TUN에서는 QUIC 트래픽이 바로 가로채지므로 강등되지 않습니다.
상황별 비교: 언제 어떤 모드를 쓸까
| 상황 | 권장 모드 | 이유 |
|---|---|---|
| 일상적인 웹 서핑 | 시스템 프록시 | 관리자 권한 불필요, 리소스 점유 낮음 |
| 개발 및 명령줄 작업 | TUN 모드 | git / npm / curl을 한 번에 커버 |
| 게임, 음성, 화상 통화 | TUN 모드 | UDP는 네트워크 계층에서 가로채야 함 |
| 회사 내부망과 프록시 병행 | 시스템 프록시 + 규칙 | 내부망을 가로채지 않아 정책 통제가 쉬움 |
| 프로그램의 관리자 권한 요청이 허용되지 않는 경우 | 시스템 프록시 | TUN은 어댑터 생성에 권한 상승 필요 |
| 전역 패킷 캡처, 전체 테스트 | TUN 모드 | 모든 프로세스가 동일한 경로 사용 |
전환 전 체크리스트
- 연결성:
curl -I https://www.gstatic.com/generate_204로 확인하세요. ping은 사용하지 마세요. ICMP가 가로채지는지는 노드와 스택에 따라 달라서 프록시 적용 여부를 판단하는 기준이 될 수 없습니다. - DNS: 직결할 수 없는 도메인을 해석했을 때
198.18.x.x가 반환되면 Fake-IP가 적용된 것입니다. 실제 IP가 반환되면dns-hijack과enhanced-mode를 확인하세요. - LAN: 프린터, NAS, 라우터 관리 페이지가 TUN에서 가로채질 수 있습니다.
tun섹션에route-exclude-address: 192.168.0.0/16을 추가하거나 규칙으로 직결 처리하세요. - Windows 호환성: 게임이나 P2P 연결이 안 될 때
stack: system→gvisor→mixed순서로 바꿔가며 다시 테스트하세요. - 잔여 환경 변수: 시스템 프록시 모드에서 터미널에
env | grep -i proxy를 실행해 남은 값이 있으면unset하세요. 그렇지 않으면 명령줄이 계속 이전 프록시를 사용합니다.
흔한 실수: TUN을 켠 뒤 시스템 프록시도 켜는 경우입니다. 둘은 중첩되지 않고 브라우저 트래픽이 7890을 한 번 더 거쳐 나올 뿐입니다. TUN 모드에서는 시스템 프록시 스위치를 끄는 것이 경로가 가장 짧고 문제를 추적하기도 깔끔합니다.