2020-12-12 11:57:13 +01:00
|
|
|
package main
|
|
|
|
|
2020-12-12 15:10:28 +01:00
|
|
|
import (
|
2020-12-13 05:04:53 +01:00
|
|
|
"encoding/json"
|
2020-12-12 15:10:28 +01:00
|
|
|
"fmt"
|
2020-12-13 04:17:07 +01:00
|
|
|
"os"
|
2020-12-12 15:10:28 +01:00
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/fatih/color"
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
"github.com/mr-karan/doggo/pkg/resolvers"
|
2020-12-13 04:17:07 +01:00
|
|
|
"github.com/olekukonko/tablewriter"
|
2020-12-12 15:10:28 +01:00
|
|
|
)
|
|
|
|
|
2020-12-13 05:04:53 +01:00
|
|
|
// Output has a list of fields which are produced for the output
|
|
|
|
type Output struct {
|
2020-12-13 08:15:45 +01:00
|
|
|
Name string `json:"name"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
Class string `json:"class"`
|
|
|
|
TTL string `json:"ttl"`
|
|
|
|
Address string `json:"address"`
|
|
|
|
TimeTaken string `json:"rtt"`
|
|
|
|
Nameserver string `json:"nameserver"`
|
2020-12-13 05:04:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type Query struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
Class string `json:"class"`
|
|
|
|
}
|
|
|
|
type Response struct {
|
|
|
|
Output []Output `json:"answers"`
|
|
|
|
Queries []Query `json:"queries"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type JSONResponse struct {
|
|
|
|
Response `json:"responses"`
|
|
|
|
}
|
|
|
|
|
2020-12-15 18:39:10 +01:00
|
|
|
func (hub *Hub) outputJSON(out []Output) {
|
2020-12-13 05:04:53 +01:00
|
|
|
// get the questions
|
2020-12-15 18:39:10 +01:00
|
|
|
queries := make([]Query, 0)
|
2020-12-13 09:26:38 +01:00
|
|
|
for _, ques := range hub.Questions {
|
|
|
|
q := Query{
|
|
|
|
Name: ques.Name,
|
2020-12-14 07:19:54 +01:00
|
|
|
Type: dns.TypeToString[ques.Qtype],
|
2020-12-13 09:26:38 +01:00
|
|
|
Class: dns.ClassToString[ques.Qclass],
|
2020-12-13 05:04:53 +01:00
|
|
|
}
|
2020-12-13 09:26:38 +01:00
|
|
|
queries = append(queries, q)
|
2020-12-13 05:04:53 +01:00
|
|
|
}
|
2020-12-13 09:26:38 +01:00
|
|
|
|
2020-12-13 05:04:53 +01:00
|
|
|
resp := JSONResponse{
|
|
|
|
Response{
|
|
|
|
Output: out,
|
|
|
|
Queries: queries,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
res, err := json.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
hub.Logger.WithError(err).Error("unable to output data in JSON")
|
|
|
|
hub.Logger.Exit(-1)
|
|
|
|
}
|
|
|
|
fmt.Printf("%s", res)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hub *Hub) outputTerminal(out []Output) {
|
2020-12-13 16:33:44 +01:00
|
|
|
green := color.New(color.FgGreen, color.Bold).SprintFunc()
|
|
|
|
blue := color.New(color.FgBlue, color.Bold).SprintFunc()
|
|
|
|
yellow := color.New(color.FgYellow, color.Bold).SprintFunc()
|
|
|
|
cyan := color.New(color.FgCyan, color.Bold).SprintFunc()
|
|
|
|
red := color.New(color.FgRed, color.Bold).SprintFunc()
|
|
|
|
|
|
|
|
if !hub.QueryFlags.Color {
|
|
|
|
color.NoColor = true // disables colorized output
|
|
|
|
}
|
2020-12-13 04:17:07 +01:00
|
|
|
|
|
|
|
table := tablewriter.NewWriter(os.Stdout)
|
2020-12-13 09:42:24 +01:00
|
|
|
header := []string{"Name", "Type", "Class", "TTL", "Address", "Nameserver"}
|
2020-12-13 04:17:07 +01:00
|
|
|
if hub.QueryFlags.DisplayTimeTaken {
|
|
|
|
header = append(header, "Time Taken")
|
|
|
|
}
|
2020-12-13 09:42:24 +01:00
|
|
|
table.SetHeader(header)
|
2020-12-13 09:26:38 +01:00
|
|
|
table.SetAutoWrapText(false)
|
|
|
|
table.SetAutoFormatHeaders(true)
|
2020-12-13 09:42:24 +01:00
|
|
|
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
|
|
|
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
|
|
|
table.SetCenterSeparator("")
|
|
|
|
table.SetColumnSeparator("")
|
|
|
|
table.SetRowSeparator("")
|
|
|
|
table.SetHeaderLine(false)
|
|
|
|
table.SetBorder(false)
|
|
|
|
table.SetTablePadding("\t") // pad with tabs
|
|
|
|
table.SetNoWhiteSpace(true)
|
2020-12-13 04:17:07 +01:00
|
|
|
|
2020-12-13 05:04:53 +01:00
|
|
|
for _, o := range out {
|
2020-12-13 16:33:44 +01:00
|
|
|
var typOut string
|
|
|
|
switch typ := o.Type; typ {
|
|
|
|
case "A":
|
|
|
|
typOut = blue(o.Type)
|
|
|
|
case "AAAA":
|
|
|
|
typOut = blue(o.Type)
|
|
|
|
case "MX":
|
2020-12-14 07:19:54 +01:00
|
|
|
typOut = red(o.Type)
|
2020-12-13 16:33:44 +01:00
|
|
|
case "NS":
|
|
|
|
typOut = cyan(o.Type)
|
|
|
|
case "CNAME":
|
|
|
|
typOut = yellow(o.Type)
|
|
|
|
case "TXT":
|
|
|
|
typOut = yellow(o.Type)
|
|
|
|
default:
|
2020-12-14 07:19:54 +01:00
|
|
|
typOut = blue(o.Type)
|
2020-12-13 16:33:44 +01:00
|
|
|
}
|
|
|
|
output := []string{green(o.Name), typOut, o.Class, o.TTL, o.Address, o.Nameserver}
|
2020-12-13 05:04:53 +01:00
|
|
|
// Print how long it took
|
|
|
|
if hub.QueryFlags.DisplayTimeTaken {
|
|
|
|
output = append(output, o.TimeTaken)
|
|
|
|
}
|
|
|
|
table.Append(output)
|
|
|
|
}
|
|
|
|
table.Render()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output takes a list of `dns.Answers` and based
|
|
|
|
// on the output format specified displays the information.
|
2020-12-15 18:39:10 +01:00
|
|
|
func (hub *Hub) Output(responses [][]resolvers.Response) {
|
2020-12-13 05:04:53 +01:00
|
|
|
out := collectOutput(responses)
|
|
|
|
if hub.QueryFlags.ShowJSON {
|
2020-12-15 18:39:10 +01:00
|
|
|
hub.outputJSON(out)
|
2020-12-13 05:04:53 +01:00
|
|
|
} else {
|
|
|
|
hub.outputTerminal(out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-15 18:39:10 +01:00
|
|
|
func collectOutput(responses [][]resolvers.Response) []Output {
|
2020-12-13 09:26:38 +01:00
|
|
|
var out []Output
|
2020-12-15 18:39:10 +01:00
|
|
|
// for each resolver
|
|
|
|
for _, rslvr := range responses {
|
|
|
|
// get the response
|
|
|
|
for _, r := range rslvr {
|
|
|
|
var addr string
|
2020-12-16 14:08:34 +01:00
|
|
|
if r.Message.Rcode != dns.RcodeSuccess {
|
|
|
|
for _, ns := range r.Message.Ns {
|
|
|
|
blah, ok := ns.(*dns.SOA)
|
|
|
|
fmt.Println(blah, ok)
|
|
|
|
blah.String()
|
|
|
|
h := ns.Header()
|
|
|
|
name := h.Name
|
|
|
|
qclass := dns.Class(h.Class).String()
|
|
|
|
ttl := strconv.FormatInt(int64(h.Ttl), 10) + "s"
|
|
|
|
qtype := dns.Type(h.Rrtype).String()
|
|
|
|
rtt := fmt.Sprintf("%dms", r.RTT.Milliseconds())
|
|
|
|
o := Output{
|
|
|
|
Name: name,
|
|
|
|
Type: qtype,
|
|
|
|
TTL: ttl,
|
|
|
|
Class: qclass,
|
|
|
|
Address: addr,
|
|
|
|
TimeTaken: rtt,
|
|
|
|
Nameserver: r.Nameserver,
|
|
|
|
}
|
|
|
|
out = append(out, o)
|
|
|
|
}
|
|
|
|
}
|
2020-12-15 18:39:10 +01:00
|
|
|
for _, a := range r.Message.Answer {
|
|
|
|
switch t := a.(type) {
|
|
|
|
case *dns.A:
|
|
|
|
addr = t.A.String()
|
|
|
|
case *dns.AAAA:
|
|
|
|
addr = t.AAAA.String()
|
|
|
|
case *dns.CNAME:
|
|
|
|
addr = t.Target
|
|
|
|
case *dns.CAA:
|
|
|
|
addr = t.Tag + " " + t.Value
|
|
|
|
case *dns.HINFO:
|
|
|
|
addr = t.Cpu + " " + t.Os
|
|
|
|
// case *dns.LOC:
|
|
|
|
// addr = t.String()
|
|
|
|
case *dns.PTR:
|
|
|
|
addr = t.Ptr
|
|
|
|
case *dns.SRV:
|
|
|
|
addr = strconv.Itoa(int(t.Priority)) + " " +
|
|
|
|
strconv.Itoa(int(t.Weight)) + " " +
|
|
|
|
t.Target + ":" + strconv.Itoa(int(t.Port))
|
|
|
|
case *dns.TXT:
|
|
|
|
addr = t.String()
|
|
|
|
case *dns.NS:
|
|
|
|
addr = t.Ns
|
|
|
|
case *dns.MX:
|
|
|
|
addr = strconv.Itoa(int(t.Preference)) + " " + t.Mx
|
|
|
|
case *dns.SOA:
|
|
|
|
addr = t.String()
|
|
|
|
case *dns.NAPTR:
|
|
|
|
addr = t.String()
|
|
|
|
}
|
2020-12-13 09:26:38 +01:00
|
|
|
|
2020-12-15 18:39:10 +01:00
|
|
|
h := a.Header()
|
|
|
|
name := h.Name
|
|
|
|
qclass := dns.Class(h.Class).String()
|
|
|
|
ttl := strconv.FormatInt(int64(h.Ttl), 10) + "s"
|
|
|
|
qtype := dns.Type(h.Rrtype).String()
|
|
|
|
rtt := fmt.Sprintf("%dms", r.RTT.Milliseconds())
|
|
|
|
o := Output{
|
|
|
|
Name: name,
|
|
|
|
Type: qtype,
|
|
|
|
TTL: ttl,
|
|
|
|
Class: qclass,
|
|
|
|
Address: addr,
|
|
|
|
TimeTaken: rtt,
|
|
|
|
Nameserver: r.Nameserver,
|
|
|
|
}
|
|
|
|
out = append(out, o)
|
2020-12-13 04:17:07 +01:00
|
|
|
}
|
2020-12-12 15:10:28 +01:00
|
|
|
}
|
|
|
|
}
|
2020-12-15 18:39:10 +01:00
|
|
|
|
2020-12-13 05:04:53 +01:00
|
|
|
return out
|
2020-12-12 15:10:28 +01:00
|
|
|
}
|