feat: refactor resolver in separate package

pull/15/head
Karan Sharma 2021-02-26 20:06:46 +05:30
parent 0e195fd9a7
commit 508a8dd7c4
17 changed files with 306 additions and 207 deletions

View File

@ -1,25 +1,35 @@
BIN := ./bin/doggo CLI_BIN := ./bin/doggo-cli.bin
API_BIN := ./bin/doggo-api.bin
HASH := $(shell git rev-parse --short HEAD) HASH := $(shell git rev-parse --short HEAD)
BUILD_DATE := $(shell date '+%Y-%m-%d %H:%M:%S') BUILD_DATE := $(shell date '+%Y-%m-%d %H:%M:%S')
VERSION := ${HASH} VERSION := ${HASH}
.PHONY: build .PHONY: build-cli
build: build-cli:
go build -o ${BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/ go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/cli/
.PHONY: run .PHONY: build-api
run: build ## Build and Execute the binary after the build step build-api:
${BIN} go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/api/
.PHONY: build
build: build-api build-cli
.PHONY: run-cli
run-cli: build-cli ## Build and Execute the CLI binary after the build step.
${CLI_BIN}
.PHONY: run-api
run-api: build-api ## Build and Execute the API binary after the build step.
${API_BIN}
.PHONY: clean .PHONY: clean
clean: clean:
go clean go clean
- rm -f ${BIN} - rm -rf ./bin/
.PHONY: lint .PHONY: lint
lint: lint:
golangci-lint run golangci-lint run
.PHONY: fresh
fresh: clean build

View File

@ -0,0 +1,82 @@
package main
import (
"encoding/json"
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/knadh/koanf"
"github.com/mr-karan/doggo/pkg/utils"
)
var (
logger = utils.InitLogger()
k = koanf.New(".")
)
type resp struct {
Status string `json:"status"`
Message string `json:"message,omitempty"`
Data interface{} `json:"data,omitempty"`
}
func main() {
r := chi.NewRouter()
// Setup middlewares.
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
sendSuccessResponse("Welcome to Doggo DNS!", w)
return
})
r.Get("/ping/", func(w http.ResponseWriter, r *http.Request) {
sendSuccessResponse("PONG", w)
return
})
r.Post("/lookup/", func(w http.ResponseWriter, r *http.Request) {
return
})
http.ListenAndServe(":3000", r)
}
// sendResponse sends an HTTP success response.
func sendResponse(data interface{}, statusText string, status int, w http.ResponseWriter) {
w.WriteHeader(status)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
out, err := json.Marshal(resp{Status: statusText, Data: data})
if err != nil {
sendErrorResponse("Internal Server Error", http.StatusInternalServerError, nil, w)
return
}
_, _ = w.Write(out)
}
// sendSuccessResponse sends an HTTP success (200 OK) response.
func sendSuccessResponse(data interface{}, w http.ResponseWriter) {
sendResponse(data, "success", http.StatusOK, w)
}
// sendErrorResponse sends an HTTP error response.
func sendErrorResponse(message string, status int, data interface{}, w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
resp := resp{Status: "error",
Message: message,
Data: data}
out, _ := json.Marshal(resp)
_, _ = w.Write(out)
}

View File

@ -3,11 +3,13 @@ package main
import ( import (
"os" "os"
"strings" "strings"
"time"
"github.com/knadh/koanf" "github.com/knadh/koanf"
"github.com/knadh/koanf/providers/posflag" "github.com/knadh/koanf/providers/posflag"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/resolvers" "github.com/mr-karan/doggo/pkg/resolvers"
"github.com/mr-karan/doggo/pkg/utils"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
) )
@ -20,7 +22,7 @@ var (
func main() { func main() {
var ( var (
logger = initLogger() logger = utils.InitLogger()
k = koanf.New(".") k = koanf.New(".")
) )
@ -110,15 +112,21 @@ func main() {
hub.Logger.Exit(2) hub.Logger.Exit(2)
} }
// Load Resolver Options.
hub.loadResolverOptions()
// Load Resolvers. // Load Resolvers.
err = hub.loadResolvers() rslvrs, err := resolvers.LoadResolvers(resolvers.Options{
Nameservers: hub.Nameservers,
UseIPv4: hub.QueryFlags.UseIPv4,
UseIPv6: hub.QueryFlags.UseIPv6,
SearchList: hub.ResolverOpts.SearchList,
Ndots: hub.ResolverOpts.Ndots,
Timeout: hub.QueryFlags.Timeout * time.Second,
Logger: hub.Logger,
})
if err != nil { if err != nil {
hub.Logger.WithError(err).Error("error loading resolver") hub.Logger.WithError(err).Error("error loading resolver")
hub.Logger.Exit(2) hub.Logger.Exit(2)
} }
hub.Resolvers = rslvrs
// Run the app. // Run the app.
hub.Logger.Debug("Starting doggo 🐶") hub.Logger.Debug("Starting doggo 🐶")
@ -130,7 +138,7 @@ func main() {
// Resolve Queries. // Resolve Queries.
var responses []resolvers.Response var responses []resolvers.Response
for _, q := range hub.Questions { for _, q := range hub.Questions {
for _, rslv := range hub.Resolver { for _, rslv := range hub.Resolvers {
resp, err := rslv.Lookup(q) resp, err := rslv.Lookup(q)
if err != nil { if err != nil {
hub.Logger.WithError(err).Error("error looking up DNS records") hub.Logger.WithError(err).Error("error looking up DNS records")

View File

@ -0,0 +1,36 @@
package main
import (
"github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/models"
"github.com/mr-karan/doggo/pkg/resolvers"
"github.com/sirupsen/logrus"
)
// Hub represents the structure for all app wide configuration.
type Hub struct {
Logger *logrus.Logger
Version string
QueryFlags models.QueryFlags
UnparsedArgs []string
Questions []dns.Question
Resolvers []resolvers.Resolver
ResolverOpts resolvers.Options
Nameservers []models.Nameserver
}
// NewHub initializes an instance of Hub which holds app wide configuration.
func NewHub(logger *logrus.Logger, buildVersion string) *Hub {
hub := &Hub{
Logger: logger,
Version: buildVersion,
QueryFlags: models.QueryFlags{
QNames: []string{},
QTypes: []string{},
QClasses: []string{},
Nameservers: []string{},
},
Nameservers: []models.Nameserver{},
}
return hub
}

View File

@ -6,19 +6,7 @@ import (
"net/url" "net/url"
"github.com/mr-karan/doggo/pkg/config" "github.com/mr-karan/doggo/pkg/config"
) "github.com/mr-karan/doggo/pkg/models"
const (
// DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS
DefaultTLSPort = "853"
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP
DefaultUDPPort = "53"
// DefaultTCPPort specifies the default port for a DNS server connecting over TCP
DefaultTCPPort = "53"
UDPResolver = "udp"
DOHResolver = "doh"
TCPResolver = "tcp"
DOTResolver = "dot"
) )
// loadNameservers reads all the user given // loadNameservers reads all the user given
@ -62,56 +50,56 @@ func (hub *Hub) loadNameservers() error {
return nil return nil
} }
func getDefaultServers() ([]Nameserver, int, []string, error) { func getDefaultServers() ([]models.Nameserver, int, []string, error) {
dnsServers, ndots, search, err := config.GetDefaultServers() dnsServers, ndots, search, err := config.GetDefaultServers()
if err != nil { if err != nil {
return nil, 0, nil, err return nil, 0, nil, err
} }
servers := make([]Nameserver, 0, len(dnsServers)) servers := make([]models.Nameserver, 0, len(dnsServers))
for _, s := range dnsServers { for _, s := range dnsServers {
ns := Nameserver{ ns := models.Nameserver{
Type: UDPResolver, Type: models.UDPResolver,
Address: net.JoinHostPort(s, DefaultUDPPort), Address: net.JoinHostPort(s, models.DefaultUDPPort),
} }
servers = append(servers, ns) servers = append(servers, ns)
} }
return servers, ndots, search, nil return servers, ndots, search, nil
} }
func initNameserver(n string) (Nameserver, error) { func initNameserver(n string) (models.Nameserver, error) {
// Instantiate a UDP resolver with default port as a fallback. // Instantiate a UDP resolver with default port as a fallback.
ns := Nameserver{ ns := models.Nameserver{
Type: UDPResolver, Type: models.UDPResolver,
Address: net.JoinHostPort(n, DefaultUDPPort), Address: net.JoinHostPort(n, models.DefaultUDPPort),
} }
u, err := url.Parse(n) u, err := url.Parse(n)
if err != nil { if err != nil {
return ns, err return ns, err
} }
if u.Scheme == "https" { if u.Scheme == "https" {
ns.Type = DOHResolver ns.Type = models.DOHResolver
ns.Address = u.String() ns.Address = u.String()
} }
if u.Scheme == "tls" { if u.Scheme == "tls" {
ns.Type = DOTResolver ns.Type = models.DOTResolver
if u.Port() == "" { if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), DefaultTLSPort) ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTLSPort)
} else { } else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port()) ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
} }
} }
if u.Scheme == "tcp" { if u.Scheme == "tcp" {
ns.Type = TCPResolver ns.Type = models.TCPResolver
if u.Port() == "" { if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), DefaultTCPPort) ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTCPPort)
} else { } else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port()) ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
} }
} }
if u.Scheme == "udp" { if u.Scheme == "udp" {
ns.Type = UDPResolver ns.Type = models.UDPResolver
if u.Port() == "" { if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), DefaultUDPPort) ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultUDPPort)
} else { } else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port()) ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
} }

