Chienomi

Bashのネットワーク機能をみんな知るべき (Linuxのテキスト/ファイル転送テクニックレシピ)

Live With Linux::technique

かなり高い頻度でこの話はしていると思っていたのだが、ChienomiではLinux的にWindowsをバックアップしてみる, 誤家庭のLinuxで大規模ストレージを取り扱う, 新品コンピュータを初期状態に戻せるようにバックアップ, 2000-2005年ころのLinuxとインターネットとパソコンと4回登場しているものの、これ自体を解説した記事がなかったので、書いておく。

これは、概要としては、 “Bashではリダイレクトの特殊な構文としてTCP/UDPによる通信が可能である” ということである。

構文

command > /dev/tcp/host/port

まず、前提として述べておくが、 あくまでCONNECTだけでLISTENはできない

hostは名前解決の対象になる。

また、仮に全二重でネットワーク接続したとしても、リダイレクトの構文として読み戻すことができないので、あくまでもBashからCONNECTしたら一方的に書き込むか読み出すかのどちらかしかできない。

例えばホストserverで次のようにして待ち受ける。

socat -u TCP-LISTEN:10000 STDOUT

ホストclientから次のようにする。

echo 'Hello, world!' > /dev/tcp/server/10000

これを利用して、ファイルを転送できる。サーバー側

socat -u TCP-LISTEN:10000 CREATE:somefile

クライアント側

cat somefile > /dev/tcp/server/10000

ファイル群の転送も可能である。サーバー側

socat -u TCP-LISTEN:10000 STDOUT | tar xvf -

クライアント側

tar cvf - . > /dev/tcp/server/10000

あくまでCONNECTであるというだけであり、読み出し側になれないという意味ではない。 だから、Bashのほうでファイルを受け取るようなことも可能だ。 サーバー側

tar cvf - . | socat -u STDIN TCP-LISTEN:10000

クライアント側

tar xvf < /dev/tcp/server/10000

もう少し解説

実際に/dev/tcp/dev/udpというファイルがあるわけではなく、Bashであっても例えば

cat /dev/tcp/server/10000

のようにしても普通にエラーになる。

これは、あくまで「リダイレクト先として/dev/tcp/dev/udpが指定されたときに、Bashが特別な扱いとしてネットワーク通信をする」という仕組みである。

なお、同じようなものとして/dev/fd/n, /dev/stdin, /dev/stdout, /dev/stderrという仮想ファイルが用意されている。UNIXドメインソケットには対応していない。

nc(netcat)とsocat

nc(netcat)は昔からあるネットワーク通信プログラムである。 標準入出力を使ってTCP/UDP/UNIX domain Socketでの通信を行うことができる。

socatはより汎用性を高めた現代的なプログラムである。ファイルデスクリプタ, TCP, UDP, ソケットのほか、ファイル、SCTP, 名前付きパイプ, コマンド, PTY, OpenSSL/TCP/IP, SOCKS4/5などもサポートしており、これらを自由につなぐことができる。HTTPプロキシ経由の接続も可能だ。

以前はnetcatがデフォルトで入っていることが多くて、とりあえずnetcatは使えるケースが多かったのだが、最近のディストリビューションはnetcatも入っていないことが多く、一方socatもnetcatも公式パッケージとして存在することが多いようだ。

このため、使うのであればsocatのほうがお勧めではある。 netcatにまつわる面倒な要素もないし。

ヒント

通信における片側がBashさえあれば良い、ということで、ライブCDなどでブートしてそのままファイル転送に使うことができる。

古いコンピュータなどにおいて古いライブディストリビューションを利用してネットワークファイル転送を行ったり、Windowsでは転送しづらいファイルをWindowsオフラインでバックアップしたい場合などにLinuxによるライブブートで転送するといったことが簡単にできる。

また、netcatやsocatの入っていないLinux環境からネットワーク接続をテストしたり、仮想マシンのホスト/ゲスト間で通信したりするのにも便利。