@ledsun blog

無味の味は佳境に入らざればすなわち知れず

VPN接続するとWSLからのHTTPS接続に失敗する

現象

WindowsVPN接続をして、WSLからHTTPS接続しようとすると

►curl -v https://www.google.com/ 2>&1 | head -n 20

* IPv6: 2404:6800:4004:81d::2004
* IPv4: 142.250.193.196
*   Trying 142.250.193.196:443...
* Connected to www.google.com (142.250.193.196) port 443
* ALPN: curl offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs

で固まります。

VPN接続していなければ繋がります。 また、PowerShellcurl -v https://www.google.com/は通ります。 どうやらWSLとVPNの組み合わせに何かあるようです。

原因

sudo ip link set dev eth0 mtu 1350を実行すると通るようになります。 MTUの問題のようです。

以下、私のおおざっぱな理解です。

Windows上のVPNクライアントがVPN接続しています。 WSLはVPNの存在を知りません。 WSLは1500バイトでパケットを送ります。 Windows上のVPNクライアントはカプセル化します。 1500を超えるためパケットは分割されます。

通信経路上のいずれかの機器が分割されたパケットを拒否する可能性があります。 また機器がパケット分割を回避するためICMP Frag-Neededを返しているのかもしれません。 が、WindowsのNATが中継しないためか、WSLは適切なパケットサイズで送っているつもりで理解できないためか検知できないようです。

そこで手動でMTUを設定します。 VPNカプセル化してもパケット分割が起きなくなります。

対処

永続化するにはWSLの /etc/wsl.conf に設定します。

[network]
mtu=1350

確認するには、 Windows側でwsl --shutdownしてWSLを再起動します。

MTU探訪

実際は何が障害なのでしょうか?

Windows VPNなし

ます、WindowsからMTUを計測してみます。 ping google.com -f -l 1432コマンドを使います。

PS C:\Windows\System32> ping google.com -f -l 1432

google.com [172.217.31.174]に ping を送信しています 1432 バイトのデータ:
172.217.31.174 からの応答: バイト数 =1432 時間 =6ms TTL=116
172.217.31.174 からの応答: バイト数 =1432 時間 =8ms TTL=116

172.217.31.174 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 6ms、最大 = 8ms、平均 = 7ms
Ctrl+C
PS C:\Windows\System32> ping google.com -f -l 1433

google.com [172.217.31.174]に ping を送信しています 1433 バイトのデータ:
192.168.1.1 からの応答: パケットの断片化が必要ですが、DF が設定されています。

1432バイトが限界です。これはIPヘッダー20バイトとICMPヘッダ8バイトを足した1460バイトです。 これがVPNを使っていない状態のMTU最適値です。

Windows VPNあり

次に、VPNに接続すると

PS C:\Windows\System32> ping google.com -f -l 1323

google.com [142.250.196.142]に ping を送信しています 1323 バイトのデータ:
パケットの断片化が必要ですが、DF が設定されています。
パケットの断片化が必要ですが、DF が設定されています。

142.250.196.142 の ping 統計:
    パケット数: 送信 = 2、受信 = 0、損失 = 2 (100% の損失)、
Ctrl+C
PS C:\Windows\System32> ping google.com -f -l 1322

google.com [142.250.196.142]に ping を送信しています 1322 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。

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

1322バイトが限界です。 IPヘッダとICMPヘッダを足して1350バイトです。 1350がVPN接続時のMTU最適値と見て良さそうです。

まあ、でもタイムアウト気になりますよね。

PS C:\Windows\System32> ping google.com -f -l 1000

google.com [172.217.31.174]に ping を送信しています 1000 バイトのデータ:
172.217.31.174 からの応答: バイト数 =1000 時間 =51ms TTL=116
172.217.31.174 からの応答: バイト数 =1000 時間 =20ms TTL=116

172.217.31.174 の ping 統計:
    パケット数: 送信 = 2、受信 = 2、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 20ms、最大 = 51ms、平均 = 35ms
Ctrl+C
PS C:\Windows\System32> ping google.com -f -l 1001

google.com [172.217.31.174]に ping を送信しています 1001 バイトのデータ:
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。
要求がタイムアウトしました。

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

1000バイト境界で何かいます。 謎の挙動です。

WSL VPNなし

sudo ip link set dev eth0 mtu 1500を実行して、MTUを1500に戻しておきます。

Linuxでは、ping -M do -s 1432 google.comコマンドを使います。

ledsun@xps24nov:/m/c/U/led_l►ping -M do -s 1432 google.com

PING google.com (142.250.193.206) 1432(1460) bytes of data.
1440 bytes from del11s17-in-f14.1e100.net (142.250.193.206): icmp_seq=1 ttl=115 time=7.75 ms
1440 bytes from del11s17-in-f14.1e100.net (142.250.193.206): icmp_seq=2 ttl=115 time=10.6 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 7.747/9.154/10.561/1.407 ms
ledsun@xps24nov:/m/c/U/led_l►ping -M do -s 1433 google.com

PING google.com (142.250.194.174) 1433(1461) bytes of data.
From ntt.setup (192.168.1.1) icmp_seq=1 Frag needed and DF set (mtu = 1460)
ping: local error: message too long, mtu=1460
^C
--- google.com ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1000ms

1432境界です。

WSL VPNあり

1322境界があると思うじゃないですか?

ledsun@xps24nov:/m/c/U/led_l[1]►ping -M do -s 1323 google.com
PING google.com (172.217.31.174) 1333(1361) bytes of data.

で固まります。 つまりICMP Frag-Neededは受け取れません。

1000の境界を試すと

ledsun@xps24nov:/m/c/U/led_l[1]►ping -M do -s 1000 google.com
PING google.com (142.250.194.174) 1000(1028) bytes of data.
1008 bytes from del12s06-in-f14.1e100.net (142.250.194.174): icmp_seq=1 ttl=115 time=21.5 ms
1008 bytes from del12s06-in-f14.1e100.net (142.250.194.174): icmp_seq=2 ttl=115 time=21.5 ms
1008 bytes from del12s06-in-f14.1e100.net (142.250.194.174): icmp_seq=3 ttl=115 time=22.9 ms
1008 bytes from del12s06-in-f14.1e100.net (142.250.194.174): icmp_seq=4 ttl=115 time=26.1 ms
1008 bytes from del12s06-in-f14.1e100.net (142.250.194.174): icmp_seq=5 ttl=115 time=24.5 ms
^C
--- google.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 21.459/23.273/26.108/1.797 ms
ledsun@xps24nov:/m/c/U/led_l►ping -M do -s 1001 google.com
PING google.com (142.250.194.174) 1001(1029) bytes of data.

これはWindowsと一致しています。 ICMP Frag-Neededが受け取れないのはWindowsと一致していません。 WSL固有の現象のようです。

どうやらWindowsのNATがそういう性質らしいです。よくわかりません。

また、いまのところMTUは1350が良さそうです。 ですが1000バイト境界の謎挙動も気になる所です。