feat: refactor resolver in separate package
This commit is contained in:
parent
0e195fd9a7
commit
508a8dd7c4
17 changed files with 306 additions and 207 deletions
82
cmd/doggo/api/api.go
Normal file
82
cmd/doggo/api/api.go
Normal 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)
|
||||
}
|
|
@ -3,11 +3,13 @@ package main
|
|||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/knadh/koanf"
|
||||
"github.com/knadh/koanf/providers/posflag"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/mr-karan/doggo/pkg/resolvers"
|
||||
"github.com/mr-karan/doggo/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
@ -20,7 +22,7 @@ var (
|
|||
|
||||
func main() {
|
||||
var (
|
||||
logger = initLogger()
|
||||
logger = utils.InitLogger()
|
||||
k = koanf.New(".")
|
||||
)
|
||||
|
||||
|
@ -110,15 +112,21 @@ func main() {
|
|||
hub.Logger.Exit(2)
|
||||
}
|
||||
|
||||
// Load Resolver Options.
|
||||
hub.loadResolverOptions()
|
||||
|
||||
// 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 {
|
||||
hub.Logger.WithError(err).Error("error loading resolver")
|
||||
hub.Logger.Exit(2)
|
||||
}
|
||||
hub.Resolvers = rslvrs
|
||||
|
||||
// Run the app.
|
||||
hub.Logger.Debug("Starting doggo 🐶")
|
||||
|
@ -130,7 +138,7 @@ func main() {
|
|||
// Resolve Queries.
|
||||
var responses []resolvers.Response
|
||||
for _, q := range hub.Questions {
|
||||
for _, rslv := range hub.Resolver {
|
||||
for _, rslv := range hub.Resolvers {
|
||||
resp, err := rslv.Lookup(q)
|
||||
if err != nil {
|
||||
hub.Logger.WithError(err).Error("error looking up DNS records")
|
36
cmd/doggo/cli/hub.go
Normal file
36
cmd/doggo/cli/hub.go
Normal 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
|
||||
}
|
|
@ -6,19 +6,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
"github.com/mr-karan/doggo/pkg/config"
|
||||
)
|
||||
|
||||
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"
|
||||
"github.com/mr-karan/doggo/pkg/models"
|
||||
)
|
||||
|
||||
// loadNameservers reads all the user given
|
||||
|
@ -62,56 +50,56 @@ func (hub *Hub) loadNameservers() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getDefaultServers() ([]Nameserver, int, []string, error) {
|
||||
func getDefaultServers() ([]models.Nameserver, int, []string, error) {
|
||||
dnsServers, ndots, search, err := config.GetDefaultServers()
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
servers := make([]Nameserver, 0, len(dnsServers))
|
||||
servers := make([]models.Nameserver, 0, len(dnsServers))
|
||||
for _, s := range dnsServers {
|
||||
ns := Nameserver{
|
||||
Type: UDPResolver,
|
||||
Address: net.JoinHostPort(s, DefaultUDPPort),
|
||||
ns := models.Nameserver{
|
||||
Type: models.UDPResolver,
|
||||
Address: net.JoinHostPort(s, models.DefaultUDPPort),
|
||||
}
|
||||
servers = append(servers, ns)
|
||||
}
|
||||
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.
|
||||
ns := Nameserver{
|
||||
Type: UDPResolver,
|
||||
Address: net.JoinHostPort(n, DefaultUDPPort),
|
||||
ns := models.Nameserver{
|
||||
Type: models.UDPResolver,
|
||||
Address: net.JoinHostPort(n, models.DefaultUDPPort),
|
||||
}
|
||||
u, err := url.Parse(n)
|
||||
if err != nil {
|
||||
return ns, err
|
||||
}
|
||||
if u.Scheme == "https" {
|
||||
ns.Type = DOHResolver
|
||||
ns.Type = models.DOHResolver
|
||||
ns.Address = u.String()
|
||||
}
|
||||
if u.Scheme == "tls" {
|
||||
ns.Type = DOTResolver
|
||||
ns.Type = models.DOTResolver
|
||||
if u.Port() == "" {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), DefaultTLSPort)
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTLSPort)
|
||||
} else {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
|
||||
}
|
||||
}
|
||||
if u.Scheme == "tcp" {
|
||||
ns.Type = TCPResolver
|
||||
ns.Type = models.TCPResolver
|
||||
if u.Port() == "" {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), DefaultTCPPort)
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTCPPort)
|
||||
} else {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
|
||||
}
|
||||
}
|
||||
if u.Scheme == "udp" {
|
||||
ns.Type = UDPResolver
|
||||
ns.Type = models.UDPResolver
|
||||
if u.Port() == "" {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), DefaultUDPPort)
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultUDPPort)
|
||||
} else {
|
||||
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
|
||||
}
|
1
cmd/doggo/cli/resolver.go
Normal file
1
cmd/doggo/cli/resolver.go
Normal file
|
@ -0,0 +1 @@
|
|||
package main
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue