Skip to content

Commit a25139b

Browse files
add printer
Signed-off-by: Bruno Schaatsbergen <[email protected]>
1 parent 22a18c0 commit a25139b

File tree

5 files changed

+127
-6
lines changed

5 files changed

+127
-6
lines changed

cmd/printer.go

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strconv"
7+
"strings"
8+
"time"
9+
10+
"github.com/miekg/dns"
11+
"github.com/fatih/color"
12+
"github.com/juju/ansiterm"
13+
)
14+
15+
// displayRecords prints the DNS records to the terminal.
16+
func displayRecords(domainName string, messages []*dns.Msg) {
17+
w := ansiterm.NewTabWriter(os.Stdout, 8, 8, 4, ' ', 0)
18+
w.SetColorCapable(true)
19+
20+
domainColored := color.HiBlueString(domainName)
21+
22+
for _, msg := range messages {
23+
for _, answer := range msg.Answer {
24+
queryType := dns.TypeToString[answer.Header().Rrtype]
25+
formattedTTL := color.HiMagentaString(formatTTL(answer.Header().Ttl))
26+
27+
switch rec := answer.(type) {
28+
case *dns.A:
29+
printARecord(w, queryType, domainColored, formattedTTL, rec)
30+
31+
case *dns.AAAA:
32+
printAAAARecord(w, queryType, domainColored, formattedTTL, rec)
33+
34+
case *dns.CNAME:
35+
printCNAMERecord(w, queryType, domainColored, formattedTTL, rec)
36+
37+
case *dns.MX:
38+
printMXRecord(w, queryType, domainColored, formattedTTL, rec)
39+
40+
case *dns.TXT:
41+
printTXTRecord(w, queryType, domainColored, formattedTTL, rec)
42+
43+
case *dns.NS:
44+
printNSRecord(w, queryType, domainColored, formattedTTL, rec)
45+
46+
case *dns.SOA:
47+
printSOARecord(w, queryType, domainColored, formattedTTL, rec)
48+
49+
case *dns.PTR:
50+
printPTRRecord(w, queryType, domainColored, formattedTTL, rec)
51+
52+
default:
53+
fmt.Fprintf(os.Stderr, "Unknown record type: %s\n", queryType)
54+
}
55+
}
56+
}
57+
58+
w.Flush()
59+
}
60+
61+
func printARecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.A) {
62+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(rec.A.String()))
63+
}
64+
65+
func printAAAARecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.AAAA) {
66+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(rec.AAAA.String()))
67+
}
68+
69+
func printCNAMERecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.CNAME) {
70+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(rec.Target))
71+
}
72+
73+
func printMXRecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.MX) {
74+
preference := color.HiRedString(strconv.FormatUint(uint64(rec.Preference), 10))
75+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s %s\n", color.HiYellowString(queryType), domain, ttl, preference, color.HiWhiteString(rec.Mx))
76+
}
77+
78+
func printTXTRecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.TXT) {
79+
txtJoined := strings.Join(rec.Txt, " ")
80+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(txtJoined))
81+
}
82+
83+
func printNSRecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.NS) {
84+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(rec.Ns))
85+
}
86+
87+
func printSOARecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.SOA) {
88+
primaryNameServer := color.HiRedString(rec.Ns)
89+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s %s\n", color.HiYellowString(queryType), domain, ttl, primaryNameServer, rec.Mbox)
90+
}
91+
92+
func printPTRRecord(w *ansiterm.TabWriter, queryType, domain, ttl string, rec *dns.PTR) {
93+
fmt.Fprintf(w, "%s\t%s.\t%s\t%s\n", color.HiYellowString(queryType), domain, ttl, color.HiWhiteString(rec.Ptr))
94+
}
95+
96+
// formatTTL converts TTL to a more readable format (hours, minutes, seconds).
97+
func formatTTL(ttl uint32) string {
98+
duration := time.Duration(ttl) * time.Second
99+
hours := int(duration.Hours())
100+
minutes := int(duration.Minutes()) % 60
101+
seconds := int(duration.Seconds()) % 60
102+
103+
if hours > 0 {
104+
return fmt.Sprintf("%02dh%02dm%02ds", hours, minutes, seconds)
105+
} else if minutes > 0 {
106+
return fmt.Sprintf("%02dm%02ds", minutes, seconds)
107+
}
108+
return fmt.Sprintf("%02ds", seconds)
109+
}
110+

cmd/root.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,13 @@ var (
3939
for _, e := range merr.Errors {
4040
fmt.Println(e)
4141
}
42-
} else { // This should never happen since all errors in zns are multierrors, but we handle it anyway.
42+
} else {
4343
fmt.Println(err)
4444
}
4545
os.Exit(1)
4646
}
4747

48-
for _, msg := range messages {
49-
fmt.Println(msg)
50-
}
48+
displayRecords(args[0], messages)
5149
},
5250
}
5351
)

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@ module github.com/znscli/zns
33
go 1.23.1
44

55
require (
6+
github.com/fatih/color v1.13.0
67
github.com/hashicorp/go-hclog v1.6.3
78
github.com/hashicorp/go-multierror v1.1.1
9+
github.com/juju/ansiterm v1.0.0
810
github.com/miekg/dns v1.1.62
911
github.com/spf13/cobra v1.8.1
1012
)
1113

1214
require (
13-
github.com/fatih/color v1.13.0 // indirect
1415
github.com/hashicorp/errwrap v1.0.0 // indirect
1516
github.com/inconshreveable/mousetrap v1.1.0 // indirect
17+
github.com/lunixbochs/vtclean v1.0.0 // indirect
1618
github.com/mattn/go-colorable v0.1.12 // indirect
1719
github.com/mattn/go-isatty v0.0.14 // indirect
1820
github.com/spf13/pflag v1.0.5 // indirect

go.sum

+12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
1212
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
1313
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1414
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
15+
github.com/juju/ansiterm v1.0.0 h1:gmMvnZRq7JZJx6jkfSq9/+2LMrVEwGwt7UR6G+lmDEg=
16+
github.com/juju/ansiterm v1.0.0/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384=
17+
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
18+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
19+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
20+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
21+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
22+
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
23+
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
1524
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
25+
github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
1626
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
1727
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
1828
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -46,5 +56,7 @@ golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
4656
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
4757
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
4858
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
59+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
60+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
4961
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
5062
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/query/query.go

-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ func NewQuerier(server string, logger hclog.Logger) Querier {
4343
Color: hclog.AutoColor,
4444
DisableTime: true,
4545
})
46-
logger.Warn("no logger provided, using default 'zns' logger")
4746
}
4847
return &Query{Server: server, Logger: logger}
4948
}

0 commit comments

Comments
 (0)