MTUを調べるスクリプト
ping で調べればよいのは知っているが、パラメータを手でいじりながら試すのはめんどくさい。だからスクリプトにしてみた。単純なスクリプトだとスタート時の値から順番に試すパターンになるけど時間がかかりすぎるわけで、その時間短縮のためにちょっとした工夫が入ってます。
また、MacOS と Linux の両方で使えます。パラメータの揺らぎはスクリプト内で吸収しています。
#!/bin/bash if [ $# -ne 1 ]; then echo "usage: $0 [target IP]" exit 1 fi # 初期値、増分 mtu_start=800 mtu_delta=1 mtu_size=$mtu_start mtu_error=0 retval=0 testcount=1 uname=$( uname ) pingopt="-q -M do -c 1 -s" if [ "$uname" == "Darwin" ]; then pingopt="-t 1 -Q -q -D -c 1 -s" else pingopt="-q -M do -c 1 -s" fi while [ 1 ]; do # ping で MTU をテストする。 #ping -q -M do -c 1 -s $(( mtu_size - 28 )) $1 >/dev/null ping $pingopt $(( mtu_size - 28 )) $1 >/dev/null 2> /dev/null retval=$? datetime=$( date +"%Y/%m/%d %H:%M:%S" ) if [ $retval -eq 0 ]; then # if [ $retval -eq 1 ]; then # 設定したMTUで ping が通る場合の処理。 echo "datetime:$datetime status:OK MTU:$mtu_size" mtu_max=$mtu_size # MTU が通らない値が分かっている場合は # 通る値と通らない値の中間をテストする。 # 通らない値が不明の場合はテスト区間を倍に広げる。 if [ $mtu_error -ne 0 ]; then mtu_delta=$(( (mtu_max + mtu_error) / 2 - mtu_max )) else mtu_delta=$(( mtu_delta * 2 )) fi # 検査範囲が 0 に収束したら終了 if [ $mtu_delta -eq 0 ]; then echo "result:$mtu_max" exit; fi else # 設定したMTUが通らない場合の処理。 mtu_error=$mtu_size echo "datetime:$datetime status:ng MTU:$mtu_size" # 次のテストでは通る値と通らない値の中間をテストする mtu_delta=$(( (mtu_max + mtu_error) / 2 - mtu_max )) fi mtu_size=$(( $mtu_max + $mtu_delta )) done
また、同じ処理をコマンドプロンプトで動く版で書いたのがこちら。
@echo off if "%1" == "" goto ERROR set mtu_start=800 set mtu_delta=1 set mtu_size=%mtu_start% set mtu_error=0 set mtu_max=0 set retval=0 set testcount=1 :LOOP rem ping で MTU をテストする。 rem 65536 以上の値は評価しない if %mtu_size% lss 65536 ( set /A mtu_testsize="( mtu_size - 28 )" ping -f -l %mtu_testsize% -n 1 %1 | find "パケットの断片化" > NUL set /A retval=%ERRORLEVEL% ) else ( set /A retval=0 ) if not %retval% == 0 ( echo status:OK MTU:%mtu_size% set mtu_max=%mtu_size% rem MTU が通らない値が分かっている場合は rem 通る値と通らない値の中間をテストする。 rem 通らない値が不明の場合はテスト区間を倍に広げる。 if not %mtu_error% == 0 ( set /A mtu_delta="(mtu_max + mtu_error)/2" set /A mtu_delta="(mtu_delta - mtu_max)" ) else ( set /A mtu_delta=%mtu_delta% * 2 ) if %mtu_delta% == 0 ( echo result:%mtu_max% goto EOF ) ) else ( set mtu_error=%mtu_size% echo status:ng MTU:%mtu_size% set /A mtu_delta="(mtu_max + mtu_error)/2" set /A mtu_delta="(mtu_delta - mtu_max)" ) set /A mtu_size=%mtu_max% + %mtu_delta% goto LOOP :ERROR echo usage: scan_mtu.bat [target IP] :EOF
そして実行例はこちら。
$ ./scanmtu.sh 192.168.0.1 status:OK MTU:1000 status:OK MTU:1002 status:OK MTU:1006 status:OK MTU:1014 status:OK MTU:1030 status:OK MTU:1062 status:OK MTU:1126 status:OK MTU:1254 status:ng MTU:1510 status:OK MTU:1382 status:OK MTU:1446 status:OK MTU:1478 status:OK MTU:1494 status:ng MTU:1502 status:OK MTU:1498 status:OK MTU:1500 status:ng MTU:1501 status:OK MTU:1500 result:1500 $ ./scanmtu.sh 8.8.8.8 status:OK MTU:1000 status:OK MTU:1002 status:OK MTU:1006 status:OK MTU:1014 status:OK MTU:1030 status:OK MTU:1062 status:OK MTU:1126 status:OK MTU:1254 status:ng MTU:1510 status:OK MTU:1382 status:OK MTU:1446 status:ng MTU:1478 status:ng MTU:1462 status:OK MTU:1454 status:ng MTU:1458 status:ng MTU:1456 status:ng MTU:1455 status:OK MTU:1454 result:1454 $ ./scanmtu.sh localhost status:OK MTU:1000 status:OK MTU:1002 status:OK MTU:1006 status:OK MTU:1014 status:OK MTU:1030 status:OK MTU:1062 status:OK MTU:1126 status:OK MTU:1254 status:OK MTU:1510 status:OK MTU:2022 status:OK MTU:3046 status:OK MTU:5094 status:OK MTU:9190 status:ng MTU:17382 status:OK MTU:13286 status:OK MTU:15334 status:OK MTU:16358 status:ng MTU:16870 status:ng MTU:16614 status:ng MTU:16486 status:OK MTU:16422 status:ng MTU:16454 status:ng MTU:16438 status:OK MTU:16430 status:OK MTU:16434 status:OK MTU:16436 status:ng MTU:16437 status:OK MTU:16436 result:16436