Shadowrocket の REJECT ルール:遮断の仕組みと適用範囲

REJECT はルールで指定できる 3 つのアウトバウンドポリシーのひとつで、マッチした接続はローカルで拒否または破棄され、リクエストがサーバーへ転送されることはありません。本記事では適用順序と実際に効く範囲、そして HTTPS・アプリ内通信・ドメインフロンティングに対する限界を整理します。

この記事の要点

REJECT が決めるのは 1 本の接続を通すかどうかだけで、通信内容を解析するわけではありません。読み終えると、REJECT と PROXY・DIRECT がルール一覧の中でどういう位置関係にあるのか、同じドメイン配下のプロモーション用 API や IP 直書きのアプリ内通信をなぜ止められないのかが分かり、「ルールを書いたのに効かない」ときの確認手順も身につきます。自分のサービス提供元からサブスクリプションを取得でき、ルールを自分で整理している人向けです。

ルールにおける REJECT とは:アウトバウンドポリシーのひとつ

Shadowrocket のルール行はタイプ,値,ポリシーという 3 段構成で、ポリシー部分に取れる値は 3 つだけです:PROXY(現在選択しているサーバーから送信)、DIRECT(ローカルで直接接続し、プロキシを通さない)、REJECT(この接続をローカルで拒否または破棄)。REJECT は Settings にある全体スイッチではなく、あくまで 1 つのルールの動作であり、そのルールにマッチした接続だけが遮断されます。

最小構成のブロックルールは次のようになります:

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 が使われるのはどんなときか

新しい接続は 1 回だけルールマッチングを行います。一覧の 1 行目から順に照合し、最初にマッチしたルールがその接続の行き先を決め、それ以降のルールは関与しません。REJECT が効くかどうかは、その手前により広いルールがあって先に接続を持っていかれないか次第です。

アプリがリクエストを送信接続がトンネルに入るルールを上から順に照合最初のマッチが有効接続がローカルで拒否される

順序の問題はルールの広さの関係から生じます。DOMAIN-KEYWORD,ads,REJECTDOMAIN-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

この 6 行はそのまま使える骨組みです:完全一致ドメイン → ドメインサフィックス → キーワード → IP レンジ → 地理的帰属 → フォールバック。具体的なものほど前に置きます。

FINAL はフォールバックルールで、それより前でマッチしなかったすべての接続に一致するため、必ず最終行に置きます。途中に書くと、その後に続くすべてのルールを無効にしてしまいます。IP 系のルールにはもう 2 つ注意点があります。no-resolve を付けるとこのルールでは DNS 解決が行われず、宛先が IP リテラルのときだけマッチします。no-resolve を付けない IP-CIDR は、まずドメインを IP に解決してから照合するため、解決結果によって効いたり効かなかったりします。

遮断の限界:HTTPS・アプリ内通信・ドメインフロンティング

REJECT が働くのは接続の確立段階です。接続をローカルで拒否または破棄するだけで、TLS ハンドシェイク後のデータ交換には関与しません。ここから能力の上限が決まります。REJECT が扱うのは「この接続が通るかどうか」であり、「ページに何が表示されるか」ではありません。

限界 1:HTTPS は接続レイヤーまで

https://ads.example.com/x.js のようなリクエストでは、REJECT が止めるのは ads.example.com:443 への接続で、スクリプトは当然読み込まれません。しかし、広告コンテンツと本文が同じドメインから配信されている場合(たとえば example.com 配下の 1 つの API)、REJECT では対処できません。ドメインごと遮断すると本文も開けなくなるからです。ルールに URL パスでマッチするキーワードはなく、クライアントから HTTPS リクエストのパスは見えません。

限界 2:アプリ内通信と IP 直書き

多くのアプリは送信先を IP リテラルで書いたり、API からドメインを動的に受け取ったりします。前者はドメインルールではマッチしないため IP-CIDR で受け止める必要があり、後者は実際のドメインが現れてからルールを追加することになります。IP で止める場合の代償は巻き添えです。同じサブネットには正常なサービスが同居していることが多く、CDN の IP を共有している場合は特にそうです。ドメインルールと IP ルールは補い合う 2 つの入口で、それぞれ次の 2 通りの接続の張り方に対応します:

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

