Shadowrocket REJECT 策略:封鎖原理與攔截邊界

REJECT 是規則裡的三種出站策略之一,命中的連線會在本機被拒絕或丟棄,請求不會轉發到任何伺服器。本文說明它的命中順序、實際生效範圍,以及它對 HTTPS、App 內請求與網域前置的邊界。

本文速覽

REJECT 只決定一條連線放不放行,不解析傳輸內容。讀完你能分清 REJECT 與 PROXY、DIRECT 在規則列表裡的位置關係,知道它為什麼攔不住同網域下的推廣 API 與硬編碼 IP 的 App 內請求,並照一套固定順序排查「規則寫了卻不生效」。適合已經能從自己的服務商取得訂閱、正在自己整理規則的人。

REJECT 在規則裡是什麼:一條出站策略

Shadowrocket 的規則行是類型,值,策略的三段式寫法,策略段只有三種取值:PROXY(交給目前選取的伺服器出站)、DIRECT(本機直連,不進代理)、REJECT(在本機拒絕或丟棄這條連線)。REJECT 不是 Settings 裡的一個總開關,它只是某一條規則的動作,只有命中這條規則的連線才會被攔下來。

一條最小可用的封鎖規則長這樣:

DOMAIN-SUFFIX,ads.example.com,REJECT
DOMAIN-KEYWORD,metrics,REJECT
IP-CIDR,203.0.113.0/24,REJECT,no-resolve
FINAL,PROXY

規則寫在目前的 Config 檔案裡(Home → 目前配置 → 編輯),也可以在 Home 的規則列表中直接增刪。改動後需要重新選取該 Config 才會參與匹配;更新訂閱會重新拉取設定檔,本機手改的規則可能被覆蓋,更新完建議再檢查一遍。

3 種
出站策略:PROXY / DIRECT / REJECT
由上而下
規則命中順序:首條匹配即生效
2 處
規則入口:Config 檔案與 Home 規則列表
連線層
REJECT 生效層級:不解析傳輸內容

命中順序:REJECT 什麼時候才輪得到

每個新連線只做一次規則匹配:從列表第一行開始逐條比對,第一條匹配成功的規則決定這條連線的走向,後面的規則不再參與。REJECT 能不能生效,取決於它前面有沒有範圍更廣的規則先把這條連線帶走。

App 發起請求連線進入隧道規則由上而下匹配首條命中生效連線在本機被拒絕

順序問題出在寬窄關係上。DOMAIN-KEYWORD,ads,REJECT 寫在 DOMAIN-SUFFIX,ads.example.com,PROXY 前面,那麼 ads.example.com 會先被 keyword 規則攔掉;反過來寫,窄規則先命中,後面的 keyword 規則對這條連線就沒有機會了。窄規則在前、寬規則在後,是規則列表的基本排法。

DOMAIN,api.example.com,DIRECT
DOMAIN-SUFFIX,example.com,PROXY
DOMAIN-KEYWORD,metrics,REJECT
IP-CIDR,198.51.100.0/24,REJECT,no-resolve
GEOIP,CN,DIRECT
FINAL,PROXY

這六行是一副可用骨架:精確網域 → 網域後綴 → 關鍵字 → IP 段 → 地理歸屬 → 兜底,越具體的越靠前。

FINAL 是兜底規則,匹配所有未被前面命中的連線,必須放在最後一行;把它寫在中間,等於給它後面的所有規則判了死刑。IP 類規則還有兩個細節:帶 no-resolve 表示這條規則不觸發 DNS 解析,只在目標本身就是 IP 字面值時匹配;不帶 no-resolveIP-CIDR 會先把網域解析成 IP 再比對,解析結果不同就可能出現時靈時不靈。

攔截邊界:HTTPS、App 內請求與網域前置

REJECT 生效在連線建立階段:它在本機拒絕或丟棄連線,不參與 TLS 握手之後的資料交換。這決定了它的能力上限——它管的是「這條連線能不能通」,不是「頁面裡顯示什麼」。

邊界一:HTTPS 只攔到連線層

https://ads.example.com/x.js 這樣的請求,REJECT 攔掉的是到 ads.example.com:443 的連線,腳本自然拿不到。但如果推廣內容與正文來自同一個網域(例如 example.com 下的一個 API),REJECT 就無能為力:攔掉整個網域,正文也會一起打不開。規則裡沒有按 URL 路徑匹配的關鍵字,用戶端看不到 HTTPS 請求的路徑。

