WireGuardトンネルの外でLinuxプロセスを一つだけ動かす方法
一つのプログラムに独自のネットワークコンテキストを与えて、フルトンネルのWireGuardホストから出られるようにし、それを妨げる転送とマークのルールを修正します。
ルートを編集しても、フルトンネルのWireGuardホストからプログラムを除外することはできません。ルートは宛先で経路を選ぶものであり、除外したいのはプロセスなので、カーネルには照合するものがありません。実用的な方法は、そのプロセスに独自のネットワークコンテキストを与えることです。つまり、独自のインターフェース、アドレス、デフォルトルートを持つ名前空間を用意し、vethペアでホストに接続します。私はUbuntu 24.04とwireguard-tools 1.0.20210914でこれを実行しましたが、名前空間が問題になったことは一度もなく、問題はホストの転送ポリシーとトンネルのマーク規則でした。
まず必要なコンテキストの種類を選ぶ
実際には二つの形があります。ホストがフルトンネルを動かしていて、一つのプログラムだけISPの経路から出したい場合は、二つ目の名前空間を作り、ホストに接続し、ホストにそのための転送とアドレス変換を任せます。名前空間がすでにVPNインターフェースを持っていて、その中でコマンドを起動するだけでよい場合は、通常のip netns execのケースで、ルーティング作業の大半はすでに済んでいます。
どちらの形でも、単一のプロセスIDに限定したルールは得られません。Netfilterはアドレス、ポート、マーク、インターフェースを照合しますが、プロセスごとのルーティングテーブルは存在しません。マークでトラフィックを誘導できますが、そのマークはすでに特定したパケットに付ける必要があり、これは一層下の同じ問題です。名前空間はそのプロセスツリーのスタック全体を分離するので、これが通常の答えになります。
要件が本当に「トンネルから何も出さない」なのであれば、代わりにトンネルを停止してください。名前空間は混在するケースのためのものです。一つのプログラムは外へ、それ以外はすべて内へ、同じマシンで、同時に。
二つ目のコンテキストを作り、ホストに接続する
例示的な構成では、ホストはデフォルトルートを持つWireGuardインターフェースと、clearnetという名前のネットワーク名前空間を持ち、vethペアでホストに接続されています。以下のアドレスは例です。
ip netns add clearnet
ip link add veth-clear-out type veth peer name veth-clear-in
ip addr add 192.168.100.1/24 dev veth-clear-out
ip link set veth-clear-out up
ip link set veth-clear-in netns clearnet
ip netns exec clearnet ip addr add 192.168.100.2/24 dev veth-clear-in
ip netns exec clearnet ip link set veth-clear-in up
ip netns exec clearnet ip route add default via 192.168.100.1
この名前空間はホストにだけ到達でき、それ以外には到達できません。ホストがトラフィックを転送し、送信元アドレスを書き換える必要があるのは、192.168.100.0/24はプライベートで上流のルーターにはそこへ戻るルートがないからです:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o <wan-interface> -j MASQUERADE
先に進む前に名前空間側を確認します。ip netns exec clearnet ip routeはvethルートと192.168.100.1経由のデフォルトルートを示し、そのアドレスへのpingが応答するはずです。ホストのアドレスへのpingが失敗するなら、アドレスかリンク状態が誤っており、ファイアウォールのルールでは解決しません。
名前は解決するのに何も戻ってこないときは、FORWARDを読みます
典型的な失敗はルーティングのバグのように見えます。名前空間が名前を解決し、パケットは出ていくのに、応答がまったく返りません。FORWARDポリシーがDROPのホストでは(複数のディストリビューションと大半の堅牢化イメージがそうしています)、パケットは途中で破棄され、アプリケーションが表示するエラーにはフィルタリングのことは何も書かれていません。
何かを追加する前にチェーンを読みます
iptables -S FORWARD
nft list chain inet filter forward
次に、カウンター付きで両方向のトラフィックを許可し、ルールが実際に一致したかどうかを確認します
iptables -A FORWARD -i veth-clear-out -o <wan-interface> -j ACCEPT
iptables -A FORWARD -i <wan-interface> -o veth-clear-out -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
watch -n1 'iptables -L FORWARD -v -n'
パケットカウンターがゼロのルールは経路に入っていません。インターフェース名が想定と違うか、チェーン内の前のルールが先にパケットを許可・破棄・返却しています。直すべきは順序であり、ルールの文言ではありません。
見落とされがちなのが戻りのトラフィックです。戻りルールには同じveth名と接続状態の一致、またはポリシーを開いたままにするなら単純なインターフェース許可が必要です。外向きのルールだけを追加すると、元の症状がそのまま戻り、新しいルールはそこに正しく見えたままになります。
トンネルのマーク規則を新しい経路に近づけない
この手順は、機能している名前空間を漏れる名前空間に変えます。WireGuardの構成は通常、ファイアウォールマークのポリシーと独自のルーティング規則、専用テーブルを導入するため、マークのないパケットはメインテーブルに戻り、マークされたパケットはトンネルのテーブルを使います。名前空間から転送されたトラフィックは出ていく際にポリシールーティングで評価され、それらの規則の書き方によってはトンネルのテーブルに入ってしまいます。
二つの追加が経路を分けます。名前空間のサブネットについてmangleチェーンで早めに戻し、そのサブネットをメインテーブルに入れる送信元ベースのルールを追加します:
iptables -t mangle -I PREROUTING -s 192.168.100.0/24 -j RETURN
ip rule add from 192.168.100.0/24 lookup main priority 100
私のホストでは優先度100がトンネルのルールより前に並ぶため、その送信元については通常のテーブルが決定します。数字を鵜呑みにせず、wg-quickがインストールする優先度はバージョンやIPv4とIPv6の構成によって異なるので、ip rule showを実行し、自分のマシンでトンネルのルールより前に来る優先度を選んでください。
ルール一覧を信じるのではなく、送信元固有の検索で確認してください
ip route get 1.1.1.1 from 192.168.100.2
ip netns exec clearnet ip route get 1.1.1.1
最初のコマンドがWireGuardインターフェースを報告するなら、新しいルールはまだトンネルのポリシーより前にありません。二つ目がまだvethのデフォルトルートを示しているのに一つ目がWANインターフェースを報告するなら、ホストと名前空間が一致していないので、両方のルーティングテーブルを読み直してください。
接続を開くプロセスを起動する
コマンドの起動は一行ですが、実際にソケットを作るプロセスを起動してください。ip netns exec clearnet curl -s https://ifconfig.meが最小の正直なテストであり、名前空間が世界に見せるアドレスを示すのであって、ホストが使うアドレスではありません。
サービスなら、プロセスが生涯そこに留まるように名前空間をパスで接続します
[Service]
NetworkNamespacePath=/run/netns/clearnet
グラフィカルアプリケーションは、一行の方法が静かに失敗する場所です。メニューから起動したブラウザーは、すでに名前空間の外で動いているインスタンスに要求を渡すことが多く、新しいウィンドウは表示されるのにトラフィックはトンネルから出ていきます。別のプロファイルを与えて新しいインスタンスを確実に作り、推測ではなくプロセスのコンテキストを確認してください。
readlink /proc/$(pgrep -f clearnet-profile | head -1)/ns/net
readlink /run/netns/clearnet
二つの出力は一致しなければなりません。同じ確認は長時間動くプログラムならどれでも使え、ランチャーが意図どおりに動いたと仮定するのではなく、アプリケーションごとに一度は実行する価値があります。
名前解決には独自の判断が必要です——名前空間を作ってもリゾルバー構成は与えられず、名前空間ごとのファイルは次でサポートされます。/etc/netns/<name>/resolv.confが、それがなければ誤読しやすい挙動を引き継ぎます。IPv6も同じ扱いが必要で、名前空間にv6のデフォルトルートがなくアプリケーションがv6を優先すると、要求はフォールバック前に止まり、壊れたトンネルのように見えます。
終了アドレスだけでなく、枠組みを確認する
機能する公開アドレスは経路を証明しますが、要件全体を証明するものではありません。残りはこの順で確認してください
ip netns exec clearnet ip route get 1.1.1.1はvethのデフォルトルートを示し、WireGuardインターフェースではありません。- 要求の実行中、両方のルールのFORWARDカウンターが増加します。
- アプリケーションのプロセスが、期待どおりの名前空間inodeを報告します。
- 再起動後、サービスが始まる前に名前空間が存在します——それより早く動くunitは失敗するか、さらに悪いことに名前空間の外で動きます。
最後に、トンネルが落ちたときにどうするかを決めます。名前空間は動き続けますが、それがこの演習の目的であり同時にリスクでもあります——除外したプログラムは接続したままで、ほかのすべては止まります。これをポリシーの選択として記録し、除外が何をカバーしないかを明確にしてください。アカウントの身元、保存されたブラウザーの状態、DNSプロバイダーはどれもネットワーク名前空間の範囲外であり、除外を匿名性とみなすことが構成より長く残る誤りです。