SSHはTCPなのに、なぜTailscaleはUDPで通信できるのか?

Tailscaleを使って自宅LANへ接続する設定をしていたときに、少し疑問に思ったことがあります。

SSHやRDPはTCP通信です。
それなのに、TailscaleやWireGuardはUDPを使って通信しています。

「TCPの通信をするなら、VPN側もTCPでよいのでは?」と思ったのですが、調べてみると、VPNでUDPが使われるのにはきちんと理由がありました。

SSHやRDPはTCP通信

SSHやRDP、HTTPSなどは基本的にTCPを使います。

TCPは、通信の信頼性を確保する仕組みを持っています。

例えば、

  • データが届いたか確認する
  • 届かなかったデータを再送する
  • 順番どおりに並べる

といった処理を行います。

そのため、SSHやファイル転送のように「データが正しく届くこと」が重要な通信に向いています。

TailscaleやWireGuardはUDPを使う

一方で、Tailscaleの内部で使われているWireGuardはUDPを使います。

ここで重要なのは、SSHのTCP通信をそのままUDPに置き換えているわけではない、という点です。

実際には、

SSH
↓
TCP
↓
Tailscale / WireGuard
↓
UDP
↓
インターネット

という形になります。

つまり、アプリケーション側ではTCP通信のままです。
そのTCP通信をVPNで暗号化して、外側をUDPで運んでいます。

イメージとしては、

SSHのTCP通信 = 荷物
WireGuardのUDP通信 = 配送用の箱

のようなものです。

なぜTCPではなくUDPなのか

最初は、TCPの方が再送や順番保証があるので、VPNにも向いているのではないかと思いました。

しかし、VPNの外側までTCPにすると問題が起きやすくなります。

例えば、

SSH
↓
TCP
↓
VPN
↓
TCP
↓
インターネット

のようになります。

この場合、内側のTCPと外側のTCPの両方が、

  • 再送
  • 順番制御
  • 速度調整

を行います。

その結果、パケットロスが発生したときに処理が二重になり、通信が詰まったり、遅延が大きくなったりします。

これを TCP over TCP問題 と呼びます。

UDPなら内側のTCPに任せられる

UDPには、TCPのような再送や順番保証はありません。

そのため、

SSH
↓
TCP
↓
WireGuard
↓
UDP

のようにすると、通信の信頼性は内側のTCPに任せることができます。

外側のVPNは、余計な再送制御をせず、暗号化したパケットを運ぶだけです。

そのため、VPNではUDPの方が効率が良くなります。

UDPでも大きなデータは送れるのか

UDPは1つのパケットで送れるサイズに上限があります。

ただし、SSHやRDPの通信全体を1つのUDPパケットで送るわけではありません。

実際には、通信はMTUに合わせて細かく分割されます。

大きなデータ
↓
小さなTCPパケット
↓
WireGuardのUDPパケット

という形で送信されます。

そのため、SSHやRDP、ファイル転送なども問題なく利用できます。

Tailscaleがつながりやすい理由

Tailscaleは、UDPホールパンチングという仕組みも使います。

通常、家庭用ルーターやモバイル回線のCGNAT環境では、外部から自宅の機器へ直接アクセスすることはできません。

しかしTailscaleでは、両方の端末が先に外向きの通信を行います。

ノートPC → 外へ通信
自宅ルーター → 外へ通信

そうすると、それぞれのルーターやNATに一時的な通信経路ができます。

Tailscaleはその情報を使って、端末同士が直接UDP通信できるようにします。

これがUDPホールパンチングです。

直接つながらない場合

環境によっては、UDPホールパンチングが成功しないこともあります。

その場合、TailscaleはDERPという中継サーバーを使います。

ノートPC
↓
DERP中継サーバー
↓
自宅ルーター

直接接続より速度は落ちますが、厳しいNAT環境でも接続できる可能性が高くなります。

まとめ

SSHやRDPはTCP通信ですが、TailscaleやWireGuardでは、そのTCP通信をVPNの中に包み、外側をUDPで運んでいます。

VPNでUDPが使われる主な理由は、

  • TCP over TCP問題を避けられる
  • 通信が軽くなる
  • UDPホールパンチングと相性が良い
  • CGNAT環境でも直接接続できる可能性がある

ためです。

最初は「TCPの通信なのに、なぜUDPで運べるのか?」と思いましたが、実際にはTCPをUDPに置き換えているのではなく、TCP通信をUDPの中に包んで運んでいる、という理解が近いと思います。

コメント