この記事の概要

ノードに接続でき、これからルーティングルールを変更したい方向けの記事です。ドメインとIPの条件の違いから始め、5つのルール例でマッチ順、outboundタグ、DNS名前解決の方針を解説し、v2rayNでの設定変更と検証方法を紹介します。ページが開くかどうかだけで設定の成否を判断せず、接続がどのルールにマッチしたかを確認することがポイントです。

接続がコアに届いてからルーティングルールが適用される

システムプロキシ、TUNによる通信の取り込み、Xrayのルーティングは、それぞれ異なる段階で機能します。システムプロキシは、対応アプリの接続をローカルの入口へ送るかどうかを決めます。ルーティングルールは、コアに届いた接続を直結・プロキシ・ブロックのいずれにするか選択します。ブラウザーがシステムプロキシを迂回している場合、ルールが正しくても該当するルーティング結果は得られません。

アプリから接続 インバウンドで受信 宛先を識別 ルールを照合 アウトバウンドへ転送

この記事ではXray標準のJSONフィールドを使用します。v2rayNとv2rayNGは、画面での設定をコア用の設定に変換します。v2flyNGはV2Flyコアを使用するため、すべてのXrayフィールドをそのまま使えるとは限りません。編集前に現在使用中のコアを確認し、既存のルーティング設定をバックアップしてください。

domain・full・regexp:マッチ範囲を指定する

誤った振り分けの多くは、マッチ範囲が広すぎることが原因です。文字列だけを指定すると、Xrayは部分文字列として照合します。「このドメインとそのサブドメイン」を対象にする場合は、domain:を明示してください。ルールにはホスト名を指定し、プロトコルやパス、クエリ文字列を含むURL全体は貼り付けないでください。

記法マッチする範囲マッチ例・対象外の例
example.comドメイン内の部分文字列にマッチnotexample.comにもマッチする可能性があります
domain:example.com指定したドメインとすべてのサブドメインexample.com、img.example.comにマッチし、notexample.comにはマッチしません
full:example.com完全なドメイン名に完全一致www.example.comは対象外です
regexp:^img[0-9]+\.example\.com$正規表現でマッチimg12.example.comにマッチし、img.example.comにはマッチしません
geosite:cnドメインデータファイル内のcnセットを参照結果は使用中のデータファイルによって異なり、中国本土のすべてのサーバーを指すわけではありません

正規表現にはJSON用のエスケープも必要です。ルーティングの編集欄では、元の式に\.を含められます。JSON文字列に記述する場合は、バックスラッシュを\\と書きます。以下は解析可能なJSONルールオブジェクトの例で、コアを単独で起動できる完全な設定ではありません。

{
  "type": "field",
  "domain": [
    "full:example.com",
    "domain:example.net",
    "regexp:^img[0-9]+\\.example\\.com$"
  ],
  "outboundTag": "direct"
}

ip・geoip・geosite:参照するデータが異なる

geositeはドメインのセット、geoipはIPアドレスのセットにマッチします。ウェブサイトが複数のコンテンツ配信先を使う場合、ドメインの分類と実際の接続先IPの地域分類が異なることがあります。特定のサイトを常にプロキシ経由にしたい場合は、IPの地域情報だけに頼らず、ドメインの例外ルールを優先してください。

{
  "type": "field",
  "ip": [
    "192.168.0.0/16",
    "10.0.0.0/8",
    "geoip:private",
    "geoip:cn"
  ],
  "outboundTag": "direct"
}

上の例の最初の2項目はCIDRの記述例で、geoip:privateと対象範囲が一部重複します。実際の設定では重複する項目を削除できます。IPv4のプライベートネットワークだけではIPv6のローカルアドレスは自動的に対象になりません。デュアルスタック環境では、使用するプライベートアドレスセットの範囲を確認してください。

ルールの優先順位:上から評価し、最初の一致で終了

1回のルーティング処理では、Xrayはrules配列の順に各ルールを確認し、すべての条件を満たす最初のルールを適用します。後ろのルールのドメインがより具体的でも、自動的にそちらが選ばれることはありません。対象を限定した例外ルールは広範な分類より前に、フォールバックルールは末尾に置いてください。

同じフィールドの配列内は、通常「OR」条件です。ドメイン配列なら、いずれかの式にマッチすれば対象になります。一方、1つのルール内の異なるフィルターフィールドは、通常「AND」条件です。domain、port、networkを指定すると、すべての条件を満たす必要があります。ドメイン条件とIP条件を同じルールに書いても、「どちらかに一致すれば直結」にはなりません。

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "domain": ["geosite:category-ads-all"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "domain": ["full:example.com"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": ["geoip:private", "geoip:cn"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "network": "tcp,udp",
        "outboundTag": "proxy"
      }
    ]
  }
}

これはルールの順序を説明するためのrouting設定例です。direct、proxy、blockの3つのアウトバウンドがすでに定義され、データファイルに例で使用するセットが含まれているものとします。タグ名はコアで予約されたアクション名ではありません。一般的な直結アウトバウンドにはfreedom、ブロックにはblackholeを使い、プロキシには実際のノードのプロトコルを指定します。

5件
例のルールは配列の順に評価されます
3つ
既存のアウトバウンドタグが必要
443
HTTPSのポート条件をテストできます

例外ルールをブロックルールより優先するか確認

あるドメインを必ず直結させたい場合、広告セットにも含まれているなら、そのドメインに完全一致する直結ルールを広告ルールより前に移動してください。cnセットより前に置くだけでは不十分です。