もう 1 つのポイントは QUIC です。UDP 443 を使う接続も同じくルールマッチングを通りますが、no-resolve 付きの IP-CIDR を書いていて、アプリがドメイン形式で接続している場合、このルールは名前解決を起こさないためマッチしません。

限界 3:ドメインフロンティング

ドメインフロンティング(domain fronting)は、TLS ハンドシェイクの SNI と実際に接続先となる Host を食い違わせる手法で、SNI にはたいてい「クリーンな」ドメインが入ります。Shadowrocket は接続先のドメイン(つまり SNI)でルールを照合するため、DOMAIN-SUFFIX が止めるのは SNI 側のドメインです。SNI で止めると同じ入口を使う正常なサービスにも影響が及び、Host 側で止めるのはクライアントのルールの守備範囲外です。

結論:REJECT はリスト方式の接続遮断であり、コンテンツフィルターではない

ドメインと IP でマッチし、接続レイヤーで働くということは、独立したドメインや独立した IP へのリクエストは止められるということです。同じドメイン配下のプロモーション用 API、URL パス単位のコンテンツ、SNI と Host が食い違う通信は、いずれも REJECT の守備範囲外です。この限界を前提に期待値を決めておけば、ルールを書き換え続ける無駄な試行錯誤をかなり減らせます。

ルールを書いたのに効かない:この順序で確認する

ルールが効かない原因は、たいてい「現在有効な構成」と「マッチング順序」の 2 点に集約されます。次の順番で 1 つずつ確認するほうが、ルールを書き直し続けるより速く解決します。

  1. 現在有効な Config を確認する

    Home に戻り、上部に表示されている構成名を見ます。ルールを A の構成に書き、選択中なのが B なら、そのルールは当然マッチングに参加しません。

  2. ルール一覧での位置を確認する

    より前にある広いルールが先にマッチしていないか、特に DOMAIN-KEYWORD が DOMAIN-SUFFIX より前に置かれていないかを見ます。

  3. 接続がドメインか IP かを確認する

    ドメインルールは IP 直結の接続にはマッチしません。no-resolve 付きの IP-CIDR も、ドメイン接続では名前解決を行いません。

  4. Global Routing の状態を確認する

    Proxy または Direct で止まっていると、ルール一覧は振り分けの判断に使われません。Config に戻して初めてルールが 1 行ずつ照合されます。

  5. サブスクリプション更新後にルールを確認する

    サブスクリプションを更新すると構成が再取得され、ローカルで手を入れたルールが上書きされることがあります。更新後は Home に戻ってルールが残っているか確認してください。

注意

REJECT は Shadowrocket のトンネルを通る接続にだけ作用し、通信内容の解析も行いません。ルールが変えられるのは接続の行き先であり、アプリ自体の挙動ではありません。

REJECT に関するよくある質問 5 つ

REJECT を追加したら、同じドメインの通常ページも開けなくなった?

そのドメインが本文と遮断対象の両方を載せているということです。REJECT はドメイン単位でまとめて止めるため、一部だけを止めることはできません。ルールを特定のサブドメインまで絞るか、DOMAIN でホスト名を 1 つずつ正確に指定してください。

REJECT と DIRECT は結局何が違う?

DIRECT は通過させる指定で、接続は通常どおり確立され、プロキシを通らないだけです。REJECT はローカルで拒否または破棄するので、接続そのものが確立できません。「つながるがプロキシを通したくない」なら DIRECT、「つながらなくしたい」なら REJECT です。

Home で書いたルールが、サブスクリプション更新後に消えた?

サブスクリプション更新は構成ファイルを再取得するため、ローカルで手を入れたルールが上書きされることがあります。長く残したいルールは、更新後に Home で確認し、必要なら追加し直してください。

IP でレンジごと止めたら、別のサービスまで落ちた?

IP-CIDR はレンジ全体を止めるため、CDN の IP を共有する正常なサービスも巻き込みます。まずはドメインルールを優先し、どうしても IP で扱う場合はレンジを細かく分割し、余計な名前解決を避けるために no-resolve を付けてください。

REJECT された接続が Data ページで流量として見えないのはなぜ?

接続が確立段階で終わっているため実際の通信量が発生せず、サーバー別・アプリ別の集計値も当然増えません。ルールがマッチしているかどうかは、Home の現在の構成とルール順序で判断してください。

App Store 正規版の確認