feat: ndots and search list support
This commit is contained in:
parent
7df12b2229
commit
d9715b1932
10 changed files with 199 additions and 82 deletions
24
cmd/cli.go
24
cmd/cli.go
|
@ -8,14 +8,13 @@ import (
|
|||
|
||||
var (
|
||||
// Version and date of the build. This is injected at build-time.
|
||||
buildVersion = "unknown"
|
||||
buildDate = "unknown"
|
||||
verboseEnabled = false
|
||||
buildVersion = "unknown"
|
||||
buildDate = "unknown"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
logger = initLogger(verboseEnabled)
|
||||
logger = initLogger()
|
||||
app = cli.NewApp()
|
||||
)
|
||||
// Initialize hub.
|
||||
|
@ -88,6 +87,17 @@ func main() {
|
|||
Usage: "Display how long it took for the response to arrive",
|
||||
Destination: &hub.QueryFlags.DisplayTimeTaken,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "search",
|
||||
Usage: "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.",
|
||||
Destination: &hub.QueryFlags.UseSearchList,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "ndots",
|
||||
Usage: "Specify the ndots paramter",
|
||||
DefaultText: "Default value is that set in `/etc/resolv.conf` or 1 if no `ndots` statement is present.",
|
||||
Destination: &hub.QueryFlags.Ndots,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "json",
|
||||
Aliases: []string{"J"},
|
||||
|
@ -95,13 +105,12 @@ func main() {
|
|||
Destination: &hub.QueryFlags.ShowJSON,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
Name: "debug",
|
||||
Usage: "Enable verbose logging",
|
||||
Destination: &verboseEnabled,
|
||||
Destination: &hub.QueryFlags.Verbose,
|
||||
DefaultText: "false",
|
||||
},
|
||||
}
|
||||
|
||||
app.Before = hub.loadQueryArgs
|
||||
app.Action = func(c *cli.Context) error {
|
||||
if len(hub.QueryFlags.QNames.Value()) == 0 {
|
||||
|
@ -110,6 +119,7 @@ func main() {
|
|||
hub.Lookup(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run the app.
|
||||
hub.Logger.Debug("Starting doggo...")
|
||||
err := app.Run(os.Args)
|
||||
|
|
13
cmd/hub.go
13
cmd/hub.go
|
@ -14,6 +14,7 @@ type Hub struct {
|
|||
QueryFlags QueryFlags
|
||||
Questions []dns.Question
|
||||
Resolver resolvers.Resolver
|
||||
cliContext *cli.Context
|
||||
}
|
||||
|
||||
// QueryFlags is used store the value of CLI flags.
|
||||
|
@ -30,6 +31,9 @@ type QueryFlags struct {
|
|||
UseIPv6 bool
|
||||
DisplayTimeTaken bool
|
||||
ShowJSON bool
|
||||
Verbose bool
|
||||
UseSearchList bool
|
||||
Ndots int
|
||||
}
|
||||
|
||||
// NewHub initializes an instance of Hub which holds app wide configuration.
|
||||
|
@ -49,18 +53,11 @@ func NewHub(logger *logrus.Logger, buildVersion string) *Hub {
|
|||
}
|
||||
|
||||
// initLogger initializes logger
|
||||
func initLogger(verbose bool) *logrus.Logger {
|
||||
func initLogger() *logrus.Logger {
|
||||
logger := logrus.New()
|
||||
logger.SetFormatter(&logrus.TextFormatter{
|
||||
DisableTimestamp: true,
|
||||
DisableLevelTruncation: true,
|
||||
})
|
||||
// Set logger level
|
||||
if verbose {
|
||||
logger.SetLevel(logrus.DebugLevel)
|
||||
logger.Debug("verbose logging enabled")
|
||||
} else {
|
||||
logger.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
|
|
@ -4,12 +4,17 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Lookup sends the DNS queries to the server.
|
||||
func (hub *Hub) Lookup(c *cli.Context) error {
|
||||
hub.prepareQuestions()
|
||||
err := hub.prepareQuestions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
responses, err := hub.Resolver.Lookup(hub.Questions)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -21,19 +26,57 @@ func (hub *Hub) Lookup(c *cli.Context) error {
|
|||
// prepareQuestions iterates on list of domain names
|
||||
// and prepare a list of questions
|
||||
// sent to the server with all possible combinations.
|
||||
func (hub *Hub) prepareQuestions() {
|
||||
var question dns.Question
|
||||
func (hub *Hub) prepareQuestions() error {
|
||||
var (
|
||||
question dns.Question
|
||||
)
|
||||
for _, name := range hub.QueryFlags.QNames.Value() {
|
||||
question.Name = dns.Fqdn(name)
|
||||
// iterate on a list of query types.
|
||||
for _, q := range hub.QueryFlags.QTypes.Value() {
|
||||
question.Qtype = dns.StringToType[strings.ToUpper(q)]
|
||||
// iterate on a list of query classes.
|
||||
for _, c := range hub.QueryFlags.QClasses.Value() {
|
||||
question.Qclass = dns.StringToClass[strings.ToUpper(c)]
|
||||
// append a new question for each possible pair.
|
||||
hub.Questions = append(hub.Questions, question)
|
||||
var (
|
||||
domains []string
|
||||
ndots int
|
||||
)
|
||||
|
||||
// If `search` flag is specified then fetch the search list
|
||||
// from `resolv.conf` and set the
|
||||
if hub.QueryFlags.UseSearchList {
|
||||
list, n, err := fetchDomainList(name, hub.cliContext.IsSet("ndots"), hub.QueryFlags.Ndots)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domains = list
|
||||
ndots = n
|
||||
} else {
|
||||
domains = []string{dns.Fqdn(name)}
|
||||
}
|
||||
for _, d := range domains {
|
||||
hub.Logger.WithFields(logrus.Fields{
|
||||
"domain": d,
|
||||
"ndots": ndots,
|
||||
}).Debug("Attmepting to resolve")
|
||||
question.Name = d
|
||||
// iterate on a list of query types.
|
||||
for _, q := range hub.QueryFlags.QTypes.Value() {
|
||||
question.Qtype = dns.StringToType[strings.ToUpper(q)]
|
||||
// iterate on a list of query classes.
|
||||
for _, c := range hub.QueryFlags.QClasses.Value() {
|
||||
question.Qclass = dns.StringToClass[strings.ToUpper(c)]
|
||||
// append a new question for each possible pair.
|
||||
hub.Questions = append(hub.Questions, question)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchDomainList(d string, isNdotsSet bool, ndots int) ([]string, int, error) {
|
||||
cfg, err := dns.ClientConfigFromFile(resolvers.DefaultResolvConfPath)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// if user specified a custom ndots parameter, override it
|
||||
if isNdotsSet {
|
||||
cfg.Ndots = ndots
|
||||
}
|
||||
return cfg.NameList(d), cfg.Ndots, nil
|
||||
}
|
||||
|
|
|
@ -14,12 +14,13 @@ import (
|
|||
|
||||
// Output has a list of fields which are produced for the output
|
||||
type Output struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Class string `json:"class"`
|
||||
TTL string `json:"ttl"`
|
||||
Address string `json:"address"`
|
||||
TimeTaken string `json:"rtt"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Class string `json:"class"`
|
||||
TTL string `json:"ttl"`
|
||||
Address string `json:"address"`
|
||||
TimeTaken string `json:"rtt"`
|
||||
Nameserver string `json:"nameserver"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
|
@ -113,12 +114,13 @@ func collectOutput(responses []resolvers.Response) []Output {
|
|||
qtype := dns.Type(h.Rrtype).String()
|
||||
rtt := fmt.Sprintf("%dms", r.RTT.Milliseconds())
|
||||
o := Output{
|
||||
Name: name,
|
||||
Type: qtype,
|
||||
TTL: ttl,
|
||||
Class: qclass,
|
||||
Address: addr,
|
||||
TimeTaken: rtt,
|
||||
Name: name,
|
||||
Type: qtype,
|
||||
TTL: ttl,
|
||||
Class: qclass,
|
||||
Address: addr,
|
||||
TimeTaken: rtt,
|
||||
Nameserver: r.Nameserver,
|
||||
}
|
||||
out = append(out, o)
|
||||
}
|
||||
|
|
10
cmd/parse.go
10
cmd/parse.go
|
@ -4,10 +4,20 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func (hub *Hub) loadQueryArgs(c *cli.Context) error {
|
||||
// set log level
|
||||
if c.Bool("debug") {
|
||||
// Set logger level
|
||||
hub.Logger.SetLevel(logrus.DebugLevel)
|
||||
} else {
|
||||
hub.Logger.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
hub.cliContext = c
|
||||
|
||||
err := hub.loadFreeArgs(c)
|
||||
if err != nil {
|
||||
cli.Exit("Error parsing arguments", -1)
|
||||
|
|
|
@ -23,7 +23,7 @@ func (hub *Hub) initResolver(c *cli.Context) error {
|
|||
if runtime.GOOS == "windows" {
|
||||
// TODO: Add a method for reading system default nameserver in windows.
|
||||
} else {
|
||||
rslvr, err := resolvers.NewResolverFromResolvFile(resolvers.DefaultResolvConfPath)
|
||||
rslvr, err := resolvers.NewSystemResolver(resolvers.DefaultResolvConfPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue