ほっしーの技術ネタ備忘録

技術ネタの備忘録です。基本的に私が忘れないためのものです。他の人の役にも立つといいなぁ。

令和にもなって MTU とか MSS とかを思い出した日

ある日から突然届くようになった daily メールの一部分。

Mail in local queue:
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
4E0851D6401    2276 --- J** 18 22:39:25  ****@*******.com
(conversation with mx01.******.jp[**.**.**.**] timed out while sending end of data -- message may be sent more than once)
                                         *****@***.jp

ほっほー。また postfix でメールが滞留してるんかー。 postqueue -f ぽちーっ。

……あれ?なんで消えないの??? ここからが長かったのであった。

まずは定石通り問題の切り分けから。

  1. まず問題の SMTP サーバに telnet で接続 → 問題なく接続成功
  2. そのまま SMTP をしゃべってみる → 特に応答は問題なさそう
  3. tcpdump しながら再送してみる → 確かに DATA の所で突然応答が消えるな?
  4. 受信者に断ってから telnet でテストメールを送ってみる → え、普通に届いちゃった……
  5. sendmail コマンドで postfix からテストメールを送信 → やっぱり届く????

該当のメールだけなぜか再送できない!!!!!!!

もう知らない。postfix さんのことなんて知らない! スパムフィルタかウイルスチェッカか IDS とかに突然 TCP コネクション切られてるんでしょ!

半泣きになりながらあれこれ調べた結果、ipfw の設定をミスって icmptype 3 を deny にしてたことが判明。

あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙ん゙????

以下、FreeBSD のソースを読んだ結果。

  • 通常、NIC の MTU は 1,500、 net.inet.tcp.path_mtu_discovery=1 になっている
  • すると TCPプロトコルスタックは MTU から算出した MSS を使い、IP ヘッダの Don't Fragment を立てる
  • 問題なく届けばそれでよし、ダメな場合は ICMP 3.4 が届いて経路上の最低 MTU が分かる
  • それを見て MSS を再調整して再送

これが本来想定されている動作。ここで私は ICMP 3.4 を ipfw でドロップしていたため、 「ICMP 3.4 が届かないってことは MTU は問題ないのに、なんで ACK が返ってこないんだろうねぇ?」 というカーネルおじさんのお気持ちがわかる。

いやわからねぇよ。

ていうか MTU とか MSS なんて、 ブロードバンド☆ とか言ってた時代にいじったっきり すっかり忘れてたテクノロジーだわ。

という訳で、ICMP 3.4 をちゃんと allow ルールとして追加。

…… postqueue -f はい、流れてったー。

ちなみに、 net.inet.tcp.path_mtu_discovery=0 の場合はその辺は経路のノードに適当におまかせするので、

  • MTU?NIC に 1,500 ってついてるからそれでええんやないか?
  • Don't Fragment をつけずに IP パケット投げれば途中で分割とかいい感じにやってくれるんとちゃう?

みたいな感じになるので、これはこれで動きそう。 という訳で結論。

net.inet.tcp.path_mtu_discovery=1 にするなら ICMP 3.4 をちゃんと通しましょう。

それはそう。でもまさかレイヤー3まで潜るハメになるとは思わんかった…… 今はもう令和やぞ。MTU とか MSS の自動調整が効いてない状態だったとか思わんかったし、 なんならどうして突然動かなくなった(最近まで普通に動いてた)んや??

インターネットの気持ち何も分からん。