feat: remove urfave/cli
This commit is contained in:
parent
6bb9a78492
commit
40c62216ec
10 changed files with 176 additions and 173 deletions
151
cmd/cli.go
151
cmd/cli.go
|
@ -1,129 +1,76 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"github.com/knadh/koanf"
|
||||
"github.com/knadh/koanf/providers/posflag"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version and date of the build. This is injected at build-time.
|
||||
buildVersion = "unknown"
|
||||
buildDate = "unknown"
|
||||
k = koanf.New(".")
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
logger = initLogger()
|
||||
app = cli.NewApp()
|
||||
)
|
||||
|
||||
// Initialize hub.
|
||||
hub := NewHub(logger, buildVersion)
|
||||
|
||||
// Configure CLI app.
|
||||
app.Name = "doggo"
|
||||
app.Usage = "Command-line DNS Client"
|
||||
app.Version = buildVersion
|
||||
|
||||
// Register command line flags.
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "query",
|
||||
Usage: "Domain name to query",
|
||||
Destination: hub.QueryFlags.QNames,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "type",
|
||||
Usage: "Type of DNS record to be queried (A, AAAA, MX etc)",
|
||||
Destination: hub.QueryFlags.QTypes,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "nameserver",
|
||||
Usage: "Address of the nameserver to send packets to",
|
||||
Destination: hub.QueryFlags.Nameservers,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "class",
|
||||
Usage: "Network class of the DNS record to be queried (IN, CH, HS etc)",
|
||||
Destination: hub.QueryFlags.QClasses,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "udp",
|
||||
Usage: "Use the DNS protocol over UDP",
|
||||
Aliases: []string{"U"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tcp",
|
||||
Usage: "Use the DNS protocol over TCP",
|
||||
Aliases: []string{"T"},
|
||||
Destination: &hub.QueryFlags.UseTCP,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "https",
|
||||
Usage: "Use the DNS-over-HTTPS protocol",
|
||||
Aliases: []string{"H"},
|
||||
Destination: &hub.QueryFlags.IsDOH,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tls",
|
||||
Usage: "Use the DNS-over-TLS",
|
||||
Aliases: []string{"S"},
|
||||
Destination: &hub.QueryFlags.IsDOT,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "ipv6",
|
||||
Aliases: []string{"6"},
|
||||
Usage: "Use IPv6 only",
|
||||
Destination: &hub.QueryFlags.UseIPv6,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "ipv4",
|
||||
Aliases: []string{"4"},
|
||||
Usage: "Use IPv4 only",
|
||||
Destination: &hub.QueryFlags.UseIPv4,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "time",
|
||||
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"},
|
||||
Usage: "Set the output format as JSON",
|
||||
Destination: &hub.QueryFlags.ShowJSON,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "Enable verbose logging",
|
||||
Destination: &hub.QueryFlags.Verbose,
|
||||
DefaultText: "false",
|
||||
},
|
||||
// Configure Flags
|
||||
// Use the POSIX compliant pflag lib instead of Go's flag lib.
|
||||
f := flag.NewFlagSet("config", flag.ContinueOnError)
|
||||
f.Usage = func() {
|
||||
fmt.Println(f.FlagUsages())
|
||||
os.Exit(0)
|
||||
}
|
||||
app.Before = hub.loadQueryArgs
|
||||
app.Action = func(c *cli.Context) error {
|
||||
if len(hub.QueryFlags.QNames.Value()) == 0 {
|
||||
cli.ShowAppHelpAndExit(c, 0)
|
||||
}
|
||||
hub.Lookup(c)
|
||||
return nil
|
||||
// Path to one or more config files to load into koanf along with some config params.
|
||||
f.StringSliceP("query", "q", []string{}, "Domain name to query")
|
||||
f.StringSliceP("type", "t", []string{}, "Type of DNS record to be queried (A, AAAA, MX etc)")
|
||||
f.StringSliceP("class", "c", []string{}, "Network class of the DNS record to be queried (IN, CH, HS etc)")
|
||||
f.StringSliceP("nameservers", "n", []string{}, "Address of the nameserver to send packets to")
|
||||
|
||||
// Protocol Options
|
||||
f.BoolP("udp", "U", false, "Use the DNS protocol over UDP")
|
||||
f.BoolP("tcp", "T", false, "Use the DNS protocol over TCP")
|
||||
f.BoolP("doh", "H", false, "Use the DNS-over-HTTPS protocol")
|
||||
f.BoolP("dot", "S", false, "Use the DNS-over-TLS")
|
||||
|
||||
// Resolver Options
|
||||
f.Bool("search", false, "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.")
|
||||
f.Int("ndots", 1, "Specify the ndots paramter")
|
||||
|
||||
// Output Options
|
||||
f.BoolP("json", "J", false, "Set the output format as JSON")
|
||||
f.Bool("time", false, "Display how long it took for the response to arrive")
|
||||
f.Bool("debug", false, "Enable debug mode")
|
||||
|
||||
// Parse and Load Flags
|
||||
f.Parse(os.Args[1:])
|
||||
if err := k.Load(posflag.Provider(f, ".", k), nil); err != nil {
|
||||
hub.Logger.Fatalf("error loading flags: %v", err)
|
||||
fmt.Println(f.FlagUsages())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Run the app.
|
||||
hub.Logger.Debug("Starting doggo...")
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
logger.Errorf("oops! we encountered an issue: %s", err)
|
||||
|
||||
// Parse Query Args
|
||||
hub.loadQueryArgs()
|
||||
|
||||
// Start App
|
||||
if len(hub.QueryFlags.QNames) == 0 {
|
||||
fmt.Println(f.FlagUsages())
|
||||
os.Exit(0)
|
||||
}
|
||||
hub.Lookup()
|
||||
|
||||
}
|
||||
|
|
21
cmd/help.go
Normal file
21
cmd/help.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Override Help Template
|
||||
var helpTmpl = `NAME:
|
||||
{{.Name}}
|
||||
{{ range $key, $value := . }}
|
||||
<li><strong>{{ $key }}</strong>: {{ $value }}</li>
|
||||
{{ end }}
|
||||
`
|
||||
|
||||
func renderCustomHelp(w io.Writer, templ string, data interface{}) {
|
||||
var helpTmplVars = map[string]string{}
|
||||
|
||||
helpTmplVars["Name"] = "doggo"
|
||||
fmt.Fprintf(w, helpTmpl, helpTmplVars)
|
||||
}
|
39
cmd/hub.go
39
cmd/hub.go
|
@ -4,7 +4,6 @@ import (
|
|||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Hub represents the structure for all app wide functions and structs.
|
||||
|
@ -14,26 +13,24 @@ type Hub struct {
|
|||
QueryFlags QueryFlags
|
||||
Questions []dns.Question
|
||||
Resolver resolvers.Resolver
|
||||
cliContext *cli.Context
|
||||
}
|
||||
|
||||
// QueryFlags is used store the value of CLI flags.
|
||||
type QueryFlags struct {
|
||||
QNames *cli.StringSlice
|
||||
QTypes *cli.StringSlice
|
||||
QClasses *cli.StringSlice
|
||||
Nameservers *cli.StringSlice
|
||||
IsDOH bool
|
||||
IsDOT bool
|
||||
IsUDP bool
|
||||
UseTCP bool
|
||||
UseIPv4 bool
|
||||
UseIPv6 bool
|
||||
DisplayTimeTaken bool
|
||||
ShowJSON bool
|
||||
Verbose bool
|
||||
UseSearchList bool
|
||||
Ndots int
|
||||
QNames []string `koanf:"query"`
|
||||
QTypes []string `koanf:"type"`
|
||||
QClasses []string `koanf:"class"`
|
||||
Nameservers []string `koanf:"namserver"`
|
||||
IsDOH bool `koanf:"doh"`
|
||||
IsDOT bool `koanf:"dot"`
|
||||
IsUDP bool `koanf:"udp"`
|
||||
UseTCP bool `koanf:"tcp"`
|
||||
UseIPv4 bool `koanf:"ipv4"`
|
||||
UseIPv6 bool `koanf:"ipv6"`
|
||||
DisplayTimeTaken bool `koanf:"time"`
|
||||
ShowJSON bool `koanf:"json"`
|
||||
UseSearchList bool `koanf:"search"`
|
||||
Ndots int `koanf:"ndots"`
|
||||
}
|
||||
|
||||
// NewHub initializes an instance of Hub which holds app wide configuration.
|
||||
|
@ -43,10 +40,10 @@ func NewHub(logger *logrus.Logger, buildVersion string) *Hub {
|
|||
Logger: logger,
|
||||
Version: buildVersion,
|
||||
QueryFlags: QueryFlags{
|
||||
QNames: cli.NewStringSlice(),
|
||||
QTypes: cli.NewStringSlice(),
|
||||
QClasses: cli.NewStringSlice(),
|
||||
Nameservers: cli.NewStringSlice(),
|
||||
QNames: []string{},
|
||||
QTypes: []string{},
|
||||
QClasses: []string{},
|
||||
Nameservers: []string{},
|
||||
},
|
||||
}
|
||||
return hub
|
||||
|
|
|
@ -6,11 +6,10 @@ import (
|
|||
"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 {
|
||||
func (hub *Hub) Lookup() error {
|
||||
err := hub.prepareQuestions()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -30,16 +29,17 @@ func (hub *Hub) prepareQuestions() error {
|
|||
var (
|
||||
question dns.Question
|
||||
)
|
||||
for _, name := range hub.QueryFlags.QNames.Value() {
|
||||
for _, name := range hub.QueryFlags.QNames {
|
||||
var (
|
||||
domains []string
|
||||
ndots int
|
||||
)
|
||||
ndots = 1
|
||||
|
||||
// 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)
|
||||
list, n, err := fetchDomainList(name, false, hub.QueryFlags.Ndots)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -55,10 +55,10 @@ func (hub *Hub) prepareQuestions() error {
|
|||
}).Debug("Attmepting to resolve")
|
||||
question.Name = d
|
||||
// iterate on a list of query types.
|
||||
for _, q := range hub.QueryFlags.QTypes.Value() {
|
||||
for _, q := range hub.QueryFlags.QTypes {
|
||||
question.Qtype = dns.StringToType[strings.ToUpper(q)]
|
||||
// iterate on a list of query classes.
|
||||
for _, c := range hub.QueryFlags.QClasses.Value() {
|
||||
for _, c := range hub.QueryFlags.QClasses {
|
||||
question.Qclass = dns.StringToClass[strings.ToUpper(c)]
|
||||
// append a new question for each possible pair.
|
||||
hub.Questions = append(hub.Questions, question)
|
||||
|
|
58
cmd/parse.go
58
cmd/parse.go
|
@ -1,32 +1,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func (hub *Hub) loadQueryArgs(c *cli.Context) error {
|
||||
func (hub *Hub) loadQueryArgs() error {
|
||||
// set log level
|
||||
if c.Bool("debug") {
|
||||
if k.Bool("debug") {
|
||||
// Set logger level
|
||||
hub.Logger.SetLevel(logrus.DebugLevel)
|
||||
} else {
|
||||
hub.Logger.SetLevel(logrus.InfoLevel)
|
||||
}
|
||||
hub.cliContext = c
|
||||
|
||||
err := hub.loadFreeArgs(c)
|
||||
err := hub.loadNamedArgs()
|
||||
|
||||
err = hub.loadFreeArgs()
|
||||
if err != nil {
|
||||
cli.Exit("Error parsing arguments", -1)
|
||||
hub.Logger.WithError(err).Error("Error parsing arguments")
|
||||
hub.Logger.Exit(2)
|
||||
}
|
||||
err = hub.initResolver(c)
|
||||
err = hub.initResolver()
|
||||
if err != nil {
|
||||
cli.Exit("Error parsing nameservers", -1)
|
||||
hub.Logger.WithError(err).Error("Error parsing nameservers")
|
||||
hub.Logger.Exit(2)
|
||||
}
|
||||
hub.loadFallbacks(c)
|
||||
hub.loadFallbacks()
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -37,29 +40,44 @@ func (hub *Hub) loadQueryArgs(c *cli.Context) error {
|
|||
// pattern we deduce the arguments and map it to internal query
|
||||
// options. In case an argument isn't able to fit in any of the existing
|
||||
// pattern it is considered to be a "query name".
|
||||
func (hub *Hub) loadFreeArgs(c *cli.Context) error {
|
||||
for _, arg := range c.Args().Slice() {
|
||||
func (hub *Hub) loadFreeArgs() error {
|
||||
args := os.Args[1:]
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(arg, "--") || strings.HasPrefix(arg, "-") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(arg, "@") {
|
||||
hub.QueryFlags.Nameservers.Set(strings.Trim(arg, "@"))
|
||||
hub.QueryFlags.Nameservers = append(hub.QueryFlags.Nameservers, strings.Trim(arg, "@"))
|
||||
} else if _, ok := dns.StringToType[strings.ToUpper(arg)]; ok {
|
||||
hub.QueryFlags.QTypes.Set(arg)
|
||||
hub.QueryFlags.QTypes = append(hub.QueryFlags.QTypes, arg)
|
||||
} else if _, ok := dns.StringToClass[strings.ToUpper(arg)]; ok {
|
||||
hub.QueryFlags.QClasses.Set(arg)
|
||||
hub.QueryFlags.QClasses = append(hub.QueryFlags.QClasses, arg)
|
||||
} else {
|
||||
// if nothing matches, consider it's a query name.
|
||||
hub.QueryFlags.QNames.Set(arg)
|
||||
hub.QueryFlags.QNames = append(hub.QueryFlags.QNames, arg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadNamedArgs checks for all flags and loads their
|
||||
// values inside the Hub.
|
||||
func (hub *Hub) loadNamedArgs() error {
|
||||
// Unmarshall flags to the struct.
|
||||
err := k.Unmarshal("", &hub.QueryFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadFallbacks sets fallbacks for options
|
||||
// that are not specified by the user.
|
||||
func (hub *Hub) loadFallbacks(c *cli.Context) {
|
||||
if len(hub.QueryFlags.QTypes.Value()) == 0 {
|
||||
hub.QueryFlags.QTypes.Set("A")
|
||||
func (hub *Hub) loadFallbacks() {
|
||||
if len(hub.QueryFlags.QTypes) == 0 {
|
||||
hub.QueryFlags.QTypes = append(hub.QueryFlags.QTypes, "A")
|
||||
}
|
||||
if len(hub.QueryFlags.QClasses.Value()) == 0 {
|
||||
hub.QueryFlags.QClasses.Set("IN")
|
||||
if len(hub.QueryFlags.QClasses) == 0 {
|
||||
hub.QueryFlags.QClasses = append(hub.QueryFlags.QClasses, "IN")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,22 +4,21 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// initResolver checks for various flags and initialises
|
||||
// the correct resolver based on the config.
|
||||
func (hub *Hub) initResolver(c *cli.Context) error {
|
||||
func (hub *Hub) initResolver() error {
|
||||
// check if DOH flag is set.
|
||||
if hub.QueryFlags.IsDOH {
|
||||
rslvr, err := resolvers.NewDOHResolver(hub.QueryFlags.Nameservers.Value())
|
||||
rslvr, err := resolvers.NewDOHResolver(hub.QueryFlags.Nameservers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hub.Resolver = rslvr
|
||||
return nil
|
||||
}
|
||||
if len(hub.QueryFlags.Nameservers.Value()) == 0 {
|
||||
if len(hub.QueryFlags.Nameservers) == 0 {
|
||||
if runtime.GOOS == "windows" {
|
||||
// TODO: Add a method for reading system default nameserver in windows.
|
||||
} else {
|
||||
|
@ -31,7 +30,7 @@ func (hub *Hub) initResolver(c *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
} else {
|
||||
rslvr, err := resolvers.NewClassicResolver(hub.QueryFlags.Nameservers.Value(), resolvers.ClassicResolverOpts{
|
||||
rslvr, err := resolvers.NewClassicResolver(hub.QueryFlags.Nameservers, resolvers.ClassicResolverOpts{
|
||||
UseIPv4: hub.QueryFlags.UseIPv4,
|
||||
UseIPv6: hub.QueryFlags.UseIPv6,
|
||||
UseTLS: hub.QueryFlags.IsDOT,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue