この記事の概要

v2rayN、v2rayNG、v2flyNGをすでに利用でき、直結・プロキシ・ブロックする通信をさらに細かく制御したい方向けです。domain、full、regexp、geosite、CIDR、geoipの正確な意味、複数条件の組み合わせ方、例外ルールからフォールバックルールまでの並べ方を解説します。

ルーティングルールが実際に処理するもの

V2Rayのルーティングは複数ノードの速度を比較する仕組みではなく、接続先の情報に応じて出力先を選ぶ機能です。アプリが接続を開始すると、コアは接続先のドメインまたはIP、ポート、ネットワーク種別、インバウンドタグなどを読み取り、routing.rulesの先頭から順に確認します。すべての条件を満たした最初のルールがoutboundTagを決定し、その接続では後続のルールは処理されません。

そのため、ルーティング設定ではまず利用可能な出力タグを定義する必要があります。プロキシの出力をproxy、直接接続をdirect、ブロック用の出力をblockとする例があります。ルール内のタグは参照に使われるだけなので、outbounds内のtagと完全に一致させてください。大文字と小文字も区別されます。

アプリがリクエストを開始接続先情報を取得ルールを順番に照合出力タグを選択接続を確立

1つのtype: fieldルールには複数のフィールドを指定できます。同じフィールドの配列内では「いずれかに一致」が適用されます。たとえばdomain配列に3つのドメインを指定した場合、そのうち1つに一致すれば十分です。一方、異なるフィールド同士は「すべての条件を満たす」関係です。domainportを同時に指定したルールでは、ドメイン条件と指定ポートの両方に一致する必要があります。

ルールのフィールド 取得する情報 組み合わせ方
domain 接続先ドメイン full:api.example.com 配列内のいずれかに一致
ip 接続先IPまたは名前解決結果 10.0.0.0/8 配列内のいずれかに一致
port 接続先ポート 5380-443 他のフィールドと同時に満たす
network トランスポート層のネットワーク tcp,udp 他のフィールドと同時に満たす
inboundTag どのインバウンドからの接続か socks-in 他のフィールドと同時に満たす

domain・full・regexpとgeosite

domainフィールドにはドメイン条件を指定しますが、配列内の各文字列には異なるプレフィックスを付けられます。プレフィックスなしの通常の文字列はキーワードとして扱われ、最も広い範囲にマッチします。domain:はドメインとサブドメインにマッチし、full:は完全一致、regexp:は正規表現によるマッチング、geosite:はローカルのルールデータにあるドメイン分類を参照します。

完全一致ドメイン

記述例
full:api.example.com
マッチする例
api.example.com
マッチしない例
www.example.com

APIのドメイン、更新用ドメイン、固定されたサービスの入口などを個別に制御する場合に適しています。

ドメインとサブドメイン

記述例
domain:example.com
マッチする例
example.com
どちらもマッチ
cdn.example.com

1つのメインドメインと、そのすべてのサブドメインを同じ出力先に振り分ける場合によく使います。

正規表現マッチング

記述例
regexp:^img[0-9]+\.example\.com$
マッチする例
img12.example.com
コスト
マッチング負荷が高い

プレフィックス、サフィックス、ルールセットでは表現できない条件に限って使用します。

ドメイン分類

記述例
geosite:cn
データソース
ローカルのgeositeデータファイル
更新方法
ルールデータの更新に合わせて更新

大量のドメインをまとめて対象にできますが、分類内容はローカルデータのバージョンに左右されます。

通常のキーワード指定はマッチ範囲が広がりやすいため注意が必要です。配列項目をexampleとすると、ドメインにこの文字列が含まれるだけでマッチする可能性があり、example.netcdn-example.orgも対象になり得ます。完全なドメインが分かっている場合はfull:を、メインドメインとサブドメインを対象にする場合はdomain:を優先すると、広すぎるキーワードより確認しやすくなります。

regexp:の式は、JSON文字列としてのエスケープも必要です。正規表現で使う\.は、JSONでは\\.と記述します。バックスラッシュのエスケープを1段省くと、設定を解析できなかったり、式の意味が想定と異なったりします。次のルールは、指定したAPIドメインと一連の画像サブドメインだけをプロキシ経由にします。

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

geositeはオンライン検索サービスではなく、ローカルのデータファイルから分類を読み取ります。よく使われる記述にはgeosite:cngeosite:privategeosite:category-ads-allがあります。分類が存在するか、どのドメインが含まれるかは、クライアントが現在使用しているデータファイルによって決まります。ルールをコピーして分類が存在しないというログが出た場合は、出力ノードを何度も変更するのではなく、まずGeoデータを更新してから分類名を確認してください。

ip・CIDR・geoipとdomainStrategy

ipフィールドには、単一アドレス、CIDRネットワーク、geoip:分類を指定できます。単一のIPv4アドレスは192.0.2.10、ネットワークは192.168.0.0/16のように記述します。IPv6も同様にCIDRを使い、たとえばfd00::/8と記述できます。プライベートネットワークは通常geoip:privateでまとめて処理し、10.0.0.0/8172.16.0.0/12192.168.0.0/16を1つずつ列挙する手間を省きます。

IPルールでドメイン宛てのリクエストをマッチできるかどうかは、routing.domainStrategyに直接関係します。ブラウザがドメインへアクセスするとき、コアが最初に受け取る接続先はまだドメインのままかもしれません。戦略がAsIsの場合、ルーティング段階でIPルールのためにドメインを自動解決しないため、geoip:cnをドメイン分類の代わりに使うことはできません。

domainStrategy 処理方法 主な用途
AsIs 元の接続先に対してマッチし、ルーティングのためにドメインを自動解決しない domainとgeositeルールを中心に使う
IPIfNonMatch ドメインルールにマッチしなかった後、IPを解決してIPルールを試す ドメインルールを優先し、geoipで補完する
IPOnDemand マッチング中にIP情報が必要なルールに到達すると接続先を解決する IP条件に大きく依存するルール構成

「ドメイン分類は直接接続、IP分類で補完」という構成の多くは、IPIfNonMatchから始めるとよいでしょう。まずgeosite:cnを確認し、マッチしなければ名前解決結果を使ってgeoip:cnを確認します。DNSが複数のアドレスを返す場合、実際の接続とルーティングの解決結果はDNS設定、キャッシュ、アドレス選択の影響も受けます。1回の名前解決だけでルール全体が機能していないと判断しないでください。

{
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "type": "field",
        "ip": [
          "geoip:private"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": [
          "geosite:cn"
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": [
          "geoip:cn"
        ],
        "outboundTag": "direct"
      }
    ]
  }
}

結論:ドメイン分類とIP分類は置き換えられない

サイト単位で分類する場合は先にgeositeを指定し、解決後のネットワーク上の位置で補完する場合にgeoipを使います。同時に、domainStrategyもこの順序に合った戦略に設定してください。

マッチング優先順位とルールの並べ方

V2Rayはfull:geosite:geoip:にグローバルな優先順位を自動で割り当てません。「完全一致ルールを優先する」という動作は、設定側でそのルールを前に置くことで実現します。前のルールがマッチして出力先を決めた時点で、後ろにあるより具体的な条件が結果を上書きすることはありません。

最も安定する並べ方は「例外を先頭、分類を中央、フォールバックを最後」です。まず必ずブロックまたは直接接続したい具体的な対象を置き、次にプライベートネットワークと地域分類、その後にプロキシへ送る分類を置きます。最後にnetwork: tcp,udpだけを含むルールで残りの接続を受けます。フォールバックルールを途中に置くと、その後のルールは同じネットワーク種別を処理できなくなります。

  1. 第1層:特定ドメイン、特定IP、特定ポートなどの明確な例外。
  2. 第2層:広告分類やブロック対象。
  3. 第3層:LAN、プライベートアドレス、直接接続を明示したサイト。
  4. 第4層:地域ドメインと地域IPの分類。
  5. 第5層:プロキシ経由にする指定ドメインまたは分類。
  6. 最終層:tcp,udpを対象にするフォールバック出力。

次は、後から拡張しやすい構成例です。広告分類を先にブロックし、続いてプライベートアドレスと指定サイトを直接接続に振り分け、その後に地域分類を処理し、最後にその他のTCP・UDP接続をプロキシへ送ります。例にあるproxydirectblockは、現在の完全な設定に実在する出力タグへ置き換えてください。

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

同じルールにdomainipを同時に指定しても、多くの場合は「どちらか一方」ではなく、両方のフィールドを満たす必要があります。「特定のドメインまたは特定のIPを直接接続にする」なら、2つのルールに分け、同じoutboundTagを指定してください。これはカスタムルーティングで最もよくある論理上の落とし穴の1つです。

