Skip to content

Use proxy for dns and ssl templates #6255

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions pkg/protocols/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
func (request *Request) getDnsClient(options *protocols.ExecutorOptions, metadata map[string]interface{}) (*retryabledns.Client, error) {
dnsClientOptions := &dnsclientpool.Configuration{
Retries: request.Retries,
Proxy: options.Options.AliveSocksProxy,
}
Comment on lines 186 to 189
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Pass the override dialer alongside the proxy for full template-level control

Other protocol implementations in this PR (network, ssl, websocket) forward options.OverrideFastdialer so that a template can completely replace the default fast-dialer.
DNS now only forwards the SOCKS proxy string which leaves the dialer override path unused for DNS templates and breaks the symmetry promised in the PR description.

 dnsClientOptions := &dnsclientpool.Configuration{
     Retries: request.Retries,
     Proxy:   options.Options.AliveSocksProxy,
+    // Keep behaviour consistent with other protocol pools
+    CustomDialer: options.OverrideFastdialer,
 }

Please verify that dnsclientpool.Configuration already exposes a CustomDialer (or similar) field; if not, extend it as was done for networkclientpool.
Failing to forward the dialer means DNS templates still funnel through the global fast-dialer even when the user explicitly asked for an override.


🏁 Script executed:

#!/bin/bash
# Inspect dnsclientpool package for Configuration and CustomDialer
grep -R "package dnsclientpool" -n pkg/protocols/dns
grep -R "type Configuration" -n pkg/protocols/dns
grep -R "CustomDialer" -n pkg/protocols/dns

# Compare with networkclientpool implementation
grep -R "package networkclientpool" -n pkg/protocols/network
grep -R "type Configuration" -n pkg/protocols/network
grep -R "CustomDialer" -n pkg/protocols/network

Length of output: 1021


Extend DNS client configuration to support dialer overrides

To restore symmetry with other protocol pools, add a CustomDialer field to the DNS client configuration and forward the override in dns.go:

• In pkg/protocols/dns/dnsclientpool/clientpool.go, modify the Configuration struct:

 type Configuration struct {
     Retries    int
     Proxy      string
+    CustomDialer *fastdialer.Dialer
 }

(Remember to import the fastdialer package.)

• In pkg/protocols/dns/dns.go, update the options passed into the pool:

 dnsClientOptions := &dnsclientpool.Configuration{
     Retries: request.Retries,
     Proxy:   options.Options.AliveSocksProxy,
+    CustomDialer: options.OverrideFastdialer,
 }

This ensures DNS templates can fully override the default fast-dialer just like network, SSL, and WebSocket.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dnsClientOptions := &dnsclientpool.Configuration{
Retries: request.Retries,
Proxy: options.Options.AliveSocksProxy,
}
dnsClientOptions := &dnsclientpool.Configuration{
Retries: request.Retries,
Proxy: options.Options.AliveSocksProxy,
// Keep behaviour consistent with other protocol pools
CustomDialer: options.OverrideFastdialer,
}
🤖 Prompt for AI Agents
In pkg/protocols/dns/dns.go around lines 186 to 189, the
dnsclientpool.Configuration is only set with Retries and Proxy, but it does not
forward the OverrideFastdialer option. To fix this, first verify and if missing,
add a CustomDialer field to the Configuration struct in
pkg/protocols/dns/dnsclientpool/clientpool.go, importing the fastdialer package
as needed. Then, update the dnsClientOptions initialization in dns.go to include
options.OverrideFastdialer assigned to the new CustomDialer field, ensuring DNS
templates can override the default fast-dialer consistently with other
protocols.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, are you recommending that I include it even though it isn’t required?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

if len(request.Resolvers) > 0 {
if len(request.Resolvers) > 0 {
Expand Down
10 changes: 9 additions & 1 deletion pkg/protocols/dns/dnsclientpool/clientpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type Configuration struct {
Retries int
// Resolvers contains the specific per request resolvers
Resolvers []string
// Proxy contains the proxy to use for the dns client
Proxy string
}

// Hash returns the hash of the configuration to allow client pooling
Expand All @@ -60,6 +62,8 @@ func (c *Configuration) Hash() string {
builder.WriteString(strconv.Itoa(c.Retries))
builder.WriteString("l")
builder.WriteString(strings.Join(c.Resolvers, ""))
builder.WriteString("p")
builder.WriteString(c.Proxy)
hash := builder.String()
return hash
}
Expand All @@ -83,7 +87,11 @@ func Get(options *types.Options, configuration *Configuration) (*retryabledns.Cl
} else if len(configuration.Resolvers) > 0 {
resolvers = configuration.Resolvers
}
client, err := retryabledns.New(resolvers, configuration.Retries)
client, err := retryabledns.NewWithOptions(retryabledns.Options{
BaseResolvers: resolvers,
MaxRetries: configuration.Retries,
Proxy: options.AliveSocksProxy,
})
if err != nil {
return nil, errors.Wrap(err, "could not create dns client")
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/protocols/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
json "github.com/json-iterator/go"
"github.com/pkg/errors"

"github.com/projectdiscovery/fastdialer/fastdialer"
_ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/time"

"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
httputil "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils/http"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/stats"
"github.com/projectdiscovery/rawhttp"
Expand Down Expand Up @@ -144,6 +146,7 @@ type Request struct {
generator *generators.PayloadGenerator // optional, only enabled when using payloads
httpClient *retryablehttp.Client
rawhttpClient *rawhttp.Client
dialer *fastdialer.Dialer

// description: |
// SelfContained specifies if the request is self-contained.
Expand Down Expand Up @@ -348,6 +351,15 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}
request.customHeaders = make(map[string]string)
request.httpClient = client

dialer, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
CustomDialer: options.OverrideFastdialer,
})
if err != nil {
return errors.Wrap(err, "could not get dialer")
}
request.dialer = dialer

request.options = options
for _, option := range request.options.Options.CustomHeaders {
parts := strings.SplitN(option, ":", 2)
Expand Down
6 changes: 3 additions & 3 deletions pkg/protocols/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
if input.MetaInput.CustomIP != "" {
outputEvent["ip"] = input.MetaInput.CustomIP
} else {
outputEvent["ip"] = protocolstate.Dialer.GetDialedIP(hostname)
outputEvent["ip"] = request.dialer.GetDialedIP(hostname)
// try getting cname
request.addCNameIfAvailable(hostname, outputEvent)
}
Expand Down Expand Up @@ -1085,11 +1085,11 @@ func (request *Request) validateNFixEvent(input *contextargs.Context, gr *genera

// addCNameIfAvailable adds the cname to the event if available
func (request *Request) addCNameIfAvailable(hostname string, outputEvent map[string]interface{}) {
if protocolstate.Dialer == nil {
if request.dialer == nil {
return
}

data, err := protocolstate.Dialer.GetDNSData(hostname)
data, err := request.dialer.GetDNSData(hostname)
if err == nil {
switch len(data.CNAME) {
case 0:
Expand Down
8 changes: 3 additions & 5 deletions pkg/protocols/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}

// Create a client for the class
client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
CustomDialer: options.OverrideFastdialer,
})
if err != nil {
return errors.Wrap(err, "could not get network client")
}
Expand All @@ -259,7 +261,3 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
func (request *Request) Requests() int {
return len(request.Address)
}

func (request *Request) SetDialer(dialer *fastdialer.Dialer) {
request.dialer = dialer
}
9 changes: 8 additions & 1 deletion pkg/protocols/network/networkclientpool/clientpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ func Init(options *types.Options) error {
}

// Configuration contains the custom configuration options for a client
type Configuration struct{}
type Configuration struct {
CustomDialer *fastdialer.Dialer
}

// Hash returns the hash of the configuration to allow client pooling
func (c *Configuration) Hash() string {
Expand All @@ -30,5 +32,10 @@ func (c *Configuration) Hash() string {

// Get creates or gets a client for the protocol based on custom configuration
func Get(options *types.Options, configuration *Configuration /*TODO review unused parameters*/) (*fastdialer.Dialer, error) {

if configuration != nil && configuration.CustomDialer != nil {
return configuration.CustomDialer, nil
}

return normalClient, nil
}
8 changes: 6 additions & 2 deletions pkg/protocols/network/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/responsehighlighter"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
errorutil "github.com/projectdiscovery/utils/errors"
Expand Down Expand Up @@ -64,7 +64,11 @@ func (request *Request) getOpenPorts(target *contextargs.Context) ([]string, err
errs = append(errs, err)
continue
}
conn, err := protocolstate.Dialer.Dial(target.Context(), "tcp", addr)
if request.dialer == nil {
request.dialer, _ = networkclientpool.Get(request.options.Options, &networkclientpool.Configuration{})
}

conn, err := request.dialer.Dial(target.Context(), "tcp", addr)
if err != nil {
errs = append(errs, err)
continue
Expand Down
3 changes: 3 additions & 0 deletions pkg/protocols/protocols.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"sync/atomic"

"github.com/projectdiscovery/fastdialer/fastdialer"
"github.com/projectdiscovery/ratelimit"
mapsutil "github.com/projectdiscovery/utils/maps"
stringsutil "github.com/projectdiscovery/utils/strings"
Expand Down Expand Up @@ -132,6 +133,8 @@ type ExecutorOptions struct {
ExportReqURLPattern bool
// GlobalMatchers is the storage for global matchers with http passive templates
GlobalMatchers *globalmatchers.Storage
// OverrideFastdialer is a fastdialer dialer instance
OverrideFastdialer *fastdialer.Dialer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this for lib usage only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think CustomFastdialer would be a better naming choice/convention in this context. the OverrideXXX naming pattern tends to sound like expecting a boolean value.

}

// todo: centralizing components is not feasible with current clogged architecture
Expand Down
4 changes: 3 additions & 1 deletion pkg/protocols/ssl/ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ func (request *Request) IsClusterable() bool {
func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.options = options

client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
CustomDialer: options.OverrideFastdialer,
})
if err != nil {
return errorutil.NewWithTag("ssl", "could not get network client").Wrap(err)
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/protocols/websocket/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const (
func (request *Request) Compile(options *protocols.ExecutorOptions) error {
request.options = options

client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{})
client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{
CustomDialer: options.OverrideFastdialer,
})
if err != nil {
return errors.Wrap(err, "could not get network client")
}
Expand Down
Loading