2010/03/05

MTU設定時の注意点

以前、 IPsecを試していた時にIPのフラグメントが原因と思われる通信障害が発生しました。 どうやらAlixで作成したブロードバンドルータのMTU設定がまずかったようです。

現状でも参考にした資料を全部読めていないのですが、いまの理解でまとめておこうと思います。

問題となった現象について

エラーメッセージ

VMWare上でTeamを組んで2つのサブネットをlinuxをルータにして接続してみました。 MTUをいろいろ変更している最中にsyslog経由で記録されたログは次のようになっています。

linuxでのメッセージ

...
Mar  3 10:05:40 lipsec01 kernel: [ 1778.358003] pmtu discovery on SA AH/09dd8188/0a000001
Mar  3 10:07:40 lipsec01 kernel: [ 1898.356663] pmtu discovery on SA AH/09dd8188/0a000001
...

netbsdでのメッセージ

...
wm0: discarding oversize frame (len=1502)
wm0: discarding oversize frame (len=1502)
...

どちらもMTUが適切に設定されていない事を示唆していますが、この時点ではまだその点にちゃんと気がついていませんでした。

設定を確認

実際に問題が発生したAlixブロードバンドルータを中心にしたネットワークは次のようになっていました。

Alixを中心にしたHomeLANの概要

192.168.1.0/24と192.168.10.0/24のサブネットのゲートウェイになるeth1, eth2のMTU値が1454になっていました。 MTU値1454はBフレッツで接続する際にNTTから指定されている値で、PPPデバイスに対しては正しいのですが、家の中で各サブネットに接続しているPCはMTU値1500が設定されているため、サブネット単位で不整合が発生しています。

対応策

サブネット単位でちゃんとMTUを揃えて対応は完了。

通常はこれで気になる事もなかったのですが、どういうわけかIPsecでAH+ESPヘッダを付与したところで顕著に影響が出てしまったようです。 IPsecはヘッダが付与される分パケットが長くなりがちですが、どうしてこれでIPsec以外の通信では問題にならなかったんだろう。

ああ、外部に出ていく時にはPPPのMTU値1454に合わせるから問題がなくて、家の中ではそもそも大きなファイルの転送をしなかったとかかな。いや、そんなことはない。

Path MTU Discoveryについて

今回の原因はMTUの不整合でした。 それとは別にMTU関連についていろいろ調べていく中で、alixを通した時にPath MTU(PMTU) Discovery(PMTUD)がちゃんと動いているのか確認する事にしまいた。

サブネット単位でMTU値を同じ値に設定した後に、ICMPパケットをtcpdumpを使って眺めてみました。 外部へ接続する時にはppp0に設定されているMTU値1454に合わせるよう、PMTUDが動いている様子がわかります。

$ sudo tcpdump -p -i eth0 icmp -vv -n

tcpdump出力ログ

...
21:26:29.868484 IP (tos 0xc0, ttl 64, id 18704, offset 0, flags [none], proto ICMP (1), length 576) 192.168.1.1 > 192.168.1.xxx: ICMP 210.xxx.yyy.zzz unreachable - need to frag (mtu 1454), length 556
	IP (tos 0x0, ttl 64, id 19526, offset 0, flags [DF], proto TCP (6), length 1499) 192.168.1.xxx.59612 > 210.xxx.yyy.zzz.80: P 3195263263:3195264710(1447) ack 810452849 win 90 <nop,nop,timestamp 89692924 674447780>[|icmp]
...

今回の反省

サブネット単位でMTUが揃っていなかったのは痛いミスでした。

今回の調査の中でPMTUDについても勉強しなおしてAlixの設定に反映させました。 まぁAlixでルータを作った時にはPMTUの事を考えずにICMPパケットを全て落していましたからね。

現在のiptables設定

現在ではいろいろな経緯で変更を加えて state モジュールをUDPとICMPにも適用した状態になっています。 またネットワーク内部を探査されないようにecho-requestとredirectについては明示的にDROPする設定にしています。

現在のiptables設定スクリプト

...
## [inppp] default rules
## - disallow some icmp inbound messages
iptables -A inppp -p icmp --icmp-type echo-request -j logdrop
iptables -A inppp -p icmp --icmp-type redirect -j logdrop
## - allow already used connections
iptables -A inppp -m state --state ESTABLISHED,RELATED -p tcp -j ACCEPT
iptables -A inppp -m state --state ESTABLISHED,RELATED -p udp -j logaccept
iptables -A inppp -m state --state ESTABLISHED,RELATED -p icmp -j logaccept

## [outppp] default rules
iptables -A outppp -m state --state ESTABLISHED,RELATED -p tcp -j ACCEPT
iptables -A outppp -m state --state ESTABLISHED,RELATED -p udp -j logaccept
iptables -A outppp -m state --state ESTABLISHED,RELATED -p icmp -j logaccept
iptables -A outppp -m state --state NEW -p tcp -j ACCEPT
iptables -A outppp -m state --state NEW -p udp -j logaccept
iptables -A outppp -m state --state NEW -p icmp -j logaccept
...

意図せず侵入を許したパケットは通過してしまうので、outboundに"ESTABLISHED,RELATED"を設定するのは少し問題なのかもしれません。 外部からのSSH接続などinboundを追加するタイミングで個別にoutboundを設定するよう変更するかな。

icmpは到達不可をちゃんと伝えるには必要そうだけど利便性の問題でたぶん必須ではないのだと思います。

0 件のコメント: