nc, dd, /dev/zero
下記のサイトの実装をやっていて、よく知らないコマンドや機能が出てきたので、頭の中を整理するためにスクラップする。
記事は TCP プロキシを実装するというもので、TCP プロキシというものも正直あまりよくわかっていないが、localhost:1212
に来たトラフィックを localhost:1313
に横流しするような機能のものを指していそう。
プログラムがやっていることは記事の通り結構単純で、
- クライアントは TCP コネクションをクライアントで受け取る。
- それをサーバーに流す。
下記のコードで、クライアントをバインドしてリスナーを作り、リスナーからやってくる接続を待ち受ける。その後、別のリモートホストに対して(この場合はサーバーに対して)接続を開く。
async fn proxy(client: &str, server: &str) -> io::Result<()> {
// Listen for connections from the eyeball and forward to the
// origin.
let listener = TcpListener::bind(client).await?;
loop {
let (eyeball, _) = listener.accept().await?;
let origin = TcpStream::connect(server).await?;
}
}
クライアントからの待受の結果を read と write の Half
(中身は実質 TcpStream
)に分割し、さらにサーバーからの read とサーバーへの write をチャネルに分割する。詳しくは tokio のドキュメントを参照。
let (mut eread, mut ewrite) = eyeball.into_split();
let (mut oread, mut owrite) = origin.into_split();
let e2o = tokio::spawn(async move { io::copy(&mut eread, &mut owrite).await });
let o2e = tokio::spawn(async move { io::copy(&mut oread, &mut ewrite).await });
e2o
では、クライアントからの読み取りをサーバーへの書き出しに流す。具体的にはクライアントのストリームから読んだ内容 eread
をサーバーへの書き出しストリーム owrite
にコピーする。
select
マクロは、設定された計算のうちどれか一つが終わった際にその結果を返す。終わらなかった他の計算は破棄されるというマクロ。
select! {
_ = e2o => println!("e2o done"),
_ = o2e => println!("o2e done"),
}
tokio はわかるので置いておくとして、そのあと GitHub でコードを確認したらよく知らないコマンドが出てきた。順番に調べた。
具体的には次のように実行していた。
nc -l 1313 > /dev/null
dd if=/dev/zero bs=1024 count=900000 | nc -v 127.0.0.1 1212
ただ、記事の中ではもう少し単純なコマンドを使用している。具体的には下記。
nc -l 1313
echo hello | nc -v 127.0.0.1 1212
これだとちょっとわかりやすい。
hello
-> ポート 1212 に投げる → 1212 では TCP proxy が待ち受けている → TCP proxy が中で 1212 から 1313 にプロキシする → 1313 に hello
が流れる → 表示される
といった流れか。
nc コマンド
nc コマンドは、普通に使うと telnet や curl のようなクライアントになることができるコマンドだが、このコマンドは -l
オプションをつけるとリッスンモードとして使用できる。つまり、サーバーになる。
nc -l 1313
すると、要するに1313ポートに来たリクエストを待ち受けるサーバー的な役割をしていることになる。
-v
は verbose オプションで、つまり情報の出力をもう少し詳細なものまで含められるようにするオプション。
dd コマンド
ここまでわかったところで、では dd コマンドが何かということになる。
下記は要するに、dd コマンドで生成したものを nc コマンドで 1212 に対して送信しているということになる。
dd if=/dev/zero bs=1024 count=900000 | nc -v 127.0.0.1 1212
dd コマンドは、ファイルをブロック単位で読み出し指定通り変換するコマンドらしい。if
で入力元ファイルを指定できるが、それに /dev/zero
を指定している。
/dev/zero
は NULL 文字をひたすら返すものらしい。どう使うんだろう?と思ったら下記のサイトを読んでよくわかった。
生成した結果を nc で 1212 に送信している。
だいたいわかったのでクローズ