Shogo's Blog

Dec 28, 2012 - 1 minute read - UDP SSH

UDPのパケットをSSHを通してトンネルする

SSHには標準でTCPのトンネリング機能は付いているのですが, UDPはトンネリングしてくれません. なんとかできないものかと試行錯誤してみました.

TCP をトンネル

TCPのトンネリングの復習から. 以下のコマンドでクライアントの8080番ポートを,リモートの80番ポートに転送することができます.

ssh -L 8080:localhost:80 remote

SOCKS proxyとして動作させることも出来ます. ブラウザのプロキシとして設定すれば,リモートのサーバがすべての通信を中継してくれます.

ssh -D 8080 remote

UDP をトンネル

NetCatを使うと TCP/UDP の通信内容と標準入出力をつなげることが出来るらしいです. これを使って,クライアント側で UDP サーバを立て,その通信内容をSSH経由でリモートの UDP クライアントに送ってあげます. 最後にリモートからクライアント側へのパケットを名前付きパイプで転送してあげればトンネル完成です.

mkfifo tunnel
nc -ul 8080 < tunnel | ssh remote nc -u localhost 8080 > tunnel

Mosh をトンネル

なんでこんなことをしようと思ったかというと,Moshをファイヤーウォール越しに使いたかったから. MoshはUDPで通信しているので,SSHしか通らない環境では使えません. そこでUDPをSSHでトンネリングしてできないかとやって見ました. セッションの確立にSSHも使っているので,以下のようにして Mosh用のUDPトンネルと SSH用のTCPトンネルを作ります.

mkfifo tunnel
nc -ul 60000 < tunnel | ssh -L 10000:localhost:22 remote nc -u localhost 60000 > tunnel &
mosh -p 60000 --ssh="ssh -p 10000" localhost

外部からのSSH通信が遅かったので,Moshのローカルエコーでなんとかならないかと挑戦してみました. 実際の効果は未確認.またあとで試してみます.

追記

試してみました. 一応通信できることは確認したのですが,非常に不安定で頻繁に通信に失敗します.

NetCatがパケットの境界を出力しないので,パケットがズタズタに切り裂かれ, パケットのデコードに失敗してしまうようです.

回線が十分速い&UDPパケットが非常に小さいときにしか上手く動きません. NetCat のオプションを見てみましたがパケット境界の指定はできないようです. ここでの方法はお手軽に試せるという利点はありますが, もっと安定したUDP通信を望むならUDP転送コマンドを真面目に作るか, いっそのことVPNを構築するのが一番ですね.