github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/headless/engine/http_client.go (about)

     1  package engine
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"net"
     7  	"net/http"
     8  	"net/http/cookiejar"
     9  	"net/url"
    10  	"time"
    11  
    12  	"golang.org/x/net/proxy"
    13  
    14  	"github.com/projectdiscovery/fastdialer/fastdialer/ja3/impersonate"
    15  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
    16  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils"
    17  	"github.com/projectdiscovery/nuclei/v2/pkg/types"
    18  )
    19  
    20  // newHttpClient creates a new http client for headless communication with a timeout
    21  func newHttpClient(options *types.Options) (*http.Client, error) {
    22  	dialer := protocolstate.Dialer
    23  
    24  	// Set the base TLS configuration definition
    25  	tlsConfig := &tls.Config{
    26  		Renegotiation:      tls.RenegotiateOnceAsClient,
    27  		InsecureSkipVerify: true,
    28  		MinVersion:         tls.VersionTLS10,
    29  	}
    30  
    31  	if options.SNI != "" {
    32  		tlsConfig.ServerName = options.SNI
    33  	}
    34  
    35  	// Add the client certificate authentication to the request if it's configured
    36  	var err error
    37  	tlsConfig, err = utils.AddConfiguredClientCertToRequest(tlsConfig, options)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	transport := &http.Transport{
    43  		ForceAttemptHTTP2: options.ForceAttemptHTTP2,
    44  		DialContext:       dialer.Dial,
    45  		DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
    46  			if options.TlsImpersonate {
    47  				return dialer.DialTLSWithConfigImpersonate(ctx, network, addr, tlsConfig, impersonate.Random, nil)
    48  			}
    49  			return dialer.DialTLS(ctx, network, addr)
    50  		},
    51  		MaxIdleConns:        500,
    52  		MaxIdleConnsPerHost: 500,
    53  		MaxConnsPerHost:     500,
    54  		TLSClientConfig:     tlsConfig,
    55  	}
    56  	if types.ProxyURL != "" {
    57  		if proxyURL, err := url.Parse(types.ProxyURL); err == nil {
    58  			transport.Proxy = http.ProxyURL(proxyURL)
    59  		}
    60  	} else if types.ProxySocksURL != "" {
    61  		socksURL, proxyErr := url.Parse(types.ProxySocksURL)
    62  		if proxyErr != nil {
    63  			return nil, err
    64  		}
    65  		dialer, err := proxy.FromURL(socksURL, proxy.Direct)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  
    70  		dc := dialer.(interface {
    71  			DialContext(ctx context.Context, network, addr string) (net.Conn, error)
    72  		})
    73  		transport.DialContext = dc.DialContext
    74  	}
    75  
    76  	jar, _ := cookiejar.New(nil)
    77  
    78  	httpclient := &http.Client{
    79  		Transport: transport,
    80  		Timeout:   time.Duration(options.Timeout*3) * time.Second,
    81  		Jar:       jar,
    82  		CheckRedirect: func(req *http.Request, via []*http.Request) error {
    83  			// the browser should follow redirects not us
    84  			return http.ErrUseLastResponse
    85  		},
    86  	}
    87  
    88  	return httpclient, nil
    89  }