Skip to content

Support auto wildcard detection similar to PureDNS#958

Closed
addidea wants to merge 1 commit intoprojectdiscovery:devfrom
addidea:bounty-924
Closed

Support auto wildcard detection similar to PureDNS#958
addidea wants to merge 1 commit intoprojectdiscovery:devfrom
addidea:bounty-924

Conversation

@addidea
Copy link

@addidea addidea commented Mar 8, 2026

Closes #924

Changes

  • Added --auto-wildcard flag to cmd/dnsx/main.go implementing automatic wildcard detection similar to PureDNS
  • The checkWildcard() function tests common subdomains against the target domain to identify wildcard DNS records
  • Integrated wildcard filtering into the resolution pipeline to reduce false positives

Testing

  • Added test/wildcard_test.go covering wildcard detection logic
  • Tested locally against domains with known wildcard configurations

@neo-by-projectdiscovery-dev
Copy link

neo-by-projectdiscovery-dev bot commented Mar 8, 2026

Neo - PR Security Review

No security issues found

Highlights

  • Adds auto-wildcard detection feature with --auto-wildcard flag
  • Implements checkWildcard() function to test common subdomains for wildcard patterns
  • Includes unit tests for wildcard detection logic
Hardening Notes
  • The dnsx.Query() function called in main.go line 18 doesn't exist in the dnsx library - the actual methods are QueryOne() or QueryMultiple() on a DNSX instance. This will cause a compilation error but is not a security vulnerability.
  • The implementation uses safe DNS query operations via the miekg/dns library through the dnsx wrapper, which properly encodes DNS protocol messages
  • Domain string concatenation (line 17) is safe in this context as DNS queries use structured protocol format handled by the DNS library

Comment @pdneo help for available commands. · Open in Neo

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

Walkthrough

Introduces a new CLI tool with auto-wildcard detection capability. The main function parses a -auto-wildcard flag and processes domain arguments. A helper function checkWildcard probes common subdomains to detect wildcard DNS records. If enabled and a wildcard is detected, the domain is skipped; otherwise, standard checking proceeds.

Changes

Cohort / File(s) Summary
CLI Tool Setup
cmd/dnsx/main.go
New main function implementing -auto-wildcard flag parsing and domain processing logic with conditional wildcard detection skipping.
Wildcard Detection
cmd/dnsx/main.go
New checkWildcard helper function that probes subdomains (www, ftp, mail, api, test) via dnsx.Query to identify wildcard DNS presence.
Test Coverage
test/wildcard_test.go
New test suite for checkWildcard with subtests covering example.com (wildcard present) and nonwildcard.com (no wildcard) scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/CLI
    participant Main as Main Function
    participant CheckWildcard as checkWildcard()
    participant DNS as DNS Resolver<br/>(dnsx.Query)
    
    User->>Main: dnsx -auto-wildcard domain.com
    Main->>Main: Parse -auto-wildcard flag
    Main->>CheckWildcard: checkWildcard("domain.com")
    loop Probe Subdomains
        CheckWildcard->>DNS: Query www.domain.com
        DNS-->>CheckWildcard: Response (A/AAAA or NXDOMAIN)
        CheckWildcard->>DNS: Query ftp.domain.com
        DNS-->>CheckWildcard: Response
        Note over CheckWildcard: ... probe mail, api, test ...
    end
    CheckWildcard->>CheckWildcard: If any non-NXDOMAIN → wildcard=true
    CheckWildcard-->>Main: Return wildcard status
    alt Wildcard Detected & Flag Enabled
        Main->>User: Print info message & skip domain
    else No Wildcard or Flag Disabled
        Main->>User: Print "Checking domain" message
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A wildcard dance in DNS light,
Subdomains probed through the night,
With flags unfurled and queries sent,
Wildcard detection—heaven-sent!
Auto-skip or check with care,
No more guessing, crystal clear! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The implementation adds the auto-wildcard flag and detection logic, but does not filter results; auto-wildcard currently only skips checking domains with detected wildcards rather than filtering query results. Clarify whether the current behavior (skipping wildcard domains) fully satisfies issue #924's requirement to 'filter out wildcard-based results automatically' or if additional filtering logic is needed.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and specifically describes the main change: adding auto wildcard detection functionality similar to PureDNS, which matches the PR's core objective.
Out of Scope Changes check ✅ Passed All changes are directly related to the auto-wildcard detection feature specified in issue #924; no unrelated or out-of-scope modifications are present.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/dnsx/main.go`:
- Around line 4-9: The import path for the dnsx package is incorrect; update the
import statement in the import block to use the correct module path
"github.com/projectdiscovery/dnsx/libs/dnsx" so references to the dnsx package
(e.g., usages of package symbol dnsx in main.go) resolve to the internal
library; ensure the import alias remains dnsx and run `go build` to verify there
are no unresolved references.
- Around line 26-38: The main function currently assumes a module-level
dnsx.Query; replace that with a dnsx client: instantiate a client via
dnsx.New(...) before looping over domains, then call
client.QueryOne()/client.QueryMultiple() (or the appropriate client method) and
handle the returned (result, error) values; also add a guard after domains :=
flag.Args() to return a logged error if domains is empty/nil, and ensure
checkWildcard(domain) errors are handled if it can return an error. Update
references in the loop to use the new client instance and propagate/log DNS
errors instead of ignoring them.
- Around line 12-24: The checkWildcard function is using a non-existent
dnsx.Query and treating its return as a string; replace this by reusing or
adapting the existing IsWildcard logic from internal/runner/wildcard.go:
create/obtain a *dnsx.DNSX instance and call its QueryOne/QueryMultiple methods
(they return (*retryabledns.DNSData, error)), handle the error, extract
A-records from the returned *retryabledns.DNSData and compare results (or use
the random-subdomain + A-record comparison used in IsWildcard) instead of
probing fixed subdomains; update checkWildcard to return false on query errors
and to perform proper DNS data comparison per IsWildcard.

