summaryrefslogtreecommitdiff
path: root/dnsLookupStatus.go
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2023-12-28 09:43:45 -0600
committerJeff Carr <[email protected]>2023-12-28 09:43:45 -0600
commit88fb976119006a8b3e3ce806c22f4f9418850f3c (patch)
tree620f2b162fe2a296efa693810d15b97dc40ef6af /dnsLookupStatus.go
parente697a29bab5806834106680892cd6efbe46df506 (diff)
Detect that a VPN is needed
IPv6() returns true if it's working display duration a 'DNS Lookup Status' window actual dig results display status and failure counters count lookup failures and successes add TCP dns lookup logic to test if dns is working at all add DNS over HTTPS cloudflare new & update kind of working holy shit, go.wit.com finally works with git mod tidy working, but cloudflare api stuff is broken AAAA '(none)' logic detection is better cloudflare control panel display the working real AAAA addresses Signed-off-by: Jeff Carr <[email protected]>
Diffstat (limited to 'dnsLookupStatus.go')
-rw-r--r--dnsLookupStatus.go370
1 files changed, 370 insertions, 0 deletions
diff --git a/dnsLookupStatus.go b/dnsLookupStatus.go
new file mode 100644
index 0000000..e623cae
--- /dev/null
+++ b/dnsLookupStatus.go
@@ -0,0 +1,370 @@
+/*
+ 'dig'
+
+ This is essentially doing what the command 'dig' does
+ It performing DNS queries on TCP and UDP
+ against localhost, cloudflare & google
+
+ IPv4() and IPv6() return true if they are working
+
+ with the 'gui' package, it can also display the results
+*/
+
+package main
+
+import (
+ "log"
+ "fmt"
+ "time"
+ "strconv"
+
+ "github.com/miekg/dns"
+ "go.wit.com/gui"
+ "go.wit.com/control-panel-dns/cloudflare"
+ "go.wit.com/shell"
+)
+
+type digStatus struct {
+ ready bool
+ statusIPv4 string
+ statusIPv6 string
+
+ parent *gui.Node
+ window *gui.Node
+ group *gui.Node
+ grid *gui.Node
+ box *gui.Node
+
+ summary *gui.Node
+ status *cloudflare.OneLiner
+ statusAAAA *cloudflare.OneLiner
+ speed *cloudflare.OneLiner
+ speedActual *cloudflare.OneLiner
+
+ details *gui.Node
+ dsLocalhost *dnsStatus
+ dsLocalNetwork *dnsStatus
+ dsCloudflare *dnsStatus
+ dsGoogle *dnsStatus
+ DnsDigUDP *gui.Node
+ DnsDigTCP *gui.Node
+}
+
+type dnsStatus struct {
+ title string
+ server string // The DNS server. Example: "127.0.0.1:53" or "1.1.1.1:53"
+ hostname string // the hostname to lookup. Example: "www.google.com" or "go.wit.com"
+
+ parent *gui.Node
+ group *gui.Node
+ grid *gui.Node
+
+ // DNS setup options
+ udpA *gui.Node
+ tcpA *gui.Node
+ udpAAAA *gui.Node
+ tcpAAAA *gui.Node
+
+ // show the display
+ aFail *gui.Node
+ aSuccess *gui.Node
+ aaaaFail *gui.Node
+ aaaaSuccess *gui.Node
+
+ // interger counters
+ aFailc int
+ aSuccessc int
+ aaaaFailc int
+ aaaaSuccessc int
+}
+
+func NewDigStatusWindow(p *gui.Node) *digStatus {
+ var ds *digStatus
+ ds = new(digStatus)
+
+ ds.ready = false
+
+ ds.window = p.NewWindow("DNS Lookup Status")
+ ds.box = ds.window.NewBox("hBox", true)
+
+ // summary of the current state of things
+ ds.summary = ds.box.NewGroup("Summary")
+
+ b := ds.summary.NewBox("hBox", true)
+ ds.status = cloudflare.NewOneLiner(b, "status")
+ ds.status.Set("unknown")
+
+ b = ds.summary.NewBox("hBox", true)
+ ds.statusAAAA = cloudflare.NewOneLiner(b, "IPv6 status")
+ ds.statusAAAA.Set("unknown")
+
+ b = ds.summary.NewBox("hBox", true)
+ ds.speed = cloudflare.NewOneLiner(b, "speed")
+ ds.speed.Set("unknown")
+
+ b = ds.summary.NewBox("hBox", true)
+ ds.speedActual = cloudflare.NewOneLiner(b, "actual")
+ ds.speedActual.Set("unknown")
+
+ // make the area to store the raw details
+ ds.details = ds.box.NewGroup("Details")
+ ds.dsLocalhost = NewDnsStatus(ds.details, "(localhost)", "127.0.0.1:53", "go.wit.com")
+ ds.dsLocalNetwork = NewDnsStatus(ds.details, "(Local Network)", "172.22.0.1:53", "go.wit.com")
+ ds.dsCloudflare = NewDnsStatus(ds.details, "(cloudflare)", "1.1.1.1:53", "go.wit.com")
+ ds.dsGoogle = NewDnsStatus(ds.details, "(google)", "8.8.8.8:53", "go.wit.com")
+ ds.makeDnsStatusGrid()
+
+ return ds
+}
+
+func (ds *digStatus) Update() {
+ duration := timeFunction(func () { ds.updateDnsStatus() })
+ s := fmt.Sprint(duration)
+ ds.speedActual.Set(s)
+
+ if (duration > 500 * time.Millisecond ) {
+ ds.speed.Set("SLOW")
+ } else if (duration > 100 * time.Millisecond ) {
+ ds.speed.Set("OK")
+ } else {
+ ds.speed.Set("FAST")
+ }
+}
+
+// Returns true if the status is valid
+func (ds *digStatus) Ready() bool {
+ return ds.ready
+}
+
+// Returns true if IPv4 is working
+func (ds *digStatus) IPv4() bool {
+ if (ds.statusIPv4 == "OK") {
+ return true
+ }
+ if (ds.statusIPv4 == "GOOD") {
+ return true
+ }
+ return false
+}
+
+// Returns true if IPv6 is working
+func (ds *digStatus) IPv6() bool {
+ if (ds.statusIPv6 == "GOOD") {
+ return true
+ }
+ return false
+}
+
+func (ds *digStatus) setIPv4(s string) {
+ ds.status.Set(s)
+ ds.statusIPv4 = s
+}
+
+func (ds *digStatus) setIPv6(s string) {
+ ds.statusAAAA.Set(s)
+ ds.statusIPv6 = s
+}
+
+func (ds *digStatus) updateDnsStatus() {
+ var cmd, out string
+ var ipv4, ipv6 bool
+
+ ipv4, ipv6 = ds.dsLocalhost.Update()
+ ipv4, ipv6 = ds.dsLocalNetwork.Update()
+ ipv4, ipv6 = ds.dsCloudflare.Update()
+ ipv4, ipv6 = ds.dsGoogle.Update()
+
+ if (ipv4) {
+ log.Println("updateDnsStatus() IPv4 A lookups working")
+ ds.setIPv4("OK")
+ } else {
+ log.Println("updateDnsStatus() IPv4 A lookups not working. No internet?")
+ ds.setIPv4("No Internet?")
+ }
+ if (ipv6) {
+ log.Println("updateDnsStatus() IPv6 AAAA lookups working")
+ ds.setIPv4("GOOD")
+ ds.setIPv6("GOOD")
+ } else {
+ log.Println("updateDnsStatus() IPv6 AAAA lookups are not working")
+ ds.setIPv6("Need VPN")
+ }
+
+ cmd = "dig +noall +answer www.wit.com A"
+ out = shell.Run(cmd)
+ log.Println("makeDnsStatusGrid() dig", out)
+ ds.DnsDigUDP.SetText(out)
+
+ cmd = "dig +noall +answer www.wit.com AAAA"
+ out = shell.Run(cmd)
+ log.Println("makeDnsStatusGrid() dig", out)
+ ds.DnsDigTCP.SetText(out)
+
+ ds.ready = true
+}
+
+// Makes a DNS Status Grid
+func NewDnsStatus(p *gui.Node, title string, server string, hostname string) *dnsStatus {
+ var ds *dnsStatus
+ ds = new(dnsStatus)
+ ds.parent = p
+ ds.group = p.NewGroup(server + " " + title + " lookup")
+ ds.grid = ds.group.NewGrid("LookupStatus", 5, 2)
+
+ ds.server = server
+ ds.hostname = hostname
+
+ ds.grid.NewLabel("")
+ ds.grid.NewLabel("UDP")
+ ds.grid.NewLabel("TCP")
+ ds.grid.NewLabel("Success")
+ ds.grid.NewLabel("Fail")
+
+ ds.grid.NewLabel("A")
+ ds.udpA = ds.grid.NewLabel("?")
+ ds.tcpA = ds.grid.NewLabel("?")
+ ds.aSuccess = ds.grid.NewLabel("?")
+ ds.aFail = ds.grid.NewLabel("?")
+
+ ds.grid.NewLabel("AAAA")
+ ds.udpAAAA = ds.grid.NewLabel("?")
+ ds.tcpAAAA = ds.grid.NewLabel("?")
+ ds.aaaaSuccess = ds.grid.NewLabel("?")
+ ds.aaaaFail = ds.grid.NewLabel("?")
+
+ ds.group.Margin()
+ ds.grid.Margin()
+ ds.group.Pad()
+ ds.grid.Pad()
+
+ return ds
+}
+
+// special thanks to the Element Hotel wifi in Philidelphia that allowed me to
+// easily debug this code since the internet connection here blocks port 53 traffic
+func (ds *dnsStatus) Update() (bool, bool) {
+ var results []string
+ var a bool = false
+ var aaaa bool = false
+
+ log.Println("dnsStatus.Update() For server", ds.server, "on", ds.hostname)
+ results, _ = dnsUdpLookup(ds.server, ds.hostname, dns.TypeA)
+ log.Println("dnsStatus.Update() UDP type A =", results)
+
+ if (len(results) == 0) {
+ ds.udpA.SetText("BROKEN")
+ ds.aFailc += 1
+ } else {
+ ds.udpA.SetText("WORKING")
+ ds.aSuccessc += 1
+ a = true
+ }
+
+ results, _ = dnsTcpLookup(ds.server, ds.hostname, dns.TypeA)
+ log.Println("dnsStatus.Update() TCP type A =", results)
+
+ if (len(results) == 0) {
+ ds.tcpA.SetText("BROKEN")
+ ds.aFailc += 1
+ } else {
+ ds.tcpA.SetText("WORKING")
+ ds.aSuccessc += 1
+ a = true
+ }
+
+ ds.aFail.SetText(strconv.Itoa(ds.aFailc))
+ ds.aSuccess.SetText(strconv.Itoa(ds.aSuccessc))
+
+ results, _ = dnsUdpLookup(ds.server, ds.hostname, dns.TypeAAAA)
+ log.Println("dnsStatus.Update() UDP type AAAA =", results)
+
+ if (len(results) == 0) {
+ ds.udpAAAA.SetText("BROKEN")
+ ds.aaaaFailc += 1
+ ds.aaaaFail.SetText(strconv.Itoa(ds.aaaaFailc))
+ } else {
+ ds.udpAAAA.SetText("WORKING")
+ ds.aaaaSuccessc += 1
+ aaaa = true
+ }
+
+ results, _ = dnsTcpLookup(ds.server, ds.hostname, dns.TypeAAAA)
+ log.Println("dnsStatus.Update() UDP type AAAA =", results)
+
+ if (len(results) == 0) {
+ ds.tcpAAAA.SetText("BROKEN")
+ ds.aaaaFailc += 1
+ ds.aaaaFail.SetText(strconv.Itoa(ds.aaaaFailc))
+ } else {
+ ds.tcpAAAA.SetText("WORKING")
+ ds.aaaaSuccessc += 1
+ aaaa = true
+ }
+
+ ds.aaaaFail.SetText(strconv.Itoa(ds.aaaaFailc))
+ ds.aaaaSuccess.SetText(strconv.Itoa(ds.aaaaSuccessc))
+
+ return a, aaaa
+}
+
+func (ds *digStatus) makeDnsStatusGrid() {
+ var cmd, out string
+ group := ds.details.NewGroup("dig results")
+ grid := group.NewGrid("LookupStatus", 2, 2)
+
+ cmd = "dig +noall +answer go.wit.com A"
+ grid.NewLabel(cmd)
+ ds.DnsDigUDP = grid.NewLabel("?")
+ out = shell.Run(cmd)
+ log.Println("makeDnsStatusGrid() dig", out)
+ ds.DnsDigUDP.SetText(out)
+
+ cmd = "dig +noall +answer go.wit.com AAAA"
+ grid.NewLabel(cmd)
+ ds.DnsDigTCP = grid.NewLabel("?")
+ out = shell.Run(cmd)
+ log.Println("makeDnsStatusGrid() dig", out)
+ ds.DnsDigTCP.SetText(out)
+
+ group.Pad()
+ grid.Pad()
+}
+
+// dnsLookup performs a DNS lookup for the specified record type (e.g., "TXT", "AAAA") for a given domain.
+func dnsUdpLookup(server string, domain string, recordType uint16) ([]string, error) {
+ var records []string
+
+ c := new(dns.Client)
+ m := new(dns.Msg)
+ m.SetQuestion(dns.Fqdn(domain), recordType)
+ r, _, err := c.Exchange(m, server) // If server = "1.1.1.1:53" then use Cloudflare's DNS server
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ans := range r.Answer {
+ records = append(records, ans.String())
+ }
+
+ return records, nil
+}
+
+func dnsTcpLookup(server string, domain string, recordType uint16) ([]string, error) {
+ var records []string
+
+ c := new(dns.Client)
+ c.Net = "tcp" // Specify to use TCP for the query
+ c.Timeout = time.Second * 5 // Set a 5-second timeout
+ m := new(dns.Msg)
+ m.SetQuestion(dns.Fqdn(domain), recordType)
+ r, _, err := c.Exchange(m, server) // If server = "1.1.1.1:53" then use Cloudflare's DNS server
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ans := range r.Answer {
+ records = append(records, ans.String())
+ }
+
+ return records, nil
+}