本文へスキップ
ecdsa.com
curl (OpenSSL 3 backend)curl

エラーメッセージ

curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0

別の表記

  • curl: (56) OpenSSL SSL_read: OpenSSL/3.5.7: error:0A000126:SSL routines::unexpected eof while reading, errno 0

最近の curl のリリースでは、「SSL_read:」の後に TLS ライブラリのバージョン(例:「OpenSSL/3.5.7:」)が挿入されます。OpenSSL 1.1.1 はこの状況をこのようには報告しませんでした。1.1.1 では、同じ切り詰めは通常「curl: (18) transfer closed with N bytes remaining to read」として表示されます。

curl (OpenSSL 3 backend) — CURLE_RECV_ERROR, SSL_R_UNEXPECTED_EOF_WHILE_READING

このエラーの意味

TLS 接続が確立してデータが流れていたところで、curl がまだ続きのデータを待っているにもかかわらず、相手側が TLS の close_notify を送らずに TCP 接続を閉じました。close_notify がない状態は切り詰め攻撃と同じ見え方をするため、OpenSSL 3 はこのような突然の終了を、通常のストリームの終わりではなくエラーとして報告します。curl はこれを受信の失敗(終了コード 56)として報告します。

発生する理由

修正方法

  1. 1.

    どのホップが接続を閉じているかを特定する

    エラーまでに何バイト転送され、何秒経過したかを記録してから、バックエンドに直接同じリクエストを送ってください。切りのよい秒数で切断されている場合は、プロキシやロードバランサーのタイムアウトが疑われます。

    bash
    # How much arrived, and for how long, before the connection died?
    curl -sv --trace-time https://api.example.com/export.csv -o out.csv 2>&1 | tail -20
    # Same request directly to the backend, bypassing the proxy / load balancer
    curl -sv --resolve api.example.com:443:10.0.0.12 https://api.example.com/export.csv -o out.csv
  2. 2.

    発動しているタイムアウトを延長する

    接続を切断しているコンポーネントの制限値を、正当なレスポンスにかかる最長の時間より大きくするか、遅いエンドポイントの応答を速くしてください(大きなエクスポートはストリーミングかページ分割で返します)。

    text
    # nginx in front of a slow upstream (both default to 60s)
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    # Load balancers: set the idle timeout above the longest legitimate response time
  3. 3.

    冪等な転送を再試行する

    不安定な回線でのダウンロードでは、curl に再試行と再開をさせてください。これは、サーバー側を調査している間にクライアント側で症状に対処する方法です。

    bash
    # For idempotent downloads: retry, and resume where the transfer stopped
    curl --retry 5 --retry-all-errors -C - -o big.iso https://downloads.example.com/big.iso
  4. 4.

    サーバーのコード:TLS 接続を正しく閉じる

    ソケットを閉じる前に close_notify を送信し(OpenSSL では SSL_shutdown、Python では unwrap()、Go では tls.Conn の Close())、HTTP のボディを Content-Length または chunked エンコーディングで区切って、正常な終了が明確にわかるようにしてください。

    python
    # Server code: shut TLS down cleanly so the peer receives close_notify
    conn.unwrap()   # Python ssl.SSLSocket: sends close_notify before closing
    conn.close()

関連するエラー

署名エラーデータベースをすべて見る