domainStrategy:ドメインをIPルールの照合に使うタイミング

ドメイン宛ての接続にIPルールを適用できるかは、ルーティングのdomainStrategyによって異なります。このフィールドはルーティング時に照合用の名前解決を行うかを制御するもので、クライアント全体のDNS設定や、直結アウトバウンドが最終的に宛先を名前解決する方法とは別です。

AsIs:宛先の種類を維持

フィールド
routing.domainStrategy
動作
AsIs
ドメイン宛て
ルーティング照合のためにIPへ積極的に名前解決しない
IPアドレス宛て
IPルールに直接マッチできる

まずドメインルールを検証したい場合に適しています。初回の切り分けでDNSの解決結果が影響するのを避けられます。

IPIfNonMatch:マッチしなければ名前解決

フィールド
routing.domainStrategy
動作
IPIfNonMatch
実行条件
ドメイン宛ての接続が1回目の照合でどのルールにもマッチしない
その後の処理
名前解決後、IPルールを含めて再度照合

末尾にすべての接続にマッチするフォールバックルールがあると、1回目の照合で結果が確定するため、その後のIPによる再判定は行われません。

そのため、前のセクションの5つのルールにIPIfNonMatchを指定していても、ドメイン宛ての接続が最後のTCP/UDPフォールバックに到達すると、1回目の照合でマッチ済みとなり、先にあるgeoip:cnのための名前解決は行われません。もともとIPアドレス宛ての接続なら、4番目のルールにマッチできます。「geoipを設定したのにドメイン宛ての通信がプロキシ経由になる」よくある原因です。

また、インバウンドが宛先IPしか受け取っていない場合、ドメインルールが元のホスト名を自動的に把握することはできません。対応する通信ではスニッフィングによってドメイン情報を補えることがありますが、あらゆるプロトコルでホスト名を復元できるわけではありません。切り分け時は、インバウンドの宛先、スニッフィング設定、最終的なアウトバウンドをあわせて確認してください。

v2rayNでルール順を変更して結果を確認する

v2rayNで「設定」→「ルーティング設定」を開き、使用するルーティング設定を選んでルール編集画面に進みます。編集や上へ・下へ移動するボタンの位置は、画面のバージョンによって異なる場合があります。確認すべきなのは設定名やルールのメモではなく、最終的に生成されたrouting.rulesの順序です。

  1. 設定を複製:元の設定を戻せるように残し、複製した設定にテスト用ドメインのfull:ルールを1つ追加します。最初はDNS、スニッフィング、コアを同時に変更しないでください。
  2. 条件を分けて入力:full:example.comはドメイン条件に、geoip:cnはIP条件に指定します。1行ずつ入力する画面では、各行にマッチ項目を1つ入力し、JSONオブジェクト全体を貼り付けないでください。
  3. アウトバウンドを確認:アウトバウンドの選択欄で使用する出口を選びます。標準設定を使う場合は、outboundTagとアウトバウンドのtagが大文字・小文字も含めて完全に一致していることを確認してください。
  4. ルール順を変更:テストルールを先にマッチする可能性のあるルールより上に移動します。保存後、対象のルーティング設定が選択されていることを確認し、画面の案内に従ってコアを再読み込みまたは再起動してください。
  5. 新しい接続でテスト:既存のウェブ接続を閉じてから、もう一度アクセスします。長時間維持される接続は、ルールを変更しても自動で出口が切り替わらないことがあります。必要に応じてブラウザーを終了してからテストしてください。
  6. ログを記録:コアが正常に起動したことを確認し、テスト先へのアクセス記録とアウトバウンドタグを確認します。必要な場合はログ設定で一時的に詳細度を上げ、テスト後に元へ戻してください。接続情報が大量に記録され続けるのを防げます。

「HTTPSだけを直結する」ルールを検証する場合は、テストルールにドメイン条件とport: "443"、network: "tcp"を設定します。UDPを使うHTTP/3はTCP条件を満たしません。同じサイトがブラウザーで開けたというだけで、ルールが機能していないとは判断できません。テスト条件に合うプロトコルとポートを使用してください。

fullを指定したのにwwwのドメインがプロキシ経由になるのはなぜ?

full:example.comはwww.example.comを含みません。まずログで実際の宛先を確認してください。サブドメインも対象にする場合はdomain:example.comに変更します。この2つのホスト名だけが必要なら、fullのマッチ条件を2つ追加してください。

ルールを最後に置いても効かないのはなぜ?

上にnetwork: "tcp,udp"、対象ドメインを含むセット、または範囲の広いドメイン条件がないか確認してください。テストルールをそれらより前に移動し、設定を再読み込みして新しい接続でテストします。

geoデータを更新したら、コアが起動しなくなった?

起動ログに記載されたファイル名とセット名を確認します。データファイルを読み取れることと、対象のセットが実際に存在することを確認してください。まずエラーの原因となったセットの指定を削除して起動できるか検証し、その後データの取得元を修正します。設定ミスを隠すためにノードを何度も変更しないでください。

ウェブページが開けば、directにマッチしたと判断できる?

いいえ。直結でもプロキシ経由でも、ページが正常に開く場合があります。コアのアクセスログで宛先とアウトバウンドタグを確認してください。現在のログにルール番号が表示されない場合は、変更前後のアウトバウンドを比較し、一度に変更するルールは1つにしてください。