Skip to content

Add --auto-wildcard option with per-domain wildcard detection#940

Open
Excellencedev wants to merge 3 commits intoprojectdiscovery:devfrom
Excellencedev:auto-wildcard
Open

Add --auto-wildcard option with per-domain wildcard detection#940
Excellencedev wants to merge 3 commits intoprojectdiscovery:devfrom
Excellencedev:auto-wildcard

Conversation

@Excellencedev
Copy link

@Excellencedev Excellencedev commented Feb 8, 2026

Motivation

  • Add an optional mode to auto-detect and filter wildcard DNS across multiple domains in a single run, matching the behavior requested (similar to PureDNS) so users do not need to pass -wd per domain.

Description

  • Add AutoWildcard option and CLI flag --auto-wildcard, plus validation to prevent incompatible combinations like --stream or -wd together with --auto-wildcard.
  • Implement wildcardBaseDomain(host) heuristic to compute a base domain (handles common 2nd-level TLD cases) and change the wildcard pipeline to operate per base domain.
  • Refactor wildcard processing: DNS results are grouped by base domain, a wildcardJob type and job channel are added, and IsWildcard signature updated to accept the wildcardDomain parameter so workers can run per-domain checks.
  • Ensure wildcard filtering automatically enables A queries when needed and store responses while filtering; update lookupAndOutput flow to output filtered results.
  • Add unit test internal/runner/wildcard_test.go for the base-domain heuristic and document the feature and example usage in README.md with --auto-wildcard usage.

Testing

  • Added unit test internal/runner/wildcard_test.go covering wildcardBaseDomain; test file included in the PR.
  • Ran gofmt on modified files successfully.

Test Logs :

$ go test ./internal/runner -run TestWildcardBaseDomain
ok      github.com/projectdiscovery/dnsx/internal/runner        1.763s

/fixes #924
/claim #924

Summary by CodeRabbit

  • New Features

    • Introduced --auto-wildcard flag for automatic detection and filtering of wildcard subdomains per base domain
    • Enhanced wildcard filtering logic with improved subdomain handling
  • Documentation

    • Updated documentation with usage examples demonstrating the new --auto-wildcard flag functionality
    • Clarified domain input requirements: now optional when using --auto-wildcard for wildcard elimination

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Walkthrough

This PR introduces an --auto-wildcard flag that automatically detects and filters wildcard subdomains per base domain, refactors wildcard filtering logic to use per-host domain contexts via a new wildcardJob type, updates the IsWildcard method signature, and adds supporting helper functions and validation rules.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added description of new --auto-wildcard flag with usage example and updated conditional requirements for domain input in wildcard elimination.
Options and Validation
internal/runner/options.go
Introduced AutoWildcard boolean option with command-line flag binding and added runtime validations to disallow this flag in stream mode and prevent its combination with WildcardDomain.
Wildcard Filtering Logic
internal/runner/runner.go, internal/runner/wildcard.go
Refactored wildcard filtering to use new wildcardJob type carrying host and domain context; updated IsWildcard signature to accept wildcardDomain parameter; added helpers (wildcardFilteringEnabled, wildcardDomainForHost, filterWildcards, hasQuestionType, wildcardBaseDomain); integrated filtering into runner flow with post-run execution and output sequencing adjustments.
Tests
internal/runner/wildcard_test.go
Added parallel unit tests for wildcardBaseDomain helper covering domain normalization, subdomain stripping, and edge cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Poem

🐰 With auto-wildcard springs forth new cheer,
Subdomains sorted, filtered clear—
No need for domain names to tell,
The rabbits' burrows serve them well! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: introducing a new --auto-wildcard option with per-domain wildcard detection capabilities.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 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.

@Excellencedev
Copy link
Author

cc @dogancanbakir Please review
Verified this works thriugh the test and showing that test passes

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/runner/runner.go (1)

499-637: ⚠️ Potential issue | 🟡 Minor

filterWildcards silently drops non-JSON output formatting (e.g. -resp, -ro).

lookupAndOutput (line 648–667) only emits raw hostnames in non-JSON mode. When --auto-wildcard is active, users who also pass -a -resp or -resp-only will get bare hostnames instead of formatted DNS responses. The existing -wd flag documents this limitation ("only json output is supported"), but --auto-wildcard has no equivalent warning or enforcement.

Consider either:

  1. Adding a validation error or warning when --auto-wildcard is combined with response-formatting flags, or
  2. Documenting the JSON-only limitation for --auto-wildcard in the help text and README.
🧹 Nitpick comments (4)
internal/runner/wildcard_test.go (1)

5-25: Consider using t.Run for subtests and adding edge cases.

The test table is solid but could benefit from two improvements:

  1. Using t.Run with a descriptive name per case gives clearer failure output and allows running individual cases.
  2. Consider adding edge cases: empty string "", an IPv6 address like "::1", and a two-level ccTLD without a known second-level (e.g., "example.uk""example.uk").
♻️ Suggested improvement
 	for _, tt := range tests {
-		if got := wildcardBaseDomain(tt.input); got != tt.expected {
-			t.Errorf("wildcardBaseDomain(%q) = %q, want %q", tt.input, got, tt.expected)
-		}
+		t.Run(tt.input, func(t *testing.T) {
+			t.Parallel()
+			if got := wildcardBaseDomain(tt.input); got != tt.expected {
+				t.Errorf("wildcardBaseDomain(%q) = %q, want %q", tt.input, got, tt.expected)
+			}
+		})
 	}
internal/runner/runner.go (2)

588-607: Dead code / unreachable branches in unfilteredHosts processing.

unfilteredHosts is only populated when r.options.AutoWildcard is true and the host is an IP or has no dot (lines 520–522). In the output loop:

  • Line 593: r.options.AutoWildcard is always true for these hosts.
  • Line 594: wildcardBaseDomain(host) will always return "" for IPs and single-label hosts.
  • Line 596: The IP/no-dot check is always true (that's how they entered unfilteredHosts).
  • Lines 598–603 and 606 are unreachable.

This doesn't cause incorrect behavior, but the redundant re-derivation makes the logic harder to follow. Consider simplifying:

♻️ Simplified unfilteredHosts output
-	for host := range unfilteredHosts {
-		if _, ok := seen[host]; ok {
-			continue
-		}
-		seen[host] = struct{}{}
-		if r.options.AutoWildcard {
-			wildcardDomain := wildcardBaseDomain(host)
-			if wildcardDomain == "" {
-				if net.ParseIP(host) != nil || !strings.Contains(host, ".") {
-					_ = r.lookupAndOutput(host)
-				} else {
-					ambiguousHosts[host] = struct{}{}
-				}
-			} else {
-				ambiguousHosts[host] = struct{}{}
-			}
-			continue
-		}
-		_ = r.lookupAndOutput(host)
-	}
+	for host := range unfilteredHosts {
+		if _, ok := seen[host]; ok {
+			continue
+		}
+		seen[host] = struct{}{}
+		_ = r.lookupAndOutput(host)
+	}

551-580: Edge case: when totalIPs == 0 the wildcard worker channel is closed without starting workers, which is correct — but wgwildcardworker is never waited on.

When totalIPs > 0, workers are started (line 559–561) and waited on (line 577). When totalIPs == 0, the channel is closed at line 579 but r.wgwildcardworker.Wait() is never called. This is technically fine since no workers were added, but for symmetry and safety against future changes, consider calling r.wgwildcardworker.Wait() after the else branch as well.

internal/runner/wildcard.go (1)

10-44: Consider using golang.org/x/net/publicsuffix for more reliable domain parsing.

The commonSecondLevelDomains + len(last) == 2 heuristic handles common cases well (.co.uk, .com.br, .co.in) but can misfire on edge cases:

  • Two-letter gTLDs where the second label matches the map: e.g. sub.example.co.de"example.co.de" (treats .co.de as a hierarchical ccTLD, which is incorrect).
  • Three+ letter ccTLD compounds: e.g. sub.example.co.com"co.com" (loses the example label).

The golang.org/x/net/publicsuffix package provides an authoritative Public Suffix List and would eliminate these edge cases. The EffectiveTLDPlusOne() function returns the registrable domain directly:

import "golang.org/x/net/publicsuffix"

func wildcardBaseDomain(host string) string {
    host = strings.TrimSpace(strings.TrimSuffix(host, "."))
    if host == "" || iputil.IsIP(host) {
        return ""
    }
    domain, err := publicsuffix.EffectiveTLDPlusOne(strings.ToLower(host))
    if err != nil {
        return ""
    }
    return domain
}

This is a recommended improvement but not blocking given the heuristic's scope targets common cases.

@Excellencedev
Copy link
Author

This is the one issue I would like to work on

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support auto wildcard detection similar to PureDNS

1 participant

Comments