手動で通信を振り分けたい方向けに、ドメイン・IP・データセットのマッチ条件を整理し、routingの例を使ってルールの順序、条件の組み合わせ、DNS名前解決のタイミングを解説します。トラブル時は、画面上の「直結」「プロキシ」という表示をそのままoutboundTagと見なさず、クライアントが実際に生成したコア設定を確認してください。
1. ルーティングの対象と評価順序
V2Rayのroutingは、接続先のアドレスやポート、ネットワーク種別、インバウンドタグなどに基づいてアウトバウンドを選択します。Webページの内容をフィルタリングする機能ではなく、URLのパスによる振り分けにも対応しません。同じドメイン内の異なるページにアクセスしても、通常はドメインルールの判定は変わりません。
routing.rulesは配列の先頭から順に評価されます。条件に合うルールが見つかると、そのルールで指定されたアウトバウンドが使われ、後続ルールとの「どちらがより詳細か」という比較は行われません。そのため、特定ドメインの例外はドメインサフィックスのルールより前に、個別ルールはフォールバックより前に配置します。
- ルール間:最初に一致したルールで結果が決まり、ドメインの長さ、プレフィックスの種類、ネットワーク範囲の大きさに応じて自動で並べ替えられることはありません。
- 同じフィールド内:たとえば
domain配列に複数の項目がある場合、そのうち1つに一致すれば条件を満たします。 - 異なる条件フィールド間:たとえば
domainとportを同時に指定した場合、両方の条件を満たす必要があります。同じルールにdomainとipを記述しても、「ドメインまたはIP」という意味にはなりません。 - どのルールにも一致しない場合:ほかのルーティング機能を設定していない一般的な構成では、
outbounds配列の先頭にあるアウトバウンドが使われます。必ずしも直結になるとは限りません。
2. domain・full・regexp・geositeの書き方
domainはルールのフィールド名で、domain:はそのフィールド内で使うマッチプレフィックスの1つです。混同しないようにしましょう。以下では、構文の説明に予約済みの例示用ドメインexample.comを使用します。実際のサービスの振り分けを推奨するものではありません。
| 記述例 | マッチする範囲 | 注意点 |
|---|---|---|
full:example.com | このドメイン名に完全一致 | www.example.comには一致しない |
domain:example.com | ドメイン自身とサブドメインに一致 | api.example.comには一致するが、notexample.comには一致しない |
example.com | プレフィックスを付けない場合は部分一致 | 文字列を含む別のドメイン名にも一致する可能性がある |
regexp:^api[0-9]+\.example\.com$ | 正規表現でマッチ | JSONに記述する場合、バックスラッシュをさらにエスケープする |
geosite:cn | ドメインデータファイル内のcnカテゴリを参照 | 対象カテゴリは実際に読み込まれているデータファイルによって異なる |
あるサイトとそのサブドメインをまとめて対象にする場合は、文字列だけに頼らずdomain:example.comを使います。ホスト名1つだけに限定する場合はfull:を使います。ドメイン項目にはhttps://、ポート、パス、クエリパラメーターを含めないでください。これらはこのフィールドで指定する形式ではありません。
{
"type": "field",
"domain": [
"full:status.example.com",
"domain:example.net",
"regexp:^api[0-9]+\\.example\\.com$"
],
"outboundTag": "proxy"
}
このJSONでは、3つのドメイン項目はOR条件です。正規表現の\\.は、JSONのデコード後に正規表現で必要な\.になります。バックスラッシュを1つだけ記述すると、JSONの解析時点で設定エラーになることがあります。正規表現にはコアが使用するGoの構文を使い、後方参照や先読み・後読みは使用できません。
判断の目安:単一サイトにはまずfullまたはdomain
正規表現を使うのは、ドメインの構造をパターンで表す必要がある場合に限ります。変更後は、メインドメイン、サブドメイン1つ、似ているものの無関係なドメインをそれぞれテストし、意図しない部分一致が起きていないか確認してください。
3. ip・geoipと接続先ポートの組み合わせ
ipフィールドには、単一のIPアドレス、CIDRネットワーク、geoip:データセット参照を指定できます。IPv4の/32は単一アドレスを表し、192.0.2.0/24はドキュメント用の例示ネットワークです。CIDRをdomain配列に入れたり、ip配列にhttps://を付けたりしないでください。
{
"type": "field",
"ip": [
"192.0.2.0/24",
"2001:db8::/32"
],
"port": "443",
"network": "tcp",
"outboundTag": "direct"
}
このルールに一致するのは、接続先アドレスが2つの例示ネットワークのいずれかに含まれ、接続先ポートが443、ネットワークがTCPの接続だけです。同じアドレスへのTCP 80やUDP 443には一致しません。ここでのportは接続先ポートであり、クライアントのローカル待ち受けポートではありません。ローカルインバウンドをタグで区別する場合は、inboundTagを使います。
geoip:privateは、プライベートアドレスやローカルアドレス範囲の振り分けによく使われます。実際の対象範囲は、読み込んだデータファイルによって異なります。geoip:cnはIPカテゴリ、geosite:cnはドメインカテゴリを参照します。互いに置き換えて使うことはできません。- ドメインカテゴリとIPカテゴリの判定が一致するとは限りません。1つのドメインが、異なる地域のCDNアドレスに解決されることもあります。
- IPv4ネットワークだけを指定しても、IPv6接続は対象になりません。デュアルスタック環境では、実際に使われているアドレスファミリーも確認してください。
4. domainStrategyがルーティング時の名前解決を制御
routing.domainStrategyは、ルーティング段階でドメインの接続先をどう扱うかを制御します。システムのDNS設定とは異なり、アウトバウンド側にある同名または類似の設定とも別のものです。ルーティング段階で名前解決しない場合でも、その後のアウトバウンドがサーバーへの接続に名前解決を必要とすることがあります。
| 値 | ルーティング段階の動作 | よくある影響 |
|---|---|---|
AsIs | 元の接続先を使って判定し、ルーティングのための追加の名前解決は行わない | 接続先がドメイン名だけの場合、IPルールで照合できる解決結果は得られない |
IPIfNonMatch | ドメイン名を使った段階で一致しなかった場合に、名前解決して再照合する | 先行するドメインルールや汎用フォールバックに一致すると、名前解決の段階に進まないことがある |
IPOnDemand | IP判定が必要なルールに到達した時点で、ドメイン名の解決を試みる | 後続のドメインルールより前に、先行するIPルールで結果が決まることがある |
見落としやすいのは、IPIfNonMatchを使いながら、末尾にTCP・UDPのすべてに一致するルールを追加するケースです。ドメイン名のリクエストはこのフォールバックにそのまま一致するため、「先行するgeoipルールに一致しなければ、その後に自動で名前解決して再判定する」とは限りません。ドメインルールを優先し、その後に解決済みIPで振り分ける場合は、名前解決の方針とフォールバックの設定を合わせて確認してください。
ドメインを先に判定し、一致しなければ名前解決
- domainStrategy
- IPIfNonMatch
- ルールの先頭
- 明示的なドメイン例外
- 後続の条件
- 追加判定が必要なIPルール
- フォールバックの確認
- 汎用ルールの早期一致を防ぐ
どのルールにも一致しない場合、先頭のアウトバウンドが想定したデフォルトになっているか確認してください。
ルール順に必要に応じて名前解決
- domainStrategy
- IPOnDemand
- ルールの先頭
- 優先して適用するドメイン例外
- 後続の条件
- IPまたはgeoipの条件
- フォールバックの確認
- IP判定の後に明示的なフォールバックを設定可能
まずDNSで名前解決できることを確認し、次にIPカテゴリの判定結果が想定どおりか調べてください。
アプリからコアに渡される接続先がもともとIPアドレスなら、この設定でアドレスを取得する必要はありません。ただし、その場合はドメイン情報が存在しないことがあります。インバウンドのスニッフィング機能で一部のプロトコルからドメイン情報を補える場合もありますが、効果は通信の種類や設定によって異なります。有効にすればすべての接続でドメイン情報が得られるわけではありません。
5. 評価順を確認するrouting設定例
以下は設定の一部であり、単独で動作する完全な設定ではありません。proxy、direct、blockというアウトバウンドタグがすでにあり、それぞれプロキシ、直結、ブロックを行うことを前提としています。タグは設定者が定義するもので、コアが自動作成する予約名ではありません。また、この例では使用可能なデータファイルにprivateカテゴリが含まれている必要があります。
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"domain": ["full:status.example.com"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["domain:example.com"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "direct"
},
{
"type": "field",
"network": "tcp,udp",
"port": "6881-6889",
"outboundTag": "block"
},
{
"type": "field",
"network": "tcp,udp",
"outboundTag": "proxy"
}
]
}
}
- 個別の例外を先に:
status.example.comは1番目のルールに一致して直結され、2番目のドメインサフィックス全体を対象とするルールには進みません。 - サイトのルールは後に:
www.example.comは2番目のルールに一致し、proxyが選択されます。 - プライベートアドレスを優先:最初の2つのルールに一致しなければ、プライベートアドレスは3番目のルールに一致します。ドメイン名の接続先は、この段階で必要に応じて名前解決される場合があります。
- ポートルールは全体に適用される禁止ルールではない:4番目のルールが対象にするのは、それ以前のルールに一致しなかった接続だけです。先行ルールに一致したサイトやプライベートアドレスは、このルールに進みません。
- 明示的なフォールバックは最後に:残ったTCP・UDP接続は5番目のルールに一致します。ここでは
IPOnDemandを使い、先行するIP判定が実行されるようにしています。
操作:全体に適用する制限は前に移動
ポート6881~6889を優先的にブロックする必要がある場合は、ポートルールをドメインルールやプライベートアドレスのルールより前に移動します。変更するのは配列内の位置であり、存在しない「優先度の数値」をルールに追加するのではありません。
geosite:cnを使う場合は、実際の要件に合わせてドメインルールを追加できます。ただし、カテゴリ名に見覚えがあるからといって、例外を確認せずにすべてを対象にしないでください。まずデータファイルが読み込めることを確認し、そのルールを個別ドメインの例外の後、IPルールの前、または別の位置のどこに置くべきか判断します。データの更新によってカテゴリの判定結果が変わることもあります。
6. クライアント画面から実際の設定を確認する方法
v2rayN、v2rayNG、v2flyNGの画面上の項目名やルーティングルールのインポート方法は、バージョンによって異なります。トラブル時は、クライアントのバージョン、コアの名称、使用中のルーティングモードを記録し、現在有効なルールセットを確認してください。サブスクリプションのノードに含まれるVMessやVLESSの接続パラメーターは、ルーティングルールではありません。ノードはアウトバウンド接続を定義し、ルーティングは使用するアウトバウンドを選択します。
- 現在のルールをバックアップ:変更前のルーティング設定を保存します。通常、サブスクリプションの更新はノードの更新に使うもので、ローカルのカスタムルーティングを配布する汎用的な仕組みではありません。
- リクエストがコアに届いているか確認:アプリがシステムプロキシまたは指定したローカルプロキシの入口を使用しているか確認します。インバウンドに届いていないリクエストは、これらのルールでは制御できません。
- 生成された設定を確認:実際の
routing.rulesの順序と、outboundTagがoutbounds[].tagと完全に一致しているかを確認します。 - 設定を反映して再テスト:ルールを保存したら、クライアントの手順に従ってコアを再読み込みまたは再起動し、新しい接続を開始します。ブラウザーが接続を再利用すると、既存の接続では以前のアウトバウンドが使われ続けることがあります。
- ログを確認:必要に応じて一時的にログレベルを
infoにし、インバウンド、接続先、選択されたアウトバウンドを確認します。ログ形式はコアごとに異なり、具体的なルール番号が表示されるとは限りません。
一度に変更する条件は1つに絞ることをおすすめします。まずfull:で特定のドメインが振り分けられるか確認し、次にdomain:で対象範囲を広げ、最後にgeositeやgeoipのカテゴリを追加します。設定項目の位置や前後関係を調べるには、設定リファレンスでインバウンド、アウトバウンド、DNSの各フィールドを確認してください。
7. ルーティングルールに関するよくある質問
ドメインルールを追加したのに、以前と同じノードが使われるのはなぜ?
まず、そのルールより前に、より広い条件のルールが一致していないか確認してください。テスト用のfull:ルールを一時的に先頭へ移動し、コアを再読み込みして新しい接続を開始します。それでも反映されない場合は、接続先がドメイン名かIPアドレスか、また通信が本当に現在のクライアントを経由しているかを確認してください。
geositeやgeoipでカテゴリが見つからない場合、どこを確認すればよい?
現在のコアが実際に使用しているデータファイルと、そこに含まれるカテゴリ名を確認します。geosite:はdomainに、geoip:はipに指定します。まず単一のドメイン名または明確なネットワーク範囲でルールの構造を確認し、その後でデータの不足に対処してください。ノードのパスワードを何度も変更する必要はありません。
同じルールにdomainとipを両方指定したら、一致しにくくなったのはなぜ?
2つのフィールドは両方の条件を満たす必要があり、どちらか一方ではありません。「このドメインまたはこのネットワーク範囲を直結したい」場合は、ルールを2つに分け、両方に同じoutboundTagを指定します。分割後は、IP条件の判定に必要な名前解決が行われる設定かどうかも確認してください。
IPIfNonMatchに変更してもgeoipが効かないのはなぜ?
末尾にnetwork: "tcp,udp"のような汎用マッチがないか確認してください。ドメイン名を使った判定の段階ですでに一致し、「不一致なら名前解決する」処理が行われないことがあります。必要に応じて名前解決の設定を見直すか、早すぎるフォールバックを削除してデフォルトのアウトバウンドを確認してください。どちらの場合も、ドメイン名とIPアドレスの接続先をそれぞれ再テストします。