ブログ

行が同じでも、順番が逆なら結果は逆です。

ルールファイルは集合ではありません。順序付きのリストです。エンジンは接続ごとに一度だけ歩き、先に当たった 1 行が動作を出し、後ろの行は見ません。構文が正しくても順番が逆なら、結果は完全に逆になり得ます。

いつ動くか

エンジンのスイッチはポリシーにあり、ファイルにはない

Shadowrocket の default.conf:Rule 289 件
ルールは設定ファイルにあります。ポリシーが Config のときだけ問われます。App Store 掲載画面。端末の版に従ってください。

どれほど揃ったルールでも、ポリシーが Proxy なら送信はすべて現在のレコードへ入り、Direct ならすべて元経路です。ファイルが「自分で開く」ことはありません。ポリシーを Config に戻して初めて、今選んでいる構成が 1 行ずつ照合を始めます。ポリシー 3 項の意味は トンネル にあります。だから「ルールが効かない」にはまったく違う二義があります。ひとつは、エンジンがそもそも問われていない。もうひとつは、問われたが、先に当たった行が思っていた行ではない。対照では前者を先に確認し、それから後者を直します。

構成ファイルは複数持てます。接続時に使うのは今選んでいる 1 つだけです。サーバーレコードは別のオブジェクトです。ハイライト行を替えてもファイルは替わらず、ファイルを替えてもハイライト行は替わりません。構成に何が書いてあるかと、一覧で今ハイライトされている出口は、独立した二件です。オブジェクトConfig を見てください。製品ページのドメインテスターは、書き込み済みの見本リストです。「上から」だけを示します。GEOIP はウェブでは模擬できません。テスターの結果を自分の端末の振り分けだと思うと、誤った結論になります。

順番

狭い条件を、広い条件より上に書く

よくある書き方は、条件タイプ、引数、動作です。動作は DIRECT、PROXY、REJECT です。照合は上からです。ある行が当たったあと、後ろの行は見ません。だから例外は通則より前に書きます。FINAL をファイルの途中に置くと、それより下の行はすべて無効です。ファイルには残っていますが、問われることはありません。行の形式と条件タイプの細部は ルール 章にあり、下では順番そのものを、入れ替え 1 組で示します。

# A: 先にホストを指名し、そのあとサフィックス
DOMAIN,api.example.com,PROXY
DOMAIN-SUFFIX,example.com,DIRECT
FINAL,PROXY

# B: 先にサフィックス
DOMAIN-SUFFIX,example.com,DIRECT
DOMAIN,api.example.com,PROXY
FINAL,PROXY

api.example.com では、リスト A は 1 行目に当たりレコードへ、リスト B はサフィックスに当たり直通です。www.example.com では、どちらもサフィックスで直通です。どちらにも指名されていないホストでは、どちらも FINAL に落ち、レコードへ行きます。差が出るのは「具体行にも広い行にも覆われる」名前だけです。KEYWORD は SUFFIX より広く、GEOIP はほとんどのドメイン行より広く、FINAL が最も広いです。安定した順は、具体ホスト → サフィックス / キーワード → 網段 → GEOIP → FINAL です。構文の要求ではなく、例外が見えるための置き方です。

DOMAIN はホスト名の完全一致です。DOMAIN-SUFFIX はそのサフィックスと等しいか、「.サフィックス」で終わる名前です。DOMAIN-KEYWORD はその文字列を含むことだけを要求します。サフィックス行は別の登録ドメインを自動では覆いません。google.com を書いても gstatic.com は対象になりません。IP-CIDR が見るのは IPv4 だけです。IPv6 の宛先はこの行を見えず、GEOIP か FINAL まで落ちます。IPv4 の私網だけ足して、端末が同じサービスを IPv6 で取るのは、ルールが「ときどき効く」ように見えます。DNS を見てください。

GEOIP は宛先 IP の地理ライブラリ上の分類であり、ドメインの登録地でも、サイトの言語でもありません。CDN が同じホスト名を別の国のアドレスに指すと、GEOIP の結果も動きます。ルールが見る名前も、アドレスバーの文字列とは限りません。アプリが IP に直接繋ぐ、または SNI を付けないなら、ドメイン行はすべて外れ、アドレス行か FINAL に落ちます。それが「同じサイトが、あるときはプロキシ、あるときは直通」の一因です。二回の要求がエンジンに渡した情報が違います。

外部ファイル

使う前に FINAL を読む

外部リストの著者は、自分の出口に合わせて書いています。FINAL が PROXY か DIRECT かが、指名されていないトラフィックすべての運命を決め、ドメイン行を百行足すより効きます。レコードが、いま普通に届くサイトの多くと同じ側にあり、少数のホストだけ通したいのに FINAL を PROXY にすると、無関係な要求が大量にノードへ入ります。レコードが別の側にあり、指名されていないものも通したいのに FINAL を DIRECT にすると、大半のサイトはノードに入りません。

一度も到達しないルールを直しても、Data は動かず、ページも変わりません。固定した 1 レコードで、ポリシーだけ切り替えて対照します。Proxy でそのホストがすでに開けるなら、Config に戻してカウンタがどちら側に立つかを見ます。レコードもファイルも FINAL も同時に替えると、毎回の変化を残りの二つの変数で説明できてしまいます。購読型ルールの更新と、サーバーコンテナの更新は、別オブジェクト上の同種の動作です。失敗時は直前に成功したファイルを残し、失敗のためにルールを空にはしません。

動作は「繋がりの度合い」ではありません。DIRECT は元経路で出て、PROXY はハイライト中のレコードへ送り、REJECT は送りません。直通であるべきシステムサービスを PROXY にすると、プッシュやストア更新が遅くなりがちです。レコードへ入れるべきホストを DIRECT にすると、Data は Direct だけ増え、REJECT にするとアプリがネットワークエラーを出し、ノードが壊れたと誤読されやすいです。動作を変える前に、その行が本当に当たるかを確認してください。

同じ接続でも、エンジンに渡る情報は欠けていることがあります。ブラウザは通常、ホスト名と解決済みアドレスの両方を持つので、ドメイン行もアドレス行も当たる機会があります。それでも先に当たった行です。IP だけに繋ぎ、SNI を付けないクライアントは、ドメイン行がすべて外れ、IP-CIDR、GEOIP、FINAL にしか落ちられません。すると「Safari はプロキシ、あるアプリは直通」になります。二つのプログラムがエンジンに渡したものが違うのであり、エンジンが無作為なのではありません。対照ではドメイン行だけ直さず、Data で今回のバイトがどちら側に立ったかも見てください。ホームのテスターはドメインしか入力できません。「アドレスだけ、名前がない」要求は模擬できず、端末上の地理ライブラリ版も模擬できません。

行が多いことは、例外が見えることではない

ファイル末尾にドメイン行を足し続けても、すでに前にある広い条件は止まりません。あるホストを別の道へ通すには、それを横取りする行より前に書きます。順番が違うと、どれほど長いリストでも、途中で切られたリストです。