/* figures out if your hostname is valid then checks if your DNS is setup correctly */ package main import ( "errors" "fmt" "os" "reflect" "sort" "strings" "time" "go.wit.com/gui" "go.wit.com/lib/gadgets" "go.wit.com/log" ) type hostnameStatus struct { ready bool hidden bool changed bool lastname string // used to watch for changes in the hostname window *gadgets.BasicWindow // Primary Directives status *gadgets.OneLiner summary *gadgets.OneLiner statusIPv4 *gadgets.OneLiner statusIPv6 *gadgets.OneLiner hostname *gadgets.OneLiner domainname *gadgets.OneLiner // what the current IP addresses your network has given you currentIPv4 *gadgets.OneLiner currentIPv6 *gadgets.OneLiner // what the DNS servers have NSrr *gadgets.OneLiner dnsA *gadgets.OneLiner dnsAAAA *gadgets.OneLiner dnsAPI *gadgets.OneLiner APIprovider string speed *gadgets.OneLiner speedActual *gadgets.OneLiner // Actions // dnsValue *gui.Node // dnsAction *gui.Node } func InitHostnameStatus() *hostnameStatus { var hs *hostnameStatus hs = new(hostnameStatus) hs.ready = false hs.hidden = true // hs.hostname = me.hostname hs.window = gadgets.RawBasicWindow("fix hostname here" + " Status") hs.window.Make() // hs.window.Draw() // hs.window.Hide() group := hs.window.Box().NewGroup("Summary") grid := group.NewGrid("LookupStatus", 2, 2) hs.status = gadgets.NewOneLiner(grid, "status").SetText("unknown") hs.statusIPv4 = gadgets.NewOneLiner(grid, "IPv4").SetText("unknown") hs.statusIPv6 = gadgets.NewOneLiner(grid, "IPv6").SetText("unknown") group.Pad() grid.Pad() group = hs.window.Box().NewGroup("Details") grid = group.NewGrid("LookupDetails", 2, 2) hs.hostname = gadgets.NewOneLiner(grid, "hostname") hs.domainname = gadgets.NewOneLiner(grid, "domain name") hs.currentIPv4 = gadgets.NewOneLiner(grid, "Current IPv4") hs.currentIPv6 = gadgets.NewOneLiner(grid, "Current IPv6") hs.NSrr = gadgets.NewOneLiner(grid, "dns NS records").SetText("unknown") hs.dnsAPI = gadgets.NewOneLiner(grid, "dns API provider").SetText("unknown") hs.dnsA = gadgets.NewOneLiner(grid, "dns IPv4 resource records").SetText("unknown") hs.dnsAAAA = gadgets.NewOneLiner(grid, "dns IPv6 resource records").SetText("unknown") hs.speed = gadgets.NewOneLiner(grid, "speed").SetText("unknown") hs.speedActual = gadgets.NewOneLiner(grid, "actual").SetText("unknown") group.Pad() grid.Pad() hs.hidden = false hs.ready = true return hs } func (hs *hostnameStatus) Domain() string { if !hs.Ready() { return "" } return hs.domainname.String() } func (hs *hostnameStatus) API() string { if !hs.Ready() { return "" } return hs.dnsAPI.String() } func (hs *hostnameStatus) Update() { // log.Info("hostnameStatus() Update() START") if hs == nil { log.Error(errors.New("hostnameStatus() Update() hs == nil")) return } duration := timeFunction(func() { hs.updateStatus() }) s := fmt.Sprint(duration) hs.set(hs.speedActual, s) if duration > 500*time.Millisecond { hs.set(hs.speed, "SLOW") } else if duration > 100*time.Millisecond { hs.set(hs.speed, "OK") } else { hs.set(hs.speed, "FAST") } // log.Info("hostnameStatus() Update() END") } // Returns true if the status is valid func (hs *hostnameStatus) Ready() bool { if hs == nil { return false } return hs.ready } // Returns true if IPv4 is working func (hs *hostnameStatus) IPv4() bool { if !hs.Ready() { return false } if hs.statusIPv4.String() == "OK" { return true } if hs.statusIPv4.String() == "GOOD" { return true } return false } // Returns true if IPv6 is working func (hs *hostnameStatus) IPv6() bool { if !hs.Ready() { return false } if hs.statusIPv6.String() == "GOOD" { return true } return false } func (hs *hostnameStatus) setIPv4(s string) { if !hs.Ready() { return } hs.statusIPv4.SetText(s) } func (hs *hostnameStatus) setIPv6(s string) { if !hs.Ready() { return } hs.statusIPv6.SetText(s) } func (hs *hostnameStatus) set(a any, s string) { if !hs.Ready() { return } if hs.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) if ol == nil { // log.Println("ol = nil", reflect.TypeOf(a), "a =", a) return } // log.Println("SETTING ol:", ol) ol.SetText(s) return } log.Warn("unknown type TypeOf(a) =", reflect.TypeOf(a), "a =", a) 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 } func (hs *hostnameStatus) GetIPv6() []string { if !hs.Ready() { return nil } // clean out any blank lines // todo: fix this whole hacky thing tmp := hs.dnsAAAA.String() tmp = strings.TrimSpace(tmp) return strings.Split(tmp, "\n") } func (hs *hostnameStatus) GetIPv4() []string { if !hs.Ready() { return nil } // clean out any blank lines // todo: fix this whole hacky thing tmp := hs.dnsA.String() tmp = strings.TrimSpace(tmp) return strings.Split(tmp, "\n") } func (hs *hostnameStatus) updateStatus() { if !hs.Ready() { return } var s string var vals []string log.Log(STATUS, "updateStatus() START") // copy the OS status over lasthostname := hs.hostname.String() hostname := me.statusOS.GetHostname() // hostname changed or was setup for the first time. Set the window title, etc if lasthostname != hostname { me.changed = true hs.hostname.SetText(hostname) hs.window.SetLabel(hostname + " Status") me.statusDNSbutton.SetLabel(hostname + " status") } hs.domainname.SetText(me.statusOS.GetDomainName()) var tmp []string tmp = me.statusOS.GetIPv4() sort.Strings(tmp) s = strings.Join(tmp, "\n") if s != hs.currentIPv4.String() { log.Log(CHANGE, "DNS IPv4 Addresses changed", tmp) hs.currentIPv4.SetText(s) hs.changed = true } tmp = me.statusOS.GetIPv6() sort.Strings(tmp) s = strings.Join(tmp, "\n") if s != hs.currentIPv6.String() { log.Log(CHANGE, "DNS IPv6 Addresses changed", tmp) hs.currentIPv6.SetText(s) hs.changed = true } if me.statusOS.ValidHostname() { vals = lookupDoH(me.statusOS.GetHostname(), "AAAA") log.Log(STATUS, "DNS IPv6 Addresses for ", me.statusOS.GetHostname(), "=", vals) hs.dnsAAAA.SetText(strings.Join(vals, "\n")) vals = lookupDoH(me.statusOS.GetHostname(), "A") log.Log(STATUS, "IPv4 Addresses for ", me.statusOS.GetHostname(), "=", vals) s = strings.Join(vals, "\n") if s == "" { s = "(none)" hs.setIPv4("NEEDS CNAME") } hs.set(hs.dnsA, s) vals = lookupDoH(me.statusOS.GetHostname(), "CNAME") s = strings.Join(vals, "\n") if s != "" { hs.set(hs.dnsA, "CNAME "+s) hs.setIPv4("GOOD") } if hs.changed { log.Log(CHANGE, "stuff changed. trying fixIPv6dns()") fixIPv6dns() hs.changed = false } } if hs.IPv4() && hs.IPv6() { hs.status.SetText("GOOD") } else { hs.status.SetText("BROKEN") } last := hs.statusIPv6.String() if ok, err := hs.verifyIPv6(); ok { if last != "WORKING" { log.Log(CHANGE, "Your DNS IPv6 has started working.", me.statusOS.GetHostname(), "should now work") hs.changed = true hs.statusIPv6.SetText("WORKING") me.DnsStatus.SetText("WORKING") } } else { if last != "BROKEN" { log.Log(CHANGE, "Your DNS entries for IPv6 have BROKEN", ok, err) hs.changed = true hs.statusIPv6.SetText("BROKEN") me.DnsStatus.SetText("BROKEN") } } } var ErrorNoIPv6 error = errors.New("OS has no IPv6") var ErrorDeleteIPv6 error = errors.New("IPv6 Delete") var ErrorCreateIPv6 error = errors.New("IPv6 Create") func (hs *hostnameStatus) verifyIPv6() (bool, error) { var working bool = true var err error = nil osAAAA := make(map[string]string) dnsAAAA := make(map[string]string) log.Log(INFO, "What are the AAAA resource records in the OS?") tmp := me.statusOS.GetIPv6() if len(tmp) == 0 { // you don't have any IPv6 addresses in your OS right now return false, ErrorNoIPv6 } for _, aaaa := range me.statusOS.GetIPv6() { log.Log(INFO, "FOUND OS AAAA ip", aaaa) osAAAA[aaaa] = "os" } log.Log(INFO, "What are the AAAA resource records in DNS?") for _, aaaa := range me.statusDNS.GetIPv6() { // log.Log(INFO, "FOUND DNS AAAA ip", aaaa) dnsAAAA[aaaa] = "dns" } for aaaa, _ := range dnsAAAA { if osAAAA[aaaa] == "os" { log.Log(INFO, "DNS AAAA is in OS", aaaa) } else { working = false log.Log(INFO, "DNS AAAA is not in OS", aaaa) addToFixWindow("DELETE", aaaa) err = ErrorDeleteIPv6 } } for aaaa, _ := range osAAAA { if dnsAAAA[aaaa] == "dns" { log.Log(INFO, "OS AAAA is in DNS", aaaa) } else { working = false log.Log(INFO, "OS AAAA is not in DNS", aaaa) addToFixWindow("CREATE", aaaa) err = ErrorCreateIPv6 } } return working, err } func (hs *hostnameStatus) Show() { log.Log(STATUS, "hostnameStatus.Show() window") if hs.hidden { hs.window.Show() } hs.hidden = false } func (hs *hostnameStatus) Hide() { log.Log(STATUS, "hostnameStatus.Hide() window") if !hs.hidden { hs.window.Hide() } hs.hidden = true } func (hs *hostnameStatus) GetDNSapi() string { return hs.APIprovider } func (hs *hostnameStatus) SetDNSapi(api string) { if api == hs.APIprovider { return } hs.APIprovider = api hs.dnsAPI.SetText(api) hs.changed = true }