Three bugs caused tlsx to hang indefinitely for certain hosts (those that accept TCP but have problematic TLS configurations):
select in ztls tlsHandshakeWithTimeout()// BEFORE (broken): Handshake() blocks synchronously, ctx.Done() never checked
select {
case <-ctx.Done():
return error
case errChan <- tlsConn.Handshake(): // ← blocks here forever
}
// AFTER: Handshake runs in goroutine, select properly races both channels
go func() { errChan <- tlsConn.Handshake() }()
select {
case <-ctx.Done():
_ = tlsConn.Close() // unblock the goroutine
return error
case err := <-errChan:
return err
}
context.TODO() (no timeout)Each cipher handshake attempt now uses context.WithTimeout based on the configured timeout.
conn.Handshake() (no timeout)Changed to conn.HandshakeContext(ctx) with a proper timeout context.
Regression test (TestHandshakeTimeout): Starts a local TCP listener that accepts connections but never speaks TLS (simulating the problematic hosts). Verifies tlsx returns within the configured timeout instead of hanging:
=== RUN TestHandshakeTimeout
--- PASS: TestHandshakeTimeout (3.00s)
PASS
Without this fix, the test would hang for 10+ seconds and fail with “tlsx hung indefinitely”.
dev branch/claim #819
jpirstin
@jpirstin
youssefosama3820009-commits
@youssefosama3820009-commits
ProjectDiscovery
@projectdiscovery