diff options
| author | Jeff Carr <[email protected]> | 2023-12-28 09:43:45 -0600 |
|---|---|---|
| committer | Jeff Carr <[email protected]> | 2023-12-28 09:43:45 -0600 |
| commit | 88fb976119006a8b3e3ce806c22f4f9418850f3c (patch) | |
| tree | 620f2b162fe2a296efa693810d15b97dc40ef6af /dnsLookupStatus.go | |
| parent | e697a29bab5806834106680892cd6efbe46df506 (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.go | 370 |
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 +} |
