サービスを事業者グレード NAT の背後にあるノート PC に置き、その PC を VPN 経由で VPS に向けると、外からは誰も到達できません。VPS に宛先 NAT ルールを足すと、沈黙より悪いものが返ります。接続は開くものの、そこで止まるのです。応答が消えているのではなく、クライアント自身の既定ルートから出ていっており、サーバーはそれを一度も見ません。この五つの確認を順に行い、最初に成り立たないところで止めてください。

サーバーがそもそも転送するかを確認する

翻訳を一行でも書く前にこの欄に印を付けてください。カーネルが転送を拒むパケットに対する DNAT ルールは、ルールパーサーには受け入れられ、その後に転送経路で破棄されます。その結果は、ファイアウォールの問題に見えるタイムアウトです。

sysctl net.ipv4.ip_forward
sysctl -w net.ipv4.ip_forward=1

実行中のカーネルで設定することと、再起動をまたいで設定することは同じではありません。net.ipv4.ip_forward=1 を /etc/sysctl.d/ 配下のファイルに書き、sysctl --system を実行し、ファイルが読み込まれたと信じるのではなく値を読み返してください。独自のネットワーク名前空間を管理するコンテナでは、ホストだけでなくその名前空間の内側にも同じ値が必要です。

読み返してもまだゼロなら、ここで止めてください。この先は何も動きません。

どのルールが参照するよりも前にトンネルのアドレスを固定する

プールは接続順にアドレスを配るため、今日のリース向けに書いたルールが来週には黙って別のクライアントを指すことがあります。アドレスは到着順ではなく証明書の身元に結び付けてください。

client-config-dir /etc/openvpn/ccd
ifconfig-push 10.77.0.14 10.77.0.13

この組はポイントツーポイントトンネルのクライアント側とピア側であり、サーバーは証明書のコモンネームに紐づきます。サブネットトポロジーでは二つ目の値は代わりにネットマスクとして読まれるので、使用中のトポロジーに合う形を書いてください。そのうえでクライアントを再接続し、アドレスはクライアント自身で読んでください。サーバーから見たプールの姿は、クライアントが設定した内容の証明にはなりません。

再接続後にアドレスが変わるなら、止めてください。動く標的を追う NAT ルールは断続的に失敗し、何も教えてくれません。

両方向に変換する

宛先変換は受信パケットをクライアントへ送ります。送信元変換こそが、クライアントに元の送信者ではなくサーバーへ応答させるものであり、人が落としがちなルールです。

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 29443 -j DNAT --to-destination 10.77.0.14:29443
iptables -t nat -A POSTROUTING -d 10.77.0.14 -p tcp --dport 29443 -j SNAT --to-source 10.77.0.13

二つ目のルールがないと、クライアントは ISP の上り回線から応答するため、遠隔のピアは一度も話していない送信元アドレスを見ることになり、サーバー側には応答の追跡エントリが残りません。外部の観測者には途中で終わるハンドシェイクが見え、それが、存在しないファイアウォールの不具合を探させる正体です。

iptables -t nat -S で両方のルールを読み返し、インターフェース名が公開アドレスを載せているものかを確認してください。すでに nftables で絞り込んでいるホストでは、道具を混ぜるのではなく、対応するアドレスファミリーの nftables NAT チェーンに変換を書いてください。

フィルターテーブルを通す

NAT テーブルはヘッダーを書き換えるだけで、許可は与えません。既定の DROP ポリシーでは、転送されるフローに独自の許可が必要で、加えて戻り方向はほとんどのポリシーが established,related ルールで既に覆っています。

iptables -A FORWARD -i eth0 -o tun0 -p tcp --dport 29443 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

何かを足す前に FORWARD チェーンのポリシーを確認してください。早い段階の DROP の順序が、あなたのルールが読まれるかどうかを決めるからです。フィルタリングが nftables にあるホストでは、同等のルールを inet テーブルの forward フックに足し、基底チェーンがローカル入力だけでなく転送トラフィックを実際に見ていることを確認してください。新しいルールのパケットカウンターがゼロのまま NAT のカウンターが増えるなら、パケットはあなたのルールより前で落ちています。それはチェーンの順序を読む合図であり、同じルールの二つ目の複製を足す合図ではありません。

外部ネットワークから証明する

無関係なネットワークから試してください。同じ LAN の別マシンからの検査はヘアピン NAT 対応を通り抜けることがあり、遠隔クライアントが使う経路を一度も通らないため、そこの緑の結果は誤ったことを証明します。

tcpdump -ni any port 29443
conntrack -L | grep 29443

サーバーとクライアントで同時にキャプチャを実行してください。サーバー側のキャプチャは変換後のパケットがトンネルへ出るかを見せ、クライアント側のキャプチャは要求が届くかと応答がどこ宛てかを見せます。conntrack -L に変換エントリがあればルールが一致した証拠であり、なければパケットが NAT チェーンに届かなかった証拠です。

ポートスキャナーは弱い証拠です。アプリケーションがバインドして待ち受けるまでポートを閉じていると報告するので、実際のサービスに実際の接続を使ってください。最終的に動いたら、露出はその一つのポートに留めてください。最初のルールが気まずかったからといって SSH や管理パネルまで転送するのは、サービスを公開するよりはるかに大きな判断です。

関連記事