VPN クライアントのトラフィックを、ポート 1080 で SOCKS リスナーが動くホストへ送るポリシールートを追加しました。パケットは届きますが、リスナーは何も記録せず、接続はぶら下がったままです。ルートに問題はありません:ネクストホップはパケットがどこへ行くかを選び、SOCKS はクライアントが開始しなければならない会話です。プロキシ経由でトラフィックを送るときに人が通常思い浮かべる三つの構成を比べれば、あなたの設定に欠けている部分がはっきりします。

ルーティング、DNAT、SOCKS は変える対象が違う

ポリシールートはレイヤー3 の判断を書き換える。二行で足ります:一台のクライアントのトラフィックを選んだネクストホップへ送るには

ip route add default via 10.50.0.2 table 101
ip rule add from 10.77.0.2 lookup 101

その後カーネルはパケットを 10.50.0.2 に渡し、元の宛先は IP ヘッダーに残ったままです。10.50.0.2 がルーターならパケットを転送し、1080 で SOCKS デーモンが動くホストなら、パケットは受け取れるものに宛てられておらず、ポート 1080 への DNAT も役に立ちません。変換されたパケットは依然として SOCKS の挨拶ではなく元のアプリケーションのペイロードを運ぶからです。

SOCKS5 はバージョンバイト、メソッド一覧、認証のやり取り、宛先を名指すリクエストから始まります。それはアプリケーションのデータです。ルーティングエントリも netfilter ターゲットもそれを生成せず、これが一行での比較です:ルーティングは経路を選び、SOCKS はサーバーに二つ目の接続を作るよう頼みます。

最初のケース:アプリケーション自身が SOCKS を話せる

プログラムにプロキシ設定があるなら、これが最短の道であり、カーネルの変更は要りません。リスナーに向け、サーバーが求めるなら資格情報を渡し、名前をローカルで解決するかプロキシに渡すかを決めます。curl ではこれらは別のフラグで、宛先がプロキシ側からしか解決できないときに違いが効いてきます:

curl --socks5 10.50.0.2:1080 https://docs.example.com
curl --socks5-hostname 10.50.0.2:1080 https://internal.example.com

プロキシの環境変数を無視するアプリケーションや、生のソケットを開くアプリケーションは、この方法では助けられません。ブラウザーとほとんどの HTTP ツールは問題ありませんが、ゲームクライアント、メールデーモン、任意のベンダーバイナリは通常そうではありません。境界はアプリケーションごと、プロトコルごとにあり、だからこそこの選択肢はテストには優れ、VPN 全体の答えとしては弱いのです。

二番目のケース:IP フローをプロキシセッションに変換するアダプター

SOCKS を話せないプログラムでは、変換は IP トラフィックを終端し、彼らの代わりにプロキシセッションを開く何かで行う必要があります。そのコンポーネントはトンネルインターフェースを持ち、ポリシールーティングが選んだフローを受け入れ、それぞれに SOCKS ハンドシェイクを行い、応答を組み立て直します。ルートはトラフィックをそこへ向け、セッションを作るのはアダプターです。

サブネット全体を任せる前に、そのドキュメントを読んでください。多くのアダプターは TCP をうまく運びますが UDP は SOCKS5 の UDP アソシエーション経由でしか扱わず、どれも ICMP をプロキシトラフィックに変えないので、ping の成功はプロキシ経路について何も語りません。DNS がもう一つの罠です:アダプターが名前をローカルで解決すると、内部専用のレコードは誤った答えに、あるいは何もないところに解決されます。

ループ防止が実際に痛いところです。アダプター自身の SOCKS サーバーへの接続をアダプターへ戻してルーティングしてはいけないので、そのトラフィックにはルールの例外か専用の送信元アドレスが必要です。これを間違えると、プロキシセッションが自分自身をプロキシしようとします。

三番目のケース:実はホストがルーティングされたゲートウェイである

動いている設定に SOCKS がまったく含まれないこともあります。リモートホストがパケットを転送したり NAT したりし、送信元ベースのルールがそれを出口として選ぶだけです。その設計は正当であり、コピーした設定が一方のネットワークで動き、他方で失敗する理由を説明します:ルールは同一で、欠けているのは向こう側の転送サービスです。

三つのケースはすぐに分かれます。実際に何がリッスンしているかを確認し、次にホストに届く最初のバイトを見てください:

ss -ltnp 'sport = :1080'
tcpdump -ni eth0 -X 'tcp port 1080'

本物の SOCKS クライアントの最初のペイロードバイトは 0x05 で、挨拶のバージョンです。もしキャプチャが代わりに元のアプリケーションデータを示すなら、交渉が始まっていないので SOCKS デーモンは応答しません。1080 で何もリッスンしていないなら、ホストはゲートウェイであり、問いは転送するかどうか、戻り経路があるかどうかになります。

四つの質問で層を選ぶ

プログラムにプロキシ設定はありますか。あるなら使って、そこで止めます。トラフィックに生き残る必要のある UDP や ICMP は含まれますか。ICMP を運ぶのはルーティングされたゲートウェイか NAT ゲートウェイだけで、UDP には両端が対応する SOCKS5 アソシエーションが必要です。設定できないものを含め、マシン上のすべてのプロセスを対象にする必要がありますか。それならインターフェースを所有しフローを終端するアダプターが要ります。そのルーティング、DNS、ループ防止の例外まで引き受けられますか。できないなら、素のゲートウェイの方が運用コストは低くなります。

一つの区別は明確にしておく価値があります。VPN クライアント自身の socks-proxy オプションは、外側のトンネル接続がどうやってサーバーに届くかを説明するもので、内側のクライアントフローの変換については何も語りません。この二つは同じチケットでしばしば混同されます。ルートに触れる前に、どちらの関係が必要かを決めてください。

関連記事