ITエンジニアのコツコツ日記

ITエンジニアの雑記です

SoftetherVPN のSecureNATの動きが怪しい

SoftetherVPNのSecureNAT

SoftetherVPNのSecureNATは仮想HUB内に仮想のルータを配置する機能。

f:id:itkotsukotsu:20201013232617p:plain

SecureNATはDHCPサーバ機能もあり、標準では192.168.30.0/24のネットワークを作成する。

f:id:itkotsukotsu:20201013233536p:plain

SecureNATを有効にするとSoftetherが動作するホストを通じて外部への通信が可能。

気を付けないのがSecureNATを有効にしている仮想HUBとローカルブリッジは一切関係ない。

SecureNATが生成するゲートウェイSoftetherホスト自体であり、ローカルブリッジのNICとは関係なく、Softetherホストの持つ経路情報によって通信が提供される。

つまり、Softetherホストがインターネット接続可能であればSecureNAT上のホストはインターネット接続が可能になるし、Softetherホストが複数NICを持ち、別のLANへのルーティング情報を持っていればそこへもつながる。

ネット上のブログや記事はSecureNATの本質を捉え間違えているものが多いので注意が必要だ。

SecureNATの動きが怪しい

さくらのVPS上のCentOS7Softetherをインストールして動作検証を行ったが、VPNを接続した後の数秒後(10秒程度)くらいに通信が途絶えてしまう。

要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。  ←ここでSecureNATを有効に
192.168.100.21 からの応答: バイト数 =32 時間 =34ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =33ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =46ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =53ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =52ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =34ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =62ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =40ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =41ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =28ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =46ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =56ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =44ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =55ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =64ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =50ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =51ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =41ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =32ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =51ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =53ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =46ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =42ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =35ms TTL=63
192.168.100.21 からの応答: バイト数 =32 時間 =33ms TTL=63
要求がタイムアウトしました。    ← なぜか通信できなくなる。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。

通信が途切れた際のSecureNATのステータスをモニタすると、カーネルモード NAT で動作中Raw IPモードで動作中はいになったとたんに接続が切れたことが分かった。

このSecureNATは動作モードがあり、「ユーザーモード」と「カーネルモード」と「Raw IP モード」があるらしい。

公式 SecureNATカーネルモードについて

ユーザーモード NAT

ユーザーモードNATは特権を必要としない一般プロセスでNAT処理を実現するもの。

このため、Linuxカーネルの機能を使えないためオーバーヘッドが大きく、パフォーマンスが低い。

IPtablesも使わないため、影響範囲は狭くほぼ動作する。

カーネルモードNAT

以下公式より引用

一般的な NAT 処理と同様にパケットの内容の解釈を行わずにヘッダの書き換えのみで動作するため、ユーザーモード SecureNAT と比較して高速に動作します。

インターフェースレベルの低レベルAPI経由でヘッダのみの書き換えで動作するモード。これは上位の権限を要求する場合があるそうだ。

Raw IP モードNAT

最後はいわゆる普通のNATを行うモードで、iptables経由でLinuxのNetfilterのnat機能を使う。

Linux Kernel のモジュールで動作するので非常に高速に動作する。

問題は利用モードの自動選択

どうも利用可能かどうかを自動判定して、適切なモードを選択してくれる仕様のようだ。

イーサネットインターフェイスでの通信に成功した場合はカーネルモード SecureNAT が使用され、Raw IP ソケットでの通信に成功した場合は Raw IP モード SecureNAT が使用されます。いずれも成功しなかった場合はユーザモード SecureNAT が使用されます。

方式ドキュメントを読む限り、ユーザモードNATからスタートして、カーネルモードの可否、RawIPモードの可否を判定するようだ。

ユーザモードNAT ⇒ カーネルモードNAT ⇒ RawIPモードNAT

この方針はいいが、なぜかエラーとなるカーネルモードとRawIPモードが有効になってしまった。

原因はDocker?

今回はCentOS7上でDockerを用いてSoftetherを動作させていた。

低レベルのネットワークアクセスのため、network driverはhostで、privilegedな権限を付与して動作させている。

ここの設定はおそらく問題ないが、いけなかったのはDockerがiptables経由でnatテーブル等を書き換えていること。

softetherが設定したnatテーブルを不当に書き戻している可能性が高い。

ホストのiptablesを操作するプロセスが共存するのはあまり好ましくないだろう。

対策はユーザモードNAT固定

幸いにも NATの利用モードの明示的な指定が可能だ。

カーネルモードを禁止する場合は「DisableKernelModeSecureNAT」を、Raw IP モードを禁止する場合は「DisableRawIpModeSecureNAT」を、ユーザモードを禁止する場合は「DisableUserModeSecureNAT」を、それぞれ 「1」に設定して下さい。 公式: 利用モードの選択

※ 公式ページのDisableRawIpModeSecureNATDisableIpRawModeSecureNATのタイポです。

以下を設定すればユーザモードで固定することが可能だ。

  • DisableKernelModeSecureNAT: 1
  • DisableIpRawModeSecureNAT: 1

上記を仮想HUBのプロパティから設定すれば問題なく動作するはずだ。