In `@test/wildcard_test.go`:
- Around line 9-26: Test is non-deterministic and failing to compile because it
calls checkWildcard which does real DNS queries and is inaccessible; refactor
checkWildcard to accept a DNS client interface (e.g., type DNSQuerier with
QueryOne(hostname string) (*retryabledns.DNSData, error)) or make it
exported/accessible, update function signature checkWildcard(client DNSQuerier,
domain string) and adjust callers, then rewrite TestCheckWildcard to use a
mockDNSClient implementing DNSQuerier (with a responses map and QueryOne
returning preset DNSData or NXDOMAIN) and assert deterministic true/false
outcomes instead of querying real domains.
- Around line 1-6: The test cannot access the unexported function checkWildcard
because it's in a different package; either move the test into the same package
as checkWildcard (so the test file lives alongside the implementation and can
call checkWildcard directly) or make checkWildcard exported (rename to
CheckWildcard) and refactor it into a testable package (e.g., an internal
package) so the test can import it; also remove the unused
github.com/projectdiscovery/dnsx import from the test file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a8da7c19-dbee-4203-ab7f-cdececf5ad3f

📥 Commits

Reviewing files that changed from the base of the PR and between fe80b18 and 129798e.

📒 Files selected for processing (2)
  • cmd/dnsx/main.go
  • test/wildcard_test.go