邊界二:App 內請求與硬編碼 IP

很多 App 把回報位址寫成 IP 字面值,或者從 API 動態下發網域。前者網域規則匹配不到,需要 IP-CIDR 兜底;後者要等實際網域出現之後再補規則。按 IP 攔的代價是容易誤傷——同一網段上往往還有正常服務,共用 CDN 的 IP 尤其如此。網域規則與 IP 規則是兩條互補入口,分別對應下面兩種發起方式:

DOMAIN-SUFFIX,ads.example.com,REJECT
IP-CIDR,203.0.113.0/24,REJECT,no-resolve

另一個細節是 QUIC。走 UDP 443 的連線同樣會經過規則匹配,但如果你寫的是帶 no-resolveIP-CIDR,而 App 是以網域形式發起連線的,這條規則不會觸發解析,也就匹配不到。

邊界三:網域前置

網域前置(domain fronting)的做法是:TLS 握手裡的 SNI 與請求實際指向的 Host 不一致,SNI 通常是一個「乾淨」的網域。Shadowrocket 按連線的目標網域(即 SNI)匹配規則,DOMAIN-SUFFIX 攔的是 SNI 上的那個網域。按 SNI 攔會連帶影響同一入口上的正常服務;按 Host 攔截則不在用戶端規則的處理範圍內。

結論:REJECT 是名單式連線攔截,不是內容過濾器

按網域與 IP 匹配、在連線層生效,意味著它能擋住獨立網域和獨立 IP 上的請求;同網域下的推廣 API、URL 路徑層級的內容、SNI 與 Host 不一致的流量,都不在它的處理範圍內。按這個邊界設預期,能省掉大量反覆改規則的試錯。

規則寫了卻不生效:按這個順序排查

規則不生效,原因大多落在「目前生效的 Config」和「匹配順序」這兩件事上。照下面的順序逐項確認,比反覆重寫規則更快。

  1. 確認目前生效的 Config

    回 Home 看頂端顯示的 Config 名稱。規則寫在 A、目前選取的卻是 B,規則自然不會參與匹配。

  2. 檢查規則在列表中的位置

    看有沒有更靠前的寬規則先命中,尤其是 DOMAIN-KEYWORD 排在 DOMAIN-SUFFIX 之前的情況。

  3. 確認連線是網域還是 IP 發起

    網域規則匹配不到 IP 直連;帶 no-resolve 的 IP-CIDR 也不會為網域連線觸發解析。

  4. 確認 Global Routing 的狀態

    停在 Proxy 或 Direct 時,規則列表不參與分流決策;回到 Config 才會按規則逐條匹配。

  5. 更新訂閱後複查規則

    訂閱更新會重新拉取設定,本機手改的規則可能被覆蓋;更新完回 Home 確認規則還在。

注意

REJECT 只作用於經過 Shadowrocket 隧道的連線,也不解析傳輸內容。規則能改變的是連線走向,不是 App 自身的行為。

關於 REJECT 的五個常見問題

加了 REJECT,同一個網域的正常頁面也打不開了?

說明這個網域同時承載正文與被攔內容。REJECT 按網域整條攔,不能只攔其中一部分;把規則收窄到具體子網域,或改用 DOMAIN 精確匹配單一主機名稱。

REJECT 和 DIRECT 到底差在哪?

DIRECT 是放行,連線照常建立,只是不走代理;REJECT 是在本機拒絕或丟棄,連線建立不起來。要「能連但不走代理」用 DIRECT,要「連不上」用 REJECT。

規則寫在 Home 裡,更新訂閱後就沒了?

訂閱更新會重新拉取設定檔,本機手改的規則可能被覆蓋。需要長期保留的規則,更新完回 Home 複查一遍,必要時重新加入。

按 IP 攔了一整段,結果別的服務也掛了?

IP-CIDR 攔的是整個網段,共用 CDN 的 IP 上往往還有正常服務。優先使用網域規則;確實要按 IP 處理時把網段切細,並帶上 no-resolve 避免額外解析。

為什麼被 REJECT 的連線在 Data 頁看不到流量?

連線在建立階段就結束了,沒有實際傳輸量,按伺服器與按 App 統計的讀數自然不會成長。判斷規則是否命中,以 Home 裡的目前 Config 與規則順序為準。

App Store 正版核驗