From f2e9c0ab00f1a36ca6f86ebc03158e4b72697778 Mon Sep 17 00:00:00 2001 From: Eri Bastos Date: Mon, 27 Apr 2020 14:05:37 -0400 Subject: [PATCH] Add dreamhost handler --- go.mod | 1 + go.sum | 2 + handler/dreamhost/dreamhost_handler.go | 124 +++++++++++++++++++++++++ handler/handler.go | 3 + utils.go | 7 ++ 5 files changed, 137 insertions(+) create mode 100644 handler/dreamhost/dreamhost_handler.go diff --git a/go.mod b/go.mod index 0eaa091..2184793 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ require ( github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6 github.com/fatih/color v1.7.0 + github.com/google/uuid v1.1.1 github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-colorable v0.0.9 // indirect github.com/mattn/go-isatty v0.0.4 // indirect diff --git a/go.sum b/go.sum index 35d85dd..ef880d2 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6 h1:oV1V+u github.com/bogdanovich/dns_resolver v0.0.0-20170211073258-a8e42bc6a5b6/go.mod h1:txOV61Nn+21z77KUMkNsp8lTHoOFTtqotltQAFenS9I= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/handler/dreamhost/dreamhost_handler.go b/handler/dreamhost/dreamhost_handler.go new file mode 100644 index 0000000..924f4a6 --- /dev/null +++ b/handler/dreamhost/dreamhost_handler.go @@ -0,0 +1,124 @@ +package dreamhost + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "runtime/debug" + "strings" + "time" + + "github.com/TimothyYe/godns" + "github.com/google/uuid" +) + +var ( + // DreamhostURL the API address for dreamhost.com + DreamhostURL = "https://api.dreamhost.com" +) + +// Handler struct +type Handler struct { + Configuration *godns.Settings +} + +// SetConfiguration pass dns settings and store it to handler instance +func (handler *Handler) SetConfiguration(conf *godns.Settings) { + handler.Configuration = conf +} + +// DomainLoop the main logic loop +func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) { + defer func() { + if err := recover(); err != nil { + log.Printf("Recovered in %v: %v\n", err, debug.Stack()) + panicChan <- *domain + } + }() + + for { + currentIP, err := godns.GetCurrentIP(handler.Configuration) + + if err != nil { + log.Println("get_currentIP:", err) + continue + } + log.Println("currentIP is:", currentIP) + + for _, subDomain := range domain.SubDomains { + hostname := subDomain + "." + domain.DomainName + lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver) + //check against currently known IP, if no change, skip update + if currentIP == lastIP { + log.Printf("IP is the same as cached one. Skip update.\n") + } else { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(hostname, currentIP, lastIP) + + // Send notification + if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil { + log.Println("Failed to send notification") + } + } + } + + // Sleep with interval + log.Printf("Going to sleep, will start next checking in %d seconds...\r\n", handler.Configuration.Interval) + time.Sleep(time.Second * time.Duration(handler.Configuration.Interval)) + } + +} + +// UpdateIP update subdomain with current IP +func (handler *Handler) UpdateIP(hostname, currentIP, lastIP string) { + + handler.updateDNS(lastIP, currentIP, hostname, "remove") + handler.updateDNS(lastIP, currentIP, hostname, "add") + +} + +// updateDNS can add or remove DNS records. +func (handler *Handler) updateDNS(dns, ip, hostname, action string) { + // Generates UUID + uid, _ := uuid.NewRandom() + values := url.Values{} + values.Add("record", hostname) + values.Add("key", handler.Configuration.LoginToken) + values.Add("type", "A") + values.Add("unique_id", uid.String()) + switch action { + case "remove": + // Build URL query (remove) + values.Add("cmd", "dns-remove_record") + values.Add("value", dns) + case "add": + // Build URL query (add) + values.Add("cmd", "dns-add_record") + values.Add("value", ip) + default: + log.Fatalf("Unknown action %s\n", action) + } + + client := godns.GetHttpClient(handler.Configuration) + req, _ := http.NewRequest("POST", DreamhostURL, strings.NewReader(values.Encode())) + req.SetBasicAuth(handler.Configuration.Email, handler.Configuration.Password) + + if handler.Configuration.UserAgent != "" { + req.Header.Add("User-Agent", handler.Configuration.UserAgent) + } + + resp, err := client.Do(req) + if err != nil { + log.Println("Request error...") + log.Println("Err:", err.Error()) + } else { + body, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode == http.StatusOK { + log.Println("Update IP success:", string(body)) + } else { + log.Println("Update IP failed:", string(body)) + } + } +} diff --git a/handler/handler.go b/handler/handler.go index 0b15fae..4455fd4 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -5,6 +5,7 @@ import ( "github.com/TimothyYe/godns/handler/alidns" "github.com/TimothyYe/godns/handler/cloudflare" "github.com/TimothyYe/godns/handler/dnspod" + "github.com/TimothyYe/godns/handler/dreamhost" "github.com/TimothyYe/godns/handler/duck" "github.com/TimothyYe/godns/handler/google" "github.com/TimothyYe/godns/handler/he" @@ -25,6 +26,8 @@ func CreateHandler(provider string) IHandler { handler = IHandler(&cloudflare.Handler{}) case godns.DNSPOD: handler = IHandler(&dnspod.Handler{}) + case godns.DREAMHOST: + handler = IHandler(&dreamhost.Handler{}) case godns.HE: handler = IHandler(&he.Handler{}) case godns.ALIDNS: diff --git a/utils.go b/utils.go index c094694..9c95b7e 100644 --- a/utils.go +++ b/utils.go @@ -49,6 +49,8 @@ const ( GOOGLE = "Google" // DUCK for Duck DNS DUCK = "DuckDNS" + // DREAMHOST for Dreamhost + DREAMHOST = "Dreamhost" // IPV4 for IPV4 mode IPV4 = "IPV4" // IPV6 for IPV6 mode @@ -218,6 +220,11 @@ func CheckSettings(config *Settings) error { if config.Password == "" { return errors.New("password cannot be empty") } + case DREAMHOST: + if config.LoginToken == "" { + return errors.New("login token cannot be empty") + } + default: return errors.New("please provide supported DNS provider: DNSPod/HE/AliDNS/Cloudflare/GoogleDomain/DuckDNS")