🐳

Rustで初めてツールを作ったときのあれこれ

2023/01/08に公開

はじめに

Rustの勉強がてら何かツールを作りたいと思いました。
ちょうどその頃、tcpdumpでパケットを眺めるとき「tcpdump起動後にパケットフィルターできないの不便だな」と思ってたのでそれを解決するツールを作ることにしました。

で、出来上がったのがこちらwirewhaleです。イメージとしてはTUIで動くWiresharkを目指しました。

https://github.com/gawetto/wirewhale

全体像

アプリケーションは主に3つのスレッド(非同期タスク)があります。まずはmainスレッドにてキーボードイベントを取得し、Appの内部状態を操作しています。次に標準入力からpcapフォーマットのデータを読み取りパケットデータとしてApp内に保存する非同期タスクがあります。標準入力からの読み込みはasync_stdのStdinを利用しているので非同期タスクとして実行(async_std::task::spawn)しています。最後にターミナルに定期的に情報を出力するスレッドがあります。ここの出力はcrosstermとtui-rsを利用しており、非同期タスクとすることができなかったのでスレッドとして実行(async_std::task::spawn_blocking)しています。

CI/CD(GithubActions)

ツールを作成にするにあたってのCI/CDは今回初めてGithubActionsを使ってみました。

まずはCIです。
https://github.com/gawetto/wirewhale/blob/v0.0.14/.github/workflows/ci.yml
CIで行うことはリントとフォーマットとテストです。actions-rs/toolchainでtoolをインストールしてactions-rs/cargoで実行するだけなのでとても簡単にできました。

次にCDです
https://github.com/gawetto/wirewhale/blob/v0.0.14/.github/workflows/cd.yml
バージョンタグ(vX.X.X)が打たれた時にトリガーされ、リリースを作成してビルドしてアップロードするようにしました。GithubActionsではクロスコンパイルせずに複数ターゲットに対してビルドできるんですね。ただ、アップロードする生成物のアーカイブを作成する処理がシェルスクリプトで書かなければいけないのがなんだかなぁという感じです。

cargo-release

GithubActionsによってバージョンタグを打つとビルドされるようになりましたが、手動でバージョンタグを打つとgitでのバージョンとCargo.tomlに記載されているバージョンに差異が生じる可能性があります。clapによって--versionで表示されるバージョンやcrate.ioで公開されるバージョンはCargo.tomlに記載されいるバージョンなのでここの差異はなくしたいところです。
cargo-releaseを使えばCargo.tomlのバージョンをインクリメントしつつバージョンタグを打つということを行ってくれるのでリリース作業はcargo-releaseを使えば差異はなくなります。また、cargo-releaseを使うとcrate.ioにpublishもできます。

https://github.com/crate-ci/cargo-release

ちなみにclapを使うと下記のような構造体を作ってmain関数でparseメソッドを呼ぶだけで--versionオプションが実装されます
https://github.com/gawetto/wirewhale/blob/v0.0.14/src/main.rs#L9-L15

おわりに

はっきり言って時間をかけて作った割にツールの完成度はイマイチです。まだまだ問題は山積みです。

  • パケット数が多いとフィルタに時間がかかる
  • フィルタがただの文字列一致しかしてない
  • 対応しているプロトコルが少ない

ただ、作るうえでいろいろなことを学ぶことができたので目的は達成しました。

Discussion