Shadowrocket 部落格 · 原理科普

為什麼 Shadowrocket 做不到
「只讓某個 App 走代理」。

不少人期待像桌面端工具一樣,精確指定「某個 App 走代理,其他 App 直連」。這個訴求在 iOS 上基本無法完整實現,原因不在 Shadowrocket 本身,而在 iOS 系統底層的網路框架設計。這篇文章說明具體限制在哪裡,以及 Shadowrocket 實際採用的替代方案。

iOS 上的 VPN,走的是蘋果自己的框架

iOS 不允許第三方 App 像桌面系統那樣直接接管網路底層、隨意攔截或修改流量。所有需要轉發網路流量的 App(包括 Shadowrocket),都必須透過蘋果提供的官方框架 Network Extension 來實現,其中負責流量轉發的核心元件叫 NEPacketTunnelProvider。這也是為什麼首次使用時系統會跳出「VPN 設定」授權提示——這是走官方框架的必經步驟,不是 Shadowrocket 自己發明的機制。

兩種執行模式,二選一,不能混用

根據蘋果官方文件,NEPacketTunnelProvider 只支援兩種路由模式,而且是互斥的:

模式運作方式限制
依目標 IP 路由
destinationIP
根據流量要造訪的目標位址決定是否進入通道,Shadowrocket 的全域代理、規則分流用的都是這種模式系統在這個模式下不會告訴 App「這個請求是哪個 App 發出的」,只能依網域或 IP 判斷,無法感知來源 App
依來源 App 路由
sourceApplication
系統依流量的來源 App 決定是否轉發到你的通道這種「分應用 VPN」模式一旦某個 App 的流量被路由進通道,就必須全部由你的 App 處理,不能只處理其中一部分再放一部分直連;且這種模式通常需要 MDM(企業裝置管理)設定才能啟用,一般使用者自己安裝的 App 用不到

換句話說,蘋果的設計裡從來就沒有「既依 App 區分,又能在同一個 App 內部再分流一部分」這種模式——這不是哪家代理工具沒做好,而是系統 API 層面就沒有開放這個能力。這一點在蘋果開發者論壇的多個官方回覆裡都有明確說明:「分應用 VPN 模式下,沒有機制可以讓你只處理某個 App 的部分流量」。

Shadowrocket 實際採用的替代方案

既然系統層面拿不到「這個請求來自哪個 App」這個資訊,Shadowrocket 走的是 依目標網域/IP 判斷 的路線:規則檔裡寫的 DOMAIN-SUFFIXIP-CIDRGEOIP 等規則,本質上是在用「這個 App 通常會連線哪些網域或伺服器」來近似還原「依 App 分流」的效果,而不是系統真的識別出發出請求的 App 是誰。

這也解釋了幾個實際使用中會遇到的現象:

這是不是意味著規則分流沒有意義?

不是。對大多數情境(例如「台灣網站直連、有地區限制的走代理」)來說,用網域和 IP 判斷已經夠準,因為這些目的地通常分得開。iOS 做不到的是:同一個 App 裡一部分流量走代理、其餘直連。

說明:本文技術細節參考 Apple 官方開發者文件(Network Extension / Packet Tunnel Provider)與蘋果開發者論壇的官方回覆整理,具體 API 行為以蘋果最新發布的開發者文件為準。

了解原理之後,實際設定起來更快 知道了限制在哪裡,規則檔該怎麼寫、什麼時候該用全域代理會更容易判斷
前往下載 →

延伸閱讀:規則分流語法詳解 · 網頁打不開的排查步驟