diff --git a/README.md b/README.md index b6824c0..68f5ddf 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,29 @@ For DNSPod, you need to provide email & password, and config all the domains & "socks5_proxy": "" } ``` + +### Config example for Cloudflare + +For Cloudflare, you need to provide email & Global API Key as password, and config all the domains & subdomains. + +```json +{ + "provider": "Cloudflare", + "email": "you@example.com", + "password": "Global API Key", + "domains": [{ + "domain_name": "example.com", + "sub_domains": ["www","test"] + },{ + "domain_name": "example2.com", + "sub_domains": ["www","test"] + } + ], + "ip_url": "https://myip.biturl.top", + "interval": 300, + "socks5_proxy": "" +} +``` ### Config example for AliDNS For AliDNS, you need to provide `AccessKeyID` & `AccessKeySecret` as `email` & `password`, and config all the domains & subdomains. diff --git a/handler/google/google_handler.go b/handler/google/google_handler.go new file mode 100644 index 0000000..8c4604e --- /dev/null +++ b/handler/google/google_handler.go @@ -0,0 +1,115 @@ +package google + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "net/url" + "runtime/debug" + "strings" + "time" + + "github.com/TimothyYe/godns" + + "golang.org/x/net/proxy" +) + +var ( + // GoogleUrl the API address for Google Domains + GoogleUrl = "https://domains.google.com/nic/update" +) + +// 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 + } + }() + + var lastIP string + + for { + currentIP, err := godns.GetCurrentIP(handler.Configuration) + + if err != nil { + log.Println("get_currentIP:", err) + continue + } + log.Println("currentIP is:", currentIP) + + //check against locally cached IP, if no change, skip update + if currentIP == lastIP { + log.Printf("IP is the same as cached one. Skip update.\n") + } else { + lastIP = currentIP + + for _, subDomain := range domain.SubDomains { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(domain.DomainName, subDomain, currentIP) + + // Send mail notification if notify is enabled + if handler.Configuration.Notify.Enabled { + log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) + if err := godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP); err != nil { + log.Println("Failed to send notificaiton") + } + } + } + } + // 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(domain, subDomain, currentIP string) { + values := url.Values{} + values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) + values.Add("username:password", fmt.Sprintf("%s:%s", handler.Configuration.Email, handler.Configuration.Password)) + values.Add("myip", currentIP) + + client := &http.Client{} + + if handler.Configuration.Socks5Proxy != "" { + log.Println("use socks5 proxy:" + handler.Configuration.Socks5Proxy) + dialer, err := proxy.SOCKS5("tcp", handler.Configuration.Socks5Proxy, nil, proxy.Direct) + if err != nil { + log.Println("can't connect to the proxy:", err) + return + } + + httpTransport := &http.Transport{} + client.Transport = httpTransport + httpTransport.Dial = dialer.Dial + } + + req, _ := http.NewRequest("POST", GoogleUrl, strings.NewReader(values.Encode())) + 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 df514cf..0dccf33 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/google" "github.com/TimothyYe/godns/handler/he" ) @@ -27,6 +28,8 @@ func CreateHandler(provider string) IHandler { handler = IHandler(&he.Handler{}) case godns.ALIDNS: handler = IHandler(&alidns.Handler{}) + case godns.GOOGLE: + handler = IHandler(&google.Handler{}) } return handler diff --git a/utils.go b/utils.go index 4f202a0..d9430ab 100644 --- a/utils.go +++ b/utils.go @@ -42,6 +42,8 @@ const ( CLOUDFLARE = "Cloudflare" // ALIDNS for AliDNS ALIDNS = "AliDNS" + // GOOGLE for Google Domains + GOOGLE = "Google" ) //GetIPFromInterface gets IP address from the specific interface