feat: add strategy flag

Ref https://github.com/mr-karan/doggo/issues/35
pull/41/head
Karan Sharma 2022-05-17 10:21:14 +05:30
parent 79c5fc7283
commit 7619cbdeb0
7 changed files with 46 additions and 9 deletions

View File

@ -62,5 +62,8 @@
- [ ] Add tests for CLI Output. - [ ] Add tests for CLI Output.
- [ ] Homebrew - Goreleaser - [ ] Homebrew - Goreleaser
- [ ] Add support for `dig +trace` like functionality. - [ ] Add support for `dig +trace` like functionality.
- [ ] Add `dig +x` short output
- [x] Add `--strategy` for picking nameservers.
- [ ] Explore `dig.rc` kinda file
- [x] Separate Authority/Answer in JSON output. - [x] Separate Authority/Answer in JSON output.
- [x] Error on NXDomain (Related upstream [bug](https://github.com/miekg/dns/issues/1198)) - [x] Error on NXDomain (Related upstream [bug](https://github.com/miekg/dns/issues/1198))

1
^ 100644
View File

@ -0,0 +1 @@
nameserver 127.0.w0.1

View File

@ -45,6 +45,7 @@ func main() {
f.Int("ndots", -1, "Specify the ndots parameter. Default value is taken from resolv.conf and fallbacks to 1 if ndots statement is missing in resolv.conf") f.Int("ndots", -1, "Specify the ndots parameter. Default value is taken from resolv.conf and fallbacks to 1 if ndots statement is missing in resolv.conf")
f.BoolP("ipv4", "4", false, "Use IPv4 only") f.BoolP("ipv4", "4", false, "Use IPv4 only")
f.BoolP("ipv6", "6", false, "Use IPv6 only") f.BoolP("ipv6", "6", false, "Use IPv6 only")
f.String("strategy", "all", "Strategy to query nameservers in resolv.conf file (`all`, `random`, `first`)")
// Output Options // Output Options
f.BoolP("json", "J", false, "Set the output format as JSON") f.BoolP("json", "J", false, "Set the output format as JSON")
@ -126,6 +127,7 @@ func main() {
Ndots: app.ResolverOpts.Ndots, Ndots: app.ResolverOpts.Ndots,
Timeout: app.QueryFlags.Timeout * time.Second, Timeout: app.QueryFlags.Timeout * time.Second,
Logger: app.Logger, Logger: app.Logger,
Strategy: app.QueryFlags.Strategy,
}) })
if err != nil { if err != nil {
app.Logger.WithError(err).Error("error loading resolver") app.Logger.WithError(err).Error("error loading resolver")

View File

@ -47,6 +47,7 @@ var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}:
{{"-x, --reverse" | color "yellow" ""}} Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively. {{"-x, --reverse" | color "yellow" ""}} Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively.
{{ "Resolver Options" | color "" "heading" }}: {{ "Resolver Options" | color "" "heading" }}:
{{"--strategy=STRATEGY" | color "yellow" ""}} Specify strategy to query nameserver listed in etc/resolv.conf. ({{"all, random, first" | color "cyan" ""}}).
{{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise. {{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
{{"--search" | color "yellow" ""}} Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list. {{"--search" | color "yellow" ""}} Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list.
{{"--timeout" | color "yellow" ""}} Specify timeout (in seconds) for the resolver to return a response. {{"--timeout" | color "yellow" ""}} Specify timeout (in seconds) for the resolver to return a response.

View File

@ -2,8 +2,10 @@ package app
import ( import (
"fmt" "fmt"
"math/rand"
"net" "net"
"net/url" "net/url"
"time"
"github.com/ameshkov/dnsstamps" "github.com/ameshkov/dnsstamps"
"github.com/mr-karan/doggo/pkg/config" "github.com/mr-karan/doggo/pkg/config"
@ -29,7 +31,7 @@ func (app *App) LoadNameservers() error {
// fallback to system nameserver // fallback to system nameserver
// in case no nameserver is specified by user. // in case no nameserver is specified by user.
if len(app.Nameservers) == 0 { if len(app.Nameservers) == 0 {
ns, ndots, search, err := getDefaultServers() ns, ndots, search, err := getDefaultServers(app.QueryFlags.Strategy)
if err != nil { if err != nil {
return fmt.Errorf("error fetching system default nameserver") return fmt.Errorf("error fetching system default nameserver")
} }
@ -117,12 +119,36 @@ func initNameserver(n string) (models.Nameserver, error) {
return ns, nil return ns, nil
} }
func getDefaultServers() ([]models.Nameserver, int, []string, error) { func getDefaultServers(strategy string) ([]models.Nameserver, int, []string, error) {
// Load nameservers from `/etc/resolv.conf`.
dnsServers, ndots, search, err := config.GetDefaultServers() dnsServers, ndots, search, err := config.GetDefaultServers()
if err != nil { if err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
servers := make([]models.Nameserver, 0, len(dnsServers)) servers := make([]models.Nameserver, 0, len(dnsServers))
switch strategy {
case "random":
// Choose a random server from the list.
rand.Seed(time.Now().Unix())
srv := dnsServers[rand.Intn(len(dnsServers))]
ns := models.Nameserver{
Type: models.UDPResolver,
Address: net.JoinHostPort(srv, models.DefaultUDPPort),
}
servers = append(servers, ns)
case "first":
// Choose the first from the list, always.
srv := dnsServers[0]
ns := models.Nameserver{
Type: models.UDPResolver,
Address: net.JoinHostPort(srv, models.DefaultUDPPort),
}
servers = append(servers, ns)
default:
// Default behaviour is to load all nameservers.
for _, s := range dnsServers { for _, s := range dnsServers {
ns := models.Nameserver{ ns := models.Nameserver{
Type: models.UDPResolver, Type: models.UDPResolver,
@ -130,5 +156,7 @@ func getDefaultServers() ([]models.Nameserver, int, []string, error) {
} }
servers = append(servers, ns) servers = append(servers, ns)
} }
}
return servers, ndots, search, nil return servers, ndots, search, nil
} }

View File

@ -35,6 +35,7 @@ type QueryFlags struct {
ShowJSON bool `koanf:"json" json:"-"` ShowJSON bool `koanf:"json" json:"-"`
UseSearchList bool `koanf:"search" json:"-"` UseSearchList bool `koanf:"search" json:"-"`
ReverseLookup bool `koanf:"reverse" reverse:"-"` ReverseLookup bool `koanf:"reverse" reverse:"-"`
Strategy string `koanf:"strategy" strategy:"-"`
} }
// Nameserver represents the type of Nameserver // Nameserver represents the type of Nameserver

View File

@ -18,6 +18,7 @@ type Options struct {
Ndots int Ndots int
Timeout time.Duration Timeout time.Duration
Logger *logrus.Logger Logger *logrus.Logger
Strategy string
} }
// Resolver implements the configuration for a DNS // Resolver implements the configuration for a DNS