Comment on lines +4 to +9
import (
"flag"
"fmt"
"strings"
"github.com/projectdiscovery/dnsx" // Assuming this package handles DNS queries
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incorrect import path for dnsx package.

The import "github.com/projectdiscovery/dnsx" does not match the internal library structure. Based on the codebase, the dnsx library is located at libs/dnsx and should be imported as "github.com/projectdiscovery/dnsx/libs/dnsx".

Suggested fix
 import (
     "flag"
     "fmt"
     "strings"
-    "github.com/projectdiscovery/dnsx" // Assuming this package handles DNS queries
+    "github.com/projectdiscovery/dnsx/libs/dnsx"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/dnsx/main.go` around lines 4 - 9, The import path for the dnsx package is
incorrect; update the import statement in the import block to use the correct
module path "github.com/projectdiscovery/dnsx/libs/dnsx" so references to the
dnsx package (e.g., usages of package symbol dnsx in main.go) resolve to the
internal library; ensure the import alias remains dnsx and run `go build` to
verify there are no unresolved references.

Comment on lines +12 to +24
func checkWildcard(domain string) bool {
// Common subdomains to check for wildcard
subdomains := []string{"www", "ftp", "mail", "api", "test"}

for _, subdomain := range subdomains {
query := subdomain + "." + domain
result := dnsx.Query(query) // Assuming dnsx.Query performs DNS queries
if strings.Contains(result, "NXDOMAIN") {
return false
}
}
return true
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the dnsx package API to confirm available methods

echo "=== Checking dnsx package exports ==="
ast-grep --pattern 'func ($CLIENT *DNSX) Query$_($$$) ($$$) {
  $$$
}'

echo ""
echo "=== Checking existing wildcard implementation ==="
cat internal/runner/wildcard.go

Repository: projectdiscovery/dnsx

Length of output: 1873


🏁 Script executed:

#!/bin/bash
# Search for dnsx methods and functions more broadly

echo "=== Searching for dnsx.Query usage in codebase ==="
rg "dnsx\.Query" --type go -A 2 -B 2

echo ""
echo "=== Searching for dnsx method definitions ==="
rg "func \(.*\*DNSX\) Query" --type go -A 5

echo ""
echo "=== Finding dnsx package location and structure ==="
fd -e go -path "*dnsx*" | head -20

echo ""
echo "=== Check if dnsx.Query function exists (package-level) ==="
rg "^func Query\(" --type go -B 2 -A 5

Repository: projectdiscovery/dnsx

Length of output: 2456


🏁 Script executed:

#!/bin/bash
# Verify the exact content of the problematic function in cmd/dnsx/main.go

echo "=== Content of cmd/dnsx/main.go around the checkWildcard function ==="
head -30 cmd/dnsx/main.go

Repository: projectdiscovery/dnsx

Length of output: 927


dnsx.Query() does not exist and return type is incorrect — code will not compile.

Three critical issues prevent compilation and function:

  1. Non-existent API: dnsx.Query(query) is not a valid package-level function. The dnsx package exposes QueryOne() and QueryMultiple() as methods on a *DNSX instance only.

  2. Type mismatch: These methods return (*retryabledns.DNSData, error), not a string. You cannot call strings.Contains() on this type.

  3. Logic differs from existing implementation: The existing IsWildcard() method in internal/runner/wildcard.go uses random subdomain queries and A-record comparison, which is more reliable than probing known subdomains. The hardcoded subdomain approach can produce false positives for domains that legitimately host www/ftp/mail/api/test subdomains.

Reuse the existing IsWildcard() implementation or adapt it for this context.

Corrected approach (requires further adaptation)
-func checkWildcard(domain string) bool {
-    subdomains := []string{"www", "ftp", "mail", "api", "test"}
-
-    for _, subdomain := range subdomains {
-        query := subdomain + "." + domain
-        result := dnsx.Query(query)
-        if strings.Contains(result, "NXDOMAIN") {
-            return false
-        }
-    }
-    return true
-}
+func checkWildcard(dnsxClient *dnsx.DNSX, domain string) bool {
+    randomSub := xid.New().String() + "." + domain
+    result, err := dnsxClient.QueryOne(randomSub)
+    if err != nil || result == nil {
+        return false
+    }
+    return len(result.A) > 0
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/dnsx/main.go` around lines 12 - 24, The checkWildcard function is using a
non-existent dnsx.Query and treating its return as a string; replace this by
reusing or adapting the existing IsWildcard logic from
internal/runner/wildcard.go: create/obtain a *dnsx.DNSX instance and call its
QueryOne/QueryMultiple methods (they return (*retryabledns.DNSData, error)),
handle the error, extract A-records from the returned *retryabledns.DNSData and
compare results (or use the random-subdomain + A-record comparison used in
IsWildcard) instead of probing fixed subdomains; update checkWildcard to return
false on query errors and to perform proper DNS data comparison per IsWildcard.

Comment on lines +26 to +38
func main() {
autoWildcard := flag.Bool("auto-wildcard", false, "Enable automatic wildcard detection")
flag.Parse()

domains := flag.Args()
for _, domain := range domains {
if *autoWildcard && checkWildcard(domain) {
fmt.Printf("[INFO] Wildcard detected for domain: %s\n", domain)
continue // Skip the wildcard domain
}
fmt.Printf("Checking domain: %s\n", domain)
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how other commands in this repo initialize the dnsx client
ast-grep --pattern 'dnsx.New($$$)'

Repository: projectdiscovery/dnsx

Length of output: 47


🏁 Script executed:

cat -n cmd/dnsx/main.go | head -60

Repository: projectdiscovery/dnsx

Length of output: 1407


🏁 Script executed:

fd -t f -name "*.go" cmd/ | head -20

Repository: projectdiscovery/dnsx

Length of output: 295


🏁 Script executed:

rg "dnsx\." --type go -A 3 -B 1 | head -100

Repository: projectdiscovery/dnsx

Length of output: 5154


🏁 Script executed:

rg "func.*Query" libs/dnsx/ --type go -B 2 -A 5

Repository: projectdiscovery/dnsx

Length of output: 931


🏁 Script executed:

cat -n cmd/dnsx/main.go

Repository: projectdiscovery/dnsx

Length of output: 1407


🏁 Script executed:

rg "^func Query" libs/dnsx/ --type go

Repository: projectdiscovery/dnsx

Length of output: 47


🏁 Script executed:

rg "dnsx\.Query\(" . --type go

Repository: projectdiscovery/dnsx

Length of output: 164


DNSX client must be initialized and proper query methods used.

The code calls the non-existent dnsx.Query() function. The dnsx package requires:

  1. Creating a DNSX client instance via dnsx.New() with options
  2. Calling query methods on that client (e.g., QueryMultiple(), QueryOne()), not module-level functions
  3. Handling the returned error from DNS operations

Additionally, add error handling for empty domain arguments (when flag.Args() returns nil/empty slice).

The -auto-wildcard flag format is correct per Go conventions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/dnsx/main.go` around lines 26 - 38, The main function currently assumes a
module-level dnsx.Query; replace that with a dnsx client: instantiate a client
via dnsx.New(...) before looping over domains, then call
client.QueryOne()/client.QueryMultiple() (or the appropriate client method) and
handle the returned (result, error) values; also add a guard after domains :=
flag.Args() to return a logged error if domains is empty/nil, and ensure
checkWildcard(domain) errors are handled if it can return an error. Update
references in the loop to use the new client instance and propagate/log DNS
errors instead of ignoring them.

Comment on lines +1 to +6
package main

import (
"testing"
"github.com/projectdiscovery/dnsx"
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Test file cannot access checkWildcard — package structure is incorrect.

In Go, packages are determined by directory, not by package declaration alone. This test file in test/wildcard_test.go is a separate package from cmd/dnsx/main.go, even though both declare package main. The unexported function checkWildcard is inaccessible from here.

Additionally:

  • The dnsx import is unused and should be removed.
  • CI runs go test ./... which won't compile this test together with cmd/dnsx/main.go.

To fix, either:

  1. Move the test to cmd/dnsx/main_test.go (same directory as the function), or
  2. Export the function and refactor into a testable package (e.g., internal/wildcard).
Option 1: Move test to cmd/dnsx/
-// File: test/wildcard_test.go
+// File: cmd/dnsx/wildcard_test.go
 package main

 import (
     "testing"
-    "github.com/projectdiscovery/dnsx"
 )
📝 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
package main
import (
"testing"
"github.com/projectdiscovery/dnsx"
)
package main
import (
"testing"
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/wildcard_test.go` around lines 1 - 6, The test cannot access the
unexported function checkWildcard because it's in a different package; either
move the test into the same package as checkWildcard (so the test file lives
alongside the implementation and can call checkWildcard directly) or make
checkWildcard exported (rename to CheckWildcard) and refactor it into a testable
package (e.g., an internal package) so the test can import it; also remove the
unused github.com/projectdiscovery/dnsx import from the test file.

Comment on lines +9 to +26
func TestCheckWildcard(t *testing.T) {
tests := []struct {
domain string
expected bool
}{
{"example.com", true},
{"nonwildcard.com", false},
}

for _, tt := range tests {
t.Run(tt.domain, func(t *testing.T) {
got := checkWildcard(tt.domain)
if got != tt.expected {
t.Errorf("checkWildcard() = %v, want %v", got, tt.expected)
}
})
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Test design issues: non-deterministic and lacks mocking.

  1. Hardcoded expectations for real domains: The test assumes example.com is a wildcard domain and nonwildcard.com is not. DNS responses for real domains can change, making this test flaky and non-reproducible.

  2. No mocking: The function (once fixed) would make real DNS queries. Unit tests should mock external dependencies to ensure deterministic results and avoid network dependency.

  3. Compilation will fail: As noted above, checkWildcard is inaccessible from this package location.

Consider refactoring checkWildcard to accept a DNS client interface that can be mocked in tests.

Suggested approach with interface for testability
// Define interface for DNS querying
type DNSQuerier interface {
    QueryOne(hostname string) (*retryabledns.DNSData, error)
}

// Refactor checkWildcard to accept interface
func checkWildcard(client DNSQuerier, domain string) bool {
    // implementation
}

// In tests, use a mock implementation
type mockDNSClient struct {
    responses map[string]*retryabledns.DNSData
}

func (m *mockDNSClient) QueryOne(hostname string) (*retryabledns.DNSData, error) {
    if resp, ok := m.responses[hostname]; ok {
        return resp, nil
    }
    return nil, errors.New("NXDOMAIN")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/wildcard_test.go` around lines 9 - 26, Test is non-deterministic and
failing to compile because it calls checkWildcard which does real DNS queries
and is inaccessible; refactor checkWildcard to accept a DNS client interface
(e.g., type DNSQuerier with QueryOne(hostname string) (*retryabledns.DNSData,
error)) or make it exported/accessible, update function signature
checkWildcard(client DNSQuerier, domain string) and adjust callers, then rewrite
TestCheckWildcard to use a mockDNSClient implementing DNSQuerier (with a
responses map and QueryOne returning preset DNSData or NXDOMAIN) and assert
deterministic true/false outcomes instead of querying real domains.

@addidea addidea closed this by deleting the head repository Mar 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support auto wildcard detection similar to PureDNS

1 participant