diff --git a/dnsx b/dnsx new file mode 100755 index 00000000..67f13df6 Binary files /dev/null and b/dnsx differ diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 52b99c01..91d0880a 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -679,7 +679,25 @@ func (r *Runner) worker() { } // add flags for cdn if r.options.OutputCDN { - dnsData.IsCDNIP, dnsData.CDNName, _ = r.dnsx.CdnCheck(domain) + if len(dnsData.A) > 0 || len(dnsData.AAAA) > 0 || len(dnsData.CNAME) > 0 { + // reuse existing DNS response to avoid redundant lookups and ensure + // consistency between reported records and CDN detection + var cdnErr error + dnsData.IsCDNIP, dnsData.CDNName, dnsData.CDNType, cdnErr = r.dnsx.CdnCheckRespData(dnsData.DNSData) + if cdnErr != nil { + gologger.Debug().Msgf("cdn check failed for %s: %v", domain, cdnErr) + } + } else { + // fall back to a fresh lookup when the response lacks A/AAAA/CNAME records + var cdnErr error + dnsData.IsCDNIP, dnsData.CDNName, cdnErr = r.dnsx.CdnCheck(domain) + if cdnErr != nil { + gologger.Debug().Msgf("cdn check failed for %s: %v", domain, cdnErr) + } + if dnsData.IsCDNIP { + dnsData.CDNType = "cdn" + } + } } if r.options.ASN { results := []*asnmap.Response{} diff --git a/libs/dnsx/cdn.go b/libs/dnsx/cdn.go index e21a0791..54a3bf77 100644 --- a/libs/dnsx/cdn.go +++ b/libs/dnsx/cdn.go @@ -5,6 +5,7 @@ import ( "fmt" "net" + retryabledns "github.com/projectdiscovery/retryabledns" iputil "github.com/projectdiscovery/utils/ip" ) @@ -18,7 +19,6 @@ func (d *DNSX) CdnCheck(domain string) (bool, string, error) { return false, "", err } ipv4Ips := []net.IP{} - // filter ipv4s for ips for _, ip := range ips { if iputil.IsIPv4(ip) { ipv4Ips = append(ipv4Ips, ip) @@ -31,5 +31,14 @@ func (d *DNSX) CdnCheck(domain string) (bool, string, error) { if !iputil.IsIP(ipAddr) { return false, "", fmt.Errorf("%s is not a valid ip", ipAddr) } - return d.cdn.CheckCDN(net.ParseIP((ipAddr))) + return d.cdn.CheckCDN(net.ParseIP(ipAddr)) +} + +// CdnCheckRespData verifies if the given DNS response data is part of known CDN/WAF/Cloud ranges, +// avoiding additional DNS lookups by reusing already-resolved data. +func (d *DNSX) CdnCheckRespData(dnsdata *retryabledns.DNSData) (matched bool, value string, itemType string, err error) { + if d.cdn == nil { + return false, "", "", errors.New("cdn client not initialized") + } + return d.cdn.CheckDNSResponse(dnsdata) } diff --git a/libs/dnsx/dnsx.go b/libs/dnsx/dnsx.go index db2dc6af..146d419b 100644 --- a/libs/dnsx/dnsx.go +++ b/libs/dnsx/dnsx.go @@ -39,6 +39,7 @@ type ResponseData struct { *retryabledns.DNSData IsCDNIP bool `json:"cdn,omitempty" csv:"cdn"` CDNName string `json:"cdn-name,omitempty" csv:"cdn-name"` + CDNType string `json:"cdn-type,omitempty" csv:"cdn-type"` ASN *AsnResponse `json:"asn,omitempty" csv:"asn"` } type AsnResponse struct {