WSL2でgit pullをするとgnutls_handshake() failed: Error in the pull function.になる問題の対処法

## どういう問題？

WSL2でgit pullコマンドを実行したときに下記のようなエラーが出た。

```sh
$ git pull
fatal: unable to access 'https://github.com/hoge/fuga/': gnutls_handshake() failed: Error in the pull function.
```

## 環境

WSL2 Distribution: Ubuntu-20.04
git version: 2.38.1

## 原因

「gnutls_handshake() failed: Error in the pull function.」でググると`git config`の問題やら`proxy`やら出てきますが、configはすべて設定済みで不備もないし、proxyは特にプロキシサーバーを経由させるようなこともやってないしなんだろうなと途方に暮れていました。

根気強く調べていると、WSLのissueで下記のようなやり取りがありました。

https://github.com/microsoft/WSL/issues/5346

そこに書いてあった内容でベストプラクティスを見つけました。  要約すると下記のような感じです。


> 問題はVPNのMTU値とLinux側のMTU値の不一致にあります。
まず、Windows PowerShell (管理者として実行)で`netsh interface ipv4 show subinterfaces`を実行し、最初の行に注目してください。これは、VPN で許可される MTU の大きさを示しています。
次に、Linux (WSL2内部) のコンソールで`ip adrr`を実行し、eth0'で始まる行に注目してください。そのMTUは、上記のものと一致するか、より低いものでなければなりません。
私の場合、LinuxのMTUの方が高かったです。

なるほど、実際に確認してみると

```bat
PS > netsh interface ipv4 show subinterfaces

   MTU  MediaSenseState  受信バイト   送信バイト  インターフェイス
------  ---------------  -----------  ----------  -----------------
4294967295                1          0     367360  Loopback Pseudo-Interface 1
  1500                1  24369484190  752500695  イーサネット 2
  1404                1    1008731   46221951  vEthernet (WSL)
```

```sh
$ ip addr                                                                                                            
...
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    ...
...
```

あー、なんとなく分かった。
VPN側だとMTU値がWSL用に1404で割り当てられているけど、WSLでは1500になっていて`VPN < WSL`でダメって感じかな？

## 対処法

対処法もissueに書いてありました。

> 以下のコマンドで即座に解決しました。
`sudo ip link set dev eth0 mtu 1400` (MTU値をVPNに合わせて更新してください)
私はこれを ~/.bashrc の中に入れて、自分のアカウントの sudoers NOPASSWD の中に /usr/sbin/ip を入れています。

とりあえずWSL2で叩いてgit pullできるかやってみましょうか。

```sh
$ sudo ip link set dev eth0 mtu 1404                                                                                 
$ git pull
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 4 (delta 3), reused 4 (delta 3), pack-reused 0
Unpacking objects: 100% (4/4), 391 bytes | 391.00 KiB/s, done.
From https://github.com/hoge/fuga
   b91f4ab..507018d  main     -> origin/main
Updating b91f4ab..507018d
Fast-forward
 "books/\343\200\220Python\343\200\221pytest\343\201\247\347\237\245\343\201\243\343\201\246\343\201\212\343\201\215\343\201\237\343\201\204\343\201\223\343\201\250.md" | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
```

出来ましたね！
あとは起動時にこのコマンドが走れば良いので、私は下記のような処理を`fish_greeting.fish`に追記しています。
(bashやzshの方は.bashrcや.zshrcに追記すれば良いと思います)

```fish
echo {sudo password} | sudo -S ip link set dev eth0 mtu 1404 > /dev/null 2>&1
```

## おまけ(MTUとは？)

下記の記事が参考になりました。

https://www.nic.ad.jp/ja/basics/terms/mtu.html

抜粋すると

> MTU (Maximum Transmission Unit)とは、 ノードが隣接したネットワークへ、1回の通信で転送可能な最大のデータグラムサイズです。
TCP/IPの階層モデルにおいては、 リンク層の通信メディア(Ethernetなど)の違いによってMTUのサイズが異なるため、 その上位のインターネット層におけるIPデータグラム(IPパケット)のサイズもこのMTUに合わせて決められます。 さらにトンネリングなどの追加ヘッダを利用する通信方式を利用する場合には、 増えたヘッダの分だけペイロードを減らす必要があるので、 MTUがネットワーク層において、より小さな値となります。

なるほどね、なんか昔に勉強したような…。「マスタリングTCP/IP―入門編―」もう一度読み直しましょうか…。