2つのカーネルの現状と系譜
オリジナル Clash(Dreamacro/clash)は2023年末にアーカイブされ、最後の正式版は v1.18.0 で、以降のコミットはありません。同時期には非公開の Clash Premium カーネルも存在し、TUN、rule-provider、script の機能を提供していましたが、ソースは公開されておらず、オリジナル版とともに更新が停止しました。Clash.Meta はコミュニティがオリジナルカーネルをベースに書き直した派生版で、2024年に mihomo へ改名され、リポジトリは MetaCubeX/mihomo として現在も更新が続いています。
設定ファイルのレベルでは両者は上位互換です。port、socks-port、mixed-port、allow-lan、mode、log-level、external-controller、proxies、proxy-groups、rules といったフィールドはどちらも認識します。違いは4つの領域に集中しています。インバウンドプロトコル、ルール種別、DNS 解決経路、TUN 実装です。以下で順に比較し、移行時に書き換えるフィールドを挙げます。
| 機能 | オリジナル Clash v1.18.0 | mihomo |
|---|---|---|
| インバウンド方式 | port、socks-port、redir-port の3つのトップレベルスイッチ | トップレベルスイッチ + listeners セクションで複数のインバウンドを宣言 |
| プロキシプロトコル | ss、vmess、trojan、snell、socks5、http | 上記すべて + vless、hysteria2、tuic、wireguard、ssh、anytls |
| ルール種別 | ドメイン、IP、ポート、GEOIP、MATCH | 上記すべて + GEOSITE、IP-ASN、正規表現、論理演算、SUB-RULE |
| ルールセット | 非対応。ルールは設定ファイルに直接書くしかない | rule-providers。mrs バイナリ形式に対応 |
| DNS | nameserver + fallback + fallback-filter | nameserver-policy、DNS 分流、DoQ、fake-ip ホワイトリストモード |
| TUN | 非対応 | system / gvisor / mixed の3スタック |
| メンテナンス状況 | 2023年末にアーカイブ | 継続的に更新 |
プロトコル対応:mihomo だけが認識する proxy type
オリジナル Clash の proxies セクションが認識する type は ss、vmess、trojan、snell、socks5、http の6つだけです。リストにない type があると、カーネルは解析段階で unsupported proxy type を出して終了し、そのノードを飛ばして動作を続けることはありません。カーネルを替えたときに最もよく遭遇するエラーの第一類です。
mihomo はこのリストに vless(XTLS Vision と REALITY を含む)、hysteria2、tuic v5、wireguard、ssh、anytls を追加し、Shadowsocks の暗号化方式も 2022 系(2022-blake3-aes-128-gcm、2022-blake3-aes-256-gcm、2022-blake3-chacha20-poly1305)まで拡張しました。以下の3ノードのフィールド構成は、オリジナルカーネルでは1つも解析できません。
proxies:
- name: vless-vision
type: vless
server: edge.example.com
port: 443
uuid: 8f2c1d40-3a7e-4b91-9c2d-5e6f7a8b9c0d
network: tcp
tls: true
udp: true
flow: xtls-rprx-vision
servername: www.example.com
client-fingerprint: chrome
reality-opts:
public-key: uM7Kd2QpX1sVbN4tRzY8wLcE3aHfJgOiPqSvTnBm5kU
short-id: 6ba85179e30d4fc2
- name: hy2-edge
type: hysteria2
server: edge.example.com
port: 8443
password: 9f2c7d1a4b6e
sni: www.example.com
skip-cert-verify: false
up: "30 Mbps"
down: "200 Mbps"
- name: tuic-edge
type: tuic
server: edge.example.com
port: 10443
uuid: 8f2c1d40-3a7e-4b91-9c2d-5e6f7a8b9c0d
password: 9f2c7d1a4b6e
congestion-controller: bbr
udp-relay-mode: native
alpn: [h3]
あるサブスクリプションをそのままオリジナルカーネルに渡せるかは、2点だけ見れば判断できます。proxies に現れる type と、ss ノードの cipher です。type が ss、vmess、trojan、snell の範囲内で、cipher も aes-128-gcm のような旧来の値であれば両方で動作します。reality-opts、congestion-controller、あるいは 2022-blake3- で始まる暗号化方式が現れた時点で、mihomo へ切り替える必要があります。
ルール構文とマッチング順序
マッチングモデルは両者で同じです。rules を上から順に照合し、最初に一致した時点で停止、MATCH が最後の受け皿になります。違いは利用できる種別、マッチングのコスト、そしてルールセットの読み込み方式です。
| ルール種別 | オリジナル Clash | mihomo | 説明 |
|---|---|---|---|
| DOMAIN / DOMAIN-SUFFIX / DOMAIN-KEYWORD | 対応 | 対応 | ドメインインデックスを使うため、1条あたりのコストは非常に低い |
| DOMAIN-REGEX / DOMAIN-WILDCARD | 非対応 | 対応 | 1条ずつ正規表現で照合するため、先頭に置くと初回パケットが遅くなる |
| IP-CIDR / IP-CIDR6 / SRC-IP-CIDR | 対応 | 対応 | ドメイン接続で解決が発生するため、no-resolve の付与を推奨 |
| GEOIP | 対応 | 対応 | GeoIP データファイルに依存 |
| GEOSITE | 非対応 | 対応 | geosite データファイルに依存 |
| IP-ASN / IP-SUFFIX | 非対応 | 対応 | ASN または IP サフィックス単位で振り分け |
| PROCESS-NAME | 非公開の Premium のみ | 対応 | デスクトップではプロセス名で振り分け |
| PROCESS-PATH / PROCESS-NAME-REGEX | 非対応 | 対応 | 実行ファイルのパスでマッチング |
| RULE-SET | 非公開の Premium のみ | 対応 | format: mrs を指定可能 |
| SUB-RULE / AND / OR / NOT | 非対応 | 対応 | 複数条件の組み合わせ。括弧とカンマに注意 |
| IN-TYPE / IN-USER / IN-PORT / NETWORK | 非対応 | 対応 | インバウンド元とトランスポート層プロトコルでマッチング |
| MATCH | 対応 | 対応 | 必ず最後の1条に置く |
ルールセットの違いはルール種別以上に見落とされやすい部分です。オリジナル Clash は rule-providers に対応しておらず、ルールは config.yaml に直接書くしかありません。mihomo の rule-providers は behavior に domain、ipcidr、classical、format に yaml、text、mrs を指定でき、mrs はバイナリ形式のため domain か ipcidr としか組み合わせられません。mrs は読み込み時にドメイン接頭辞でインデックスを構築するため、YAML 全体をオブジェクトへ展開する必要がなく、ルールが1万条を超えるあたりで差が最も顕著になります。
rule-providers:
reject-list:
type: http
behavior: domain
format: mrs
url: "https://rules.example.com/reject.mrs"
path: ./ruleset/reject.mrs
interval: 86400
rules:
- DOMAIN-SUFFIX,example.org,ダイレクト
- GEOSITE,category-ads-all,REJECT
- RULE-SET,reject-list,REJECT
- IP-CIDR,198.18.0.0/16,ダイレクト,no-resolve
- AND,((NETWORK,udp),(DST-PORT,443)),ノード選択
- MATCH,ノード選択
rules セクションを書くとき、順序でつまずきやすい点が3つあります。
- 具体的なドメインは GEOSITE より前に置きます。GEOSITE は一致範囲が広く、DOMAIN-SUFFIX,example.org より前に書いてしまうと、後ろのルールは永遠に実行されません。
- IP-CIDR をドメインルールより前に置くと、ドメイン接続はまず IP を解決しないと照合できません。DNS クエリが1回増えるうえ、解決結果が上流リゾルバに渡ってしまいます。no-resolve を付ければ、ドメイン接続はこのルールをそのまま飛ばせます。
- MATCH が指すポリシーグループには、少なくとも1つの有効なノードを残してください。ルールセット更新後に未カバーのドメインが現れると、すべてのトラフィックが MATCH に落ち、グループが空だと端末全体がネットワークから切断された状態になります。
GEOSITE と GEOIP はデータファイルに依存します。オリジナル Clash は初回起動時に Country.mmdb をダウンロードします。mihomo は geodata-mode、geox-url、geo-auto-update、geo-update-interval が追加され、データソースを自前のアドレスに差し替えたり、時間単位で自動更新したりでき、手動でファイルを置き換える必要がありません。
DNS と fake-ip の実装差
オリジナル Clash の dns セクションには nameserver、fallback、fallback-filter、enhanced-mode、fake-ip-range、fake-ip-filter、hosts といったスイッチしかなく、すべてのドメインが同じ解決経路を通り、fallback-filter の geoip と ipcidr で結果の信頼性を判断します。以下は古い設定で最もよく見られる書き方です。
# オリジナル Clash の書き方。mihomo でも解析できるが、そのまま使い続けるのは非推奨
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 223.5.5.5
fallback:
- https://1.1.1.1/dns-query
fallback-filter:
geoip: true
ipcidr:
- 240.0.0.0/4
mihomo は解決を複数の経路に分割します。default-nameserver は DNS サーバー自身のドメイン解決にのみ使い、IP の記入が必須です。proxy-server-nameserver はプロキシサーバーのアドレス解決を担当します。direct-nameserver は直接接続のトラフィックを処理します。nameserver-policy はドメインやルールセット単位で上流を指定します。この分割が解決するのは同じ1つの問題です。プロキシサーバーのドメインをどの経路で解決するかが、ノードに接続できるかどうかを直接左右します。
dns:
enable: true
listen: 0.0.0.0:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter-mode: blacklist
fake-ip-filter:
- "*.lan"
- "+.stun.*.*"
default-nameserver:
- 223.5.5.5
- 1.1.1.1
proxy-server-nameserver:
- https://223.5.5.5/dns-query
nameserver:
- https://1.1.1.1/dns-query
- quic://dns.adguard-dns.com:784
nameserver-policy:
"geosite:cn":
- 223.5.5.5
"rule-set:reject-list":
- rcode://refused
respect-rules: true
cache-algorithm: arc
単独で覚えておく価値のある挙動差が2つあります。fake-ip-filter はオリジナル Clash ではブラックリストの意味しか持ちませんが、mihomo は fake-ip-filter-mode: whitelist が追加され、逆にリスト内のドメインにだけ偽 IP を割り当てる書き方ができます。nameserver-policy のキーは geosite: と rule-set: の接頭辞に対応し、長い fallback-filter.domain を維持する必要がなくなります。また respect-rules: true を指定すると DNS クエリ自体も rules の分流を通るため、有効にする前に proxy-server-nameserver を設定しておかないと、解決リクエストが自分自身へ戻って無限ループになる可能性があります。
TUN の実装と3つのネットワークスタック
オリジナルのオープンソース Clash には TUN がまったくなく、TUN は非公開の Premium カーネルにのみ存在し、調整できるパラメータもわずかでした。mihomo は TUN を設定ファイル内の一級機能として扱い、デバイス名や MTU から Android のパッケージ名単位の許可まで網羅しています。
tun:
enable: true
stack: mixed
device: mihomo
mtu: 9000
auto-route: true
auto-detect-interface: true
strict-route: false
dns-hijack:
- any:53
udp-timeout: 300
endpoint-independent-nat: false
gso: true
gso-max-size: 65536
stack の3つの値の使い分け:
- system:パケットをシステムのプロトコルスタックに転送する方式で、スループットが最も高い反面、システムのルーティングとファイアウォールの状態に依存し、複数 NIC や IPv6 環境ではループバックや取りこぼしが起きやすくなります。
- gvisor:完全にユーザー空間で実装され、プラットフォームを問わず挙動が一定で、システムの転送に依存しません。単一接続のスループットは system より低く、ルーティングテーブルが複雑な環境や権限が制限された環境に適しています。
- mixed:TCP はシステムスタック、UDP は gvisor スタックに任せる方式で、多くのクライアントのデフォルト値です。gvisor から system へ切り替える前に一度試す中間的な選択肢でもあります。
プラットフォームごとに依存するものは異なります。Windows では wintun ドライバとシステムサービスの権限が必要で、仮想 NIC の作成に失敗するとログに configure tun interface が現れます。macOS は utun デバイスを使い、初回有効化時にネットワーク権限を要求します。Linux では auto-route がルーティングテーブルを書き込み、auto-redirect が nftables でトラフィックを TUN へリダイレクトするため、iptables ルールを手書きする必要はありません。Android クライアントは include-package と exclude-package でどのアプリを TUN に通すかを制御します。
性能のトレードオフと移行手順
ルールマッチングのコストは主に種別と条数で決まります。ドメイン系ルールはインデックスを使うため1条あたりのコストはごく低く、DOMAIN-REGEX と PROCESS-NAME-REGEX は1条ずつ正規表現で照合するため、rules の先頭に置くと新しい接続ごとの初回パケットが遅くなります。接続側には必要に応じて有効にしたいスイッチがいくつかあります。
- tcp-concurrent: true —— 同じドメインの複数の解決結果へ並行してハンドシェイクし、初回パケットの待ち時間を短縮します。代わりに同時接続数が増えます。
- unified-delay: true —— 遅延テストを完全なハンドシェイク所要時間で統一して計算し、プロトコル間で数値が比較できない事態を避けます。
- sniffer セクション —— IP 直結のトラフィックからドメインを復元し、ドメイン系ルールにヒットさせます。override-destination は宛先アドレスを復元したドメインに書き換えるため、一部の社内ネットワークでは無効化が必要です。
- find-process-mode: strict —— プロセスマッチングは新しい接続の確立時に一度だけ照会するため、always より CPU を節約できます。
mixed-port: 7890
allow-lan: false
mode: rule
log-level: warning
ipv6: false
unified-delay: true
tcp-concurrent: true
find-process-mode: strict
external-controller: 127.0.0.1:9090
profile:
store-selected: true
store-fake-ip: true
sniffer:
enable: true
sniff:
HTTP:
ports: [80, 8080-8880]
override-destination: true
TLS:
ports: [443, 8443]
QUIC:
ports: [443]
オリジナル Clash から mihomo への移行は、6つの手順に固定すると、各段階で結果を個別に検証できます。
-
旧設定をバックアップ
config.yaml と ruleset ディレクトリをまるごとコピーし、旧カーネルのバージョン文字列を控えておくと、ロールバック時の照合が楽になります。
-
まず構文チェック
mihomo -t -f config.yaml -d /etc/mihomo で起動せずに解析を1回実行します。unsupported proxy type はこの段階で露見するため、起動後のログを待つ必要はありません。
-
プロトコル部分を処理
hysteria2、tuic、vless ノードは残し、フィールド名を1つずつ確認します。ss ノードの 2022-blake3- 暗号化はカーネル側の対応が必要で、古いバージョンのカーネルはそのまま拒否します。
-
DNS を書き換え
default-nameserver と proxy-server-nameserver を追加し、fallback のリストを nameserver-policy へ移します。fake-ip-range は 198.18.0.1/16 のままで問題ありません。
-
最後に TUN を有効化
まずドライバとサービスが準備できていることを確認し、stack は mixed から始め、dns-hijack は any:53 を使います。ルーティングと解決がどちらも正常だと確認できてから system への変更を検討します。
-
接続とルールのヒット状況を確認
external-controller: 127.0.0.1:9090 を有効にし、ダッシュボードで接続リストとルールのヒット状況を見て、すべてのトラフィックが MATCH に落ちていないことを確認します。
オリジナル Clash に留まるべきケースも存在します。設定ファイルに ss、vmess、trojan しかなく、ルールはすべて rules セクションに書き、TUN も不要であれば、カーネルを替えるメリットは限定的で、変更によるリスクのほうが大きくなります。移行すべきかの判断基準はシンプルです。上記4つの領域のうち、mihomo 固有の書き方を使っているものがあるかどうか。あれば移行し、なければそのままにしておきます。