Skip to content

Commit

Permalink
introduce query type selection (#465)
Browse files Browse the repository at this point in the history
* introduce query type selection

* add all as a flag and exclude it from exclude types

* enable `-resp` when `-all` is used and colorize the output

* exclude `-ptr` if hostname is not an IP

* fix filter logic

* exclude any

* misc updates

* dedupe SOA

---------

Co-authored-by: sandeep <[email protected]>
  • Loading branch information
dogancanbakir and ehsandeep authored Mar 3, 2024
1 parent 41751c6 commit 1053558
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 27 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,20 @@ INPUT:
-w, -wordlist string list of words to bruteforce (file or comma separated or stdin)

QUERY:
-a query A record (default)
-aaaa query AAAA record
-cname query CNAME record
-ns query NS record
-txt query TXT record
-srv query SRV record
-ptr query PTR record
-mx query MX record
-soa query SOA record
-axfr query AXFR
-caa query CAA record
-any query ANY record
-a query A record (default)
-aaaa query AAAA record
-cname query CNAME record
-ns query NS record
-txt query TXT record
-srv query SRV record
-ptr query PTR record
-mx query MX record
-soa query SOA record
-any query ANY record
-axfr query AXFR
-caa query CAA record
-all query all records
-eq, -exclude-type value dns query type to exclude (a,aaaa,cname,ns,txt,srv,ptr,mx,soa,axfr,caa,any) (default none)

FILTER:
-re, -resp display dns response
Expand Down
57 changes: 57 additions & 0 deletions internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Options struct {
Silent bool
Verbose bool
Version bool
NoColor bool
Response bool
ResponseOnly bool
A bool
Expand Down Expand Up @@ -65,6 +66,8 @@ type Options struct {
HostsFile bool
Stream bool
CAA bool
QueryAll bool
ExcludeType []string
OutputCDN bool
ASN bool
HealthCheck bool
Expand Down Expand Up @@ -94,6 +97,22 @@ func ParseOptions() *Options {
flagSet.StringVarP(&options.WordList, "wordlist", "w", "", "list of words to bruteforce (file or comma separated or stdin)"),
)

queries := goflags.AllowdTypes{
"none": goflags.EnumVariable(0),
"a": goflags.EnumVariable(1),
"aaaa": goflags.EnumVariable(2),
"cname": goflags.EnumVariable(3),
"ns": goflags.EnumVariable(4),
"txt": goflags.EnumVariable(5),
"srv": goflags.EnumVariable(6),
"ptr": goflags.EnumVariable(7),
"mx": goflags.EnumVariable(8),
"soa": goflags.EnumVariable(9),
"axfr": goflags.EnumVariable(10),
"caa": goflags.EnumVariable(11),
"any": goflags.EnumVariable(12),
}

flagSet.CreateGroup("query", "Query",
flagSet.BoolVar(&options.A, "a", false, "query A record (default)"),
flagSet.BoolVar(&options.AAAA, "aaaa", false, "query AAAA record"),
Expand All @@ -107,6 +126,8 @@ func ParseOptions() *Options {
flagSet.BoolVar(&options.ANY, "any", false, "query ANY record"),
flagSet.BoolVar(&options.AXFR, "axfr", false, "query AXFR"),
flagSet.BoolVar(&options.CAA, "caa", false, "query CAA record"),
flagSet.BoolVar(&options.QueryAll, "recon", false, "query all the dns records (a,aaaa,cname,ns,txt,srv,ptr,mx,soa,axfr,caa)"),
flagSet.EnumSliceVarP(&options.ExcludeType, "exclude-type", "eq", []goflags.EnumVariable{0}, "dns query type to exclude (a,aaaa,cname,ns,txt,srv,ptr,mx,soa,axfr,caa)", queries),
)

flagSet.CreateGroup("filter", "Filter",
Expand Down Expand Up @@ -143,6 +164,7 @@ func ParseOptions() *Options {
flagSet.BoolVarP(&options.Raw, "debug", "raw", false, "display raw dns response"),
flagSet.BoolVar(&options.ShowStatistics, "stats", false, "display stats of the running scan"),
flagSet.BoolVar(&options.Version, "version", false, "display version of dnsx"),
flagSet.BoolVarP(&options.NoColor, "no-color", "nc", false, "disable color in output"),
)

flagSet.CreateGroup("optimization", "Optimization",
Expand All @@ -168,6 +190,8 @@ func ParseOptions() *Options {
os.Exit(0)
}

options.configureQueryOptions()

// Read the inputs and configure the logging
options.configureOutput()

Expand Down Expand Up @@ -359,3 +383,36 @@ func (options *Options) configureResume() error {
}
return nil
}

func (options *Options) configureQueryOptions() {
queryMap := map[string]*bool{
"a": &options.A,
"aaaa": &options.AAAA,
"cname": &options.CNAME,
"ns": &options.NS,
"txt": &options.TXT,
"srv": &options.SRV,
"ptr": &options.PTR,
"mx": &options.MX,
"soa": &options.SOA,
"axfr": &options.AXFR,
"caa": &options.CAA,
"any": &options.ANY,
}

if options.QueryAll {
for _, val := range queryMap {
*val = true
}
options.Response = true
// the ANY query type is not supported by the retryabledns library,
// thus it's hard to filter the results when it's used in combination with other query types
options.ExcludeType = append(options.ExcludeType, "any")
}

for _, et := range options.ExcludeType {
if val, ok := queryMap[et]; ok {
*val = false
}
}
}
32 changes: 18 additions & 14 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"sync"
"time"

"github.com/logrusorgru/aurora"
"github.com/miekg/dns"
"github.com/pkg/errors"
asnmap "github.com/projectdiscovery/asnmap/libs"
Expand Down Expand Up @@ -45,6 +46,7 @@ type Runner struct {
hm *hybrid.HybridMap
stats clistats.StatisticsClient
tmpStdinFile string
aurora aurora.Aurora
}

func New(options *Options) (*Runner, error) {
Expand Down Expand Up @@ -115,6 +117,7 @@ func New(options *Options) (*Runner, error) {
questionTypes = append(questionTypes, dns.TypeA)
}
dnsxOptions.QuestionTypes = questionTypes
dnsxOptions.QueryAll = options.QueryAll

dnsX, err := dnsx.New(dnsxOptions)
if err != nil {
Expand Down Expand Up @@ -152,6 +155,7 @@ func New(options *Options) (*Runner, error) {
limiter: limiter,
hm: hm,
stats: stats,
aurora: aurora.NewAurora(!options.NoColor),
}

return &r, nil
Expand Down Expand Up @@ -731,25 +735,25 @@ func (r *Runner) worker() {
continue
}
if r.options.A {
r.outputRecordType(domain, dnsData.A, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.A, "A", dnsData.CDNName, dnsData.ASN)
}
if r.options.AAAA {
r.outputRecordType(domain, dnsData.AAAA, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.AAAA, "AAAA", dnsData.CDNName, dnsData.ASN)
}
if r.options.CNAME {
r.outputRecordType(domain, dnsData.CNAME, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.CNAME, "CNAME", dnsData.CDNName, dnsData.ASN)
}
if r.options.PTR {
r.outputRecordType(domain, dnsData.PTR, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.PTR, "PTR", dnsData.CDNName, dnsData.ASN)
}
if r.options.MX {
r.outputRecordType(domain, dnsData.MX, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.MX, "MX", dnsData.CDNName, dnsData.ASN)
}
if r.options.NS {
r.outputRecordType(domain, dnsData.NS, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.NS, "NS", dnsData.CDNName, dnsData.ASN)
}
if r.options.SOA {
r.outputRecordType(domain, dnsData.GetSOARecords(), dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, sliceutil.Dedupe(dnsData.GetSOARecords()), "SOA", dnsData.CDNName, dnsData.ASN)
}
if r.options.ANY {
allParsedRecords := sliceutil.Merge(
Expand All @@ -758,27 +762,27 @@ func (r *Runner) worker() {
dnsData.CNAME,
dnsData.MX,
dnsData.PTR,
dnsData.GetSOARecords(),
sliceutil.Dedupe(dnsData.GetSOARecords()),
dnsData.NS,
dnsData.TXT,
dnsData.SRV,
dnsData.CAA,
)
r.outputRecordType(domain, allParsedRecords, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, allParsedRecords, "ANY", dnsData.CDNName, dnsData.ASN)
}
if r.options.TXT {
r.outputRecordType(domain, dnsData.TXT, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.TXT, "TXT", dnsData.CDNName, dnsData.ASN)
}
if r.options.SRV {
r.outputRecordType(domain, dnsData.SRV, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.SRV, "SRV", dnsData.CDNName, dnsData.ASN)
}
if r.options.CAA {
r.outputRecordType(domain, dnsData.CAA, dnsData.CDNName, dnsData.ASN)
r.outputRecordType(domain, dnsData.CAA, "CAA", dnsData.CDNName, dnsData.ASN)
}
}
}

func (r *Runner) outputRecordType(domain string, items interface{}, cdnName string, asn *dnsx.AsnResponse) {
func (r *Runner) outputRecordType(domain string, items interface{}, queryType, cdnName string, asn *dnsx.AsnResponse) {
var details string
if cdnName != "" {
details = fmt.Sprintf(" [%s]", cdnName)
Expand All @@ -802,7 +806,7 @@ func (r *Runner) outputRecordType(domain string, items interface{}, cdnName stri
if r.options.ResponseOnly {
r.outputchan <- fmt.Sprintf("%s%s", item, details)
} else if r.options.Response {
r.outputchan <- fmt.Sprintf("%s [%s] %s", domain, item, details)
r.outputchan <- fmt.Sprintf("%s [%s] [%s] %s", domain, r.aurora.Magenta(queryType), r.aurora.Green(item).String(), details)
} else {
// just prints out the domain if it has a record type and exit
r.outputchan <- fmt.Sprintf("%s%s", domain, details)
Expand Down
14 changes: 13 additions & 1 deletion libs/dnsx/dnsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/projectdiscovery/cdncheck"
retryabledns "github.com/projectdiscovery/retryabledns"
iputil "github.com/projectdiscovery/utils/ip"
sliceutil "github.com/projectdiscovery/utils/slice"
)

// DNSX is structure to perform dns lookups
Expand All @@ -28,6 +29,7 @@ type Options struct {
TraceMaxRecursion int
Hostsfile bool
OutputCDN bool
QueryAll bool
}

// ResponseData to show output result
Expand Down Expand Up @@ -131,7 +133,17 @@ func (d *DNSX) QueryOne(hostname string) (*retryabledns.DNSData, error) {

// QueryMultiple performs a DNS question of the specified types and returns raw responses
func (d *DNSX) QueryMultiple(hostname string) (*retryabledns.DNSData, error) {
return d.dnsClient.QueryMultiple(hostname, d.Options.QuestionTypes)
// Omit PTR queries unless the input is an IP address to decrease execution time, as PTR queries can lead to timeouts.
filteredQuestionTypes := d.Options.QuestionTypes
if d.Options.QueryAll {
isIP := iputil.IsIP(hostname)
if !isIP {
filteredQuestionTypes = sliceutil.PruneEqual(filteredQuestionTypes, miekgdns.TypePTR)
} else {
filteredQuestionTypes = []uint16{miekgdns.TypePTR}
}
}
return d.dnsClient.QueryMultiple(hostname, filteredQuestionTypes)
}

// Trace performs a DNS trace of the specified types and returns raw responses
Expand Down

0 comments on commit 1053558

Please sign in to comment.