View File

@ -0,0 +1 @@
package main

View File

@ -1,71 +0,0 @@
package main
import (
"time"
"github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/resolvers"
"github.com/sirupsen/logrus"
)
// Hub represents the structure for all app wide configuration.
type Hub struct {
Logger *logrus.Logger
Version string
QueryFlags QueryFlags
UnparsedArgs []string
Questions []dns.Question
Resolver []resolvers.Resolver
ResolverOpts resolvers.Options
Nameservers []Nameserver
}
// QueryFlags is used store the query params
// supplied by the user.
type QueryFlags struct {
QNames []string `koanf:"query"`
QTypes []string `koanf:"type"`
QClasses []string `koanf:"class"`
Nameservers []string `koanf:"nameserver"`
UseIPv4 bool `koanf:"ipv4"`
UseIPv6 bool `koanf:"ipv6"`
DisplayTimeTaken bool `koanf:"time"`
ShowJSON bool `koanf:"json"`
UseSearchList bool `koanf:"search"`
Ndots int `koanf:"ndots"`
Color bool `koanf:"color"`
Timeout time.Duration `koanf:"timeout"`
}
// Nameserver represents the type of Nameserver
// along with the server address.
type Nameserver struct {
Address string
Type string
}
// NewHub initializes an instance of Hub which holds app wide configuration.
func NewHub(logger *logrus.Logger, buildVersion string) *Hub {
hub := &Hub{
Logger: logger,
Version: buildVersion,
QueryFlags: QueryFlags{
QNames: []string{},
QTypes: []string{},
QClasses: []string{},
Nameservers: []string{},
},
Nameservers: []Nameserver{},
}
return hub
}
// initLogger initializes logger
func initLogger() *logrus.Logger {
logger := logrus.New()
logger.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
DisableLevelTruncation: true,
})
return logger
}

View File

@ -1,79 +0,0 @@
package main
import (
"time"
"github.com/mr-karan/doggo/pkg/resolvers"
)
// loadResolverOptions loads the common options
// to configure a resolver from the query args.
func (hub *Hub) loadResolverOptions() {
hub.ResolverOpts.Timeout = hub.QueryFlags.Timeout
}
// loadResolvers loads differently configured
// resolvers based on a list of nameserver.
func (hub *Hub) loadResolvers() error {
var resolverOpts = resolvers.Options{
Timeout: hub.QueryFlags.Timeout * time.Second,
Ndots: hub.ResolverOpts.Ndots,
SearchList: hub.ResolverOpts.SearchList,
Logger: hub.Logger,
}
// for each nameserver, initialise the correct resolver
for _, ns := range hub.Nameservers {
if ns.Type == DOHResolver {
hub.Logger.Debug("initiating DOH resolver")
rslvr, err := resolvers.NewDOHResolver(ns.Address, resolverOpts)
if err != nil {
return err
}
hub.Resolver = append(hub.Resolver, rslvr)
}
if ns.Type == DOTResolver {
hub.Logger.Debug("initiating DOT resolver")
rslvr, err := resolvers.NewClassicResolver(ns.Address,
resolvers.ClassicResolverOpts{
IPv4Only: hub.QueryFlags.UseIPv4,
IPv6Only: hub.QueryFlags.UseIPv6,
UseTLS: true,
UseTCP: true,
}, resolverOpts)
if err != nil {
return err
}
hub.Resolver = append(hub.Resolver, rslvr)
}
if ns.Type == TCPResolver {
hub.Logger.Debug("initiating TCP resolver")
rslvr, err := resolvers.NewClassicResolver(ns.Address,
resolvers.ClassicResolverOpts{
IPv4Only: hub.QueryFlags.UseIPv4,
IPv6Only: hub.QueryFlags.UseIPv6,
UseTLS: false,
UseTCP: true,
}, resolverOpts)
if err != nil {
return err
}
hub.Resolver = append(hub.Resolver, rslvr)
}
if ns.Type == UDPResolver {
hub.Logger.Debug("initiating UDP resolver")
rslvr, err := resolvers.NewClassicResolver(ns.Address,
resolvers.ClassicResolverOpts{
IPv4Only: hub.QueryFlags.UseIPv4,
IPv6Only: hub.QueryFlags.UseIPv6,
UseTLS: false,
UseTCP: false,
}, resolverOpts)
if err != nil {
return err
}
hub.Resolver = append(hub.Resolver, rslvr)
}
}
return nil
}

