unfinished mess

This commit is contained in:
Karan Sharma 2022-07-06 21:52:59 +05:30
parent 6c3b17ba0d
commit 2e2e3b1ec8
26 changed files with 364 additions and 171 deletions

View file

@ -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()

View file

@ -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))

View file

@ -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"
)

108
cmd/doggo-v1/help.go Normal file
View file

@ -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)
}

10
cmd/doggo/init.go Normal file
View file

@ -0,0 +1,10 @@
package main
import "github.com/mr-karan/logf"
func initLogger() *logf.Logger {
logf := logf.New()
logf.SetColorOutput(true)
return logf
}

77
cmd/doggo/main.go Normal file
View file

@ -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
}