diff --git a/.gitignore b/.gitignore index 148dce4..cd8a456 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ control-panel-dns *.swp /plugins/* -examples/cloudflare/cloudflare +examples/control-panel-cloudflare/control-panel-cloudflare 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 +} diff --git a/examples/cloudflare/config.go b/examples/cloudflare/config.go deleted file mode 100644 index a65ad25..0000000 --- a/examples/cloudflare/config.go +++ /dev/null @@ -1,71 +0,0 @@ -// This is a simple example -package main - -import ( - "os" - "log" - "bufio" - "strings" - - "go.wit.com/control-panel-dns/cloudflare" -) - -func saveConfig() { - log.Println("TODO") -} - -func readConfig() { - homeDir, err := os.UserHomeDir() - if err != nil { - log.Println("searchPaths() error. exiting here?") - } - filename := homeDir + "/" + configfile - log.Println("filename =", filename) - - readFileLineByLine(filename) - // os.Exit(0) -} - -// readFileLineByLine opens a file and reads through each line. -func readFileLineByLine(filename string) error { - // Open the file. - file, err := os.Open(filename) - if err != nil { - return err - } - defer file.Close() - - log.Println("readFileLineByLine() =", filename) - - // Create a new Scanner for the file. - scanner := bufio.NewScanner(file) - - // Read through each line using scanner. - for scanner.Scan() { - var newc *cloudflare.ConfigT - newc = new(cloudflare.ConfigT) - - line := scanner.Text() - parts := strings.Fields(line) - - if (len(parts) < 4) { - log.Println("readFileLineByLine() SKIP =", parts) - continue - } - - newc.Domain = parts[0] - newc.ZoneID = parts[1] - newc.Auth = parts[2] - newc.Email = parts[3] - - cloudflare.Config[parts[0]] = newc - log.Println("readFileLineByLine() =", newc.Domain, newc.ZoneID, newc.Auth, newc.Email) - } - - // Check for errors during Scan. - if err := scanner.Err(); err != nil { - return err - } - - return nil -} diff --git a/hostname.go b/hostname.go index a0da280..7b7132a 100644 --- a/hostname.go +++ b/hostname.go @@ -6,17 +6,22 @@ package main import ( + "log" +// "net" + "strings" + "go.wit.com/shell" "go.wit.com/control-panel-dns/cloudflare" - "go.wit.com/control-panel-dns/dnssecsocket" + + "github.com/miekg/dns" ) // will try to get this hosts FQDN import "github.com/Showmax/go-fqdn" // this is the king of dns libraries -import "github.com/miekg/dns" +// import "github.com/miekg/dns" func getHostname() { @@ -98,6 +103,7 @@ func goodHostname(h string) bool { return false } +/* func digAAAA(s string) []string { var aaaa []string // lookup the IP address from DNS @@ -114,5 +120,52 @@ func digAAAA(s string) []string { me.ipv6s[ipaddr] = rr } debug(true, args.VerboseDNS, "aaaa =", aaaa) + log.Println("digAAAA() returned =", aaaa) + log.Println("digAAAA() me.ipv6s =", me.ipv6s) + os.Exit(0) return aaaa } +*/ + +func digAAAA(hostname string) []string { + var blah, ipv6Addresses []string + // domain := hostname + recordType := dns.TypeAAAA // dns.TypeTXT + + // Cloudflare's DNS server + blah, _ = dnsUdpLookup("1.1.1.1:53", hostname, recordType) + log.Println("digAAAA() has BLAH =", blah) + + if (len(blah) == 0) { + log.Println("digAAAA() RUNNING dnsLookupDoH(domain)") + ipv6Addresses, _ = dnsLookupDoH(hostname) + log.Println("digAAAA() has ipv6Addresses =", strings.Join(ipv6Addresses, " ")) + log.Printf("digAAAA() IPv6 Addresses for %s:\n", hostname) + for _, addr := range ipv6Addresses { + log.Println(addr) + } + return ipv6Addresses + } + + // TODO: check digDoH vs blah, if so, then port 53 TCP and/or UDP is broken or blocked + log.Println("digAAAA() has BLAH =", blah) + + return blah +} + +/* +func dnsHttpsLookup(domain string, recordType uint16) ([]string, error) { + domain := "google.com" + dnsLookupDoH(domain string) ([]string, error) { + ipv6Addresses, err := dnsLookupDoH(domain) + if err != nil { + fmt.Println("Error:", err) + return + } + + fmt.Printf("IPv6 Addresses for %s:\n", domain) + for _, addr := range ipv6Addresses { + fmt.Println(addr) + } +} +*/ diff --git a/net.go b/net.go index 487486e..10b909a 100644 --- a/net.go +++ b/net.go @@ -97,7 +97,11 @@ func checkInterface(i net.Interface) { } } -func realAAAA() []string { +/* + These are the real IP address you have been + given from DHCP +*/ +func dhcpAAAA() []string { var aaaa []string for s, t := range me.ipmap {