構成としては以下のようなスター型のネットワークで、外部へのインターネットもセンター側を経由して行くようにしています。
さて、拠点側から一部のWEBサイトが見えないという問合せがありました。
例えばMicrosoftのサイト(htt://www.microsoft.com/)とか、借りている一部のレンタルサーバ上のWEBとかです。
IEで見ると、ずっと接続に行ってるような感じですが、何も表示されず最終的にタイムアウトしてしまっているようです。
Googleとかは普通に表示されまし、センター側の端末も何も問題なく表示されます。
ということで、拠点側のPCで WireShark を使ってパケットをキャプチャして見ました。
閲覧できないレンタルサーバ上(IP:xxx.xxx.xx.xxx)に、数キロバイトのHTMLを置きそれにアクセスした時の状態です。
No. Time Source Sport Destination Dport Protocol Length Info
5 13.089742 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 62 gamegen1 > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1
6 13.116909 xxx.xxx.xx.xxx 80 192.168.100.100 1738 TCP 62 http > gamegen1 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 SACK_PERM=1
7 13.116934 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 54 gamegen1 > http [ACK] Seq=1 Ack=1 Win=65535 Len=0
8 13.117216 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 609 gamegen1 > http [PSH, ACK] Seq=1 Ack=1 Win=65535 Len=555
9 13.945675 xxx.xxx.xx.xxx 80 192.168.100.100 1712 TCP 60 http > registrar [RST, ACK] Seq=1 Ack=1 Win=65535 Len=0
10 16.269908 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 609 [TCP Retransmission] gamegen1 > http [PSH, ACK] Seq=1 Ack=1 Win=65535 Len=555
11 22.285239 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 609 [TCP Retransmission] gamegen1 > http [PSH, ACK] Seq=1 Ack=1 Win=65535 Len=555
12 34.316287 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 590 [TCP Retransmission] [TCP segment of a reassembled PDU]
13 46.456608 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 590 [TCP Retransmission] gamegen1 > http [ACK] Seq=1 Ack=1 Win=65535 Len=536
14 58.597028 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 609 [TCP Retransmission] gamegen1 > http [PSH, ACK] Seq=1 Ack=1 Win=65535 Len=555
15 59.854326 xxx.xxx.xx.xxx 80 192.168.100.100 1738 TCP 60 http > gamegen1 [RST, ACK] Seq=2829 Ack=556 Win=65535 Len=0
16 59.854345 192.168.100.100 1738 xxx.xxx.xx.xxx 80 TCP 54 [TCP Dup ACK 14#1] gamegen1 > http [ACK] Seq=556 Ack=1 Win=65535 Len=0
17 59.880261 xxx.xxx.xx.xxx 80 192.168.100.100 1738 TCP 60 http > gamegen1 [RST] Seq=1 Win=0 Len=0
最初のTCPのコネクションは上手く行っているようですが、その後クライアントからの[TCP Retransmission]が大量に出ていますね。
TCP Retransmissionは再送要求をしているようです。時間内にサーバからパケットが来なかったので要求してると思われます。
で、最終的にサーバ側から RST フラグつまり、TCP接続を中断したというメッセージが来ています。
(TCPのフラグの意味は@IT:TCPパケットの構造を参照)
で、今度は別の閲覧可能なレンタルサーバ上(IP:xxx.xx.xx.xxx)に、同じく数キロバイトのHTMLを置きそれにアクセスした時は以下のようになりました。
No. Time Source Sport Destination Dport Protocol Length Info
1 0 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 62 netview-aix-1 > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1
2 0.013593 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 62 http > netview-aix-1 [SYN, ACK] Seq=0 Ack=1 Win=5632 Len=0 MSS=1408 SACK_PERM=1
3 0.01362 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 54 netview-aix-1 > http [ACK] Seq=1 Ack=1 Win=65535 Len=0
4 0.013877 192.168.100.100 1661 xxx.xx.xx.xxx 80 HTTP 496 GET /hoge.html HTTP/1.1
5 0.026311 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 60 http > netview-aix-1 [ACK] Seq=1 Ack=443 Win=6432 Len=0
6 0.02715 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 1294 [TCP segment of a reassembled PDU]
7 0.027209 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 1294 [TCP segment of a reassembled PDU]
8 0.027221 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 54 netview-aix-1 > http [ACK] Seq=443 Ack=2481 Win=65103 Len=0
9 0.027235 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 54 [TCP Dup ACK 8#1] netview-aix-1 > http [ACK] Seq=443 Ack=2481 Win=65103 Len=0
10 0.04047 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 1294 [TCP segment of a reassembled PDU]
11 0.040535 xxx.xx.xx.xxx 80 192.168.100.100 1661 TCP 1294 [TCP segment of a reassembled PDU]
12 0.040549 xxx.xx.xx.xxx 80 192.168.100.100 1661 HTTP 652 HTTP/1.1 200 OK (text/html)
13 0.040581 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 54 netview-aix-1 > http [ACK] Seq=443 Ack=5559 Win=64505 Len=0
14 0.04062 192.168.100.100 1661 xxx.xx.xx.xxx 80 TCP 54 [TCP Dup ACK 13#1] netview-aix-1 > http [ACK] Seq=443 Ack=5559 Win=64505 Len=0
データ受信時に[TCP segment of a reassembled PDU]が発生してますが、これはセグメントが分割されて送ってきたよというメッセージのようです。
(分割には、IPレベルで分割というかフラグメントする方法がありますが、これはそれではありません。IPレベルでの分割の場合が起こっている場合、Wiresharkでは [Fragmented IP protocol] となります。IPレベルで分割されると、ルータがパケットを分割するためスループットが非常に悪くなります。よって、大抵の通信はIPプロトコルで分割しないフラグ Don't Fragment をONにしてるようです)
この[TCP segment of a reassembled PDU]は大きなデータを送受信するときは必ず発生します。
なぜなら、通信では1回の転送で送信できるデータの最大値(MTU)が決まっていますが、アプリケーション側からみた1回のデータの送信はMTU(IPパケット全体の長さ)やMSS(IPパケット内のデータ部分の長さ)を考えないからです。
送信時に、大きいデータはお互いの通信路で適切なMTU値に分割されて、受信側で、[TCP segment of a reassembled PDU]で送られてきたパケットを結合してアプリケーション側に渡していると思われます。
このことから、この分割は普通、アプリケーションから送るデータがMSSを超えている場合に起こることがわかります。
さて、サーバとクライアントはどのように分割するサイズ、つまりMSSを知るのでしょうか。
TCPではコネクションを確立する3wayハンドシェイクで、お互いのMSSを通知し合って、値が小さい方を採用するようです。
例えば、上記の閲覧できたレンタルサーバのパケットキャプチャを見ると、以下のようになっていることがわかります。
で、今回問題となっていたのはVPN内のMTUです。
@IT:pingでMTUサイズを調査するを参考にして、センター側と拠点間のMTUサイズを測って見ました。
最終的に以下のパケットサイズより大きい値にすると、"Packet needs to be fragmented but DF set."エラーが出てしまいました。つまり、1253以上のパケットになるとIPフラグメントするわけですね。
ping xxx.xxx.xxx.xxx -l 1252 -f
なのでこのVPNルータ間のMTUは以下の計算によると、1280Byteのようです。
1252+8(ICMPヘッダ)+20(IPヘッダ)=1280(MTU)
(1280なのはヤマハのRTXルータでVPN組んだ時のデフォルト値のようです。本当はもっと大きい値でも問題なさそうな気がするのですが。。。)
IP,TCPのヘッダはそれぞれ20Byteなので、このVPNルータ間のMSSは以下のように1240Byteになります。
1280-20(IP)-20(TCP)=1240(MSS)
さて、送られてきたデータのサイズが大きすぎる場合でDFビットON(分割不可)の場合、ルータはパケットを破棄し、ICMP Type3 Coede4を送信元ホストに送信し、ホストはそれによりパケットサイズを調整して再送という段取りをとるようです。
上記のような仕組みを、Path MTU Discovery(経路MTU検索)と言うようです。
DFビットが設定されていないと、ルータはフラグメントを行なってパケットを送信するようです。(スループットは落ちます)
しかし、送信元に「パケットでかいから小さくしてよ」というICMPパケットがFWなどによって遮断されるとどうなるでしょうか。
WEBサーバ側はクライアントからACKパケットが帰ってこないため、RST パケットを送り、パケットが届かねぇから通信辞めると捨て台詞を吐いてるようです。
おそらく、MSのサイトを始め幾つかのサイトが見れなかったのはこれが原因だと思います。
試しに、拠点側PCのMTUを強制的に 1280 に書き換えてみたところ、閲覧出来なかったサイトも見れるようになりました。
MTUのサイズを変更するには、MSサポート:ブラック ホール ルーターの問題をトラブルシュートする方法の方法3に有るように、以下の手順を行います。(以下引用)
(ネットワークのMTUサイズを変更する - @ITにも書かれてます)
1.[スタート] ボタン、[コントロール パネル] の順にクリックします。
2.[ネットワークとインターネット接続]をクリックし、[ネットワーク接続] をクリックして開きます。
3.複数のネットワーク接続が表示された場合は、各接続をダブルクリックし、表示された [状態] インターフェイスの [サポート] タブをクリックします。[デフォルト ゲートウェイ] エントリが表示された場合、その接続がインターネット接続に使用されているネットワーク接続であると考えられます。接続名 ("ローカル エリア接続 2" など) をメモします。
4.レジストリ エディタ (Regedit.exe) を起動します。
5.HKEY_LOCAL_MACHINE ツリーの下にある次のレジストリ キーに移動します。
SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\
6.このキーの下に、数字の識別子を持ついくつかのキーがあります。各キーには Connection サブキーが設定されています。次のようなキーをすべて調べます。
アダプタの ID\Connection
Connection サブキーの [Name] 値には、ネットワーク接続フォルダに使用されるネットワーク接続名が設定されています。ステップ 3 でメモした名前と一致するものが見つかったら、そのネットワーク接続名の アダプタの ID をメモします。
7.HKEY_LOCAL_MACHINE に戻り、次のレジストリ キーに移動します。
SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\アダプタの ID
アダプタの ID は、ステップ 6 でメモした番号です。このキーを強調表示すると、画面の右側にいくつかの値が表示され、その中に [DefaultGateway] および [EnableDHCP] が含まれています。
8.画面の右側を右クリックし、[新規] をクリックして、[DWORD 値] をクリックします。この値に [MTU] という名前を付けます。
9.その値をダブルクリックして編集します。[表記] を [10 進数] に変更し、Ping テストで確認した MTU の最大許容サイズを入力します。
10.レジストリ エディタを終了します。
以下のような感じです。
このあたりの話は、Path MTU Discovery 1で詳しく図入りでまとめられています。
この現象を再現するために、センター側にxpでWEBサーバを立てて検証して見ました。
全パケット素通しにした場合は、VPNの向こう側の拠点からページの閲覧できました。(MTUは1280になっており、ルータからICMPパケットが届いているのが確認できました。)
しかし、WEBサーバ側にFW(今回はフリーのKerio使いました)を入れ、ICMP全遮断すると、拠点からページの閲覧ができない状態になりました。
さて、この場合の解決方法としてはどうすればいいのでしょうか。
ICMPパケットがブロックされるのは向こう側の問題なので、どうしようもありません。つまり、経路MTU検索は使えないというわけです。
拠点側のクライアント全部のMTUを、VPNのMTUより小さくすればOKですが、端末数が多い場合設定に手間取ります。
幸い今回VPNルータに使ったYAMAH RTX1200には、TCPコネクション開始時にMSSを調整してくれる機能があるようです。
コマンドどしては以下になります。
ip tunnel tcp mss limit auto
上記のコマンドによって以下のようになります。
これで、なんとかまともに通信ができるようになりました。
補足ですが、強制的にMTUを指定したい場合は以下のように出来ます。
(設定する値はMSS(MTUから40バイト引いた値)なので、MTUと間違えないように注意)
ip tunnel tcp mss limit 1240
LAN3のインターフェイスでMSS指定したい場合は以下のようにします。
ip lan3 tcp mss limit 1240
今回のように、経路MTU検索が使えず、VPN内でMTUが小さくなる故に通信できなくなるという現象は、VPN組んでいると結構あるようです。
ルータによっては経路MTUより検索に対応しておらず、ICMP type3 code4パケットを返さないものもあるようで、このようなルータはブラックホールルータと呼ばれているようです。
まぁ理屈がわかれば非常に簡単な話ですが、TCP/IPの基礎を忘れかけてた3流PGは、原因突き止めるのに結構時間がかかってしまいました。
参考:
ペンギンの覚書: ネットワーク更改時のトラブル "YAMAHAのルータではVPN等のMTUがデフォルトで1280バイトになっている。対応策は、ip tunnel tcp mss limit auto"
◎IPの分割化と再構築 ここの"3.MTUとMSSとの違い。"に、ヤマハルータでのMSS自動調整"ip tunnel tcp mss limit auto"に関する記述があります。
あんじーのテクニカルブログ: MTUが小さいVPN間でファイル共有通信をすると通信できなくなる問題 "VPN通信では1280Byte、それ以外は1500Byteになっていて、ICMPパケットを破棄する設定になっていると通信できなくなる問題を引き起こすようです。"
@IT:VPNの実力を知る(後編)"(4)MTUに関する確認"あたりにMTUの話があります。