From 9e3656fae97f7d2f826479c460852419f978250a Mon Sep 17 00:00:00 2001 From: Karan Sharma Date: Fri, 25 Jun 2021 17:25:04 +0530 Subject: [PATCH] feat: Add support for reverse DNS lookups Closes https://github.com/mr-karan/doggo/issues/25 --- README.md | 1 + cmd/doggo/cli/cli.go | 10 ++++++++++ cmd/doggo/cli/help.go | 1 + internal/app/questions.go | 20 ++++++++++++++++++++ pkg/models/models.go | 7 ++++--- 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 500a407..6f828fb 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ to experiment with writing a DNS Client from scratch in `Go` myself. Hence the n - Supports IPv4 **and** IPv6 _both_. - Available as a web tool as well: [https://doggo.mrkaran.dev](https://doggo.mrkaran.dev). - Shell completions for `zsh` and `fish`. +- Reverse DNS Lookups. ## Installation diff --git a/cmd/doggo/cli/cli.go b/cmd/doggo/cli/cli.go index ff8a9f6..a413f18 100644 --- a/cmd/doggo/cli/cli.go +++ b/cmd/doggo/cli/cli.go @@ -37,6 +37,7 @@ func main() { f.StringSliceP("type", "t", []string{}, "Type of DNS record to be queried (A, AAAA, MX etc)") f.StringSliceP("class", "c", []string{}, "Network class of the DNS record to be queried (IN, CH, HS etc)") f.StringSliceP("nameservers", "n", []string{}, "Address of the nameserver to send packets to") + f.BoolP("reverse", "x", false, "Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively.") // Resolver Options f.Int("timeout", 5, "Sets the timeout for a query to T seconds. The default timeout is 5 seconds.") @@ -94,6 +95,15 @@ func main() { app.QueryFlags.QClasses = append(app.QueryFlags.QClasses, qc...) app.QueryFlags.QNames = append(app.QueryFlags.QNames, qn...) + // Check if reverse flag is passed. If it is, then set + // query type as PTR and query class as IN. + // Modify query name like 94.2.0.192.in-addr.arpa if it's an IPv4 address. + // Use IP6.ARPA nibble format otherwise. + + if app.QueryFlags.ReverseLookup { + app.ReverseLookup() + } + // Load fallbacks. app.LoadFallbacks() diff --git a/cmd/doggo/cli/help.go b/cmd/doggo/cli/help.go index c27ccf8..a391dbc 100644 --- a/cmd/doggo/cli/help.go +++ b/cmd/doggo/cli/help.go @@ -43,6 +43,7 @@ var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}: {{"-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" }}: {{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise. diff --git a/internal/app/questions.go b/internal/app/questions.go index d95de6d..b31a1e3 100644 --- a/internal/app/questions.go +++ b/internal/app/questions.go @@ -33,3 +33,23 @@ func (app *App) PrepareQuestions() { } } } + +// 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).Error("error formatting address") + app.Logger.Exit(2) + } + formattedNames = append(formattedNames, addr) + } + app.QueryFlags.QNames = formattedNames +} diff --git a/pkg/models/models.go b/pkg/models/models.go index a3c0852..e6cca57 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -3,11 +3,11 @@ package models import "time" const ( - // DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS + // 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 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 specifies the default port for a DNS server connecting over TCP. DefaultTCPPort = "53" UDPResolver = "udp" DOHResolver = "doh" @@ -31,6 +31,7 @@ type QueryFlags struct { DisplayTimeTaken bool `koanf:"time" json:"-"` ShowJSON bool `koanf:"json" json:"-"` UseSearchList bool `koanf:"search" json:"-"` + ReverseLookup bool `koanf:"reverse" reverse:"-"` } // Nameserver represents the type of Nameserver