ローカルアプリと VPN ルール: FORWARD チェーンが動かない理由
端末上のプロセスが使うのは OUTPUT で、FORWARD ではありません。正しい名前空間のフックを選び、マークと単純な経路のどちらで足りるかを決めます。
VPN トラフィック用のルールを FORWARD チェーンに追加し、同じ Linux マシンからリクエストを実行しても、カウンターはゼロのままです。ルール自体はおそらく正しいのです。パケットがその経路を通らなかったのは、マシン自身で生成されたリクエストがそこでは転送されないからです。パケットの一生をソケットからケーブルまでたどると、なぜそうなるのか、ルールをどこに置くべきかが見えてきます。
パケットが生まれた場所を突き止める
Netfilter のフック順序は三つの場合を分けており、そのうち FORWARD が関わるのは一つだけです:
| Origin | Path | Hook that sees it |
|---|---|---|
| Local process | OUTPUT then POSTROUTING | OUTPUT, POSTROUTING |
| Addressed to a local service | PREROUTING then INPUT | PREROUTING, INPUT |
| Received for another host | PREROUTING, FORWARD, POSTROUTING | FORWARD |
ローカルアプリケーションは OUTPUT 経路から始まります。カーネルはすでに、パケットがここで発生し転送の対象にはならないと判定しており、トンネルを作ってもこの分類は変わりません — トンネルはパケットが出て行くことのあるデバイスであり、ローカルの出力を通過トラフィックに変える段階ではありません。
二つのパケット、一つの物語
トンネルが上がると、アプリの内側パケットと暗号化された外側パケットは別のオブジェクトになります。内側パケットはアプリが選んだ宛先とペイロードを運びます。外側パケットは暗号文をピアのアドレスとポートへ運び、実際に物理インターフェースを越えるのはこちらです。
ポリシーが対象にするのはどちらか一方で、間違った方を選ぶとルールが何もしていないように見えます。ピアの外側アドレスに一致するルールは、内側のアプリが何をしていても、すべてのトンネルパケットを同じように見ます。内側の宛先に一致するルールは、必要なトラフィックを見ますが、そのパケットがルールを設置したフックに届いたときだけ機能します。
名前空間が境界を動かす
コンテナは原則を変えずにこれを難しくします。アプリのリクエストは、コンテナのネットワーク名前空間の内部でのローカル出力です。ホストはそのトラフィックを仮想 Ethernet インターフェースで受け取り、転送できる場合があり、したがって、リクエストを生成したプロセスがホストの OUTPUT チェーンに触れていなくても、ホスト側の FORWARD ルールが意味を持つことがあります。
フックを選ぶ前に、ルールセットとトンネルが実際どこに住んでいるかを確認します。コンテナ内のトンネル、コンテナを経由させたホスト上のトンネル、別の名前空間のトンネルは、それぞれ異なる三つのトポロジーと三つのルール配置です。デフォルトだけでなく、デバイスを所有する名前空間の内側でルールを読みます。
マークが本当に必要かを問う
目的が一つの宛先プレフィックスをトンネルに通すことなら、そのプレフィックスの経路だけで足りるかもしれません。サーバーが押し込んだものも含め、まず有効な経路を確認してください — リダイレクトされたデフォルト経路は想定していた狭いポリシーよりはるかに多くのトラフィックを VPN に通し、どれだけマークしても結果は意図と一致しません。
分類が必要になるのは、判断が経路では表現できないもの — 送信元、ユーザー、プロセスなど — に依存するときです。受信トラフィックなら PREROUTING でのマークが機能します。ローカルトラフィックなら、マークを設定した後に新しい経路検索を起こせる出力段階でマークする必要があります。nftables では出力フックの route 型チェーンがそれで、通常の出力フィルターチェーンでは値が設定されるだけで経路は変わりません。
iptables では同等のものが mangle OUTPUT の構成にあり、同じ条件が当てはまります。マークが存在した後に経路判定をやり直す必要があり、そのうえでポリシールールがマークを消費し、使える経路を持つテーブルを指す必要があります。conntrack マークの設定は三つ目の別操作で、フローに値を保存するだけで、その値を現在のパケットに載せて経路探索に読ませるものではありません。
経路検索とカウンターを一緒に確かめる
nft list ruleset
ip route get 198.51.100.25
ip route get 198.51.100.25 mark 0x1
アドレスとマークは例示であり、二つの経路クエリは別の問いに答えます。二つ目は、パケットがそのマークを運んでいたらカーネルがどうするかを問うもので、ルールセットがマークを付けることを示すものではありません。これは仮説の検証として扱い、ポリシーが機能する証拠とは考えないでください。
次に無害なリクエストを実行し、選んだフックのカウンターと、パケットが実際に取った出口を同時に見ます。カウンターが動いてパケットが別の場所から出ていくなら、マークかテーブルが間違っています。どちらも動かないなら、パケットはそのフックにまったく届いておらず、次の問いは名前空間か経路です。
最後に、テストの範囲を仕組みが表現できるものに限定します。一つのアドレスに対する一つの経路は、アドレスが変わるサービスの恒久的なポリシーにはなりません。まずパケットの範囲を決め、再接続後も経路とマークの設計がその範囲を保てるかを確認します。