unfinished mess
parent
6c3b17ba0d
commit
2e2e3b1ec8
|
@ -6,7 +6,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mr-karan/doggo/internal/app"
|
||||
"github.com/mr-karan/doggo/internal/hub"
|
||||
"github.com/mr-karan/doggo/pkg/utils"
|
||||
"github.com/mr-karan/logf"
|
||||
|
||||
|
@ -31,7 +31,7 @@ func main() {
|
|||
initConfig()
|
||||
|
||||
// Initialize app.
|
||||
app := app.New(logger, buildString)
|
||||
app := hub.New(logger, buildString)
|
||||
|
||||
// Register router instance.
|
||||
r := chi.NewRouter()
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mr-karan/doggo/internal/app"
|
||||
"github.com/mr-karan/doggo/internal/hub"
|
||||
"github.com/mr-karan/doggo/pkg/models"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
)
|
||||
|
@ -21,7 +21,7 @@ type httpResp struct {
|
|||
|
||||
func handleIndexAPI(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
app = r.Context().Value("app").(app.App)
|
||||
app = r.Context().Value("app").(hub.Hub)
|
||||
)
|
||||
|
||||
sendResponse(w, http.StatusOK, fmt.Sprintf("Welcome to Doggo API. Version: %s", app.Version))
|
||||
|
@ -35,21 +35,21 @@ func handleHealthCheck(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func handleLookup(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
app = r.Context().Value("app").(app.App)
|
||||
app = r.Context().Value("app").(hub.Hub)
|
||||
)
|
||||
|
||||
// Read body.
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
defer r.Body.Close()
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Error("error reading request body")
|
||||
app.Log.WithError(err).Error("error reading request body")
|
||||
sendErrorResponse(w, fmt.Sprintf("Invalid JSON payload"), http.StatusBadRequest, nil)
|
||||
return
|
||||
}
|
||||
// Prepare query flags.
|
||||
var qFlags models.QueryFlags
|
||||
if err := json.Unmarshal(b, &qFlags); err != nil {
|
||||
app.Logger.WithError(err).Error("error unmarshalling payload")
|
||||
app.Log.WithError(err).Error("error unmarshalling payload")
|
||||
sendErrorResponse(w, fmt.Sprintf("Invalid JSON payload"), http.StatusBadRequest, nil)
|
||||
return
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
|
|||
// Load Nameservers.
|
||||
err = app.LoadNameservers()
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Error("error loading nameservers")
|
||||
app.Log.WithError(err).Error("error loading nameservers")
|
||||
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
|
||||
return
|
||||
}
|
||||
|
@ -82,10 +82,10 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
|
|||
SearchList: app.ResolverOpts.SearchList,
|
||||
Ndots: app.ResolverOpts.Ndots,
|
||||
Timeout: app.QueryFlags.Timeout * time.Second,
|
||||
Logger: app.Logger,
|
||||
Logger: app.Log,
|
||||
})
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Error("error loading resolver")
|
||||
app.Log.WithError(err).Error("error loading resolver")
|
||||
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
|
||||
return
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
|
|||
for _, rslv := range app.Resolvers {
|
||||
resp, err := rslv.Lookup(q)
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Error("error looking up DNS records")
|
||||
app.Log.WithError(err).Error("error looking up DNS records")
|
||||
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
|
||||
return
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// wrap is a middleware that wraps HTTP handlers and injects the "app" context.
|
||||
func wrap(app app.App, next http.HandlerFunc) http.HandlerFunc {
|
||||
func wrap(app hub.Hub, next http.HandlerFunc) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "app", app)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"github.com/knadh/koanf"
|
||||
"github.com/knadh/koanf/providers/posflag"
|
||||
"github.com/mr-karan/doggo/internal/app"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/mr-karan/doggo/pkg/utils"
|
||||
"github.com/mr-karan/doggo/internal/resolvers"
|
||||
"github.com/mr-karan/doggo/internal/utils"
|
||||
"github.com/mr-karan/logf"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
|
@ -0,0 +1,108 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// appHelpTextTemplate is the text/template to customise the Help output.
|
||||
// Uses text/template to render templates.
|
||||
var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}:
|
||||
{{ .Name | color "green" "bold" }} 🐶 {{.Description}}
|
||||
|
||||
{{ "USAGE" | color "" "heading" }}:
|
||||
{{ .Name | color "green" "bold" }} [--] {{ "[query options]" | color "yellow" "" }} {{ "[arguments...]" | color "cyan" "" }}
|
||||
|
||||
{{ "VERSION" | color "" "heading" }}:
|
||||
{{.Version | color "red" "" }}
|
||||
|
||||
{{ "EXAMPLES" | color "" "heading" }}:
|
||||
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev" | color "cyan" "" }} {{"\t"}} Query a domain using defaults.
|
||||
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev CNAME" | color "cyan" "" }} {{"\t"}} Looks up for a CNAME record.
|
||||
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev MX @9.9.9.9" | color "cyan" "" }} {{"\t"}} Uses a custom DNS resolver.
|
||||
{{ .Name | color "green" "bold" }} {{"-q mrkaran.dev -t MX -n 1.1.1.1" | color "yellow" ""}} {{"\t"}} Using named arguments.
|
||||
|
||||
{{ "Free Form Arguments" | color "" "heading" }}:
|
||||
Supply hostnames, query types, classes without any flag. For eg:
|
||||
{{ .Name | color "green" "bold" }} {{"mrkaran.dev A @1.1.1.1" | color "cyan" "" }}
|
||||
|
||||
{{ "Transport Options" | color "" "heading" }}:
|
||||
Based on the URL scheme the correct resolver is chosen.
|
||||
Fallbacks to UDP resolver if no scheme is present.
|
||||
|
||||
{{"@udp://" | color "yellow" ""}} eg: @1.1.1.1 initiates a {{"UDP" | color "cyan" ""}} resolver for 1.1.1.1:53.
|
||||
{{"@tcp://" | color "yellow" ""}} eg: @tcp://1.1.1.1 initiates a {{"TCP" | color "cyan" ""}} resolver for 1.1.1.1:53.
|
||||
{{"@https://" | color "yellow" ""}} eg: @https://cloudflare-dns.com/dns-query initiates a {{"DOH" | color "cyan" ""}} resolver for Cloudflare DoH server.
|
||||
{{"@tls://" | color "yellow" ""}} eg: @tls://1.1.1.1 initiates a {{"DoT" | color "cyan" ""}} resolver for 1.1.1.1:853.
|
||||
{{"@sdns://" | color "yellow" ""}} initiates a {{"DNSCrypt" | color "cyan" ""}} or {{"DoH" | color "cyan" ""}} resolver using its DNS stamp.
|
||||
{{"@quic://" | color "yellow" ""}} initiates a {{"DOQ" | color "cyan" ""}} resolver.
|
||||
|
||||
{{ "Query Options" | color "" "heading" }}:
|
||||
{{"-q, --query=HOSTNAME" | color "yellow" ""}} Hostname to query the DNS records for (eg {{"mrkaran.dev" | color "cyan" ""}}).
|
||||
{{"-t, --type=TYPE" | color "yellow" ""}} Type of the DNS Record ({{"A, MX, NS" | color "cyan" ""}} etc).
|
||||
{{"-n, --nameserver=ADDR" | color "yellow" ""}} Address of a specific nameserver to send queries to ({{"9.9.9.9, 8.8.8.8" | color "cyan" ""}} etc).
|
||||
{{"-c, --class=CLASS" | color "yellow" ""}} Network class of the DNS record ({{"IN, CH, HS" | color "cyan" ""}} etc).
|
||||
{{"-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" }}:
|
||||
{{"--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.
|
||||
{{"--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.
|
||||
{{"-4 --ipv4" | color "yellow" ""}} Use IPv4 only.
|
||||
{{"-6 --ipv6" | color "yellow" ""}} Use IPv6 only.
|
||||
{{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
|
||||
{{"--tls-hostname=HOSTNAME" | color "yellow" ""}} Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP.
|
||||
{{"--skip-hostname-verification" | color "yellow" ""}} Skip TLS Hostname Verification in case of DOT Lookups.
|
||||
|
||||
{{ "Output Options" | color "" "heading" }}:
|
||||
{{"-J, --json " | color "yellow" ""}} Format the output as JSON.
|
||||
{{"--short" | color "yellow" ""}} Short output format. Shows only the response section.
|
||||
{{"--color " | color "yellow" ""}} Defaults to true. Set --color=false to disable colored output.
|
||||
{{"--debug " | color "yellow" ""}} Enable debug logging.
|
||||
{{"--time" | color "yellow" ""}} Shows how long the response took from the server.
|
||||
`
|
||||
|
||||
func renderCustomHelp() {
|
||||
helpTmplVars := map[string]string{
|
||||
"Name": "doggo",
|
||||
"Description": "DNS Client for Humans",
|
||||
"Version": buildString,
|
||||
}
|
||||
tmpl, err := template.New("test").Funcs(template.FuncMap{
|
||||
"color": func(clr string, format string, str string) string {
|
||||
formatter := color.New()
|
||||
switch c := clr; c {
|
||||
case "yellow":
|
||||
formatter = formatter.Add(color.FgYellow)
|
||||
case "red":
|
||||
formatter = formatter.Add(color.FgRed)
|
||||
case "cyan":
|
||||
formatter = formatter.Add(color.FgCyan)
|
||||
case "green":
|
||||
formatter = formatter.Add(color.FgGreen)
|
||||
}
|
||||
switch f := format; f {
|
||||
case "bold":
|
||||
formatter = formatter.Add(color.Bold)
|
||||
case "underline":
|
||||
formatter = formatter.Add(color.Underline)
|
||||
case "heading":
|
||||
formatter = formatter.Add(color.Bold, color.Underline)
|
||||
}
|
||||
return formatter.SprintFunc()(str)
|
||||
},
|
||||
}).Parse(appHelpTextTemplate)
|
||||
if err != nil {
|
||||
// should ideally never happen.
|
||||
panic(err)
|
||||
}
|
||||
err = tmpl.Execute(os.Stdout, helpTmplVars)
|
||||
if err != nil {
|
||||
// should ideally never happen.
|
||||
panic(err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package main
|
||||
|
||||
import "github.com/mr-karan/logf"
|
||||
|
||||
func initLogger() *logf.Logger {
|
||||
logf := logf.New()
|
||||
logf.SetColorOutput(true)
|
||||
|
||||
return logf
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
buildString = "unknown"
|
||||
lo = initLogger()
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Intialize new CLI app.
|
||||
app := cli.NewApp()
|
||||
app.Name = "doggo"
|
||||
app.Usage = "DNS Client for Humans"
|
||||
app.Version = buildString
|
||||
|
||||
// Query Options.
|
||||
queryFlags := []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "query",
|
||||
Value: cli.NewStringSlice(),
|
||||
Aliases: []string{"q"},
|
||||
Usage: "Hostname to query the DNS records for (eg mrkaran.dev)",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "type",
|
||||
Value: cli.NewStringSlice(),
|
||||
Aliases: []string{"t"},
|
||||
Usage: "Type of DNS record to be queried (A, AAAA, MX etc)",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "class",
|
||||
Value: cli.NewStringSlice(),
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Network class of the DNS record to be queried (IN, CH, HS etc)",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "nameservers",
|
||||
Value: cli.NewStringSlice(),
|
||||
Aliases: []string{"n"},
|
||||
Usage: "DNS Server address to send queries (eg 1.1.1.1, 8.8.8.8)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "reverse",
|
||||
Value: false,
|
||||
Aliases: []string{"x"},
|
||||
Usage: "Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively",
|
||||
},
|
||||
}
|
||||
|
||||
// Resolver Options.
|
||||
|
||||
cli.AppHelpTemplate = appHelpTextTemplate
|
||||
|
||||
app.Flags = append(app.Flags, queryFlags...)
|
||||
|
||||
sort.Sort(cli.FlagsByName(app.Flags))
|
||||
|
||||
// // Define actions.
|
||||
app.Action = Lookup
|
||||
|
||||
// Run the app.
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
lo.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func Lookup(c *cli.Context) error {
|
||||
fmt.Println(c.StringSlice("query"))
|
||||
return nil
|
||||
}
|
4
go.mod
4
go.mod
|
@ -13,6 +13,7 @@ require (
|
|||
github.com/mr-karan/logf v0.3.2
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/urfave/cli/v2 v2.10.3
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b
|
||||
)
|
||||
|
||||
|
@ -21,6 +22,7 @@ require (
|
|||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
|
@ -36,6 +38,8 @@ require (
|
|||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 // indirect
|
||||
|
|
12
go.sum
12
go.sum
|
@ -41,6 +41,8 @@ github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitf
|
|||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -183,8 +185,6 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
|
|||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mr-karan/logf v0.3.1 h1:IEv+xcatG7lY9w/EQ/QVM9FNxbR17USaVRA+WOKPb9o=
|
||||
github.com/mr-karan/logf v0.3.1/go.mod h1:644G+9amD9WMHx0SnzpXksL9iN613UkryU+8RBwsuHM=
|
||||
github.com/mr-karan/logf v0.3.2 h1:Hk/77c6nUdXBw+bNMcyVN2vmlaRQjBC9Qu6SVv5QMdg=
|
||||
github.com/mr-karan/logf v0.3.2/go.mod h1:644G+9amD9WMHx0SnzpXksL9iN613UkryU+8RBwsuHM=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
|
@ -225,6 +225,8 @@ github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8d
|
|||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
|
@ -262,8 +264,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/urfave/cli/v2 v2.10.3 h1:oi571Fxz5aHugfBAJd5nkwSk3fzATXtMlpxdLylSCMo=
|
||||
github.com/urfave/cli/v2 v2.10.3/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
|
@ -425,8 +431,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/pkg/models"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/mr-karan/logf"
|
||||
)
|
||||
|
||||
// App represents the structure for all app wide configuration.
|
||||
type App struct {
|
||||
Logger *logf.Logger
|
||||
Version string
|
||||
QueryFlags models.QueryFlags
|
||||
Questions []dns.Question
|
||||
Resolvers []resolvers.Resolver
|
||||
ResolverOpts resolvers.Options
|
||||
Nameservers []models.Nameserver
|
||||
}
|
||||
|
||||
// NewApp initializes an instance of App which holds app wide configuration.
|
||||
func New(logger *logf.Logger, buildVersion string) App {
|
||||
app := App{
|
||||
Logger: logger,
|
||||
Version: buildVersion,
|
||||
QueryFlags: models.QueryFlags{
|
||||
QNames: []string{},
|
||||
QTypes: []string{},
|
||||
QClasses: []string{},
|
||||
Nameservers: []string{},
|
||||
},
|
||||
Nameservers: []models.Nameserver{},
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// Attempts a DNS Lookup with retries for a given Question.
|
||||
func (app *App) LookupWithRetry(attempts int, resolver resolvers.Resolver, ques dns.Question) (resolvers.Response, error) {
|
||||
resp, err := resolver.Lookup(ques)
|
||||
if err != nil {
|
||||
// Retry lookup.
|
||||
attempts--
|
||||
if attempts > 0 {
|
||||
// Add some random delay.
|
||||
time.Sleep(time.Millisecond*300 + (time.Duration(rand.Int63n(int64(time.Millisecond*100))))/2)
|
||||
app.Logger.Debug("retrying lookup")
|
||||
return app.LookupWithRetry(attempts, resolver, ques)
|
||||
}
|
||||
return resolvers.Response{}, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// LoadFallbacks sets fallbacks for options
|
||||
// that are not specified by the user but necessary
|
||||
// for the resolver.
|
||||
func (app *App) LoadFallbacks() {
|
||||
if len(app.QueryFlags.QTypes) == 0 {
|
||||
app.QueryFlags.QTypes = append(app.QueryFlags.QTypes, "A")
|
||||
}
|
||||
if len(app.QueryFlags.QClasses) == 0 {
|
||||
app.QueryFlags.QClasses = append(app.QueryFlags.QClasses, "IN")
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareQuestions takes a list of query names, query types and query classes
|
||||
// and prepare a question for each combination of the above.
|
||||
func (app *App) PrepareQuestions() {
|
||||
for _, n := range app.QueryFlags.QNames {
|
||||
for _, t := range app.QueryFlags.QTypes {
|
||||
for _, c := range app.QueryFlags.QClasses {
|
||||
app.Questions = append(app.Questions, dns.Question{
|
||||
Name: n,
|
||||
Qtype: dns.StringToType[strings.ToUpper(t)],
|
||||
Qclass: dns.StringToClass[strings.ToUpper(c)],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReverseLookup is used to perform a reverse DNS Lookup
|
||||
// using an IPv4 or IPv6 address.
|
||||
// Query Type is set to PTR, Query Class is set to IN.
|
||||
// Query Names must be formatted in in-addr.arpa. or ip6.arpa format.
|
||||
func (app *App) ReverseLookup() {
|
||||
app.QueryFlags.QTypes = []string{"PTR"}
|
||||
app.QueryFlags.QClasses = []string{"IN"}
|
||||
formattedNames := make([]string, 0, len(app.QueryFlags.QNames))
|
||||
|
||||
for _, n := range app.QueryFlags.QNames {
|
||||
addr, err := dns.ReverseAddr(n)
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Fatal("error formatting address")
|
||||
}
|
||||
formattedNames = append(formattedNames, addr)
|
||||
}
|
||||
app.QueryFlags.QNames = formattedNames
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/internal/models"
|
||||
"github.com/mr-karan/doggo/internal/resolvers"
|
||||
"github.com/mr-karan/logf"
|
||||
)
|
||||
|
||||
// Client represents the structure for all app wide configuration.
|
||||
type Client struct {
|
||||
Log *logf.Logger
|
||||
Version string
|
||||
QueryFlags models.QueryFlags
|
||||
Questions []dns.Question
|
||||
Resolvers []resolvers.Resolver
|
||||
Nameservers []models.Nameserver
|
||||
}
|
||||
|
||||
// New initializes an instance of App which holds app wide configuration.
|
||||
func New(logger *logf.Logger, buildVersion string) Client {
|
||||
return Client{
|
||||
Log: logger,
|
||||
Version: buildVersion,
|
||||
QueryFlags: models.QueryFlags{
|
||||
QNames: []string{},
|
||||
QTypes: []string{},
|
||||
QClasses: []string{},
|
||||
Nameservers: []string{},
|
||||
},
|
||||
Nameservers: []models.Nameserver{},
|
||||
}
|
||||
}
|
||||
|
||||
// LookupWithRetry attempts a DNS Lookup with retries for a given Question.
|
||||
func (hub *Client) LookupWithRetry(attempts int, resolver resolvers.Resolver, ques dns.Question) (resolvers.Response, error) {
|
||||
resp, err := resolver.Lookup(ques)
|
||||
if err != nil {
|
||||
// Retry lookup.
|
||||
attempts--
|
||||
if attempts > 0 {
|
||||
// Add some random delay.
|
||||
time.Sleep(time.Millisecond*300 + (time.Duration(rand.Int63n(int64(time.Millisecond*100))))/2)
|
||||
hub.Log.Debug("retrying lookup")
|
||||
return hub.LookupWithRetry(attempts, resolver, ques)
|
||||
}
|
||||
return resolvers.Response{}, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package app
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -8,47 +8,47 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ameshkov/dnsstamps"
|
||||
"github.com/mr-karan/doggo/pkg/config"
|
||||
"github.com/mr-karan/doggo/pkg/models"
|
||||
"github.com/mr-karan/doggo/internal/config"
|
||||
"github.com/mr-karan/doggo/internal/models"
|
||||
)
|
||||
|
||||
// LoadNameservers reads all the user given
|
||||
// nameservers and loads to App.
|
||||
func (app *App) LoadNameservers() error {
|
||||
for _, srv := range app.QueryFlags.Nameservers {
|
||||
// nameservers and loads to Client.
|
||||
func (hub *Client) LoadNameservers() error {
|
||||
for _, srv := range hub.QueryFlags.Nameservers {
|
||||
ns, err := initNameserver(srv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing nameserver: %s", srv)
|
||||
}
|
||||
// check if properly initialised.
|
||||
if ns.Address != "" && ns.Type != "" {
|
||||
app.Nameservers = append(app.Nameservers, ns)
|
||||
hub.Nameservers = append(hub.Nameservers, ns)
|
||||
}
|
||||
}
|
||||
|
||||
// Set `ndots` to the user specified value.
|
||||
app.ResolverOpts.Ndots = app.QueryFlags.Ndots
|
||||
hub.ResolverOpts.Ndots = hub.QueryFlags.Ndots
|
||||
// fallback to system nameserver
|
||||
// in case no nameserver is specified by user.
|
||||
if len(app.Nameservers) == 0 {
|
||||
ns, ndots, search, err := getDefaultServers(app.QueryFlags.Strategy)
|
||||
if len(hub.Nameservers) == 0 {
|
||||
ns, ndots, search, err := getDefaultServers(hub.QueryFlags.Strategy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching system default nameserver")
|
||||
}
|
||||
// `-1` indicates the flag is not set.
|
||||
// use from config if user hasn't specified any value.
|
||||
if app.ResolverOpts.Ndots == -1 {
|
||||
app.ResolverOpts.Ndots = ndots
|
||||
if hub.ResolverOpts.Ndots == -1 {
|
||||
hub.ResolverOpts.Ndots = ndots
|
||||
}
|
||||
if len(search) > 0 && app.QueryFlags.UseSearchList {
|
||||
app.ResolverOpts.SearchList = search
|
||||
if len(search) > 0 && hub.QueryFlags.UseSearchList {
|
||||
hub.ResolverOpts.SearchList = search
|
||||
}
|
||||
app.Nameservers = append(app.Nameservers, ns...)
|
||||
hub.Nameservers = append(hub.Nameservers, ns...)
|
||||
}
|
||||
// if the user hasn't given any override of `ndots` AND has
|
||||
// given a custom nameserver. Set `ndots` to 1 as the fallback value
|
||||
if app.ResolverOpts.Ndots == -1 {
|
||||
app.ResolverOpts.Ndots = 0
|
||||
if hub.ResolverOpts.Ndots == -1 {
|
||||
hub.ResolverOpts.Ndots = 0
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package app
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -7,20 +7,20 @@ import (
|
|||
|
||||
"github.com/fatih/color"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/mr-karan/doggo/internal/resolvers"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
func (app *App) outputJSON(rsp []resolvers.Response) {
|
||||
func (hub *Client) outputJSON(rsp []resolvers.Response) {
|
||||
// Pretty print with 4 spaces.
|
||||
res, err := json.MarshalIndent(rsp, "", " ")
|
||||
if err != nil {
|
||||
app.Logger.WithError(err).Fatal("unable to output data in JSON")
|
||||
hub.Log.WithError(err).Fatal("unable to output data in JSON")
|
||||
}
|
||||
fmt.Printf("%s", res)
|
||||
}
|
||||
|
||||
func (app *App) outputShort(rsp []resolvers.Response) {
|
||||
func (hub *Client) outputShort(rsp []resolvers.Response) {
|
||||
for _, r := range rsp {
|
||||
for _, a := range r.Answers {
|
||||
fmt.Printf("%s\n", a.Address)
|
||||
|
@ -28,7 +28,7 @@ func (app *App) outputShort(rsp []resolvers.Response) {
|
|||
}
|
||||
}
|
||||
|
||||
func (app *App) outputTerminal(rsp []resolvers.Response) {
|
||||
func (hub *Client) outputTerminal(rsp []resolvers.Response) {
|
||||
var (
|
||||
green = color.New(color.FgGreen, color.Bold).SprintFunc()
|
||||
blue = color.New(color.FgBlue, color.Bold).SprintFunc()
|
||||
|
@ -39,14 +39,14 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
|
|||
)
|
||||
|
||||
// Disables colorized output if user specified.
|
||||
if !app.QueryFlags.Color {
|
||||
if !hub.QueryFlags.Color {
|
||||
color.NoColor = true
|
||||
}
|
||||
|
||||
// Conditional Time column.
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
header := []string{"Name", "Type", "Class", "TTL", "Address", "Nameserver"}
|
||||
if app.QueryFlags.DisplayTimeTaken {
|
||||
if hub.QueryFlags.DisplayTimeTaken {
|
||||
header = append(header, "Time Taken")
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
|
|||
}
|
||||
output := []string{green(ans.Name), typOut, ans.Class, ans.TTL, ans.Address, ans.Nameserver}
|
||||
// Print how long it took
|
||||
if app.QueryFlags.DisplayTimeTaken {
|
||||
if hub.QueryFlags.DisplayTimeTaken {
|
||||
output = append(output, ans.RTT)
|
||||
}
|
||||
if outputStatus {
|
||||
|
@ -124,7 +124,7 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
|
|||
}
|
||||
output := []string{green(auth.Name), typOut, auth.Class, auth.TTL, auth.MName, auth.Nameserver}
|
||||
// Print how long it took
|
||||
if app.QueryFlags.DisplayTimeTaken {
|
||||
if hub.QueryFlags.DisplayTimeTaken {
|
||||
output = append(output, auth.RTT)
|
||||
}
|
||||
if outputStatus {
|
||||
|
@ -138,12 +138,12 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
|
|||
|
||||
// Output takes a list of `dns.Answers` and based
|
||||
// on the output format specified displays the information.
|
||||
func (app *App) Output(responses []resolvers.Response) {
|
||||
if app.QueryFlags.ShowJSON {
|
||||
app.outputJSON(responses)
|
||||
} else if app.QueryFlags.ShortOutput {
|
||||
app.outputShort(responses)
|
||||
func (hub *Client) Output(responses []resolvers.Response) {
|
||||
if hub.QueryFlags.ShowJSON {
|
||||
hub.outputJSON(responses)
|
||||
} else if hub.QueryFlags.ShortOutput {
|
||||
hub.outputShort(responses)
|
||||
} else {
|
||||
app.outputTerminal(responses)
|
||||
hub.outputTerminal(responses)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// LoadFallbacks sets fallbacks for options
|
||||
// that are not specified by the user but necessary
|
||||
// for the resolver.
|
||||
func (hub *Client) LoadFallbacks() {
|
||||
if len(hub.QueryFlags.QTypes) == 0 {
|
||||
hub.QueryFlags.QTypes = append(hub.QueryFlags.QTypes, "A")
|
||||
}
|
||||
if len(hub.QueryFlags.QClasses) == 0 {
|
||||
hub.QueryFlags.QClasses = append(hub.QueryFlags.QClasses, "IN")
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareQuestions takes a list of query names, query types and query classes
|
||||
// and prepare a question for each combination of the above.
|
||||
func (hub *Client) PrepareQuestions() {
|
||||
for _, n := range hub.QueryFlags.QNames {
|
||||
for _, t := range hub.QueryFlags.QTypes {
|
||||
for _, c := range hub.QueryFlags.QClasses {
|
||||
hub.Questions = append(hub.Questions, dns.Question{
|
||||
Name: n,
|
||||
Qtype: dns.StringToType[strings.ToUpper(t)],
|
||||
Qclass: dns.StringToClass[strings.ToUpper(c)],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReverseLookup is used to perform a reverse DNS Lookup
|
||||
// using an IPv4 or IPv6 address.
|
||||
// Query Type is set to PTR, Query Class is set to IN.
|
||||
// Query Names must be formatted in in-addr.arpa. or ip6.arpa format.
|
||||
func (hub *Client) ReverseLookup() {
|
||||
hub.QueryFlags.QTypes = []string{"PTR"}
|
||||
hub.QueryFlags.QClasses = []string{"IN"}
|
||||
formattedNames := make([]string, 0, len(hub.QueryFlags.QNames))
|
||||
|
||||
for _, n := range hub.QueryFlags.QNames {
|
||||
addr, err := dns.ReverseAddr(n)
|
||||
if err != nil {
|
||||
hub.Log.WithError(err).Fatal("error formatting address")
|
||||
}
|
||||
formattedNames = append(formattedNames, addr)
|
||||
}
|
||||
hub.QueryFlags.QNames = formattedNames
|
||||
}
|
|
@ -72,6 +72,8 @@ func (r *ClassicResolver) Lookup(question dns.Question) (Response, error) {
|
|||
"nameserver": r.server,
|
||||
}).Debug("attempting to resolve")
|
||||
|
||||
r.resolverOptions.Logger.Debug("abc")
|
||||
|
||||
// Since the library doesn't include tcp.Dial time,
|
||||
// it's better to not rely on `rtt` provided here and calculate it ourselves.
|
||||
now := time.Now()
|
|
@ -1,12 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"github.com/mr-karan/logf"
|
||||
)
|
||||
|
||||
// InitLogger initializes logger.
|
||||
func InitLogger() *logf.Logger {
|
||||
logger := logf.New()
|
||||
logger.SetColorOutput(true)
|
||||
return logger
|
||||
}
|
Loading…
Reference in New Issue