Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,26 @@ func (r *Runner) processInputElementWorker(inputs chan taskInput, wg *sync.WaitG
gologger.Info().Msgf("Processing input %s:%s", task.host, task.port)
}

response, err := tlsxService.ConnectWithOptions(task.host, task.ip, task.port, clients.ConnectOptions{SNI: task.sni})
var response *clients.Response
var err error
// Use a per-connection timeout to prevent indefinite hangs
connTimeout := time.Duration(r.options.Timeout) * time.Second
if connTimeout <= 0 {
connTimeout = 10 * time.Second
}
// For enum modes that make multiple connections, allow more time
if r.options.TlsVersionsEnum || r.options.TlsCiphersEnum {
connTimeout *= 3
}
ctx, cancel := context.WithTimeout(context.Background(), connTimeout)
response, err = r.connectWithTimeout(ctx, tlsxService, task.host, task.ip, task.port, task.sni)
cancel()
if err != nil {
gologger.Warning().Msgf("Could not connect input %s: %s", task.Address(), err)
if ctx.Err() == context.DeadlineExceeded {
gologger.Warning().Msgf("Could not connect input %s: timeout after %v", task.Address(), connTimeout)
} else {
gologger.Warning().Msgf("Could not connect input %s: %s", task.Address(), err)
}
}

if response == nil {
Expand All @@ -418,6 +435,25 @@ func (r *Runner) processInputElementWorker(inputs chan taskInput, wg *sync.WaitG
}
}

// connectWithTimeout wraps ConnectWithOptions with a context timeout to prevent indefinite hangs
func (r *Runner) connectWithTimeout(ctx context.Context, tlsxService *tlsx.Service, host, ip, port, sni string) (*clients.Response, error) {
type result struct {
response *clients.Response
err error
}
ch := make(chan result, 1)
go func() {
resp, err := tlsxService.ConnectWithOptions(host, ip, port, clients.ConnectOptions{SNI: sni})
ch <- result{resp, err}
}()
select {
case res := <-ch:
return res.response, res.err
case <-ctx.Done():
return nil, ctx.Err()
}
}

// normalizeAndQueueInputs normalizes the inputs and queues them for execution
func (r *Runner) normalizeAndQueueInputs(inputs chan taskInput) error {
// Process Normal Inputs
Expand Down
4 changes: 3 additions & 1 deletion pkg/tlsx/openssl/openssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ func (c *Client) ConnectWithOptions(hostname, ip, port string, options clients.C
if c.options.Timeout < 3 {
c.options.Timeout = 3
}
dialCtx, dialCancel := context.WithTimeout(context.Background(), time.Duration(c.options.Timeout)*time.Second)
defer dialCancel()
// validate dialer before using
if c.dialer == nil {
var err error
Expand All @@ -56,7 +58,7 @@ func (c *Client) ConnectWithOptions(hostname, ip, port string, options clients.C
}
// There is no guarantee that dialed ip is same as ip used by openssl
// this is only used to avoid inconsistencies
rawConn, err := c.dialer.Dial(context.TODO(), "tcp", opensslOpts.Address)
rawConn, err := c.dialer.Dial(dialCtx, "tcp", opensslOpts.Address)
if err != nil || rawConn == nil {
return nil, errorutils.NewWithErr(err).WithTag(PkgTag, "fastdialer").Msgf("could not dial address:%v", opensslOpts.Address) //nolint
}
Expand Down