How to Debug Connection Issues When Running testssl.sh

Use the --debug=<1-6> flag to retain temporary files in /tmp/testssl.*, inspect the raw OpenSSL s_client output, and adjust MAX_OSSL_FAIL or MAX_SOCKET_FAIL environment variables to prevent premature aborts during transient failures.

When testssl.sh fails to establish a TLS connection, the root cause often hides in OpenSSL handshake details or network timeouts. This guide explains how to leverage the built-in debug infrastructure in the drwetter/testssl.sh repository to diagnose connection failures by examining temporary files, interpreting failure counters, and using the debugme helper function.

How testssl.sh Handles Connection Failures

Two core components manage connection problems according to the source code.

$OPENSSL s_client invocations – All TLS handshakes are executed via OpenSSL's s_client command (defined around line 36 in testssl.sh). This is the actual mechanism performing network probes and capturing server responses.

connectivity_problem function – Located at lines 2579-2595, this function tracks failure counts using NR_OSSL_FAIL and NR_SOCKET_FAIL counters. It aborts execution when reaching MAX_OSSL_FAIL (OpenSSL errors) or MAX_SOCKET_FAIL (TCP errors) thresholds, printing a fatal error message when limits are exceeded.

Debug Infrastructure and Flags

Debug Levels (--debug)

The --debug=<0-6> parameter (documented near line 21621) controls verbosity and file retention:

  • 0 – No debug output (default)
  • 1-2 – Preserves temporary files in /tmp/ or the current directory for post-run analysis
  • 3-6 – Activates verbose internal diagnostics via the debugme helper

The debugme Helper Function

Defined at lines 834-837, debugme executes commands only when DEBUG is set to 2 or higher. It prints diagnostics to stderr and archives output in the temporary directory, allowing you to see exactly what commands were executed during the scan.

Temporary Directory Structure

Each execution creates $TEMPDIR (default /tmp/testssl.<PID>, implemented at line 21658). This directory stores critical intermediate data:

  • Raw handshake data: $TEMPDIR/<host>.s_client.txt
  • Parsed server responses: $TEMPDIR/<host>.parse_tls_serverhello.txt
  • Error streams: $ERRFILE

Failure Thresholds

Environment variables control abort behavior to prevent infinite loops on broken targets:

  • MAX_OSSL_FAIL – Maximum OpenSSL handshake failures before fatal exit (default is typically low for fast failure)
  • MAX_SOCKET_FAIL – Maximum TCP connection failures before fatal exit

When connectivity_problem detects threshold breaches, it issues a fatal error suggesting you increase the corresponding limit.

Special Debug Options

The -Z flag forces TLS fallback SCSV testing (referenced at lines 18898-18899). Combined with --debug=1, it generates extra log files (*tls_fallback_scsv.txt) useful when normal handshakes are rejected by the server.

Step-by-Step Debugging Workflow

Follow this sequence to isolate connection problems.

  1. Run with debug retention

    testssl.sh --debug=2 example.com:443

    Note the TEMPDIR path printed in the output summary.

  2. Inspect temporary files

    cat /tmp/testssl.XXXXXX/example.com.s_client.txt
  3. Handle OpenSSL-specific failures

    If you see "openssl s_client connect problem", increase the threshold to bypass transient TLS issues:

    MAX_OSSL_FAIL=20 testssl.sh --debug=1 example.com:443
  4. Handle TCP-level failures

    For "TCP connect problem" errors, verify reachability with telnet or nc first, then adjust:

    MAX_SOCKET_FAIL=15 testssl.sh --debug=1 example.com:443
  5. Force fallback testing

    testssl.sh -Z --debug=1 example.com:443

Practical Code Examples

Basic Debug Run with File Retention


# Retain all temporary files for inspection

testssl.sh --debug=2 example.com:443

After completion, examine the directory path printed in the output summary.

Custom Temporary Directory

TEMPDIR=$(mktemp -d)
testssl.sh --debug=2 --tempdir "$TEMPDIR" example.com:443

# Inspect raw OpenSSL output

cat "$TEMPDIR/example.com.s_client.txt"

Override Failure Thresholds


# Allow 15 OpenSSL failures before aborting

MAX_OSSL_FAIL=15 testssl.sh --debug=1 example.com:443

# Allow 10 TCP timeouts

MAX_SOCKET_FAIL=10 testssl.sh --debug=1 example.com:443

Debug TLS Fallback Issues

testssl.sh -Z --debug=1 example.com:443
cat "$TEMPDIR/example.com.tls_fallback_scsv.txt"

Key Source Files

Understanding these files in the repository helps trace connection logic:

  • testssl.sh (main script) – Line 36 defines the $OPENSSL s_client invocation; line 21658 creates $TEMPDIR; line 21621 documents debug flags
  • debugme function – Lines 834-837 implement the conditional execution wrapper that logs commands only when DEBUG ≥ 2
  • connectivity_problem function – Lines 2579-2595 contain the failure counting and abort logic for both OpenSSL and socket errors
  • utils/resume.sh – Helper for session resumption tests using s_client
  • utils/checkcert.sh – Extracts certificates via s_client -showcerts
  • etc/client-simulation.txt – Data file used by the client simulation engine; useful when debugging simulated browser handshakes

Summary

  • Enable debugging with --debug=2 to preserve temporary files in /tmp/testssl.<PID> for post-scan analysis
  • Inspect raw output in $TEMPDIR/<host>.s_client.txt to see exact OpenSSL error messages and server responses
  • Adjust thresholds using MAX_OSSL_FAIL and MAX_SOCKET_FAIL environment variables for flaky networks or slow targets
  • Use -Z flag with --debug=1 to diagnose TLS fallback SCSV rejection issues
  • Check the debugme function at line 834 to understand how conditional logging wraps sensitive commands

Frequently Asked Questions

How do I see the exact OpenSSL error when testssl.sh fails to connect?

Run testssl.sh with --debug=2 and inspect the *.s_client.txt file in the temporary directory printed at the end of the scan. This file contains the raw stderr and stdout from the $OPENSSL s_client command that failed, including specific handshake error codes.

What is the difference between MAX_OSSL_FAIL and MAX_SOCKET_FAIL?

MAX_OSSL_FAIL counts failures occurring during the TLS handshake phase (certificate validation errors, protocol version mismatches), while MAX_SOCKET_FAIL counts TCP-level connection failures (timeouts, connection refused, network unreachable). Increase the relevant variable based on which error message appears in the connectivity_problem output at lines 2579-2595.

Where are the debug log files stored?

By default, logs are stored in /tmp/testssl.<PID>/. When using --debug=1 or higher, the script prints the exact TEMPDIR path at the end of execution. You can also specify a custom location with --tempdir /path/to/dir to make files easier to locate.

Why does testssl.sh abort even with --debug enabled?

The script uses hardcoded failure thresholds in the connectivity_problem function. If NR_OSSL_FAIL exceeds MAX_OSSL_FAIL (or the socket equivalent), it calls fatal and exits regardless of debug settings. Override these limits by setting the environment variables (e.g., MAX_OSSL_FAIL=50) before invoking the script.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →