TT Lab
はじめる
学ぶ 学習パス コース

ネットワーク基礎 — Linux VM で手を動かす

ping が実際に送るものと MTU

TT Labで続きを見る

このラボはVM上で動きます

2つのネームスペース(pa・pb)をvethでつなぎ、その上でICMPとUDPを見ます。2つ目のラボと同じ形ですが、今回の主役はフレームではなく、パケットサイズとエラーメッセージです。

目標

pingが送るICMP echoを捕まえ、MTUを超えたパケットがフラグメント化されたり拒否されたりする様子を見て、UDPが閉じたポートをどう知らせるか(ICMP port unreachable)を確認します。

なぜ重要なのか

「pingは通るのに、大きなファイルだけ止まる」「SSHは通るのに、Webページが半分しか表示されない」。ほとんどいつもMTUです。小さなパケットは通り、大きなパケットだけがどこかで捨てられます。DFビットのためフラグメント化もできず、そのことを知らせるICMPをファイアウォールがブロックしているのが、よくある事故の形です。VPN・オーバーレイネットワーク・トンネルがヘッダーを付け足すたびにこの問題が再発するので、1500と1472がどこから来る数字なのかを、手で数えてみます。

ステップ

  1. ネームスペースpa・pbとvethpa0↔pb0を作成し、10.60.0.1/24・10.60.0.2/24を付けて、お互いにpingが通るようにしてください。
  2. paからpbへping -c 3を実行した結果を /root/icmp/ping.txt に保存してください。
  3. pa0でICMPをキャプチャしながらpingを1回送り、echo requestとecho replyを含む出力を /root/icmp/echo.txt に保存してください。
  4. ping -M doでフラグメント化を禁止したままサイズを変えて、通過する最大ペイロードを探し、/root/icmp/mtu.txt にmtu=・max_payload=の2行と失敗メッセージを保存してください。
  5. フラグメント化を許可したまま、ペイロード3000バイトのpingをキャプチャして、フラグメント化されたパケットが見える出力を /root/icmp/frag.txt に保存してください。
  6. pbでUDPポート9001を待ち受けるnc -luを起動し(受信したものは /root/icmp/udp.txt へ)、paからhello-udpを送ってください。
  7. paからpbの閉じたUDPポート9999へデータグラムを送りながらキャプチャして、udp port 9999 unreachableが見える出力を /root/icmp/unreach.txt に保存してください。
  8. pa0のMTUを1400に下げ、/root/icmp/report.md に、mtu=1400・max_payload=の2行と、その数がなぜそうなるのか、そしてフラグメント化がなぜ問題になるのかを書いてください。

参考

2台をつなぐ

ネームスペースpa・pbとvethpa0↔pb0を作成し、10.60.0.1/24・10.60.0.2/24を付けて、お互いにpingが通るようにしてください。

2つ目のラボと同じ順序です: netns add → link add veth → link set netns → addr add → link set up(loを含む)。ip netns exec pa ping -c 1 10.60.0.2で確認します。

pingを3回

paからpbへping -c 3を実行した結果を /root/icmp/ping.txt に保存してください。

ip netns exec pa ping -c 3 10.60.0.2 > /root/icmp/ping.txt。統計の行に3 receivedがある必要があります。time=が往復時間(RTT)です。

echoを捕まえる

pa0でICMPをキャプチャしながらpingを1回送り、echo requestとecho replyを含む出力を /root/icmp/echo.txt に保存してください。

ip netns exec pa timeout 5 tcpdump -i pa0 -nn -l icmp > /root/icmp/echo.txt 2>&1 &のあと1秒待って、ip netns exec pa ping -c 1 10.60.0.2を実行します。ファイルに、ICMP echo requestとICMP echo replyが1行ずつある必要があります。

フラグメント化の禁止

ping -M doでフラグメント化を禁止したままサイズを変えて、通過する最大ペイロードを探し、/root/icmp/mtu.txt にmtu=・max_payload=の2行と失敗メッセージを保存してください。

ip -n pa link show pa0のmtuは1500です。ping -M do -s 1472は通り、-s 1473はmessage too long, mtu=1500で失敗します。失敗したpingの出力(2>&1)を、2行の下に貼り付けてください。

フラグメント化させる

フラグメント化を許可したまま、ペイロード3000バイトのpingをキャプチャして、フラグメント化されたパケットが見える出力を /root/icmp/frag.txt に保存してください。

キャプチャを起動して、ip netns exec pa ping -c 1 -s 3000 10.60.0.2を実行します。3028バイトのパケットが1500バイトのフラグメントに分かれ、最初のフラグメントだけがICMP echo request、残りはip-proto-1と表示されます(ICMPヘッダーが最初のフラグメントにしかないためです)。

UDPにはハンドシェイクがない

pbでUDPポート9001を待ち受けるnc -luを起動し(受信したものは /root/icmp/udp.txt へ)、paからhello-udpを送ってください。

サーバー: ip netns exec pb setsid timeout 20 nc -lu 10.60.0.2 9001 > /root/icmp/udp.txt 2>&1 < /dev/null &。クライアント: echo hello-udp | ip netns exec pa nc -u -q 1 -w 1 10.60.0.2 9001。ファイルにhello-udpが入っていれば完了です。

閉じたUDPポートはICMPで答える

paからpbの閉じたUDPポート9999へデータグラムを送りながらキャプチャして、udp port 9999 unreachableが見える出力を /root/icmp/unreach.txt に保存してください。

キャプチャフィルターを'icmp or udp'にして、echo x | ip netns exec pa nc -u -q 1 -w 1 10.60.0.2 9999を実行します。UDPデータグラムの行の後に、ICMP 10.60.0.2 udp port 9999 unreachableが続きます。

MTUを下げてまとめる

pa0のMTUを1400に下げ、/root/icmp/report.md に、mtu=1400・max_payload=の2行と、その数がなぜそうなるのか、そしてフラグメント化がなぜ問題になるのかを書いてください。

ip -n pa link set pa0 mtu 1400のあと、ping -M do -s 1372は通り、-s 1373は通りません。max_payloadは1400 - 28です。説明には、MTUとフラグメント(またはfragment)という語を含める必要があります。