From 6fa6d6dfc9e5a88e7dff2ed3c148b3b4271f566c Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 28 Dec 2023 09:43:45 -0600 Subject: 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 --- cloudflare/api.go | 26 +++---- cloudflare/cloudflare.go | 182 ------------------------------------------- cloudflare/durationSlider.go | 2 + cloudflare/http.go | 49 ++++++------ cloudflare/mainWindow.go | 3 +- cloudflare/oneLiner.go | 42 ++++++++++ cloudflare/rr.go | 157 +++++++++++++++++++++++++++++++++++++ cloudflare/structs.go | 2 +- 8 files changed, 237 insertions(+), 226 deletions(-) delete mode 100644 cloudflare/cloudflare.go create mode 100644 cloudflare/oneLiner.go create mode 100644 cloudflare/rr.go (limited to 'cloudflare') diff --git a/cloudflare/api.go b/cloudflare/api.go index 1769f6b..036adc7 100644 --- a/cloudflare/api.go +++ b/cloudflare/api.go @@ -10,11 +10,20 @@ import ( "github.com/davecgh/go-spew/spew" ) +/* + This function should run each time + the user chanegs anything in the GUi + or each time something in general changes + + It returns a RR record which then can be + turned into JSON and sent via http + to cloudflare's API +*/ func DoChange() *RRT { var dnsRow *RRT dnsRow = new(RRT) - log.Println("Look for changes in row", dnsRow.ID) + log.Println("DoChange() START") if (CFdialog.proxyNode.S == "On") { dnsRow.Proxied = true } else { @@ -88,21 +97,6 @@ func SetRow(dnsRow *RRT) { log.Println("http PUT curl =", pretty) CFdialog.curlNode.SetText(pretty) } - - return - log.Println("UPDATE VALUE", CFdialog.NameNode.Name, CFdialog.TypeNode.Name, "to", CFdialog.ValueNode.S) - stuff, result := httpPut(dnsRow) - if (CFdialog.curlNode != nil) { - pretty, _ := FormatJSON(stuff) - log.Println("http PUT curl =", pretty) - CFdialog.curlNode.SetText(pretty) - } - if (CFdialog.resultNode != nil) { - pretty, _ := FormatJSON(result) - log.Println("http PUT result =", pretty) - CFdialog.resultNode.SetText(pretty) - } - // CFdialog.saveNode.Disable() } func GetZonefile(c *ConfigT) *DNSRecords { diff --git a/cloudflare/cloudflare.go b/cloudflare/cloudflare.go deleted file mode 100644 index db98c92..0000000 --- a/cloudflare/cloudflare.go +++ /dev/null @@ -1,182 +0,0 @@ -// This is a simple example -package cloudflare - -import ( - "log" - "os" - - "go.wit.com/gui" -) - -func init() { - Config = make(map[string]*ConfigT) -} - -func CreateRR(myGui *gui.Node, zone string, zoneID string) { - if (CFdialog.cloudflareW != nil) { - // skip this if the window has already been created - log.Println("createRR() the cloudflare window already exists") - CFdialog.cloudflareB.Disable() - return - } - CFdialog.cloudflareW = myGui.NewWindow("cloudflare " + zone + " API") - CFdialog.cloudflareW.Custom = func () { - log.Println("createRR() don't really exit here") - CFdialog.cloudflareW = nil - CFdialog.cloudflareB.Enable() - } - - group := CFdialog.cloudflareW.NewGroup("Create a new DNS Resource Record (rr)") - - // make a grid 2 things wide - grid := group.NewGrid("gridnuts", 2, 3) - - grid.NewLabel("zone") - CFdialog.zoneNode = grid.NewLabel("zone") - CFdialog.zoneNode.SetText(zone) - - grid.NewLabel("zone ID") - CFdialog.zoneIdNode = grid.NewLabel("zoneID") - CFdialog.zoneIdNode.SetText(zoneID) - - grid.NewLabel("shell env $CF_API_EMAIL") - CFdialog.emailNode = grid.NewLabel("type") - CFdialog.emailNode.SetText(os.Getenv("CF_API_EMAIL")) - - grid.NewLabel("shell env $CF_API_KEY") - CFdialog.apiNode = grid.NewLabel("type") - CFdialog.apiNode.SetText(os.Getenv("CF_API_KEY")) - - grid.NewLabel("Resource Record ID") - CFdialog.rrNode = grid.NewLabel("type") - CFdialog.rrNode.SetText(os.Getenv("cloudflare RR id")) - - grid.NewLabel("Record Type") - CFdialog.TypeNode = grid.NewCombobox("type") - CFdialog.TypeNode.AddText("A") - CFdialog.TypeNode.AddText("AAAA") - CFdialog.TypeNode.AddText("CNAME") - CFdialog.TypeNode.AddText("TXT") - CFdialog.TypeNode.AddText("MX") - CFdialog.TypeNode.AddText("NS") - CFdialog.TypeNode.Custom = func () { - DoChange() - } - CFdialog.TypeNode.SetText("AAAA") - - grid.NewLabel("Name (usually the hostname)") - CFdialog.NameNode = grid.NewCombobox("name") - CFdialog.NameNode.AddText("www") - CFdialog.NameNode.AddText("mail") - CFdialog.NameNode.AddText("git") - CFdialog.NameNode.AddText("go") - CFdialog.NameNode.AddText("blog") - CFdialog.NameNode.AddText("ns1") - CFdialog.NameNode.Custom = func () { - DoChange() - } - CFdialog.NameNode.SetText("www") - - grid.NewLabel("Cloudflare Proxy") - CFdialog.proxyNode = grid.NewDropdown("proxy") - CFdialog.proxyNode.AddText("On") - CFdialog.proxyNode.AddText("Off") - CFdialog.proxyNode.Custom = func () { - DoChange() - } - CFdialog.proxyNode.SetText("Off") - - grid.NewLabel("Value") - CFdialog.ValueNode = grid.NewCombobox("value") - CFdialog.ValueNode.AddText("127.0.0.1") - CFdialog.ValueNode.AddText("2001:4860:4860::8888") - CFdialog.ValueNode.AddText("ipv6.wit.com") - CFdialog.ValueNode.Custom = func () { - DoChange() - } - CFdialog.ValueNode.SetText("127.0.0.1") - CFdialog.ValueNode.Expand() - - grid.NewLabel("URL") - CFdialog.urlNode = grid.NewLabel("URL") - - group.NewLabel("curl") - CFdialog.curlNode = group.NewTextbox("curl") - CFdialog.curlNode.Custom = func () { - DoChange() - } - CFdialog.curlNode.SetText("put the curl text here") - - CFdialog.resultNode = group.NewTextbox("result") - CFdialog.resultNode.SetText("API response will show here") - - CFdialog.saveNode = group.NewButton("Save", func () { - dnsRow := DoChange() - result := curlPost(dnsRow) - CFdialog.resultNode.SetText(result) - // CreateCurlRR() - // url, data := CreateCurlRR() - // result := curl(url, data) - // CFdialog.resultNode.SetText(result) - }) - // CFdialog.saveNode.Disable() - - group.Pad() - grid.Pad() - grid.Expand() -} - -/* -func CreateCurlRR() (string, string) { - // enable the Save/Create Button - if (CFdialog.saveNode != nil) { - CFdialog.saveNode.Enable() - } - - if (CFdialog.TypeNode != nil) { - CFdialog.Type = CFdialog.TypeNode.S - } - if (CFdialog.NameNode != nil) { - CFdialog.Name = CFdialog.NameNode.S - } - if (CFdialog.proxyNode != nil) { - if (CFdialog.proxyNode.S == "On") { - CFdialog.ProxyS = "true" - } else { - CFdialog.ProxyS = "false" - } - } - if (CFdialog.ValueNode != nil) { - CFdialog.Content = CFdialog.ValueNode.S - } - CFdialog.Ttl = "3600" - - var url string = "https://api.cloudflare.com/client/v4/zones/" + CFdialog.ID + "/dns_records" - // https://api.cloudflare.com/client/v4/zones/zone_identifier/dns_records \ - // var authKey string = os.Getenv("CF_API_KEY") - // var email string = os.Getenv("CF_API_EMAIL") - - // make a json record to send on port 80 to cloudflare - var tmp string - tmp = `{"content": "` + CFdialog.Content + `", ` - tmp += `"name": "` + CFdialog.Name + `", ` - tmp += `"type": "` + CFdialog.Type + `", ` - tmp += `"ttl": ` + CFdialog.Ttl + `, ` - tmp += `"proxied": ` + CFdialog.ProxyS + `, ` - tmp += `"comment": "WIT DNS Control Panel"` - tmp += `}` - data := []byte(tmp) - - log.Println("http PUT url =", url) - // log.Println("http PUT data =", data) - // spew.Dump(data) - pretty, _ := FormatJSON(string(data)) - log.Println("http URL =", url) - log.Println("http PUT data =", pretty) - if (CFdialog.curlNode != nil) { - CFdialog.curlNode.SetText("URL: " + url + "\n" + pretty) - } - - return url, tmp -} -*/ diff --git a/cloudflare/durationSlider.go b/cloudflare/durationSlider.go index 0d9559b..1ab0e50 100644 --- a/cloudflare/durationSlider.go +++ b/cloudflare/durationSlider.go @@ -9,6 +9,8 @@ import ( "go.wit.com/gui" ) +// TODO: use: https://github.com/robfig/cron/ + // ttl := cloudflare.DurationSlider(g2, "control panel TTL (in tenths of seconds)", 10 * time.Millisecond, 5 * time.Second) // ttl.Set(200 * time.Millisecond) diff --git a/cloudflare/http.go b/cloudflare/http.go index f258f61..1917c8b 100644 --- a/cloudflare/http.go +++ b/cloudflare/http.go @@ -3,7 +3,6 @@ package cloudflare import ( "log" - "fmt" "io/ioutil" "net/http" "bytes" @@ -27,45 +26,43 @@ curl --request POST \ }' */ -func httpPut(dnsRow *RRT) (string, string) { - var url string = cloudflareURL + dnsRow.ZoneID + "/dns_records/" + dnsRow.ID - var authKey string = dnsRow.Auth - var email string = dnsRow.Email - - var tmp string - tmp = makeJSON(dnsRow) - data := []byte(tmp) +func doCurl(method string, rr *RRT) string { + var err error + var req *http.Request - log.Println("http PUT url =", url) - // log.Println("http PUT data =", data) - // spew.Dump(data) - pretty, _ := FormatJSON(string(data)) - log.Println("http PUT data =", pretty) + data := []byte(rr.data) - req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(data)) + if (method == "PUT") { + req, err = http.NewRequest(http.MethodPut, rr.url, bytes.NewBuffer(data)) + } else { + req, err = http.NewRequest(http.MethodPost, rr.url, bytes.NewBuffer(data)) + } // Set headers req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Auth-Key", authKey) - req.Header.Set("X-Auth-Email", email) + req.Header.Set("X-Auth-Key", rr.Auth) + req.Header.Set("X-Auth-Email", rr.Email) + + log.Println("http PUT url =", rr.url) + log.Println("http PUT Auth =", rr.Auth) + log.Println("http PUT Email =", rr.Email) + log.Println("http PUT data =", rr.data) client := &http.Client{} resp, err := client.Do(req) if err != nil { log.Println(err) - return tmp, fmt.Sprintf("blah err =", err) + return "" } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println(err) - return tmp, fmt.Sprintf("blah err =", err) + return "" } - // log.Println("http PUT body =", body) - // spew.Dump(body) - return tmp, string(body) + return string(body) } func curlPost(dnsRow *RRT) string { @@ -75,10 +72,10 @@ func curlPost(dnsRow *RRT) string { url := dnsRow.url tmp := dnsRow.data - log.Println("curl() START") - log.Println("curl() authkey = ", authKey) - log.Println("curl() email = ", email) - log.Println("curl() url = ", url) + log.Println("curlPost() START") + log.Println("curlPost() authkey = ", authKey) + log.Println("curlPost() email = ", email) + log.Println("curlPost() url = ", url) data := []byte(tmp) req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data)) diff --git a/cloudflare/mainWindow.go b/cloudflare/mainWindow.go index dddb0b7..af5b221 100644 --- a/cloudflare/mainWindow.go +++ b/cloudflare/mainWindow.go @@ -9,7 +9,7 @@ import ( ) // This creates a window -func MakeCloudflareWindow(n *gui.Node) { +func MakeCloudflareWindow(n *gui.Node) *gui.Node { CFdialog.rootGui = n var t *gui.Node @@ -54,6 +54,7 @@ func MakeCloudflareWindow(n *gui.Node) { showCloudflareCredentials(more) makeDebugWindow(CFdialog.mainWindow) + return CFdialog.mainWindow } func makeConfigWindow(n *gui.Node) { diff --git a/cloudflare/oneLiner.go b/cloudflare/oneLiner.go new file mode 100644 index 0000000..5fc7a51 --- /dev/null +++ b/cloudflare/oneLiner.go @@ -0,0 +1,42 @@ +// This is a simple example +package cloudflare + +import ( + "log" + + "go.wit.com/gui" +) + +type OneLiner struct { + p *gui.Node // parent widget + l *gui.Node // label widget + v *gui.Node // value widget + + value string + label string + + Custom func() +} + +func (n *OneLiner) Set(value string) { + log.Println("OneLiner.Set() =", value) + n.v.Set(value) + n.value = value +} + +func NewOneLiner(n *gui.Node, name string) *OneLiner { + d := OneLiner { + p: n, + value: "", + } + + // various timeout settings + d.l = n.NewLabel(name) + d.v = n.NewLabel("") + d.v.Custom = func() { + d.value = d.v.S + log.Println("OneLiner.Custom() user changed value to =", d.value) + } + + return &d +} diff --git a/cloudflare/rr.go b/cloudflare/rr.go new file mode 100644 index 0000000..05065b2 --- /dev/null +++ b/cloudflare/rr.go @@ -0,0 +1,157 @@ +/* + This will let you edit a single Resource Record within + a DNS zone file. For example: + google-dns.wit.com. 1 IN A 8.8.8.8 +*/ + +package cloudflare + +import ( + "log" + "os" + + "go.wit.com/gui" +) + +func init() { + Config = make(map[string]*ConfigT) +} + +func CreateRR(myGui *gui.Node, zone string, zoneID string) { + if (CFdialog.cloudflareW != nil) { + // skip this if the window has already been created + log.Println("createRR() the cloudflare window already exists") + CFdialog.cloudflareB.Disable() + return + } + CFdialog.cloudflareW = myGui.NewWindow("cloudflare " + zone + " API") + CFdialog.cloudflareW.Custom = func () { + log.Println("createRR() don't really exit here") + CFdialog.cloudflareW = nil + CFdialog.cloudflareB.Enable() + } + + group := CFdialog.cloudflareW.NewGroup("Create a new DNS Resource Record (rr)") + + // make a grid 2 things wide + grid := group.NewGrid("gridnuts", 2, 3) + + grid.NewLabel("zone") + CFdialog.zoneNode = grid.NewLabel("zone") + CFdialog.zoneNode.SetText(zone) + + grid.NewLabel("zone ID") + CFdialog.zoneIdNode = grid.NewLabel("zoneID") + CFdialog.zoneIdNode.SetText(zoneID) + + grid.NewLabel("shell env $CF_API_EMAIL") + CFdialog.emailNode = grid.NewLabel("type") + CFdialog.emailNode.SetText(os.Getenv("CF_API_EMAIL")) + + grid.NewLabel("shell env $CF_API_KEY") + CFdialog.apiNode = grid.NewLabel("type") + CFdialog.apiNode.SetText(os.Getenv("CF_API_KEY")) + + grid.NewLabel("Resource Record ID") + CFdialog.rrNode = grid.NewLabel("type") + CFdialog.rrNode.SetText(os.Getenv("cloudflare RR id")) + + grid.NewLabel("Record Type") + CFdialog.TypeNode = grid.NewCombobox("type") + CFdialog.TypeNode.AddText("A") + CFdialog.TypeNode.AddText("AAAA") + CFdialog.TypeNode.AddText("CNAME") + CFdialog.TypeNode.AddText("TXT") + CFdialog.TypeNode.AddText("MX") + CFdialog.TypeNode.AddText("NS") + CFdialog.TypeNode.Custom = func () { + DoChange() + } + CFdialog.TypeNode.SetText("AAAA") + + grid.NewLabel("Name (usually the hostname)") + CFdialog.NameNode = grid.NewCombobox("name") + CFdialog.NameNode.AddText("www") + CFdialog.NameNode.AddText("mail") + CFdialog.NameNode.AddText("git") + CFdialog.NameNode.AddText("go") + CFdialog.NameNode.AddText("blog") + CFdialog.NameNode.AddText("ns1") + CFdialog.NameNode.Custom = func () { + DoChange() + } + CFdialog.NameNode.SetText("www") + + grid.NewLabel("Cloudflare Proxy") + CFdialog.proxyNode = grid.NewDropdown("proxy") + CFdialog.proxyNode.AddText("On") + CFdialog.proxyNode.AddText("Off") + CFdialog.proxyNode.Custom = func () { + DoChange() + } + CFdialog.proxyNode.SetText("Off") + + grid.NewLabel("Value") + CFdialog.ValueNode = grid.NewCombobox("value") + CFdialog.ValueNode.AddText("127.0.0.1") + CFdialog.ValueNode.AddText("2001:4860:4860::8888") + CFdialog.ValueNode.AddText("ipv6.wit.com") + CFdialog.ValueNode.Custom = func () { + DoChange() + } + CFdialog.ValueNode.SetText("127.0.0.1") + CFdialog.ValueNode.Expand() + + grid.NewLabel("URL") + CFdialog.urlNode = grid.NewLabel("URL") + + group.NewLabel("curl") + CFdialog.curlNode = group.NewTextbox("curl") + CFdialog.curlNode.Custom = func () { + DoChange() + } + CFdialog.curlNode.SetText("put the curl text here") + + CFdialog.resultNode = group.NewTextbox("result") + CFdialog.resultNode.SetText("API response will show here") + + CFdialog.SaveNode = group.NewButton("Save curlPost()", func () { + dnsRow := DoChange() + result := curlPost(dnsRow) + CFdialog.resultNode.SetText(result) + // CreateCurlRR() + // url, data := CreateCurlRR() + // result := curl(url, data) + // CFdialog.resultNode.SetText(result) + }) + // CFdialog.saveNode.Disable() + group.NewButton("New RR doCurl(PUT)", func () { + rr := DoChange() + + rr.url = "https://api.cloudflare.com/client/v4/zones/" + rr.ZoneID + "/dns_records" + + result := doCurl("POST", rr) + CFdialog.resultNode.SetText(result) + + pretty, _ := FormatJSON(result) + log.Println(pretty) + }) + + group.NewButton("Update RR doCurl(PUT)", func () { + rr := DoChange() + + rr.url = "https://api.cloudflare.com/client/v4/zones/" + rr.ZoneID + "/dns_records/" + rr.ID + + result := doCurl("PUT", rr) + CFdialog.resultNode.SetText(result) + + pretty, _ := FormatJSON(result) + log.Println(pretty) + }) + // CFdialog.saveNode.Disable() + + + group.Pad() + grid.Pad() + grid.Expand() +} diff --git a/cloudflare/structs.go b/cloudflare/structs.go index f0a23d8..9efef62 100644 --- a/cloudflare/structs.go +++ b/cloudflare/structs.go @@ -50,7 +50,7 @@ type dialogT struct { ttlNode *gui.Node // just set to 1 which means automatic to cloudflare curlNode *gui.Node // shows you what you could run via curl resultNode *gui.Node // what the cloudflare API returned - saveNode *gui.Node // button to send it to cloudflare + SaveNode *gui.Node // button to send it to cloudflare zoneNode *gui.Node // "wit.com" zoneIdNode *gui.Node // cloudflare zone ID -- cgit v1.2.3