diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 16c7b25b..66eff6e3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -13,10 +13,10 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2.5.2 + uses: golangci/golangci-lint-action@v2 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.31 + version: latest args: --timeout 5m # Optional: working directory, useful for monorepos diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..dd004678 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,111 @@ +linters-settings: + dupl: + threshold: 100 + exhaustive: + default-signifies-exhaustive: false + # funlen: + # lines: 100 + # statements: 50 + goconst: + min-len: 2 + min-occurrences: 2 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - ifElseChain + # gocyclo: + # min-complexity: 15 + goimports: + local-prefixes: github.com/golangci/golangci-lint + gomnd: + settings: + mnd: + # don't include the "operation" and "assign" + checks: argument,case,condition,return + govet: + check-shadowing: true + settings: + printf: + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + # lll: + # line-length: 140 + maligned: + suggest-new: true + misspell: + locale: US + nolintlint: + allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + disable-all: true + enable: + - bodyclose + - deadcode + - dogsled + - dupl + - errcheck + - exhaustive + - gochecknoinits + - goconst + - gocritic + - gofmt + - goimports + - gomnd + - goprintffuncname + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - noctx + - nolintlint + - rowserrcheck + - exportloopref + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + - whitespace + - revive + + # don't enable: + # - depguard + # - asciicheck + # - funlen + # - gochecknoglobals + # - gocognit + # - gocyclo + # - godot + # - godox + # - goerr113 + # - gosec + # - lll + # - nestif + # - prealloc + # - testpackage + # - wsl + +issues: + exclude-use-default: false + exclude: + # should have a package comment, unless it's in another file for this package (golint) + - 'in another file for this package' diff --git a/cmd/dnsx/dnsx.go b/cmd/dnsx/dnsx.go index 5e943d2f..387e871a 100644 --- a/cmd/dnsx/dnsx.go +++ b/cmd/dnsx/dnsx.go @@ -9,12 +9,11 @@ func main() { // Parse the command line flags and read config files options := runner.ParseOptions() - runner, err := runner.New(options) + r, err := runner.New(options) if err != nil { gologger.Fatal().Msgf("Could not create runner: %s\n", err) } - // nolint:errcheck - runner.Run() - runner.Close() + _ = r.Run() + r.Close() } diff --git a/go.mod b/go.mod index 385b3e3f..6606c2ef 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,8 @@ go 1.14 require ( github.com/golang/protobuf v1.4.3 // indirect github.com/google/go-cmp v0.5.4 // indirect - github.com/miekg/dns v1.1.42 + github.com/json-iterator/go v1.1.11 // indirect + github.com/miekg/dns v1.1.43 github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.15.0 // indirect github.com/onsi/gomega v1.10.5 // indirect @@ -16,9 +17,10 @@ require ( github.com/projectdiscovery/mapcidr v0.0.7 github.com/projectdiscovery/retryabledns v1.0.12-0.20210602155924-fbe3f476df22 github.com/rs/xid v1.3.0 + go.uber.org/atomic v1.8.0 // indirect go.uber.org/ratelimit v0.2.0 - golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect - golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b // indirect + golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect google.golang.org/protobuf v1.25.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 4c4e2d64..3ae1cdc0 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY= -github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -107,8 +107,9 @@ github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFd github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4= +go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/internal/runner/options.go b/internal/runner/options.go index 2d22c987..7fac9a31 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -9,6 +9,7 @@ import ( "github.com/projectdiscovery/gologger/levels" ) +// Options of the runner type Options struct { Resolvers string Hosts string @@ -44,7 +45,7 @@ func ParseOptions() *Options { options := &Options{} flag.StringVar(&options.Resolvers, "r", "", "List of resolvers (file or command separated)") flag.StringVar(&options.Hosts, "l", "", "File input with list of subdomains") - flag.IntVar(&options.Threads, "t", 100, "Number of concurrent threads to make") + flag.IntVar(&options.Threads, "t", defaultThreads, "Number of concurrent threads to make") flag.IntVar(&options.Retries, "retry", 1, "Number of DNS retries") flag.IntVar(&options.RateLimit, "rl", -1, "Number of DNS request/second") flag.StringVar(&options.OutputFile, "o", "", "File to write output to (optional)") @@ -63,7 +64,7 @@ func ParseOptions() *Options { flag.BoolVar(&options.SOA, "soa", false, "Query SOA record") flag.BoolVar(&options.TXT, "txt", false, "Query TXT record") flag.BoolVar(&options.JSON, "json", false, "JSON output") - flag.IntVar(&options.WildcardThreshold, "wt", 5, "Wildcard Filter Threshold") + flag.IntVar(&options.WildcardThreshold, "wt", five, "Wildcard Filter Threshold") flag.StringVar(&options.WildcardDomain, "wd", "", "Wildcard Top level domain for wildcard filtering (other flags will be ignored)") flag.BoolVar(&options.ShowStatistics, "stats", false, "Enable statistic on keypress (terminal may become unresponsive till the end)") flag.BoolVar(&options.Trace, "trace", false, "Perform dns trace") diff --git a/internal/runner/runner.go b/internal/runner/runner.go index ea920c8d..c6fb9f7b 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -34,6 +34,7 @@ type Runner struct { stats clistats.StatisticsClient } +// New creates new runner instance func New(options *Options) (*Runner, error) { dnsxOptions := dnsx.DefaultOptions dnsxOptions.MaxRetries = options.Retries @@ -129,6 +130,7 @@ func New(options *Options) (*Runner, error) { return &r, nil } +// InputWorker handle parsing and elaborating the input func (r *Runner) InputWorker() { r.hm.Scan(func(k, _ []byte) error { if r.options.ShowStatistics { @@ -150,7 +152,7 @@ func (r *Runner) prepareInput() error { if err != nil { return err } - defer f.Close() + defer f.Close() //nolint } else if (stat.Mode() & os.ModeCharDevice) == 0 { f = os.Stdin } else { @@ -170,10 +172,8 @@ func (r *Runner) prepareInput() error { if _, ok := r.hm.Get(host); ok { continue } - numHosts++ - // nolint:errcheck - r.hm.Set(host, nil) - } + numHosts++ + _ = r.hm.Set(host, nil) } if r.options.ShowStatistics { @@ -181,14 +181,12 @@ func (r *Runner) prepareInput() error { r.stats.AddStatic("startedAt", time.Now()) r.stats.AddCounter("requests", 0) r.stats.AddCounter("total", uint64(numHosts*len(r.dnsx.Options.QuestionTypes))) - // nolint:errcheck - r.stats.Start(makePrintCallback(), time.Duration(5)*time.Second) + _ = r.stats.Start(makePrintCallback(), time.Duration(five)*time.Second) } return nil } -// nolint:deadcode func makePrintCallback() func(stats clistats.StatisticsClient) { builder := &strings.Builder{} return func(stats clistats.StatisticsClient) { @@ -225,6 +223,7 @@ func makePrintCallback() func(stats clistats.StatisticsClient) { } } +// Run the internal logic func (r *Runner) Run() error { err := r.prepareInput() if err != nil { @@ -254,6 +253,7 @@ func (r *Runner) Run() error { return nil } +// HandleOutput results func (r *Runner) HandleOutput() { defer r.wgoutputworker.Done() @@ -268,15 +268,14 @@ func (r *Runner) HandleOutput() { if err != nil { gologger.Fatal().Msgf("%s\n", err) } - defer foutput.Close() + defer foutput.Close() //nolint w = bufio.NewWriter(foutput) - defer w.Flush() + defer w.Flush() //nolint } for item := range r.outputchan { if r.options.OutputFile != "" { // uses a buffer to write to file - // nolint:errcheck - w.WriteString(item + "\n") + _, _ = w.WriteString(item + "\n") } // otherwise writes sequentially to stdout gologger.Silent().Msgf("%s\n", item) @@ -341,8 +340,7 @@ func (r *Runner) worker() { // if wildcard filtering just store the data if r.options.WildcardDomain != "" { - // nolint:errcheck - r.storeDNSData(dnsData) + _ = r.storeDNSData(dnsData) continue } if r.options.JSON { @@ -383,7 +381,7 @@ func (r *Runner) worker() { func (r *Runner) outputRecordType(domain string, items []string) { for _, item := range items { - item := strings.ToLower(item) + item = strings.ToLower(item) if r.options.ResponseOnly { r.outputchan <- item } else if r.options.Response { @@ -406,7 +404,7 @@ func (r *Runner) storeDNSData(dnsdata *retryabledns.DNSData) error { // Close running instance func (r *Runner) Close() { - r.hm.Close() + _ = r.hm.Close() } // TODO - wip - just ignore @@ -484,5 +482,4 @@ func (r *Runner) wildcardWorker() { } } } - } diff --git a/internal/runner/util.go b/internal/runner/util.go index 7264d6ce..d3f04a32 100644 --- a/internal/runner/util.go +++ b/internal/runner/util.go @@ -9,6 +9,11 @@ import ( "time" ) +const ( + five = 5 + defaultThreads = 100 +) + func fileExists(fileName string) bool { info, err := os.Stat(fileName) if os.IsNotExist(err) { @@ -23,7 +28,7 @@ func linesInFile(fileName string) ([]string, error) { if err != nil { return result, err } - defer f.Close() + defer f.Close() //nolint scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() @@ -47,8 +52,8 @@ func isURL(toTest string) bool { return true } -func extractDomain(URL string) string { - u, err := url.Parse(URL) +func extractDomain(target string) string { + u, err := url.Parse(target) if err != nil { return "" } diff --git a/internal/runner/wildcard.go b/internal/runner/wildcard.go index ff1d5ec5..1791f4f4 100644 --- a/internal/runner/wildcard.go +++ b/internal/runner/wildcard.go @@ -7,9 +7,9 @@ import ( ) // IsWildcard checks if a host is wildcard -func (r *Runner) IsWildcard(host string) (bool, map[string]struct{}) { +func (r *Runner) IsWildcard(host string) (iswildcard bool, wildcards map[string]struct{}) { orig := make(map[string]struct{}) - wildcards := make(map[string]struct{}) + wildcards = make(map[string]struct{}) subdomainPart := strings.TrimSuffix(host, "."+r.options.WildcardDomain) subdomainTokens := strings.Split(subdomainPart, ".") @@ -19,8 +19,7 @@ func (r *Runner) IsWildcard(host string) (bool, map[string]struct{}) { // We use a rand prefix at the beginning like %rand%.domain.tld // A permutation is generated for each level of the subdomain. var hosts []string - hosts = append(hosts, host) - hosts = append(hosts, xid.New().String()+"."+r.options.WildcardDomain) + hosts = append(hosts, host, xid.New().String()+"."+r.options.WildcardDomain) for i := 0; i < len(subdomainTokens); i++ { newhost := xid.New().String() + "." + strings.Join(subdomainTokens[i:], ".") + "." + r.options.WildcardDomain @@ -50,9 +49,10 @@ func (r *Runner) IsWildcard(host string) (bool, map[string]struct{}) { // check if original ip are among wildcards for a := range orig { if _, ok := wildcards[a]; ok { - return true, wildcards + iswildcard = true + break } } - return false, wildcards + return //nolint }