socatを使用してlocalhostをHTTPSにプロキシすると、初めて接続が拒否されます。

socatを使用してlocalhostをHTTPSにプロキシすると、初めて接続が拒否されます。

https://termbin.com/9hc2kBashリダイレクトを使用してページをインポートしようとしていますsocat。特に特殊ファイルを使用して/dev/tcp/localhost/8080ネットワーク接続を開こうとします。

# fetch.sh
# fetch uploaded text from termbin.com

url=$1

# check if url is provided as argument
if [[ $# -lt 1 ]]; then
    echo "error: provide url" >&2
    echo >&2
    echo "Usage: fetch.sh [url]" >&2
    exit 1
fi

n1=$'\r\n'
request=$(cat <<END
GET /${url}/ HTTP/1.1
Host: termbin.com
Connection: close
$n1 
$n1
END
)
#echo "$request"

socat TCP-LISTEN:8080,fork,reuseaddr ssl:termbin.com:443,verify=0 &
socat_pid=$!
exec 3<>/dev/tcp/localhost/8080
echo "$request" >&3
cat <&3

exec 3>&-

私が取得しようとするとhttps://termbin.com/9hc2k

$ ./fetch.sh 9hc2k
./fetch.sh: connect: Connection refused
./fetch.sh: line 26: /dev/tcp/localhost/8080: Connection refused
./fetch.sh: line 27: 3: Bad file descriptor
./fetch.sh: line 28: 3: Bad file descriptor

初めて接続拒否エラーが発生しました。

しかし、もう一度試してみると、

$ ./fetch.sh 9hc2k
2022/07/30 12:29:18 socat[497218] E bind(5, {AF=2 0.0.0.0:8080}, 16): Address already in use
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 30 Jul 2022 02:29:20 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 6
Last-Modified: Sat, 30 Jul 2022 01:51:42 GMT
Connection: close
ETag: "62e48eae-6"
Accept-Ranges: bytes

hello

ご覧のとおり、2回目の試みでは機能します。helloリンクからテキストをインポートしました。

最初は失敗し、2番目(およびそれ以降)には機能する理由がわかりません。なぜこれが起こるのか、そして最も合理的な解決策は何であるのか教えてください。ありがとうございます。

答え1

私の考えにはexec 3<>/dev/tcp/localhost/8080そのようなことがあったと思います。早すぎるそれ以降はsocat … &まだsocat準備ができていません。

あなたのスクリプトは生成されたものを殺しませんsocat。再試行すると、古い接続がsocatすでに存在し、新しい接続を処理できます。

sleep 1あなたが行く前に迅速かつ汚れた修正が必要ですexec 3<>…。より良い解決策は、exec 3<>…成功するまで、または試行回数が合理的なしきい値に達するまで(その後失敗したと仮定するまで)定期的に試して再試行することです。kill -s 0 "$socat_pid"socat失敗します(これは何らかの理由で終了したことがわかります)。

答え2

説明してくれたCamilleに感謝します。最終的にsocat pidの状態を監視し、「S」に変更して問題を解決しました。

これは私の固定コードです。

# fetch uploaded text from termbin.com

url=$1

# check if url is provided as argument
if [[ $# -lt 1 ]]; then
    echo "error: provide url" >&2
    echo >&2
    echo "Usage: fetch.sh [url]" >&2
    exit 1
fi

n1=$'\r\n'
request=$(cat <<END
GET /${url}/ HTTP/1.1
Host: termbin.com
Connection: close
$n1 
$n1
END
)
#echo "$request"

socat TCP-LISTEN:8080,fork,reuseaddr ssl:termbin.com:443,verify=0 &
socat_pid=$!

# loop until socat's pid status becomes 'S'
while [[ -z $(ps -p $socat_pid -o stat --no-headers | grep 'S') ]]; do
    :
done

exec 3<>/dev/tcp/localhost/8080
echo "$request" >&3
cat <&3

# if socat's pid status is 'S' then kill it
if [[ -n $(ps -p $socat_pid -o stat --no-headers | grep 'S') ]]; then
    kill -9 $socat_pid
fi

exec 3>&-

関連情報