結論:まずルールを分け、その後に順序を調整する

1つのルールに複数の異なるフィールドを含めてもマッチしない場合は、まずdomain、ip、portを独立したルールに分けてテストします。各条件が単独で機能することを確認してから、「すべての条件を満たす」形で統合する必要があるか判断してください。

クライアントへの反映と検証

デスクトップ版v2rayN 7.xでは、まず「設定」→「ルーティング設定」を開き、現在のルーティング方式をコピーしてから編集すると、使用中の方式を直接上書きせずに済みます。編集後に保存してその方式を選択し、コアを再起動してください。最終的に生成された内容を確認する場合は、「設定」→「設定ファイルを表示」からコアへ渡される実際のJSONを確認し、routingrulesoutboundTagを重点的に検索します。

Android版v2rayNGとv2flyNGは、バージョンによって画面上の入口が変わることがありますが、検証の原則は同じです。まず現在の設定でカスタムルーティングが有効になっていることを確認し、定義済みルール、ドメイン戦略、アプリ単位のプロキシ設定が互いに上書きしていないか確認します。通常、サブスクリプション更新で更新されるのはサーバー設定だけです。クライアントごとのカスタムルーティング方式まで保持されるとは限らないため、変更前にルール本文を保存しておくと移行しやすくなります。

ポート条件をテストするときは、ローカルプロキシの待受ポートと接続先ポートを区別する必要があります。v2rayNでよく使われるローカルSOCKS待受ポートは10808で、これはインバウンド側のポートです。一方、ルーティングルールのport: 443はリモートの接続先ポートを指します。10808を接続先ポートのルールに書いても、通常は「すべてのブラウザ通信」を対象にはできません。

変更後にすべてのWebサイトへ接続できなくなった場合は、まずフォールバックルール1つだけの最小構成へ戻し、1つずつ復元してください。コアのログにfailed to parseが出る場合は、JSONのカンマ、引用符、正規表現のエスケープを確認します。geositeまたはgeoip分類が見つからない場合は、対応するデータファイルを更新します。接続は確立するのに出力先が想定と異なる場合は、ルールの順序とタグの綴りを優先して確認してください。

fullルールを書いたのに、なぜフォールバックプロキシへ送られるのですか?

まずログ上の接続先がドメインのままか、アプリが先に解決したIPになっていないか確認します。続いて完全なドメイン名、ポート条件、出力タグを確認してください。アプリが直接IPへ接続している場合、単独のfull:ルールにはマッチしません。

geosite:cnとgeoip:cnはどちらか1つだけにすべきですか?

両者が扱う情報は異なります。まずgeosite:cnでドメインをマッチさせ、IPIfNonMatchの下でgeoip:cnを使い、解決されたアドレスに基づく接続を補完できます。

directを1番目に置くと、なぜプロキシルールが機能しないのですか?

1番目のルールに、すべての接続を対象にするnetwork: tcp,udpが指定されていないか確認してください。この種のルールはフォールバックルールなので、一覧の末尾へ移します。そうしないと、後続の同じネットワーク種別のルールにはマッチしません。

同じルールにdomainとportを書くと、どのような関係になりますか?

2つのフィールドを同時に満たす必要があります。たとえばdomain:example.comport:443を組み合わせると、そのメインドメインとサブドメインから接続先ポート443へ送られる通信だけが対象になり、接続先ポート80は含まれません。

保守しやすいルールの最終チェック

保守しやすいルーティング設定では、重複した項目を大量に積み重ねる必要はありません。例外は明確なfull:domain:で表現し、分類はgeositegeoipでまとめ、最後に読みやすいフォールバックルールを1つ残します。変更するたびに追加する条件は1種類だけにし、ログで実際にマッチしたルールと出力先を確認してください。

ルール数が増えたら、「ブロック、プライベートネットワーク、強制直結、分類による直結、強制プロキシ、フォールバックプロキシ」の順にグループ化できます。クライアントの画面で並べ替えられる場合でも、参照用に整形済みJSONを保存し、domainStrategy、出力タグ、依存するGeo分類を記録しておくと安心です。v2rayN、v2rayNG、v2flyNG間で設定の考え方を移行する際も、画面上の項目をコアの構文と取り違えずに済みます。