make new resolverStatus()

also fix dns-https

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-01-06 01:41:33 -06:00
parent 2d1e321326
commit ca3a01f478
10 changed files with 700 additions and 711 deletions

16
args.go
View File

@ -18,11 +18,13 @@ var args struct {
VerboseDNS bool `arg:"--verbose-dns" help:"debug your dns settings"` VerboseDNS bool `arg:"--verbose-dns" help:"debug your dns settings"`
} }
var NET log.LogFlag
var NOW log.LogFlag var NOW log.LogFlag
var NET log.LogFlag
var DNS log.LogFlag
var PROC log.LogFlag var PROC log.LogFlag
var SPEW log.LogFlag var SPEW log.LogFlag
var CHANGE log.LogFlag var CHANGE log.LogFlag
var STATUS log.LogFlag
func init() { func init() {
arg.MustParse(&args) arg.MustParse(&args)
@ -40,6 +42,12 @@ func init() {
NET.Desc = "Network logging" NET.Desc = "Network logging"
NET.Register() NET.Register()
DNS.B = false
DNS.Name = "DNS"
DNS.Subsystem = "cpdns"
DNS.Desc = "dnsStatus.update()"
DNS.Register()
PROC.B = false PROC.B = false
PROC.Name = "PROC" PROC.Name = "PROC"
PROC.Subsystem = "cpdns" PROC.Subsystem = "cpdns"
@ -58,6 +66,12 @@ func init() {
CHANGE.Desc = "show droplet state changes" CHANGE.Desc = "show droplet state changes"
CHANGE.Register() CHANGE.Register()
STATUS.B = false
STATUS.Name = "STATUS"
STATUS.Subsystem = "cpdns"
STATUS.Desc = "updateStatus()"
STATUS.Register()
if debugger.ArgDebug() { if debugger.ArgDebug() {
log.Log(true, "INIT() gui debug == true") log.Log(true, "INIT() gui debug == true")
} else { } else {

314
digStatus.go Normal file
View File

@ -0,0 +1,314 @@
/*
'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 (
"os"
"fmt"
"time"
"strings"
"reflect"
"errors"
"go.wit.com/log"
"go.wit.com/gui/gui"
"go.wit.com/gui/gadgets"
"go.wit.com/shell"
)
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 *resolverStatus
dsLocalNetwork *resolverStatus
dsCloudflare *resolverStatus
dsGoogle *resolverStatus
DnsDigUDP *gui.Node
DnsDigTCP *gui.Node
httpGoWitCom *gadgets.OneLiner
statusHTTP *gadgets.OneLiner
}
func NewDigStatusWindow(p *gui.Node) *digStatus {
var ds *digStatus
ds = new(digStatus)
ds.ready = false
ds.hidden = true
ds.window = gadgets.NewBasicWindow(p, "DNS Resolver Status")
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 = NewResolverStatus(ds.details, "(localhost)", "127.0.0.1:53", "go.wit.com")
ds.dsLocalNetwork = NewResolverStatus(ds.details, "(Local Network)", "192.168.86.1:53", "go.wit.com")
ds.dsCloudflare = NewResolverStatus(ds.details, "(cloudflare)", "1.1.1.1:53", "go.wit.com")
ds.dsGoogle = NewResolverStatus(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)
me.digStatus.set(ds.speedActual, s)
if (duration > 500 * time.Millisecond ) {
me.digStatus.set(ds.speed, "SLOW")
} else if (duration > 100 * time.Millisecond ) {
me.digStatus.set(ds.speed, "OK")
} else {
me.digStatus.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}
me.digStatus.set(ds.status, s)
}
func (ds *digStatus) setIPv6status(s string) {
ds.statusIPv6 = s
if ! ds.Ready() {return}
me.digStatus.set(ds.statusAAAA, s)
}
func (ds *digStatus) SetIPv6(s string) {
if ! ds.Ready() {return}
log.Warn("Should SetIPv6() here to", s)
log.Warn("Should SetIPv6() here to", s)
log.Warn("Should SetIPv6() here to", s)
log.Warn("Should SetIPv6() here to", s)
me.DnsAAAA.Set(s)
// me.digStatus.set(ds.httpGoWitCom, addr)
}
func (ds *digStatus) set(a any, s string) {
if ! ds.Ready() {return}
if ds.hidden {
return
}
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()
if me.status.ValidHostname() {
if ds.checkLookupDoH(me.status.GetHostname()) {
log.Log(DNS, "updateDnsStatus() HTTP DNS lookups working")
me.digStatus.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")
me.digStatus.set(ds.statusHTTP, "BROKEN")
}
} else {
me.digStatus.set(ds.statusHTTP, "INVALID HOSTNAME")
}
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)
me.digStatus.set(ds.DnsDigUDP, out)
cmd = "dig +noall +answer www.wit.com AAAA"
out = shell.Run(cmd)
log.Log(DNS, "makeDnsStatusGrid() dig", out)
me.digStatus.set(ds.DnsDigTCP, out)
}
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")
me.digStatus.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)
me.digStatus.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)
me.digStatus.set(ds.DnsDigTCP, out)
group.Pad()
grid.Pad()
}
func (ds *digStatus) checkLookupDoH(hostname string) bool {
var status bool = false
ipv6Addresses := lookupDoH(hostname, "AAAA")
log.Log(DNS, "IPv6 Addresses for ", hostname)
var s []string
for _, addr := range ipv6Addresses {
log.Log(DNS, addr)
s = append(s, addr)
status = true
}
me.digStatus.SetIPv6(strings.Join(s, "\n"))
return status
}
func (ds *digStatus) Show() {
log.Info("digStatus.Show() window")
if me.digStatus.hidden {
me.digStatus.window.Show()
}
me.digStatus.hidden = false
}
func (ds *digStatus) Hide() {
log.Info("digStatus.Hide() window")
if ! me.digStatus.hidden {
me.digStatus.window.Hide()
}
me.digStatus.hidden = true
}

View File

@ -8,70 +8,18 @@ import (
"net/http" "net/http"
) )
/*
func getAAAArecords() {
hostname := "go.wit.com"
ipv6Addresses, err := dnsLookupDoH(hostname)
if err != nil {
log.Error(err, "getAAAArecords")
return
}
fmt.Printf("IPv6 Addresses for %s:\n", hostname)
for _, addr := range ipv6Addresses {
log.Println(addr)
}
}
*/
// dnsLookupDoH performs a DNS lookup for AAAA records over HTTPS.
func dnsAAAAlookupDoH(domain string) ([]string, error) {
var ipv6Addresses []string
// Construct the URL for a DNS query with Google's DNS-over-HTTPS API
url := fmt.Sprintf("https://dns.google/resolve?name=%s&type=AAAA", domain)
log.Println("curl", url)
// Perform the HTTP GET request
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("error performing DNS-over-HTTPS request: %w", err)
}
defer resp.Body.Close()
// Read and unmarshal the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response: %w", err)
}
var data struct {
Answer []struct {
Data string `json:"data"`
} `json:"Answer"`
}
if err := json.Unmarshal(body, &data); err != nil {
return nil, fmt.Errorf("error unmarshaling response: %w", err)
}
// Extract the IPv6 addresses
for _, answer := range data.Answer {
ipv6Addresses = append(ipv6Addresses, answer.Data)
}
return ipv6Addresses, nil
}
// dnsLookupDoH performs a DNS lookup for AAAA records over HTTPS. // dnsLookupDoH performs a DNS lookup for AAAA records over HTTPS.
func lookupDoH(hostname string, rrType string) []string { func lookupDoH(hostname string, rrType string) []string {
var values []string var values []string
// Construct the URL for a DNS query with Google's DNS-over-HTTPS API // Construct the URL for a DNS query with Google's DNS-over-HTTPS API
url := fmt.Sprintf("https://dns.google/resolve?name=%s&type=%s", hostname, rrType) url := fmt.Sprintf("https://dns.google.com/resolve?name=%s&type=%s", hostname, rrType)
log.Println("curl", url) log.Log(DNS, "lookupDoH()", url)
if hostname == "" {
log.Warn("lookupDoH() was sent a empty hostname")
return nil
}
// Perform the HTTP GET request // Perform the HTTP GET request
resp, err := http.Get(url) resp, err := http.Get(url)

View File

@ -1,476 +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 main
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"
)
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 {
var ds *digStatus
ds = new(digStatus)
ds.ready = false
ds.hidden = true
ds.window = gadgets.NewBasicWindow(p, "DNS Resolver Status")
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.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()
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)
me.digStatus.set(ds.speedActual, s)
if (duration > 500 * time.Millisecond ) {
me.digStatus.set(ds.speed, "SLOW")
} else if (duration > 100 * time.Millisecond ) {
me.digStatus.set(ds.speed, "OK")
} else {
me.digStatus.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) setIPv4(s string) {
ds.statusIPv4 = s
if ! ds.Ready() {return}
me.digStatus.set(ds.status, s)
}
func (ds *digStatus) setIPv6(s string) {
ds.statusIPv6 = s
if ! ds.Ready() {return}
me.digStatus.set(ds.statusAAAA, s)
}
func (ds *digStatus) set(a any, s string) {
if ! ds.Ready() {return}
if ds.hidden {
return
}
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()
if ds.checkLookupDoH("go.wit.com") {
log.Println("updateDnsStatus() HTTP DNS lookups working")
me.digStatus.set(ds.statusHTTP, "WORKING")
} else {
log.Println("updateDnsStatus() HTTP DNS lookups not working")
log.Println("updateDnsStatus() It's really unlikely you are on the internet")
me.digStatus.set(ds.statusHTTP, "BROKEN")
}
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)
me.digStatus.set(ds.DnsDigUDP, out)
cmd = "dig +noall +answer www.wit.com AAAA"
out = shell.Run(cmd)
log.Println("makeDnsStatusGrid() dig", out)
me.digStatus.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 (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) {
me.digStatus.set(ds.udpA, "BROKEN")
ds.aFailc += 1
} else {
me.digStatus.set(ds.udpA, "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) {
me.digStatus.set(ds.tcpA, "BROKEN")
ds.aFailc += 1
} else {
me.digStatus.set(ds.tcpA, "WORKING")
ds.aSuccessc += 1
a = true
}
me.digStatus.set(ds.aFail, strconv.Itoa(ds.aFailc))
me.digStatus.set(ds.aSuccess,strconv.Itoa(ds.aSuccessc))
results, _ = dnsUdpLookup(ds.server, ds.hostname, dns.TypeAAAA)
log.Println("dnsStatus.update() UDP type AAAA =", results)
if (len(results) == 0) {
me.digStatus.set(ds.udpAAAA, "BROKEN")
ds.aaaaFailc += 1
me.digStatus.set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc))
} else {
me.digStatus.set(ds.udpAAAA, "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) {
me.digStatus.set(ds.tcpAAAA, "BROKEN")
ds.aaaaFailc += 1
me.digStatus.set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc))
} else {
me.digStatus.set(ds.tcpAAAA, "WORKING")
ds.aaaaSuccessc += 1
aaaa = true
}
me.digStatus.set(ds.aaaaFail, strconv.Itoa(ds.aaaaFailc))
me.digStatus.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")
me.digStatus.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.Println("makeDnsStatusGrid() dig", out)
me.digStatus.set(ds.DnsDigUDP, 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)
me.digStatus.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
domain := "go.wit.com"
ipv6Addresses, err := dnsAAAAlookupDoH(domain)
if err != nil {
log.Error(err, "checkLookupDoH()")
return status
}
log.Println("IPv6 Addresses for %s:\n", domain)
for _, addr := range ipv6Addresses {
log.Println(addr)
me.digStatus.set(ds.httpGoWitCom, addr)
status = true
}
return status
}
func (ds *digStatus) Show() {
log.Info("digStatus.Show() window")
if me.digStatus.hidden {
me.digStatus.window.Show()
}
me.digStatus.hidden = false
}
func (ds *digStatus) Hide() {
log.Info("digStatus.Hide() window")
if ! me.digStatus.hidden {
me.digStatus.window.Hide()
}
me.digStatus.hidden = true
}

120
gui.go
View File

@ -6,11 +6,9 @@ import (
"os" "os"
"os/user" "os/user"
"strconv" "strconv"
// "net"
"strings" "strings"
"go.wit.com/log" "go.wit.com/log"
"go.wit.com/shell"
"go.wit.com/gui/gui" "go.wit.com/gui/gui"
"go.wit.com/gui/gadgets" "go.wit.com/gui/gadgets"
@ -27,8 +25,6 @@ func setupControlPanelWindow() {
mainWindow("DNS and IPv6 Control Panel") mainWindow("DNS and IPv6 Control Panel")
detailsTab("OS Details") detailsTab("OS Details")
debugTab("Debug") debugTab("Debug")
// me.digStatus = NewDigStatusWindow(me.window)
} }
func detailsTab(title string) { func detailsTab(title string) {
@ -100,8 +96,9 @@ func debugTab(title string) {
}) })
g2.NewButton("dig +trace", func () { g2.NewButton("dig +trace", func () {
o := shell.Run("dig +trace +noadditional DS " + me.hostname + " @8.8.8.8") log.Log(NOW, "TODO: redo this")
log.Println(o) // o := shell.Run("dig +trace +noadditional DS " + me.hostname + " @8.8.8.8")
// log.Println(o)
}) })
g2 = me.debug.Box().NewGroup("debugging options") g2 = me.debug.Box().NewGroup("debugging options")
@ -149,14 +146,14 @@ func missingAAAA() string {
func displayDNS() string { func displayDNS() string {
var aaaa []string var aaaa []string
aaaa = dhcpAAAA() // your AAAA records right now aaaa = dhcpAAAA() // your AAAA records right now
h := me.hostname // h := me.hostname
var all string var all string
var broken string = "unknown" var broken string = "unknown"
for _, s := range aaaa { for _, s := range aaaa {
log.Log(NOW, "host", h, "DNS AAAA =", s, "ipmap[s] =", me.ipmap[s]) log.Log(STATUS, "host", "fixme", "DNS AAAA =", s, "ipmap[s] =", me.ipmap[s])
all += s + "\n" all += s + "\n"
if ( me.ipmap[s] == nil) { if ( me.ipmap[s] == nil) {
log.Warn("THIS IS THE WRONG AAAA DNS ENTRY: host", h, "DNS AAAA =", s) log.Warn("THIS IS THE WRONG AAAA DNS ENTRY: host", "fixme", "DNS AAAA =", s)
broken = "wrong AAAA entry" broken = "wrong AAAA entry"
} else { } else {
if (broken == "unknown") { if (broken == "unknown") {
@ -166,7 +163,7 @@ func displayDNS() string {
} }
all = sortLines(all) all = sortLines(all)
if (me.workingIPv6.S != all) { if (me.workingIPv6.S != all) {
log.Warn("workingIPv6.SetText() to:", all) log.Log(NOW, "workingIPv6.SetText() to:", all)
me.workingIPv6.SetText(all) me.workingIPv6.SetText(all)
} }
@ -174,11 +171,11 @@ func displayDNS() string {
a = realA() a = realA()
all = sortLines(strings.Join(a, "\n")) all = sortLines(strings.Join(a, "\n"))
if (all == "") { if (all == "") {
log.Info("THERE IS NOT a real A DNS ENTRY") log.Log(NOW, "THERE IS NOT a real A DNS ENTRY")
all = "CNAME ipv6.wit.com" all = "CNAME ipv6.wit.com"
} }
if (me.DnsA.S != all) { if (me.DnsA.S != all) {
log.Warn("DnsA.SetText() to:", all) log.Log(NOW, "DnsA.SetText() to:", all)
me.DnsA.SetText(all) me.DnsA.SetText(all)
} }
return broken return broken
@ -199,19 +196,18 @@ func mainWindow(title string) {
grid.NewLabel("hostname =") grid.NewLabel("hostname =")
me.fqdn = grid.NewLabel("?") me.fqdn = grid.NewLabel("?")
me.hostname = ""
grid.NewLabel("DNS AAAA =") // grid.NewLabel("DNS AAAA =")
me.DnsAAAA = grid.NewLabel("?") me.DnsAAAA = gadgets.NewOneLiner(grid, "DNS AAAA =").Set("unknown")
grid.NewLabel("DNS A =") grid.NewLabel("DNS A =")
me.DnsA = grid.NewLabel("?") me.DnsA = grid.NewLabel("?")
me.digStatus = NewDigStatusWindow(me.myGui) me.digStatus = NewDigStatusWindow(me.myGui)
me.hostnameStatus = NewHostnameStatusWindow(me.myGui) me.status = NewHostnameStatusWindow(me.myGui)
me.hostnameStatusButton = me.mainStatus.NewButton("Fix hostname DNS", func () { me.hostnameStatusButton = me.mainStatus.NewButton("Fix hostname DNS", func () {
me.hostnameStatus.window.Toggle() me.status.window.Toggle()
}) })
grid.Margin() grid.Margin()
@ -220,19 +216,16 @@ func mainWindow(title string) {
statusGrid(me.window.Box()) statusGrid(me.window.Box())
gr := me.window.Box().NewGroup("debugging") gr := me.window.Box().NewGroup("debugging")
gr.NewButton("GO GUI Debugger", func () {
debugger.DebugWindow(me.myGui)
})
gr.NewButton("OS Details", func () { gr.NewButton("OS Details", func () {
me.details.Toggle() me.details.Toggle()
}) })
gr.NewButton("DNS Debug", func () {
me.debug.Toggle()
})
gr.NewButton("Resolver Status", func () { gr.NewButton("Resolver Status", func () {
if ! me.digStatus.Ready() {return} if ! me.digStatus.Ready() {return}
me.digStatus.window.Toggle() me.digStatus.window.Toggle()
}) })
gr.NewButton("Control Panel Debug", func () {
me.debug.Toggle()
})
} }
func statusGrid(n *gui.Node) { func statusGrid(n *gui.Node) {
@ -240,15 +233,15 @@ func statusGrid(n *gui.Node) {
gridP := problems.NewGrid("nuts", 2, 2) gridP := problems.NewGrid("nuts", 2, 2)
gridP.NewLabel("hostname =")
me.hostnameStatus = gridP.NewLabel("invalid")
gridP.NewLabel("DNS Status =") gridP.NewLabel("DNS Status =")
me.DnsStatus = gridP.NewLabel("unknown") me.DnsStatus = gridP.NewLabel("unknown")
me.statusIPv6 = gadgets.NewOneLiner(gridP, "IPv6 working") me.statusIPv6 = gadgets.NewOneLiner(gridP, "IPv6 working")
me.statusIPv6.Set("known") me.statusIPv6.Set("known")
gridP.NewLabel("hostname =")
me.hostnameStatusOLD = gridP.NewLabel("invalid")
gridP.NewLabel("dns resolution") gridP.NewLabel("dns resolution")
me.DnsSpeed = gridP.NewLabel("unknown") me.DnsSpeed = gridP.NewLabel("unknown")
@ -279,52 +272,51 @@ func statusGrid(n *gui.Node) {
// run everything because something has changed // run everything because something has changed
func updateDNS() { func updateDNS() {
var aaaa []string
h := me.hostname
if (h == "") {
h = "test.wit.com"
}
me.digStatus.Update() me.digStatus.Update()
me.hostnameStatus.Update() me.status.Update()
// log.Println("digAAAA()") // log.Println("digAAAA()")
aaaa = digAAAA(h)
log.Log(NOW, "digAAAA() =", aaaa)
// log.Println(SPEW, me) if me.status.ValidHostname() {
if (aaaa == nil) { var aaaa []string
log.Warn("There are no DNS AAAA records for hostname: ", h) h := me.status.GetHostname()
me.DnsAAAA.SetText("(none)") aaaa = digAAAA(h)
if (cloudflare.CFdialog.TypeNode != nil) { log.Log(NOW, "digAAAA() for", h, "=", aaaa)
cloudflare.CFdialog.TypeNode.SetText("AAAA new")
}
if (cloudflare.CFdialog.NameNode != nil) { // log.Println(SPEW, me)
cloudflare.CFdialog.NameNode.SetText(me.hostname) if (aaaa == nil) {
} log.Warn("There are no DNS AAAA records for hostname: ", h)
me.DnsAAAA.Set("(none)")
d := deleteAAA() if (cloudflare.CFdialog.TypeNode != nil) {
if (d != "") { cloudflare.CFdialog.TypeNode.SetText("AAAA new")
if (cloudflare.CFdialog.ValueNode != nil) {
cloudflare.CFdialog.ValueNode.SetText(d)
} }
}
m := missingAAAA() if (cloudflare.CFdialog.NameNode != nil) {
if (m != "") { cloudflare.CFdialog.NameNode.SetText(h)
if (cloudflare.CFdialog.ValueNode != nil) {
cloudflare.CFdialog.ValueNode.SetText(m)
} }
/*
rr := &cloudflare.RRT{ d := deleteAAA()
Type: "AAAA", if (d != "") {
Name: me.hostname, if (cloudflare.CFdialog.ValueNode != nil) {
Ttl: "Auto", cloudflare.CFdialog.ValueNode.SetText(d)
Proxied: false, }
Content: m, }
m := missingAAAA()
if (m != "") {
if (cloudflare.CFdialog.ValueNode != nil) {
cloudflare.CFdialog.ValueNode.SetText(m)
}
/*
rr := &cloudflare.RRT{
Type: "AAAA",
Name: me.hostname,
Ttl: "Auto",
Proxied: false,
Content: m,
}
cloudflare.Update(rr)
*/
} }
cloudflare.Update(rr)
*/
} }
} }
status := displayDNS() // update the GUI based on dig results status := displayDNS() // update the GUI based on dig results

View File

@ -22,14 +22,7 @@ func getHostname() {
log.Error(err, "FQDN hostname error") log.Error(err, "FQDN hostname error")
return return
} }
if (me.fqdn != nil) { me.status.SetHostname(s)
if (me.hostname != s) {
me.fqdn.SetText(s)
me.hostname = s
me.changed = true
}
}
log.Log(NET, "FQDN =", s)
dn := run("domainname") dn := run("domainname")
if (me.domainname.S != dn) { if (me.domainname.S != dn) {
@ -47,17 +40,17 @@ func getHostname() {
var test string var test string
test = hshort + "." + dn test = hshort + "." + dn
if (me.hostname != test) { if (me.status.GetHostname() != test) {
log.Info("me.hostname", me.hostname, "does not equal", test) log.Log(CHANGE, "me.hostname", me.status.GetHostname(), "does not equal", test)
if (me.hostnameStatusOLD.S != "BROKEN") { if (me.hostnameStatus.S != "BROKEN") {
log.Log(CHANGE, "me.hostname", me.hostname, "does not equal", test) log.Log(CHANGE, "me.hostname", me.status.GetHostname(), "does not equal", test)
me.changed = true me.changed = true
me.hostnameStatusOLD.SetText("BROKEN") me.hostnameStatus.SetText("BROKEN")
} }
} else { } else {
if (me.hostnameStatusOLD.S != "VALID") { if (me.hostnameStatus.S != "VALID") {
log.Log(CHANGE, "me.hostname", me.hostname, "is valid") log.Log(CHANGE, "me.hostname", me.status.GetHostname(), "is valid")
me.hostnameStatusOLD.SetText("VALID") me.hostnameStatus.SetText("VALID")
me.changed = true me.changed = true
} }
// enable the cloudflare button if the provider is cloudflare // enable the cloudflare button if the provider is cloudflare
@ -76,7 +69,7 @@ func getHostname() {
// check that all the OS settings are correct here // check that all the OS settings are correct here
// On Linux, /etc/hosts, /etc/hostname // On Linux, /etc/hosts, /etc/hostname
// and domainname and hostname // and domainname and hostname
func goodHostname(h string) bool { func goodHostname() bool {
hostname := shell.Chomp(shell.Cat("/etc/hostname")) hostname := shell.Chomp(shell.Cat("/etc/hostname"))
log.Log(NOW, "hostname =", hostname) log.Log(NOW, "hostname =", hostname)
@ -93,30 +86,6 @@ func goodHostname(h string) bool {
return false return false
} }
/*
func digAAAA(s string) []string {
var aaaa []string
// lookup the IP address from DNS
rrset := dnssecsocket.Dnstrace(s, "AAAA")
// log.Spew(args.VerboseDNS, SPEW, rrset)
for i, rr := range rrset {
ipaddr := dns.Field(rr, 1)
// how the hell do you detect a RRSIG AAAA record here?
if (ipaddr == "28") {
continue
}
log.Log(NOW, "r.Answer =", i, "rr =", rr, "ipaddr =", ipaddr)
aaaa = append(aaaa, ipaddr)
me.ipv6s[ipaddr] = rr
}
log.Info(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 { func digAAAA(hostname string) []string {
var blah, ipv6Addresses []string var blah, ipv6Addresses []string
// domain := hostname // domain := hostname
@ -128,7 +97,7 @@ func digAAAA(hostname string) []string {
if (len(blah) == 0) { if (len(blah) == 0) {
log.Println("digAAAA() RUNNING dnsAAAAlookupDoH(domain)") log.Println("digAAAA() RUNNING dnsAAAAlookupDoH(domain)")
ipv6Addresses, _ = dnsAAAAlookupDoH(hostname) ipv6Addresses = lookupDoH(hostname, "AAAA")
log.Println("digAAAA() has ipv6Addresses =", strings.Join(ipv6Addresses, " ")) log.Println("digAAAA() has ipv6Addresses =", strings.Join(ipv6Addresses, " "))
for _, addr := range ipv6Addresses { for _, addr := range ipv6Addresses {
log.Println(addr) log.Println(addr)
@ -141,20 +110,3 @@ func digAAAA(hostname string) []string {
return 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 {
log.Println("Error:", err)
return
}
log.Printf("IPv6 Addresses for %s:\n", domain)
for _, addr := range ipv6Addresses {
log.Println(addr)
}
}
*/

View File

@ -23,7 +23,8 @@ type hostnameStatus struct {
ready bool ready bool
hidden bool hidden bool
hostname string // my hostname. Example: "test.wit.com" // hostname string // my hostname. Example: "test.wit.com"
lastname string // used to watch for changes in the hostname
window *gadgets.BasicWindow window *gadgets.BasicWindow
@ -60,9 +61,9 @@ func NewHostnameStatusWindow(p *gui.Node) *hostnameStatus {
hs.ready = false hs.ready = false
hs.hidden = true hs.hidden = true
hs.hostname = me.hostname // hs.hostname = me.hostname
hs.window = gadgets.NewBasicWindow(p, hs.hostname + " Status") hs.window = gadgets.NewBasicWindow(p, "fix hostname here" + " Status")
hs.window.Draw() hs.window.Draw()
hs.window.Hide() hs.window.Hide()
@ -116,6 +117,25 @@ func NewHostnameStatusWindow(p *gui.Node) *hostnameStatus {
return hs return hs
} }
func (hs *hostnameStatus) ValidHostname() bool {
return goodHostname()
}
func (hs *hostnameStatus) GetHostname() string {
return hs.lastname
}
func (hs *hostnameStatus) SetHostname(hostname string) {
if hostname == hs.lastname {return}
log.Log(CHANGE, "the hostname is changing from", hs.lastname, "to", hostname)
hs.lastname = hostname
me.changed = true
if (me.fqdn != nil) {
me.fqdn.SetText(hostname)
}
}
func (hs *hostnameStatus) Domain() string { func (hs *hostnameStatus) Domain() string {
if ! hs.Ready() {return ""} if ! hs.Ready() {return ""}
return hs.domainname.Get() return hs.domainname.Get()
@ -128,26 +148,26 @@ func (hs *hostnameStatus) API() string {
func (hs *hostnameStatus) deleteDNSrecord(value string) bool { func (hs *hostnameStatus) deleteDNSrecord(value string) bool {
log.Info("deleteDNSrecord() START for", value) log.Info("deleteDNSrecord() START for", value)
log.Info("deleteDNSrecord() hostname =", me.hostname) log.Info("deleteDNSrecord() hostname =", me.status.GetHostname())
log.Info("deleteDNSrecord() domain =", hs.Domain()) log.Info("deleteDNSrecord() domain =", hs.Domain())
log.Info("deleteDNSrecord() DNS API Provider =", hs.API()) log.Info("deleteDNSrecord() DNS API Provider =", hs.API())
if (hs.API() == "cloudflare") { if (hs.API() == "cloudflare") {
log.Info("deleteDNSrecord() Try to delete via cloudflare") log.Info("deleteDNSrecord() Try to delete via cloudflare")
return cloudflare.Delete(hs.Domain(), me.hostname, value) return cloudflare.Delete(hs.Domain(), me.status.GetHostname(), value)
} }
return false return false
} }
func (hs *hostnameStatus) createDNSrecord(value string) bool { func (hs *hostnameStatus) createDNSrecord(value string) bool {
log.Info("createDNSrecord() START for", value) log.Info("createDNSrecord() START for", value)
log.Info("createDNSrecord() hostname =", me.hostname) log.Info("createDNSrecord() hostname =", me.status.GetHostname())
log.Info("createDNSrecord() domain =", hs.Domain()) log.Info("createDNSrecord() domain =", hs.Domain())
log.Info("createDNSrecord() DNS API Provider =", hs.API()) log.Info("createDNSrecord() DNS API Provider =", hs.API())
if (hs.API() == "cloudflare") { if (hs.API() == "cloudflare") {
log.Warn("createDNSrecord() Try to delete via cloudflare:", me.hostname, value) log.Warn("createDNSrecord() Try to create via cloudflare:", me.status.GetHostname(), value)
return cloudflare.Create(hs.Domain(), me.hostname, value) return cloudflare.Create(hs.Domain(), me.status.GetHostname(), value)
} }
return false return false
} }
@ -229,10 +249,10 @@ func (hs *hostnameStatus) set(a any, s string) {
if reflect.TypeOf(a) == reflect.TypeOf(ol) { if reflect.TypeOf(a) == reflect.TypeOf(ol) {
ol = a.(*gadgets.OneLiner) ol = a.(*gadgets.OneLiner)
if ol == nil { if ol == nil {
log.Println("ol = nil", reflect.TypeOf(a), "a =", a) // log.Println("ol = nil", reflect.TypeOf(a), "a =", a)
return return
} }
log.Println("SETTING ol:", ol) // log.Println("SETTING ol:", ol)
ol.Set(s) ol.Set(s)
return return
} }
@ -240,69 +260,82 @@ func (hs *hostnameStatus) set(a any, s string) {
os.Exit(0) os.Exit(0)
} }
// returns true if AAAA record already exists in DNS
func (hs *hostnameStatus) existsAAAA(s string) bool {
log.Log(NOW, "existsAAAA() try to see if AAAA is already set", s)
return false
}
// figure out if I'm missing any IPv6 address in DNS // figure out if I'm missing any IPv6 address in DNS
func (hs *hostnameStatus) missingAAAA() bool { func (hs *hostnameStatus) missingAAAA() bool {
var aaaa []string var aaaa []string
aaaa = dhcpAAAA() aaaa = dhcpAAAA()
for _, s := range aaaa { for _, s := range aaaa {
log.Log(NET, "my actual AAAA = ",s) log.Log(NET, "my actual AAAA = ",s)
hs.dnsValue.SetText(s) if hs.existsAAAA(s) {
hs.dnsAction.SetText("CREATE") log.Log(NOW, "my actual AAAA already exists in DNS =",s)
return true } else {
log.Log(NOW, "my actual AAAA is missing from DNS",s)
hs.dnsValue.SetText(s)
hs.dnsAction.SetText("CREATE")
return true
}
} }
return false return false
} }
func (hs *hostnameStatus) updateStatus() { func (hs *hostnameStatus) updateStatus() {
if ! hs.Ready() { return }
var s string var s string
var vals []string var vals []string
log.Info("updateStatus() START") log.Log(STATUS, "updateStatus() START")
if ! hs.Ready() { return }
hs.hostShort.Set(me.hostshort.S) hs.hostShort.Set(me.hostshort.S)
hs.domainname.Set(me.domainname.S) hs.domainname.Set(me.domainname.S)
vals = lookupDoH(hs.hostname, "AAAA") if hs.ValidHostname() {
vals = lookupDoH(hs.GetHostname(), "AAAA")
log.Println("DNS IPv6 Addresses for ", hs.hostname, "=", vals) log.Log(STATUS, "DNS IPv6 Addresses for ", hs.GetHostname(), "=", vals)
if len(vals) == 0 { if len(vals) == 0 {
s = "(none)" s = "(none)"
hs.setIPv6("Check for real IPv6 addresses here") } else {
if hs.missingAAAA() { hs.setIPv6("Check for real IPv6 addresses here")
hs.setIPv6("Add the missing IPv6 address") if hs.missingAAAA() {
hs.setIPv6("Add the missing IPv6 address")
}
for _, addr := range vals {
log.Log(STATUS, addr)
s += addr + " (DELETE)" + "\n"
hs.setIPv6("NEEDS DELETE")
hs.dnsValue.SetText(addr)
hs.dnsAction.SetText("DELETE")
}
} }
} else { hs.set(hs.dnsAAAA, s)
for _, addr := range vals {
log.Println(addr) vals = lookupDoH(hs.GetHostname(), "A")
s += addr + " (DELETE)" log.Log(STATUS, "IPv4 Addresses for ", hs.GetHostname(), "=", vals)
hs.setIPv6("NEEDS DELETE") s = strings.Join(vals, "\n")
hs.dnsValue.SetText(addr) if (s == "") {
hs.dnsAction.SetText("DELETE") s = "(none)"
hs.setIPv4("NEEDS CNAME")
} }
} hs.set(hs.dnsA, s)
hs.set(hs.dnsAAAA, s)
vals = lookupDoH(hs.hostname, "A") vals = lookupDoH(hs.GetHostname(), "CNAME")
log.Println("IPv4 Addresses for ", hs.hostname, "=", vals) s = strings.Join(vals, "\n")
s = strings.Join(vals, "\n") if (s != "") {
if (s == "") { hs.set(hs.dnsA, "CNAME " + s)
s = "(none)" hs.setIPv4("GOOD")
hs.setIPv4("NEEDS CNAME") }
}
hs.set(hs.dnsA, s)
vals = lookupDoH(hs.hostname, "CNAME")
s = strings.Join(vals, "\n")
if (s != "") {
hs.set(hs.dnsA, "CNAME " + s)
hs.setIPv4("GOOD")
} }
hs.currentIPv4.Set(me.IPv4.S) hs.currentIPv4.Set(me.IPv4.S)
hs.currentIPv6.Set(me.IPv6.S) hs.currentIPv6.Set(me.IPv6.S)
if hs.IPv4() && hs.IPv4() { if hs.IPv4() && hs.IPv6() {
hs.status.Set("GOOD") hs.status.Set("GOOD")
} else { } else {
hs.status.Set("BROKEN") hs.status.Set("BROKEN")
@ -312,7 +345,7 @@ func (hs *hostnameStatus) updateStatus() {
} }
func (hs *hostnameStatus) Show() { func (hs *hostnameStatus) Show() {
log.Info("hostnameStatus.Show() window") log.Log(STATUS, "hostnameStatus.Show() window")
if hs.hidden { if hs.hidden {
hs.window.Show() hs.window.Show()
} }
@ -320,7 +353,7 @@ func (hs *hostnameStatus) Show() {
} }
func (hs *hostnameStatus) Hide() { func (hs *hostnameStatus) Hide() {
log.Info("hostnameStatus.Hide() window") log.Log(STATUS, "hostnameStatus.Hide() window")
if ! hs.hidden { if ! hs.hidden {
hs.window.Hide() hs.window.Hide()
} }

View File

@ -22,7 +22,7 @@ func nsupdate() {
cmd := "go-nsupdate --tsig-algorithm=hmac-sha512" cmd := "go-nsupdate --tsig-algorithm=hmac-sha512"
tsigSecret = os.Getenv("TIG_SECRET") tsigSecret = os.Getenv("TIG_SECRET")
cmd += " --tig-secret=\"" + tsigSecret + "\"" cmd += " --tig-secret=\"" + tsigSecret + "\""
cmd += " -i wlo1 " + me.hostname cmd += " -i wlo1 " + me.status.GetHostname()
log.Log(NET, "nsupdate() RUN:", cmd) log.Log(NET, "nsupdate() RUN:", cmd)
for s, t := range me.ipmap { for s, t := range me.ipmap {

209
resolverBox.go Normal file
View File

@ -0,0 +1,209 @@
/*
Performs DNS queries on TCP and UDP
*/
package main
import (
"os"
"time"
"strconv"
"reflect"
"go.wit.com/log"
"go.wit.com/gui/gui"
"go.wit.com/gui/gadgets"
"github.com/miekg/dns"
)
type resolverStatus 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 (rs *resolverStatus) 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)
}
// Makes a DNS Status Grid
func NewResolverStatus(p *gui.Node, title string, server string, hostname string) *resolverStatus {
var rs *resolverStatus
rs = new(resolverStatus)
rs.parent = p
rs.group = p.NewGroup(server + " " + title + " lookup")
rs.grid = rs.group.NewGrid("LookupStatus", 5, 2)
rs.server = server
rs.hostname = hostname
rs.grid.NewLabel("")
rs.grid.NewLabel("UDP")
rs.grid.NewLabel("TCP")
rs.grid.NewLabel("Success")
rs.grid.NewLabel("Fail")
rs.grid.NewLabel("A")
rs.udpA = rs.grid.NewLabel("?")
rs.tcpA = rs.grid.NewLabel("?")
rs.aSuccess = rs.grid.NewLabel("?")
rs.aFail = rs.grid.NewLabel("?")
rs.grid.NewLabel("AAAA")
rs.udpAAAA = rs.grid.NewLabel("?")
rs.tcpAAAA = rs.grid.NewLabel("?")
rs.aaaaSuccess = rs.grid.NewLabel("?")
rs.aaaaFail = rs.grid.NewLabel("?")
rs.group.Margin()
rs.grid.Margin()
rs.group.Pad()
rs.grid.Pad()
return rs
}
// 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 (rs *resolverStatus) update() (bool, bool) {
var results []string
var a bool = false
var aaaa bool = false
log.Log(DNS, "resolverStatus.update() For server", rs.server, "on", rs.hostname)
results, _ = dnsUdpLookup(rs.server, rs.hostname, dns.TypeA)
log.Log(DNS, "resolverStatus.update() UDP type A =", results)
if (len(results) == 0) {
rs.set(rs.udpA, "BROKEN")
rs.aFailc += 1
} else {
rs.set(rs.udpA, "WORKING")
rs.aSuccessc += 1
a = true
}
results, _ = dnsTcpLookup(rs.server, rs.hostname, dns.TypeA)
log.Log(DNS, "resolverStatus.update() TCP type A =", results)
if (len(results) == 0) {
rs.set(rs.tcpA, "BROKEN")
rs.aFailc += 1
} else {
me.digStatus.set(rs.tcpA, "WORKING")
rs.aSuccessc += 1
a = true
}
me.digStatus.set(rs.aFail, strconv.Itoa(rs.aFailc))
me.digStatus.set(rs.aSuccess,strconv.Itoa(rs.aSuccessc))
results, _ = dnsUdpLookup(rs.server, rs.hostname, dns.TypeAAAA)
log.Log(DNS, "resolverStatus.update() UDP type AAAA =", results)
if (len(results) == 0) {
me.digStatus.set(rs.udpAAAA, "BROKEN")
rs.aaaaFailc += 1
me.digStatus.set(rs.aaaaFail, strconv.Itoa(rs.aaaaFailc))
} else {
me.digStatus.set(rs.udpAAAA, "WORKING")
rs.aaaaSuccessc += 1
aaaa = true
}
results, _ = dnsTcpLookup(rs.server, rs.hostname, dns.TypeAAAA)
log.Log(DNS, "resolverStatus.update() UDP type AAAA =", results)
if (len(results) == 0) {
me.digStatus.set(rs.tcpAAAA, "BROKEN")
rs.aaaaFailc += 1
me.digStatus.set(rs.aaaaFail, strconv.Itoa(rs.aaaaFailc))
} else {
me.digStatus.set(rs.tcpAAAA, "WORKING")
rs.aaaaSuccessc += 1
aaaa = true
}
me.digStatus.set(rs.aaaaFail, strconv.Itoa(rs.aaaaFailc))
me.digStatus.set(rs.aaaaSuccess,strconv.Itoa(rs.aaaaSuccessc))
return a, aaaa
}
// 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
}

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"go.wit.com/gui/gui" "go.wit.com/gui/gui"
"go.wit.com/gui/gadgets" "go.wit.com/gui/gadgets"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -13,10 +14,13 @@ import (
var me Host var me Host
type Host struct { type Host struct {
hostname string // mirrors status *hostnameStatus // keeps track of the hostname and it's status
hostnameStatus *gui.Node // a summary for the user of where things are
// hostname string // mirrors
domainname *gui.Node // kernel.org domainname *gui.Node // kernel.org
hostshort *gui.Node // hostname -s hostshort *gui.Node // hostname -s
hostnameStatusOLD *gui.Node // is the hostname configured correctly in the OS?
// fqdn string // mirrors.kernel.org // fqdn string // mirrors.kernel.org
// dnsTTL int `default:"3"` // Recheck DNS is working every TTL (in seconds) // dnsTTL int `default:"3"` // Recheck DNS is working every TTL (in seconds)
@ -59,7 +63,7 @@ type Host struct {
// DNS stuff // DNS stuff
NSrr *gui.Node // NS resource records for the domain name NSrr *gui.Node // NS resource records for the domain name
DnsAPI *gui.Node // what DNS API to use? DnsAPI *gui.Node // what DNS API to use?
DnsAAAA *gui.Node // the actual DNS AAAA results DnsAAAA *gadgets.OneLiner // the actual DNS AAAA results
workingIPv6 *gui.Node // currently working AAAA workingIPv6 *gui.Node // currently working AAAA
DnsA *gui.Node // the actual DNS A results (ignore for status since mostly never happens?) DnsA *gui.Node // the actual DNS A results (ignore for status since mostly never happens?)
DnsStatus *gui.Node // the current state of DNS DnsStatus *gui.Node // the current state of DNS
@ -81,7 +85,6 @@ type Host struct {
statusIPv6 *gadgets.OneLiner statusIPv6 *gadgets.OneLiner
digStatusButton *gui.Node digStatusButton *gui.Node
hostnameStatus *hostnameStatus
hostnameStatusButton *gui.Node hostnameStatusButton *gui.Node
myDebug *gui.Node myDebug *gui.Node