Closed3

nc, dd, /dev/zero

yukiyuki

下記のサイトの実装をやっていて、よく知らないコマンドや機能が出てきたので、頭の中を整理するためにスクラップする。

記事は TCP プロキシを実装するというもので、TCP プロキシというものも正直あまりよくわかっていないが、localhost:1212 に来たトラフィックを localhost:1313 に横流しするような機能のものを指していそう。

https://zmedley.com/tcp-proxy.html

プログラムがやっていることは記事の通り結構単純で、

  • クライアントは 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"),
        }
yukiyuki

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 文字をひたすら返すものらしい。どう使うんだろう?と思ったら下記のサイトを読んでよくわかった。

https://wa3.i-3-i.info/word11744.html

生成した結果を nc で 1212 に送信している。

このスクラップは2021/07/10にクローズされました