MTU計測 Script＋α

# MTU計測ツール＋αの話
Linuxにて、pingオプション”-M do”を付加すると、DF(Don't fragment)ビットがIPヘッダにセットされる。これを利用して、MTUを計測するツール（Script）を作成してみた＋αの話。

## 早速Script
Script（ファイル名：calcMtu2）中にコメント記載。

```bash:calcMtu2
#!/bin/bash
function exit_func() {       # 実行中に中断された時にCallされる関数
    echo "Done by ctrl-c, etc."
    exit 1
}
trap 'exit_func' 1 2 3 15    # ctrl-cなどのSIGNAL受信時に上記”exit_func”をCall

first_mtu=1420               # 最初にトライするPayloadの初期値
ip="8.8.8.8"                 # 宛先の初期値
arg1=$1                      # 第1引数を格納
arg2=$2                      # 第2引数を格納

if [ -n "$arg1" ]; then
    first_mtu=$arg1          # 第1引数を最初にチェックするPayload値に設定
    # Todo: Error Check      # 入力エラーチェック未サポート
fi
if [ -n "$arg2" ]; then
    ip=$arg2                 # 第2引数を宛先に設定
    # Todo: Error Check      # 入力エラーチェック未サポート
fi

try_mtu=$first_mtu
ok_mtu=0
while true
do
    echo ""
    echo "<< Try payload size =" $try_mtu ">>"
    ping -s $try_mtu -M do $ip -c 2    # DFビットをセットしてping実行
    if [ $? -eq 1 ]; then              # ping NG（シェル変数である直前コマンドの実行結果利用）
		if [ $((ok_mtu)) -eq 0 ]; then # 最初のトライでNG
	    	echo "### MTU is less than "$((try_mtu+28))". ###"  # 最初のトライ値（+28（IPヘッダサイズ+ICMPヘッダサイズ））より小さいMTU値であることを表示
		else
	    	echo "### MTU =" $((ok_mtu+28)) "###"  # MTU値を表示
		fi
		break
    fi
    ok_mtu=$((try_mtu))     # ping OK時にはトライしたPayload値を格納
    try_mtu=$((try_mtu+1))  # 次にトライするPayload値（+1）をセット
done
```

## 検証
### 通常
本Scriptの実行状況を下記する。
```
$ bash calcMtu2 1420 1.1.1.1

<< Try payload size = 1420 >>
PING 1.1.1.1 (1.1.1.1) 1420(1448) bytes of data.
1428 bytes from 1.1.1.1: icmp_seq=1 ttl=57 time=12.7 ms
1428 bytes from 1.1.1.1: icmp_seq=2 ttl=57 time=8.96 ms

....

<< Try payload size = 1426 >>
PING 1.1.1.1 (1.1.1.1) 1426(1454) bytes of data.
1434 bytes from 1.1.1.1: icmp_seq=1 ttl=57 time=6.96 ms
1434 bytes from 1.1.1.1: icmp_seq=2 ttl=57 time=11.4 ms

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 6.957/9.189/11.421/2.232 ms

<< Try payload size = 1427 >>
PING 1.1.1.1 (1.1.1.1) 1427(1455) bytes of data.
ping: sendmsg: Message too long
ping: sendmsg: Message too long

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1001ms

### MTU = 1454 ###
```
pingのPayloadサイズ1420から開始。1427でエラーとなっている。なので、1454(=1426+28)がMTU値となる。

### VPN経由だと
あるVPN経由で同様のことを実施してみる。
```
$ bash calcMtu2 1420 1.1.1.1

<< Try payload size = 1420 >>
PING 1.1.1.1 (1.1.1.1) 1420(1448) bytes of data.
ping: sendmsg: Message too long
ping: sendmsg: Message too long

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1001ms

### MTU is less than 1448. ###
```
同じく1420から開始しようとしたが、すぐにエラーとなった。なので、かなり小さい値1320を開始値として実行。
```
$ bash calcMtu2 1320 1.1.1.1

<< Try payload size = 1346 >>
PING 1.1.1.1 (1.1.1.1) 1346(1374) bytes of data.
1354 bytes from 1.1.1.1: icmp_seq=1 ttl=53 time=15.9 ms
1354 bytes from 1.1.1.1: icmp_seq=2 ttl=53 time=17.5 ms

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 15.885/16.715/17.545/0.830 ms

<< Try payload size = 1347 >>
PING 1.1.1.1 (1.1.1.1) 1347(1375) bytes of data.

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1001ms

### MTU = 1374 ###
```
MTU値は1374となった。VPNなし時の1454と比べて、トンネリングによるオーバーヘッドが相当存在することがわかる。

### エラーも確認
pingのPayloadサイズを大きめに指定して、エラーが表示されることを確認。
```
$ bash calcMtu2 1450 1.1.1.1

<< Try payload size = 1450 >>
PING 1.1.1.1 (1.1.1.1) 1450(1478) bytes of data.
ping: sendmsg: Message too long

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1005ms

### MTU is less than 1478. ###
```

## +α
### DFビットをWiresharkで確認
”-M do”オプションなし時にはDFビットがない。

![DFなしのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/c3c9949f-5c3d-2f00-065e-b40d4c43c80d.png)

”-M do”オプションあり時にはDFビットがある。

![DFありのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/830c4f0d-0af6-ddb0-8838-5346ebf73e90.png)

### ネットワークインターフェースのMTUを変更
変更前は1500となっており、まずは、この状態で、Payloadサイズ1400バイトを指定してpingを実行。

```
$ ip link
...

3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DORMANT group default qlen 1000
    link/ether 6c:40:08:xx:yy:zz brd ff:ff:ff:ff:ff:ff
...

$ ping 192.168.10.1 -s 1400 -M do -c 1
PING 192.168.10.1 (192.168.10.1) 1400(1428) bytes of data.
1408 bytes from 192.168.10.1: icmp_seq=1 ttl=64 time=3.16 ms
```

次に、MTU値を1280に変更し、同じ条件でpingを実行。

```
$ sudo ip link set wlp2s0 mtu 1280
$  ip link
...

3: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1280 qdisc fq_codel state UP mode DORMANT group default qlen 1000
    link/ether 6c:40:08:xx:yy:zz brd ff:ff:ff:ff:ff:ff
...

$ ping 192.168.10.1 -s 1400 -M do -c 1
PING 192.168.10.1 (192.168.10.1) 1400(1428) bytes of data.
ping: local error: message too long, mtu=1280
```

Payloadサイズが大きすぎると、MTU値が表示されて、エラーとなる。

EOF