2
go.mod
View File

@ -4,6 +4,8 @@ go 1.16
require ( require (
github.com/fatih/color v1.10.0 github.com/fatih/color v1.10.0
github.com/go-chi/chi v1.5.3
github.com/go-chi/render v1.0.1
github.com/knadh/koanf v0.14.0 github.com/knadh/koanf v0.14.0
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.35

10
go.sum
View File

@ -1,4 +1,3 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -8,6 +7,10 @@ github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGE
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-chi/chi v1.5.3 h1:+DVDS9/D3MTbEu3WrrH3oz9oP6PlSPSNj8LLw3X17yU=
github.com/go-chi/chi v1.5.3/go.mod h1:Q8xfe6s3fjZyMr8ZTv5jL+vxhVaFyCq2s+RvSfzTD0E=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
@ -37,7 +40,6 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
@ -54,20 +56,16 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -0,0 +1,40 @@
package models
import "time"
const (
// DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS
DefaultTLSPort = "853"
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP
DefaultUDPPort = "53"
// DefaultTCPPort specifies the default port for a DNS server connecting over TCP
DefaultTCPPort = "53"
UDPResolver = "udp"
DOHResolver = "doh"
TCPResolver = "tcp"
DOTResolver = "dot"
)
// QueryFlags is used store the query params
// supplied by the user.
type QueryFlags struct {
QNames []string `koanf:"query"`
QTypes []string `koanf:"type"`
QClasses []string `koanf:"class"`
Nameservers []string `koanf:"nameserver"`
UseIPv4 bool `koanf:"ipv4"`
UseIPv6 bool `koanf:"ipv6"`
DisplayTimeTaken bool `koanf:"time"`
ShowJSON bool `koanf:"json"`
UseSearchList bool `koanf:"search"`
Ndots int `koanf:"ndots"`
Color bool `koanf:"color"`
Timeout time.Duration `koanf:"timeout"`
}
// Nameserver represents the type of Nameserver
// along with the server address.
type Nameserver struct {
Address string
Type string
}

View File

@ -4,12 +4,16 @@ import (
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/models"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// Options represent a set of common options // Options represent a set of common options
// to configure a Resolver. // to configure a Resolver.
type Options struct { type Options struct {
Nameservers []models.Nameserver
UseIPv4 bool
UseIPv6 bool
SearchList []string SearchList []string
Ndots int Ndots int
Timeout time.Duration Timeout time.Duration
@ -59,3 +63,70 @@ type Authority struct {
RTT string `json:"rtt"` RTT string `json:"rtt"`
Nameserver string `json:"nameserver"` Nameserver string `json:"nameserver"`
} }
// LoadResolvers loads differently configured
// resolvers based on a list of nameserver.
func LoadResolvers(opts Options) ([]Resolver, error) {
var resolverOpts = Options{
Timeout: opts.Timeout,
Ndots: opts.Ndots,
SearchList: opts.SearchList,
Logger: opts.Logger,
}
// for each nameserver, initialise the correct resolver
rslvrs := make([]Resolver, 0, len(opts.Nameservers))
for _, ns := range opts.Nameservers {
if ns.Type == models.DOHResolver {
opts.Logger.Debug("initiating DOH resolver")
rslvr, err := NewDOHResolver(ns.Address, resolverOpts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.DOTResolver {
opts.Logger.Debug("initiating DOT resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: true,
UseTCP: true,
}, resolverOpts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.TCPResolver {
opts.Logger.Debug("initiating TCP resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false,
UseTCP: true,
}, resolverOpts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.UDPResolver {
opts.Logger.Debug("initiating UDP resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false,
UseTCP: false,
}, resolverOpts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
}
return rslvrs, nil
}

View File

@ -0,0 +1,13 @@
package utils
import "github.com/sirupsen/logrus"
// InitLogger initializes logger.
func InitLogger() *logrus.Logger {
logger := logrus.New()
logger.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
DisableLevelTruncation: true,
})
return logger
}