WindowsでMTU計測

# MTU計測バッチファイル：Windowsバッチファイルでハマる
こちらの「[Linux版MTU計測スクリプト](https://qiita.com/infinite1oop/items/5138f8827d6ad902c976)」の続きで、Windowsバッチファイルを作ることにした。WindowsとLinuxのpingでは、DF(Don't fragment)ビット用のオプション指定が異なる、バッチ（スクリプト）の文法が異なるだけなのだが、バッチファイル作成時に少々はまったので、記録することにした。すべて基本的なことかもしれない。

## はまった内容
てこずった内容が下記。部分的に説明。
```
@echo off
rem if 条件1 or 条件2 .... が存在しない
if "%~1"=="" (
  echo IPアドレスを指定してください
  exit /b
) else if "%~2"=="" (
  echo 送信サイズを指定してください
  exit /b
)
```
まず、バッチファイルでは、if文内に条件を複数記載できず、、、らしい。なので、if elseが多数発生する。

```
set ip=%1%
set /a first=%2%

rem echo %1% -f -l %2% -n 2  引数をそのまま使うとNG
echo %1% -f -l %2% -n 2
rem echo %ip% -f -l %first% -n 2  引数を変数に代入するとOK
echo %ip% -f -l %first% -n 2
```
IPアドレスや最初にトライするPayloadサイズを引数（%1、%2）として渡すのであるが、そのまま実行するとNGとなる。ここのechoの結果は下記となる（calcMtu00がバッチファイル）。

```
I:\>calcMtu00 8.8.8.8 1440
8.8.8.82 -n 2
8.8.8.8 -f -l 1440 -n 2
```

Windowsでは、”-f”がDFビットオプション、”-l”がPayloadサイズ指定オプションである。

```
set /a try=first
set /a okMTU=first
:doWhileLoop
  ping %ip% -f -l %try% -n 2
  set /a mtu=okMTU+28
  if %errorlevel% == 1 (
    rem １回目の実行時に変数testに正しい価が設定されない
    set /a test=okMTU+28
    echo. 
    if %okMTU% == %first% (
      echo ###  MTU is less than %mtu%  ###
      echo test = %test%
    ) else (
      echo ###  MTU is %mtu%  ###
      echo test = %test%
    )
    rem endlocal
  ) else (
    set /a okMTU=try
    set /a try=try+1
    goto doWhileLoop
  )
```

pingの実行結果を変数%errorlevel%で判断しており、エラー時にMTU値を計算して（IPヘッダ20バイト+ICMPヘッダサイズ8バイトを付加）処理を終了する。%errorlevel%の前後で計算した値が、1回目の実行時では異なっていた。下記は1回目の結果。

```
I:\>calcMtu00 8.8.8.8 1440

8.8.8.8 に ping を送信しています 1440 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 0、損失 = 2 (100% の損失)、

###  MTU is less than 1468  ###
test = 1518
```
前者の値が正しい。後者の値（test）は、前回実行時の結果（かもしれない）。2回目の結果は下記。

```
I:\>calcMtu00 8.8.8.8 1440

8.8.8.8 に ping を送信しています 1440 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 0、損失 = 2 (100% の損失)、

###  MTU is less than 1468  ###
test = 1468
```
2回目以降は同じ値となった（同じ引数を与えた場合）。

## 正式版
こちらが確実に動作するもの（今のところ）。
```bat:calcMtu1.bat
@echo off

if "%~1"=="" (
  echo IPアドレスを指定してください
  exit /b
) else if "%~2"=="" (
  echo 最初にトライする送信サイズを指定してください
  exit /b
)
set ip=%1%
set /a first=%2%

set /a try=first
set /a okMTU=first
:doWhileLoop
  ping %ip% -f -l %try% -n 2
  set /a mtu=okMTU+28
  if %errorlevel% == 1 (
    echo. 
    if %okMTU% == %first% (
      echo ###  MTU is less than %mtu%  ###
    ) else (
      echo ###  MTU is %mtu%  ###
    )
  ) else (
    set /a okMTU=try
    set /a try=try+1
    goto doWhileLoop
  )
```

### VPNなし
ある環境下での、VPN接続なし（通常ネットワーク接続時）の結果は下記となる。
```
C:\>calcMtu1 8.8.8.8 1424

8.8.8.8 に ping を送信しています 1424 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1424 時間 =10ms TTL=116
8.8.8.8 からの応答: バイト数 =1424 時間 =8ms TTL=116

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 8ms、最大 = 10ms、平均 = 9ms

8.8.8.8 に ping を送信しています 1425 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1425 時間 =14ms TTL=116
8.8.8.8 からの応答: バイト数 =1425 時間 =7ms TTL=116

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 7ms、最大 = 14ms、平均 = 10ms

8.8.8.8 に ping を送信しています 1426 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1426 時間 =5ms TTL=116
8.8.8.8 からの応答: バイト数 =1426 時間 =7ms TTL=116

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 5ms、最大 = 7ms、平均 = 6ms

8.8.8.8 に ping を送信しています 1427 バイトのデータ:
パケットの断片化が必要ですが、DF が設定されています。
パケットの断片化が必要ですが、DF が設定されています。

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 0、損失 = 2 (100% の損失)、

###  MTU is 1454  ###
```

### VPNあり
同じ環境下での、あるVPN経由の結果は下記となる。
```
C:\>calcMtu1 8.8.8.8 1344

8.8.8.8 に ping を送信しています 1344 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1344 時間 =20ms TTL=56
8.8.8.8 からの応答: バイト数 =1344 時間 =14ms TTL=56

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 14ms、最大 = 20ms、平均 = 17ms

8.8.8.8 に ping を送信しています 1345 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1345 時間 =13ms TTL=56
8.8.8.8 からの応答: バイト数 =1345 時間 =15ms TTL=56

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 13ms、最大 = 15ms、平均 = 14ms

8.8.8.8 に ping を送信しています 1346 バイトのデータ:
8.8.8.8 からの応答: バイト数 =1346 時間 =16ms TTL=56
8.8.8.8 からの応答: バイト数 =1346 時間 =22ms TTL=56

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 16ms、最大 = 22ms、平均 = 19ms

8.8.8.8 に ping を送信しています 1347 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。

8.8.8.8 の ping 統計:
    パケット数: 送信 = 2、受信 = 0、損失 = 2 (100% の損失)、

###  MTU is 1374  ###
```

VPN経由の場合、相当量のヘッダが追加され、MTU値が小さくなるのがわかる。

EOF