今回は IPv4 のお話ではなく IPv6 のお話です。でもって Path MTU Discovery のお話です。
僕は IPv6 は Hurricane Electric の IPv6 Tunnel Broker を利用しています。以前からここの IPv6 トンネルを利用させてもらっているのですが、とあるタイミングで IPv6 の http や ftp が通らなくなりました。あらま。 ping や ssh は通るので、仕事柄の経験上「あぁ。 Path MTU Discovery にハマったな。」というのはすぐに解りました。
『ハマった』というのは『送受信の二点間において MTU の最小値を決定することができなかった。』と、いうことかな。
どうして『決定できなかった』のかと言えば『Path MTU を探査できなかったから。』と、いうことになると思います。
Path MTU が Discovery できないとパケットのフラグメントが発生しないので MTU サイズ以降のパケットは捨てられてしまうために通信が行えなくなります。
しかし、Hurricane Electric の IPv6 トンネルは今まで利用できていたのにどうしてある日突然 Path MTU Discovery ができなくなってパケットサイズの大きい通信が止まるのだぁ? などと不思議に思うのであります。
まず、どうして Path MTU Discovery に失敗するのか?
1). 自分が設定したファイアーウォールで ICMPv6 の Type2 (Packet Too Big)を止めてしまった
2). ISP がある日突然 ICMPv6 の Type2 に ACL をかけた
3). Hurricane Electric で仕様が変わった
が考えられると思います。 1). については自分が設定したファイアーウォールを flush して確認できると思います。
2). の場合、僕は ISP を二つ契約している(自宅でマルチホームっ!!;-)ので両方の ISP で Hurricane Electric のサービスにトンネルを掘って確認してみましたが、どちらも http が止まります。
すると、残りは 3). が原因か、もしかして 2). の二つの ISP の両方が ICMPv6 Type2 に ACL を設定しているか。ですね。
まぁ、どっちにしても通信はできません。orz
次に、本当に IPv6 Path MTU Discovery ができていないのかの確認方法です。
1). IPv4 は ping・ssh・http の通信ができることを確認
2). IPv6 で ping・ssh・http の通信ができることを確認
3). ping6 -s 1434 au.kddi.com もしくは ping -s 1280 au.kddi.com
1). の確認において IPv4 で上記プロトコルが全て利用できるようであれば、問題は IPv6 のみに特定できます。
2). では Path MTU Discovery にハマると http の通信のみできなくなります。まぁ、ftp ででかいデータを持ってくるときとか、パケットサイズが 1,500 バイトに近くなる通信では止まってしまいます。
3). は、じゃぁ実際に何バイトのバケットサイズであれば通るのだ?という確認のために ping でパケットサイズを指定します。 1,434 もしくは 1,280 バイトで ping してみて、通る、通らないでサイズを変更して色々確認してみるのが良いかと思われます。
さてさて。これらで確認することにより IPv6 Path MTU Discovery な地雷を踏んだか確認できますが、次にその対応について考えてみたいと思います。
まずはネットワーク構成図などを。
真ん中の黄色いのがトンネルルータで Hurricane Electric に対して gif0 でトンネルを掘っております。 em0 のインターフェースは一個目の IPv6 セグメントです。
また、トンネルルータでは dtcps を起動していて gif10 と gif10 で更に二つのセグメントとトンネルを掘っております。
このネットワークでの IPv6 Path MTU Discovery の状態は・・。
1). 同一セグメント内では通信ができる
2). セグメント 1,2,3 の間ではで通信ができる
3). セグメント 1,2,3 から gif0 を抜けて Hurricane Electric の先にある IPv6 サイトと通信ができない
と、いうことが解りました。 どうやら MTU もしくは MSS の調整は re0 か gif0 で行う必要がありそうです。
が、その前に、クライアント PC 側で何か対応する手立ては無いか調べてみました。
1). クライアント PC の MTU を 1434 にする
2). IPv6 より IPv4 を先に利用するようにする
1). の場合は UNIX 系 OS だと比較的容易にできます。以下は FreeBSD で MTU を変更する場合のコマンドです。
|
IPv6 Path MTU Discovery でハマった時には MTU を1434 にしてあげると通信が復活します。セグメント内にいる全ての UNIX 系 OS で上記コマンドを叩く必要があります。
2). のほうは WindowsOS で有効な手段です。 DOS のプロンプトをアドミン権限で起動し、以下のコマンドを打ちます。
|
一行目のコマンドはステータスの確認です。これを見ると IPv6 のほうが先に利用されるように設定されているので IPv4 を先に利用するようにその後のコマンドでプライオリティを変更してあけます。
もとに戻すときにはこちらのコマンドで。
|
これで WindowsOS もなんとか IPv6 Path MTU Discovery を回避できたのではないかと思われます。ちょっと弱い問題解決ですが・・。
しかし、IPv6 に対応しているスマートフォン(iOS や Windows Phone OS など)は IPv6 サイトが見られないんですよねぇ・・。
さてさて。こんなことばっかりしていても根本的な問題解決にならないので次に根本的な解決をしてみたいと思います。
IPv6 Path MTU Discovery ができないときの原因としては ICMPv6 の Type2 (Packet Too Big) パケットのやりとりができず、通信するための最小 MTU サイズが特定できないために発生します。それならばパケットを送信する側でパケットの最小サイズを明示的に指定して送信すれば良い(それはつまりは TCP SYN パケットの MSS オプション値を書き換えてあげる。と、いうことです)わけなんですけども FreeBSD にその機能があるのか?
今回利用しているトンネルルータは FreeBSD 9.1-RELEASE です。こいつには pf(4) があるのでそれを利用することにします。と、いうか、現状では pf(4) でしか制御できないようです。
他にもports に net/tcpmssd があるようなのですが、今回は pf(4) を利用することにします。
ちなみにトンネルルータのファイアーウォールは ipfw で設定しているのですが MSS のサイズは pf で設定することにします。
今回は ipfw の設定は省きます。以下は /etc/pf.conf の設定です。
|
FreeBSD の MSS サイズを固定に設定するためには max-mss を利用します。サイズは 1280 にします。上記構成図では re0 から抜けるパケットのみが 1,280 バイトになります。通常 IPv4 パケットは別の BB ルータから抜けていく(構成図には書かれていない)のでまぁ、問題は無いでしょ。
re0 と gif0 の両方の MSS サイズを小さくしている設定をしていますが、試した結果 gif0 のみの MSS を1280 に設定するだけで十分でした。
設定が完了したら以下のコマンドを打ちます。
|
カーネルモジュールをロードし、無事にロードできたか確認します。次に /etc/rc.d/pf を onestart で実行します。無事に実行できたかは pfctl の二行で確認(オプション -sr と -sa)しましょう。出力結果は省略します;-)。
無事に動作することができたら /etc/rc.conf などに pf_enable=”YES” などと書きましょう。
最後に確認方法ですが、簡単です;-)。セグメント 1,2,3 の各クライアント PC から IPv6 サイトが無事に見えるかどうか。だけです;-)。
au.kddi.com とか running-dog.net とか icmpv6.org などが無事に見えると pf で設定した max-mss 1280 が有効になっている。と、いうことですね。
とまぁ、ある日突然 IPv6 Path MTU Discovery が通信できない問題が降ってきたわけですけども、その対応策などをツラツラと書いてみました。皆さん、是非とも IPv6 Path MTU Discovery にハマらないようにしたいと思うわけですけども、もしハマったら pf で回避してみてください。
ふぅ。それにしても復活だぁ・・。