diff --git a/digstatus/args.go b/digstatus/args.go deleted file mode 100644 index 91eefb1..0000000 --- a/digstatus/args.go +++ /dev/null @@ -1,21 +0,0 @@ -package digstatus - -/* - this parses the command line arguements - - this enables command line options from other packages like 'gui' and 'log' -*/ - -import ( - "go.wit.com/log" -) - -var DNS log.LogFlag - -func init() { - DNS.B = false - DNS.Name = "DNS" - DNS.Subsystem = "cpdns" - DNS.Desc = "dnsStatus.update()" - DNS.Register() -} diff --git a/digstatus/digStatus.go b/digstatus/digStatus.go deleted file mode 100644 index c7b5fef..0000000 --- a/digstatus/digStatus.go +++ /dev/null @@ -1,500 +0,0 @@ -/* - '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 digstatus - -import ( - "os" - "fmt" - "time" - "strconv" - "reflect" - "errors" - - "go.wit.com/log" - "go.wit.com/gui/gui" - "go.wit.com/gui/gadgets" - "go.wit.com/shell" - - "github.com/miekg/dns" -) - -var ds *DigStatus - -type DigStatus struct { - ready bool - hidden bool - statusIPv4 string - statusIPv6 string - - parent *gui.Node - window *gadgets.BasicWindow - group *gui.Node - grid *gui.Node - - summary *gui.Node - status *gadgets.OneLiner - statusAAAA *gadgets.OneLiner - speed *gadgets.OneLiner - speedActual *gadgets.OneLiner - - details *gui.Node - dsLocalhost *dnsStatus - dsLocalNetwork *dnsStatus - dsCloudflare *dnsStatus - dsGoogle *dnsStatus - DnsDigUDP *gui.Node - DnsDigTCP *gui.Node - - httpGoWitCom *gadgets.OneLiner - statusHTTP *gadgets.OneLiner -} - -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 { - ds = new(DigStatus) - - ds.ready = false - ds.hidden = true - - ds.window = gadgets.NewBasicWindow(p, "DNS Resolver Status (DigStatus.go)") - ds.window.Draw() - // ds.window.Hide() - - // summary of the current state of things - ds.summary = ds.window.Box().NewGroup("Summary") - g := ds.summary.NewGrid("LookupStatus", 2, 2) - g.Pad() - - ds.status = gadgets.NewOneLiner(g, "status").Set("unknown") - ds.statusAAAA = gadgets.NewOneLiner(g, "IPv6 status").Set("unknown") - ds.statusHTTP = gadgets.NewOneLiner(g, "IPv6 via HTTP").Set("unknown") - ds.speed = gadgets.NewOneLiner(g, "speed").Set("unknown") - ds.speedActual = gadgets.NewOneLiner(g, "actual").Set("unknown") - - // make the area to store the raw details - ds.details = ds.window.Box().NewGroup("Details") - ds.dsLocalhost = NewDnsStatus(ds.details, "(localhost)", "127.0.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() - ds.makeHttpStatusGrid() - - ds.hidden = false - ds.ready = true - return ds -} - -func (ds *DigStatus) Update() { - log.Info("DigStatus() Update() START") - if ds == nil { - log.Error(errors.New("DigStatus() Update() ds == nil")) - return - } - duration := timeFunction(func () { - ds.updateDnsStatus() - }) - s := fmt.Sprint(duration) - // ds.speedActual.Set(s) - set(ds.speedActual, s) - - if (duration > 500 * time.Millisecond ) { - set(ds.speed, "SLOW") - } else if (duration > 100 * time.Millisecond ) { - set(ds.speed, "OK") - } else { - set(ds.speed, "FAST") - } - log.Info("DigStatus() Update() END") -} - -// Returns true if the status is valid -func (ds *DigStatus) Ready() bool { - if ds == nil {return false} - return ds.ready -} - -// Returns true if IPv4 is working -func (ds *DigStatus) IPv4() bool { - if ! ds.Ready() {return false} - 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.Ready() {return false} - if (ds.statusIPv6 == "GOOD") { - return true - } - return false -} - -func (ds *DigStatus) setIPv4status(s string) { - ds.statusIPv4 = s - if ! ds.Ready() {return} - set(ds.status, s) -} - -func (ds *DigStatus) setIPv6status(s string) { - ds.statusIPv6 = s - if ! ds.Ready() {return} - set(ds.statusAAAA, s) -} - -/* -func (ds *DigStatus) SetIPv6(s string) { - if ! ds.Ready() {return} - // me.DnsAAAA.Set(s) - // me.DigStatus.set(ds.httpGoWitCom, addr) -} -*/ - -func set(a any, s string) { - if a == nil { - return - } - var n *gui.Node - if reflect.TypeOf(a) == reflect.TypeOf(n) { - n = a.(*gui.Node) - n.SetText(s) - return - } - var ol *gadgets.OneLiner - if reflect.TypeOf(a) == reflect.TypeOf(ol) { - ol = a.(*gadgets.OneLiner) - ol.Set(s) - return - } - log.Warn("unknown type TypeOf(a) =", reflect.TypeOf(a), "a =", a) - os.Exit(0) -} - -func (ds *DigStatus) updateDnsStatus() { - var cmd, out string - var ipv4, ipv6 bool - - log.Info("updateDnsStatus() START") - if (ds == nil) { - log.Error(errors.New("updateDnsStatus() not initialized yet. ds == nil")) - return - } - - if (! ds.ready) { - log.Error(errors.New("updateDnsStatus() not ready yet")) - return - } - - ipv4, ipv6 = ds.dsLocalhost.update() - ipv4, ipv6 = ds.dsLocalNetwork.update() - ipv4, ipv6 = ds.dsCloudflare.update() - ipv4, ipv6 = ds.dsGoogle.update() - - // This looks up the known host go.wit.com to verify DNS over HTTP is working - // if this doesn't work, probably your internet connection isn't working either - if ds.checkLookupDoH("go.wit.com") { - log.Log(DNS, "updateDnsStatus() HTTP DNS lookups working") - set(ds.statusHTTP, "WORKING") - } else { - log.Log(DNS, "updateDnsStatus() HTTP DNS lookups not working") - log.Log(DNS, "updateDnsStatus() It's really unlikely you are on the internet") - set(ds.statusHTTP, "BROKEN") - } - - if (ipv4) { - log.Log(DNS, "updateDnsStatus() IPv4 A lookups working") - ds.setIPv4status("OK") - } else { - log.Log(DNS, "updateDnsStatus() IPv4 A lookups not working. No internet?") - ds.setIPv4status("No Internet?") - } - if (ipv6) { - log.Log(DNS, "updateDnsStatus() IPv6 AAAA lookups working") - ds.setIPv4status("GOOD") - ds.setIPv6status("GOOD") - } else { - log.Log(DNS, "updateDnsStatus() IPv6 AAAA lookups are not working") - ds.setIPv6status("Need VPN") - } - - cmd = "dig +noall +answer www.wit.com A" - out = shell.Run(cmd) - log.Log(DNS, "makeDnsStatusGrid() dig", out) - set(ds.DnsDigUDP, out) - - cmd = "dig +noall +answer www.wit.com AAAA" - out = shell.Run(cmd) - log.Log(DNS, "makeDnsStatusGrid() dig", out) - set(ds.DnsDigTCP, out) -} - -// 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 (dns *dnsStatus) update() (bool, bool) { - if ! ds.Ready() {return false, false} - var results []string - var a bool = false - var aaaa bool = false - - if dns == nil { - log.Warn("ds == nil") - } else { - log.Warn("dnsStatus.update() For server", dns.server, "on", dns.hostname) - } - - log.Log(DNS, "dnsStatus.update() For server", dns.server, "on", dns.hostname) - results, _ = DnsUdpLookup(dns.server, dns.hostname, dns.TypeA) - log.Log(DNS, "dnsStatus.update() UDP type A =", results) - - if (len(results) == 0) { - set(dns.udpA, "BROKEN") - dns.aFailc += 1 - } else { - set(dns.udpA, "WORKING") - dns.aSuccessc += 1 - a = true - } - - results, _ = dnsTcpLookup(dns.server, dns.hostname, dns.TypeA) - log.Log(DNS, "dnsStatus.update() TCP type A =", results) - - if (len(results) == 0) { - set(ds.tcpA, "BROKEN") - ds.aFailc += 1 - } else { - set(ds.tcpA, "WORKING") - ds.aSuccessc += 1 - a = true - } - - set(ds.aFail, strconv.Itoa(ds.aFailc)) - set(ds.aSuccess,strconv.Itoa(ds.aSuccessc)) - - results, _ = DnsUdpLookup(ds.server, ds.hostname, dns.TypeAAAA) - log.Log(DNS, "dnsStatus.update() UDP type AAAA =", results) - - if (len(results) == 0) { - set(ds.udpAAAA, "BROKEN") - ds.aaaaFailc += 1 - set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc)) - } else { - set(ds.udpAAAA, "WORKING") - ds.aaaaSuccessc += 1 - aaaa = true - } - - results, _ = dnsTcpLookup(ds.server, ds.hostname, dns.TypeAAAA) - log.Log(DNS, "dnsStatus.update() UDP type AAAA =", results) - - if (len(results) == 0) { - set(ds.tcpAAAA, "BROKEN") - ds.aaaaFailc += 1 - set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc)) - } else { - set(ds.tcpAAAA, "WORKING") - ds.aaaaSuccessc += 1 - aaaa = true - } - - set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc)) - set(ds.aaaaSuccess,strconv.Itoa(ds.aaaaSuccessc)) - - return a, aaaa -} - -func (ds *DigStatus) makeHttpStatusGrid() { - group := ds.details.NewGroup("dns.google.com via HTTPS") - grid := group.NewGrid("LookupStatus", 2, 2) - - ds.httpGoWitCom = gadgets.NewOneLiner(grid, "go.wit.com") - set(ds.httpGoWitCom, "unknown") - - group.Pad() - grid.Pad() -} - -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.Log(DNS, "makeDnsStatusGrid() dig", out) - set(ds.DnsDigUDP, out) - - cmd = "dig +noall +answer go.wit.com AAAA" - grid.NewLabel(cmd) - ds.DnsDigTCP = grid.NewLabel("?") - out = shell.Run(cmd) - log.Log(DNS, "makeDnsStatusGrid() dig", out) - set(ds.DnsDigTCP, 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 -} - -func (ds *DigStatus) checkLookupDoH(hostname string) bool { - var status bool = false - - aaaa := lookupDoH(hostname, "AAAA") - - log.Log(DNS, "IPv6 Addresses for ", hostname, "=", aaaa) - var s []string - for _, addr := range aaaa { - log.Log(DNS, addr) - s = append(s, addr) - status = true - } - return status -} - -func (ds *DigStatus) Show() { - log.Info("DigStatus.Show() window") - if ds.hidden { - ds.window.Show() - } - ds.hidden = false -} - -func (ds *DigStatus) Hide() { - log.Info("DigStatus.Hide() window") - if ! ds.hidden { - ds.window.Hide() - } - ds.hidden = true -} - -func (ds *DigStatus) Toggle() { - if ds.hidden { - ds.window.Show() - } else { - ds.window.Hide() - } -} - -// timeFunction takes a function as an argument and returns the execution time. -func timeFunction(f func()) time.Duration { - startTime := time.Now() // Record the start time - f() // Execute the function - return time.Since(startTime) // Calculate the elapsed time -} diff --git a/digstatus/dns-https.go b/digstatus/dns-https.go deleted file mode 100644 index 2ad13df..0000000 --- a/digstatus/dns-https.go +++ /dev/null @@ -1,56 +0,0 @@ -package digstatus - -import ( - "fmt" - "go.wit.com/log" - "io/ioutil" - "encoding/json" - "net/http" -) - -// dnsLookupDoH performs a DNS lookup for AAAA records over HTTPS. -func lookupDoH(hostname string, rrType string) []string { - var values []string - - // Construct the URL for a DNS query with Google's DNS-over-HTTPS API - url := fmt.Sprintf("https://dns.google.com/resolve?name=%s&type=%s", hostname, rrType) - - log.Log(DNS, "lookupDoH()", url) - if hostname == "" { - log.Warn("lookupDoH() was sent a empty hostname") - return nil - } - - // Perform the HTTP GET request - resp, err := http.Get(url) - if err != nil { - log.Error(err, "error performing DNS-over-HTTPS request") - return nil - } - defer resp.Body.Close() - - // Read and unmarshal the response body - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Error(fmt.Errorf("error reading response: %w", err)) - return nil - } - - var data struct { - Answer []struct { - Data string `json:"data"` - } `json:"Answer"` - } - - if err := json.Unmarshal(body, &data); err != nil { - log.Error(fmt.Errorf("error unmarshaling response: %w", err)) - return nil - } - - // Extract the IPv6 addresses - for _, answer := range data.Answer { - values = append(values, answer.Data) - } - - return values -}