socat TUNとopensslを組みわせるとInvalid argumentが発生する原因
書きたいこと
なぜ以下を実行するとsocat[15382] E write(5, 0x563b06a8f000, 1): Invalid argumentというエラーが出てしまうのかについて。
code:bash
# マシンA
curl -sSN https://ppng.io/btoa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | sudo socat TUN:192.168.255.1/24,up - | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - https://ppng.io/atob code:bash
# マシンB
curl -sSN https://ppng.io/atob | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | sudo socat TUN:192.168.255.2/24,up - | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | curl -sSNT - https://ppng.io/btoa 結論
調査して分かったのは、socat TUNに流し込むデータの速度が一定値より遅くなると上記のエラーが起こるということ。
socatの作者さんに報告する予定。
結論に至るまでの経緯
code:version
socat version 1.7.4.1 on Mar 25 2022 09:51:32
以下のコマンドを使うと暗号化と復号ができる。
暗号化: stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256
復号: stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256
試すときは以下のようにecho hello | <暗号化> | <復号>とすれば何もしなかったのと同じになりhelloが出力される。
code:bash
echo hello | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256 | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256
stdbuf -i0 -o0はストリーミングするためにある。理想としては元データが1バイトずつ流れるようにする。
この暗号化手法とsocat自体は以下のようにしてポートフォワーディングする時には上手く行く実績があった。
code:bash
# サーバーホスト
curl -sSN https://ppng.io/aaa | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 | nc localhost 22 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 | curl -sSNT - https://ppng.io/bbb code:bash
# クライアントホスト
curl -sSN https://ppng.io/bbb | stdbuf -i0 -o0 openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 | nc -lp 2222 | stdbuf -i0 -o0 openssl aes-256-ctr -pass "pass:mypass" -bufsize 1 -pbkdf2 | curl -sSNT - https://ppng.io/aaa stdbuf ... <コマンド>は$LD_PRELOADを変えて<コマンド>のwrite()の挙動を変えたりするので、最初はstdbufに副作用があるのでは疑ってstdbufを隔離するためにサブシェルなど使うとかunsetするとか思いつく限り可能性を潰したがstdbufが原因ではなかった。stdbufを隔離する過程で全く別マシンでstdbuf ... opensslを実行させても問題が発生したので、それ以外の要因を疑い最終的に速度の制限をpv -Lでしたら再現した。
以下のコマンドは単純にpv -L 10を加えただけ。暗号化は一切関係ないシンプルなコマンド。
これでもsocat[15382] E write(5, 0x563b06a8f000, 1): Invalid argumentが発生した。
code:bash
# マシンA
code:bash
# マシンB
pv -L 10は10B/秒の速度でデータが流れるようにする。-L 1000ではエラーは発生せず、-L 100だとたまにエラーした。
pvの一般的な目的はパイプに流れるデータの速度を見ることだが、速度制限の用途にも使える。curl単体にも速度制限機能があるが、元のcurlのコマンドを変更しない点や汎用性が高い点でpvを使っている。