Path: blob/dev/pkg/protocols/dns/dnsclientpool/clientpool.go
2072 views
package dnsclientpool12import (3"strconv"4"strings"5"sync"67"github.com/pkg/errors"8"github.com/projectdiscovery/nuclei/v3/pkg/types"9"github.com/projectdiscovery/retryabledns"10mapsutil "github.com/projectdiscovery/utils/maps"11)1213var (14clientPool *mapsutil.SyncLockMap[string, *retryabledns.Client]1516normalClient *retryabledns.Client17m sync.Mutex18)1920// defaultResolvers contains the list of resolvers known to be trusted.21var defaultResolvers = []string{22"1.1.1.1:53", // Cloudflare23"1.0.0.1:53", // Cloudflare24"8.8.8.8:53", // Google25"8.8.4.4:53", // Google26}2728// Init initializes the client pool implementation29func Init(options *types.Options) error {30m.Lock()31defer m.Unlock()3233// Don't create clients if already created in the past.34if normalClient != nil {35return nil36}37clientPool = mapsutil.NewSyncLockMap[string, *retryabledns.Client]()3839resolvers := defaultResolvers40if len(options.InternalResolversList) > 0 {41resolvers = options.InternalResolversList42}43var err error44normalClient, err = retryabledns.New(resolvers, 1)45if err != nil {46return errors.Wrap(err, "could not create dns client")47}48return nil49}5051func getNormalClient() *retryabledns.Client {52m.Lock()53defer m.Unlock()54return normalClient55}5657// Configuration contains the custom configuration options for a client58type Configuration struct {59// Retries contains the retries for the dns client60Retries int61// Resolvers contains the specific per request resolvers62Resolvers []string63// Proxy contains the proxy to use for the dns client64Proxy string65}6667// Hash returns the hash of the configuration to allow client pooling68func (c *Configuration) Hash() string {69builder := &strings.Builder{}70builder.WriteString("r")71builder.WriteString(strconv.Itoa(c.Retries))72builder.WriteString("l")73builder.WriteString(strings.Join(c.Resolvers, ""))74builder.WriteString("p")75builder.WriteString(c.Proxy)76hash := builder.String()77return hash78}7980// Get creates or gets a client for the protocol based on custom configuration81func Get(options *types.Options, configuration *Configuration) (*retryabledns.Client, error) {82if (configuration.Retries <= 1) && len(configuration.Resolvers) == 0 {83return getNormalClient(), nil84}85hash := configuration.Hash()86if client, ok := clientPool.Get(hash); ok {87return client, nil88}8990resolvers := defaultResolvers91if len(options.InternalResolversList) > 0 {92resolvers = options.InternalResolversList93} else if len(configuration.Resolvers) > 0 {94resolvers = configuration.Resolvers95}96client, err := retryabledns.NewWithOptions(retryabledns.Options{97BaseResolvers: resolvers,98MaxRetries: configuration.Retries,99Proxy: options.AliveSocksProxy,100})101if err != nil {102return nil, errors.Wrap(err, "could not create dns client")103}104_ = clientPool.Set(hash, client)105106return client, nil107}108109110