diff --git a/Makefile b/Makefile
index 6aba0eb..1e75c74 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,8 @@
DOGGO-BIN := doggo.bin
HASH := $(shell git rev-parse --short HEAD)
-COMMIT_DATE := $(shell git show -s --format=%ci ${HASH})
BUILD_DATE := $(shell date '+%Y-%m-%d %H:%M:%S')
-VERSION := ${HASH} (${COMMIT_DATE})
+VERSION := ${HASH}
.PHONY: build
build: ## Build the doggo binary
diff --git a/TODO.md b/TODO.md
index d009dd7..b8645e9 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,4 +1,4 @@
-# doggo - v1.0 Milestone
+# doggo - Initial Release Milestone
## Resolver
- [x] Create a DNS Resolver struct
@@ -6,20 +6,22 @@
- [x] Add a resolve method
- [x] Make it separate from Hub
- [x] Parse output into separate fields
-- [ ] Test IPv6
+- [ ] Test IPv6/IPv4 only options
- [x] Add DOH support
- [x] Add DOT support
- [x] Add DNS protocol on TCP mode support.
- [ ] Error on NXDomain (Realted upstream [bug](https://github.com/miekg/dns/issues/1198))
+- [ ] Support all DNS records?
+ - [x] Major records supported
## CLI Features
- [ ] `digfile`
-- [x] `ndots` support
+- [ ] `ndots` support
- [x] `search list` support
- [x] JSON output
- [x] Colorized output
- [x] Table output
-- [ ] Parsing options free-form
+- [x] Parsing options free-form
- [x] Remove urfave/cli in favour of `flag`
## CLI Grunt
@@ -27,15 +29,27 @@
- [x] Neatly package them to load args in different functions
- [x] Upper case is not mandatory for query type/classes
- [x] Output
+- [ ] Custom Help Text
+ - [x] Add examples
+ - [ ] Colorize
+ - [ ] Add different commands
- [x] Add client transport options
+- [ ] Fix an issue while loading free form args, where the same records are being added twice
## Tests
## Documentation
+- [ ] Mkdocs init project
+ - [ ] Custom Index (Landing Page)
+
## Release Checklist
- [ ] Goreleaser
- [ ] Snap
- [ ] Homebrew
- [ ] ARM
+
+## v1.0
+
+- [ ] Support obscure protocal tweaks in `dig`
diff --git a/cmd/cli.go b/cmd/cli.go
index 7ba14fd..5c51bc8 100644
--- a/cmd/cli.go
+++ b/cmd/cli.go
@@ -1,11 +1,11 @@
package main
import (
- "fmt"
"os"
"github.com/knadh/koanf"
"github.com/knadh/koanf/providers/posflag"
+ "github.com/sirupsen/logrus"
flag "github.com/spf13/pflag"
)
@@ -27,10 +27,7 @@ func main() {
// 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)
- }
+ f.Usage = renderCustomHelp
// 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)")
@@ -50,26 +47,32 @@ func main() {
// 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("color", true, "Show colored output")
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)
+ hub.Logger.Errorf("error loading flags: %v", err)
+ f.Usage()
+ hub.Logger.Exit(2)
+ }
+ // set log level
+ if k.Bool("debug") {
+ // Set logger level
+ hub.Logger.SetLevel(logrus.DebugLevel)
+ } else {
+ hub.Logger.SetLevel(logrus.InfoLevel)
}
-
// Run the app.
- hub.Logger.Debug("Starting doggo...")
+ hub.Logger.Debug("Starting doggo 🐶")
// Parse Query Args
hub.loadQueryArgs()
// Start App
if len(hub.QueryFlags.QNames) == 0 {
- fmt.Println(f.FlagUsages())
- os.Exit(0)
+ f.Usage()
}
hub.Lookup()
diff --git a/cmd/help.go b/cmd/help.go
index 6d2b339..39adfbd 100644
--- a/cmd/help.go
+++ b/cmd/help.go
@@ -1,21 +1,42 @@
package main
import (
- "fmt"
- "io"
+ "html/template"
+ "os"
)
-// Override Help Template
-var helpTmpl = `NAME:
- {{.Name}}
- {{ range $key, $value := . }}
-
{{ $key }}: {{ $value }}
-{{ end }}
+// AppHelpTemplate is the text template to customise the Help output.
+// Uses text/template to render templates.
+var AppHelpTemplate = `NAME:
+ {{.Name}} {{.Description}}
+
+USAGE:
+ {{.Name}} [OPTIONS] [--]
+
+VERSION:
+ {{.Version}} Built at {{.Date}}
+
+EXAMPLES:
+ doggo mrkaran.dev Query a domain using defaults
+ doggo mrkaran.dev CNAME Looks up for a CNAME record.
+ doggo mrkaran.dev MX @9.9.9.9 Uses a custom DNS resolver.
+ doggo -q mrkaran.dev -t MX -n 1.1.1.1 Using named arguments
`
-func renderCustomHelp(w io.Writer, templ string, data interface{}) {
- var helpTmplVars = map[string]string{}
-
- helpTmplVars["Name"] = "doggo"
- fmt.Fprintf(w, helpTmpl, helpTmplVars)
+func renderCustomHelp() {
+ helpTmplVars := map[string]string{
+ "Name": "doggo",
+ "Description": "DNS Client for Humans",
+ "Version": buildVersion,
+ "Date": buildDate,
+ }
+ tmpl, err := template.New("test").Parse(AppHelpTemplate)
+ if err != nil {
+ panic(err)
+ }
+ err = tmpl.Execute(os.Stdout, helpTmplVars)
+ if err != nil {
+ panic(err)
+ }
+ os.Exit(0)
}
diff --git a/cmd/hub.go b/cmd/hub.go
index ee91d4c..8b2f7ab 100644
--- a/cmd/hub.go
+++ b/cmd/hub.go
@@ -31,6 +31,7 @@ type QueryFlags struct {
ShowJSON bool `koanf:"json"`
UseSearchList bool `koanf:"search"`
Ndots int `koanf:"ndots"`
+ Color bool `koanf:"color"`
}
// NewHub initializes an instance of Hub which holds app wide configuration.
diff --git a/cmd/output.go b/cmd/output.go
index 8aa2065..3bc9d7c 100644
--- a/cmd/output.go
+++ b/cmd/output.go
@@ -64,9 +64,15 @@ func (hub *Hub) outputJSON(out []Output, msgs []resolvers.Response) {
}
func (hub *Hub) outputTerminal(out []Output) {
- green := color.New(color.FgGreen).SprintFunc()
- blue := color.New(color.FgBlue).SprintFunc()
- magenta := color.New(color.FgMagenta).SprintFunc()
+ green := color.New(color.FgGreen, color.Bold).SprintFunc()
+ blue := color.New(color.FgBlue, color.Bold).SprintFunc()
+ yellow := color.New(color.FgYellow, color.Bold).SprintFunc()
+ cyan := color.New(color.FgCyan, color.Bold).SprintFunc()
+ red := color.New(color.FgRed, color.Bold).SprintFunc()
+
+ if !hub.QueryFlags.Color {
+ color.NoColor = true // disables colorized output
+ }
table := tablewriter.NewWriter(os.Stdout)
header := []string{"Name", "Type", "Class", "TTL", "Address", "Nameserver"}
@@ -87,7 +93,24 @@ func (hub *Hub) outputTerminal(out []Output) {
table.SetNoWhiteSpace(true)
for _, o := range out {
- output := []string{green(o.Name), blue(o.Type), o.Class, o.TTL, magenta(o.Address), o.Nameserver}
+ var typOut string
+ switch typ := o.Type; typ {
+ case "A":
+ typOut = blue(o.Type)
+ case "AAAA":
+ typOut = blue(o.Type)
+ case "MX":
+ typOut = cyan(o.Type)
+ case "NS":
+ typOut = cyan(o.Type)
+ case "CNAME":
+ typOut = yellow(o.Type)
+ case "TXT":
+ typOut = yellow(o.Type)
+ default:
+ typOut = red(o.Type)
+ }
+ output := []string{green(o.Name), typOut, o.Class, o.TTL, o.Address, o.Nameserver}
// Print how long it took
if hub.QueryFlags.DisplayTimeTaken {
output = append(output, o.TimeTaken)
@@ -125,10 +148,28 @@ func collectOutput(responses []resolvers.Response) []Output {
addr = t.AAAA.String()
case *dns.CNAME:
addr = t.Target
+ case *dns.CAA:
+ addr = t.Tag + " " + t.Value
+ case *dns.HINFO:
+ addr = t.Cpu + " " + t.Os
+ // case *dns.LOC:
+ // addr = t.String()
+ case *dns.PTR:
+ addr = t.Ptr
+ case *dns.SRV:
+ addr = strconv.Itoa(int(t.Priority)) + " " +
+ strconv.Itoa(int(t.Weight)) + " " +
+ t.Target + ":" + strconv.Itoa(int(t.Port))
+ case *dns.TXT:
+ addr = t.String()
+ case *dns.NS:
+ addr = t.String()
case *dns.MX:
addr = strconv.Itoa(int(t.Preference)) + " " + t.Mx
case *dns.SOA:
addr = t.String()
+ case *dns.NAPTR:
+ addr = t.String()
}
h := a.Header()
diff --git a/cmd/parse.go b/cmd/parse.go
index 0961f93..8a35499 100644
--- a/cmd/parse.go
+++ b/cmd/parse.go
@@ -5,17 +5,9 @@ import (
"strings"
"github.com/miekg/dns"
- "github.com/sirupsen/logrus"
)
func (hub *Hub) loadQueryArgs() error {
- // set log level
- if k.Bool("debug") {
- // Set logger level
- hub.Logger.SetLevel(logrus.DebugLevel)
- } else {
- hub.Logger.SetLevel(logrus.InfoLevel)
- }
err := hub.loadNamedArgs()