From 975d7062b682ff631c74fa60097647b5e0fe848d Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 17 Aug 2017 09:57:41 +0800 Subject: [PATCH 01/99] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f7f4e16..b0bc57c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ GoDNS is a dynamic DNS (DDNS) tool, it is based on my early open source project: Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). +__For MIPS32 platform__, please checkout the __mips32__ branch, this branch is contributed by [hguandl](https://github.com/hguandl), it provides the support for mips32 is added, which means it could run properly on Openwrt and LEDE. + ## Pre-condition * GoDNS relies on [DNSPod](http://dnspod.cn) and its API. From 9885d599404dad29660934bb6720b8fb33574a73 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 17 Aug 2017 09:59:45 +0800 Subject: [PATCH 02/99] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b0bc57c..19cdfb3 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ GoDNS is a dynamic DNS (DDNS) tool, it is based on my early open source project: Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). -__For MIPS32 platform__, please checkout the __mips32__ branch, this branch is contributed by [hguandl](https://github.com/hguandl), it provides the support for mips32 is added, which means it could run properly on Openwrt and LEDE. +## MIPS32 Platform + +For MIPS32 platform, please checkout the __mips32__ branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. ## Pre-condition From f9bd43d299e095aa9089c916a1266218ea787e69 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 17 Aug 2017 10:02:12 +0800 Subject: [PATCH 03/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19cdfb3..31e9667 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call i ## MIPS32 Platform -For MIPS32 platform, please checkout the __mips32__ branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. +For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/godns/tree/mips32) branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. ## Pre-condition From e421c27afc939d7f30950e4cf7b18aa461c04788 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 17 Aug 2017 10:36:58 +0800 Subject: [PATCH 04/99] format code --- dns_handler.go | 5 +++-- settings.go | 18 +++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dns_handler.go b/dns_handler.go index 5bef4ca..59f3952 100644 --- a/dns_handler.go +++ b/dns_handler.go @@ -9,8 +9,9 @@ import ( "net/url" "strconv" "strings" - "golang.org/x/net/proxy" + "github.com/bitly/go-simplejson" + "golang.org/x/net/proxy" ) func getCurrentIP(url string) (string, error) { @@ -193,7 +194,7 @@ func postData(url string, content url.Values) (string, error) { } values := generateHeader(content) - req, _ := http.NewRequest("POST", "https://dnsapi.cn" + url, strings.NewReader(values.Encode())) + req, _ := http.NewRequest("POST", "https://dnsapi.cn"+url, strings.NewReader(values.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("User-Agent", fmt.Sprintf("GoDNS/0.1 (%s)", configuration.Email)) diff --git a/settings.go b/settings.go index 54b4936..b94d85e 100644 --- a/settings.go +++ b/settings.go @@ -14,15 +14,15 @@ type Domain struct { //Settings struct type Settings struct { - Email string `json:"email"` - Password string `json:"password"` - LoginToken string `json:"login_token"` - Domains []Domain `json:"domains"` - IPUrl string `json:"ip_url"` - LogPath string `json:"log_path"` - LogSize int `json:"log_size"` - LogNum int `json:"log_num"` - Socks5Proxy string `json:"socks5_proxy"` + Email string `json:"email"` + Password string `json:"password"` + LoginToken string `json:"login_token"` + Domains []Domain `json:"domains"` + IPUrl string `json:"ip_url"` + LogPath string `json:"log_path"` + LogSize int `json:"log_size"` + LogNum int `json:"log_num"` + Socks5Proxy string `json:"socks5_proxy"` } //LoadSettings -- Load settings from config file From 17f41e45f834962e3625b8ddbb84aaa4a73e3ded Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 17 Aug 2017 11:07:31 +0800 Subject: [PATCH 05/99] fix golint warnings --- dns_handler.go | 2 +- godns.go | 10 +-- logger.go | 176 +++++++++++++++++++++++++++---------------------- settings.go | 1 + 4 files changed, 105 insertions(+), 84 deletions(-) diff --git a/dns_handler.go b/dns_handler.go index 59f3952..29fb465 100644 --- a/dns_handler.go +++ b/dns_handler.go @@ -41,7 +41,7 @@ func generateHeader(content url.Values) url.Values { header.Add("error_on_empty", "no") if content != nil { - for k, _ := range content { + for k := range content { header.Add(k, content.Get(k)) } } diff --git a/godns.go b/godns.go index 3af621d..a941e46 100644 --- a/godns.go +++ b/godns.go @@ -11,8 +11,10 @@ import ( ) const ( + //Max allowed panic times PANIC_MAX = 5 - INTERVAL = 5 //Minute + //Minute + INTERVAL = 5 ) var ( @@ -72,13 +74,13 @@ func main() { func dnsLoop() { for _, domain := range configuration.Domains { - go DomainLoop(&domain) + go domainLoop(&domain) } select {} } -func DomainLoop(domain *Domain) { +func domainLoop(domain *Domain) { defer func() { if err := recover(); err != nil { panicCount++ @@ -87,7 +89,7 @@ func DomainLoop(domain *Domain) { log.Print(identifyPanic()) if panicCount < PANIC_MAX { log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go DomainLoop(domain) + go domainLoop(domain) } else { os.Exit(1) } diff --git a/logger.go b/logger.go index a6474c1..a3a3a52 100644 --- a/logger.go +++ b/logger.go @@ -16,14 +16,21 @@ import ( ) const ( + //L_INFO log level L_INFO int = iota + //L_WARNING log level L_WARNING + //L_DEBUG log level L_DEBUG - PRE_INFO = "[ INFO]" + //PRE_INFO log level + PRE_INFO = "[ INFO]" + //PRE_WARNING log level PRE_WARNING = "[WARNING]" - PRE_DEBUG = "[ DEBUG]" + //PRE_DEBUG log level + PRE_DEBUG = "[ DEBUG]" ) +//Logger struct type Logger struct { DEV_MODE bool fd *os.File @@ -38,6 +45,7 @@ type Logger struct { log *log.Logger } +//NewLogger returns a new created logger func NewLogger(logfile string, size, num int, level int, flushInterval int64, flushSize int) (logger *Logger, err error) { if size < 1 || num < 1 || level < L_INFO || len(logfile) < 1 { err = errors.New("NewLogWriter:param error.") @@ -69,6 +77,7 @@ func NewLogger(logfile string, size, num int, level int, flushInterval int64, fl return } +//InitLogger initialize logger with specified log filename & size func InitLogger(logfile string, size, num int) (err error) { logger, err := NewLogger(logfile, size, num, L_INFO, -1, -1) if logger != nil { @@ -78,27 +87,27 @@ func InitLogger(logfile string, size, num int) (err error) { } //immplement write -func (this *Logger) Write(p []byte) (n int, err error) { - if this.DEV_MODE { +func (logger *Logger) Write(p []byte) (n int, err error) { + if logger.DEV_MODE { n, err = os.Stdout.Write(p) return } - n, err = this.fd.Write(p) + n, err = logger.fd.Write(p) if err == nil { - fi, e := this.fd.Stat() + fi, e := logger.fd.Stat() if e != nil { err = e return } - if fi.Size() > int64(this.size) { - this.muSplit.Lock() - defer this.muSplit.Unlock() + if fi.Size() > int64(logger.size) { + logger.muSplit.Lock() + defer logger.muSplit.Unlock() fname := fi.Name() strings.HasSuffix(fname, ".log") fbase := fname[:len(fname)-3] - oldBs := make([]byte, 0, this.size) + oldBs := make([]byte, 0, logger.size) newBs := []byte{} fd, e := os.Open(fname) if e != nil { @@ -115,7 +124,7 @@ func (this *Logger) Write(p []byte) (n int, err error) { err = e return } - if len(oldBs)+len(line) > this.size { + if len(oldBs)+len(line) > logger.size { newBs = append(newBs, line...) } else { oldBs = append(oldBs, line...) @@ -123,11 +132,11 @@ func (this *Logger) Write(p []byte) (n int, err error) { } fd.Close() - _, err = this.saveLog(1, fbase, oldBs) + _, err = logger.saveLog(1, fbase, oldBs) if err != nil { return } - err = this.fd.Close() + err = logger.fd.Close() if err != nil { return } @@ -135,11 +144,11 @@ func (this *Logger) Write(p []byte) (n int, err error) { if err != nil { return } - this.fd, err = os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666) + logger.fd, err = os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666) if err != nil { return } - _, err = this.fd.Write(newBs) + _, err = logger.fd.Write(newBs) if err != nil { return } @@ -148,16 +157,16 @@ func (this *Logger) Write(p []byte) (n int, err error) { return } -func (this *Logger) saveLog(index int, fbase string, data []byte) (n int, err error) { +func (logger *Logger) saveLog(index int, fbase string, data []byte) (n int, err error) { fn := fbase + strconv.Itoa(index) + ".log" _, err = os.Stat(fn) - if index < this.num && err == nil { + if index < logger.num && err == nil { var b []byte b, err = ioutil.ReadFile(fn) if err != nil { return } - n, err = this.saveLog(index+1, fbase, b) + n, err = logger.saveLog(index+1, fbase, b) if err != nil { return } @@ -172,121 +181,130 @@ func (this *Logger) saveLog(index int, fbase string, data []byte) (n int, err er return } -//flush buf data to std log -func (this *Logger) Flush() { - if this.buf.Len() > 0 { - this.mu.Lock() - defer this.mu.Unlock() +//Flush buf data to std log +func (logger *Logger) Flush() { + if logger.buf.Len() > 0 { + logger.mu.Lock() + defer logger.mu.Unlock() log.SetFlags(0) - log.Print(this.buf) + log.Print(logger.buf) log.SetFlags(log.LstdFlags) - this.buf.Reset() + logger.buf.Reset() } } -//clean prefix and check buf size -func (this *Logger) clean() { - this.log.SetPrefix("") - if this.buf.Len()/1024 > this.flushSize { - go this.Flush() +//Clean prefix and check buf size +func (logger *Logger) clean() { + logger.log.SetPrefix("") + if logger.buf.Len()/1024 > logger.flushSize { + go logger.Flush() } } -func (this *Logger) setPrefix(lv int) bool { - if lv > this.level { +func (logger *Logger) setPrefix(lv int) bool { + if lv > logger.level { return false } switch lv { case L_INFO: - this.log.SetPrefix(PRE_INFO) + logger.log.SetPrefix(PRE_INFO) case L_WARNING: - this.log.SetPrefix(PRE_WARNING) + logger.log.SetPrefix(PRE_WARNING) case L_DEBUG: - this.log.SetPrefix(PRE_DEBUG) + logger.log.SetPrefix(PRE_DEBUG) default: return false } return true } -func (this *Logger) logPrint(lv int, args ...interface{}) { - this.mu.Lock() - defer this.mu.Unlock() +func (logger *Logger) logPrint(lv int, args ...interface{}) { + logger.mu.Lock() + defer logger.mu.Unlock() - if !this.setPrefix(lv) { + if !logger.setPrefix(lv) { return } - this.log.Print(args...) - this.clean() + logger.log.Print(args...) + logger.clean() } -func (this *Logger) logPrintln(lv int, args ...interface{}) { - this.mu.Lock() - defer this.mu.Unlock() +func (logger *Logger) logPrintln(lv int, args ...interface{}) { + logger.mu.Lock() + defer logger.mu.Unlock() - if !this.setPrefix(lv) { + if !logger.setPrefix(lv) { return } - this.log.Println(args...) - this.clean() + logger.log.Println(args...) + logger.clean() } -func (this *Logger) logPrintf(lv int, format string, args ...interface{}) { - this.mu.Lock() - defer this.mu.Unlock() +func (logger *Logger) logPrintf(lv int, format string, args ...interface{}) { + logger.mu.Lock() + defer logger.mu.Unlock() - if !this.setPrefix(lv) { + if !logger.setPrefix(lv) { return } - this.log.Printf(format, args...) - this.clean() + logger.log.Printf(format, args...) + logger.clean() } -//close fd -func (this *Logger) Close() { - if this.fd != nil { - this.Flush() - this.fd.Close() +//Close fd +func (log *Logger) Close() { + if log.fd != nil { + log.Flush() + log.fd.Close() } } -func (this *Logger) Info(args ...interface{}) { - this.logPrint(L_INFO, args...) +//Info output info log +func (logger *Logger) Info(args ...interface{}) { + logger.logPrint(L_INFO, args...) } -func (this *Logger) Infoln(args ...interface{}) { - this.logPrintln(L_INFO, args...) +//Infoln output info log with newline +func (logger *Logger) Infoln(args ...interface{}) { + logger.logPrintln(L_INFO, args...) } -func (this *Logger) Infof(format string, args ...interface{}) { - this.logPrintf(L_INFO, format, args...) +//Infof output formatted info log +func (logger *Logger) Infof(format string, args ...interface{}) { + logger.logPrintf(L_INFO, format, args...) } -func (this *Logger) Warning(args ...interface{}) { - this.logPrint(L_WARNING, args...) +//Warning output warning log +func (logger *Logger) Warning(args ...interface{}) { + logger.logPrint(L_WARNING, args...) } -func (this *Logger) Warningln(args ...interface{}) { - this.logPrintln(L_WARNING, args...) +//Warningln output warning log with newline +func (logger *Logger) Warningln(args ...interface{}) { + logger.logPrintln(L_WARNING, args...) } -func (this *Logger) Warningf(format string, args ...interface{}) { - this.logPrintf(L_WARNING, format, args...) +//Warningf output formatted warning log +func (logger *Logger) Warningf(format string, args ...interface{}) { + logger.logPrintf(L_WARNING, format, args...) } -func (this *Logger) Debug(args ...interface{}) { - this.logPrint(L_DEBUG, args...) - this.Flush() +//Debug output debug log +func (logger *Logger) Debug(args ...interface{}) { + logger.logPrint(L_DEBUG, args...) + logger.Flush() } -func (this *Logger) Debugln(args ...interface{}) { - this.logPrintln(L_DEBUG, args...) - this.Flush() +//Debugln output debug log with newline +func (logger *Logger) Debugln(args ...interface{}) { + logger.logPrintln(L_DEBUG, args...) + logger.Flush() } -func (this *Logger) Debugf(format string, args ...interface{}) { - this.logPrintf(L_DEBUG, format, args...) - this.Flush() +//Debugf output formatted debug log +func (logger *Logger) Debugf(format string, args ...interface{}) { + logger.logPrintf(L_DEBUG, format, args...) + logger.Flush() } diff --git a/settings.go b/settings.go index b94d85e..e11f333 100644 --- a/settings.go +++ b/settings.go @@ -7,6 +7,7 @@ import ( "strings" ) +//Domain struct type Domain struct { DomainName string `json:"domain_name"` SubDomains []string `json:"sub_domains"` From 03d62f04986dffe9810ce5c740e790f01b6d4148 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 17 Aug 2017 11:11:00 +0800 Subject: [PATCH 06/99] fix golint warnings --- godns.go | 4 ++-- logger.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/godns.go b/godns.go index a941e46..26c2767 100644 --- a/godns.go +++ b/godns.go @@ -11,9 +11,9 @@ import ( ) const ( - //Max allowed panic times + //PANIC_MAX is the max allowed panic times PANIC_MAX = 5 - //Minute + //INTERVAL is minute INTERVAL = 5 ) diff --git a/logger.go b/logger.go index a3a3a52..50e802d 100644 --- a/logger.go +++ b/logger.go @@ -254,10 +254,10 @@ func (logger *Logger) logPrintf(lv int, format string, args ...interface{}) { } //Close fd -func (log *Logger) Close() { - if log.fd != nil { - log.Flush() - log.fd.Close() +func (logger *Logger) Close() { + if logger.fd != nil { + logger.Flush() + logger.fd.Close() } } From 3bbb84b4e06fb01cceab4e4781fb5a09278d7820 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 17 Aug 2017 12:11:07 +0800 Subject: [PATCH 07/99] fix golint warnings --- godns.go | 6 +++--- logger.go | 42 +++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/godns.go b/godns.go index 26c2767..c643472 100644 --- a/godns.go +++ b/godns.go @@ -11,9 +11,9 @@ import ( ) const ( - //PANIC_MAX is the max allowed panic times + // PANIC_MAX is the max allowed panic times PANIC_MAX = 5 - //INTERVAL is minute + // INTERVAL is minute INTERVAL = 5 ) @@ -33,7 +33,7 @@ func main() { } if *optDocker { - //Load settings from ENV + // Load settings from ENV configuration = Settings{ Email: os.Getenv("EMAIL"), Password: os.Getenv("PASSWORD"), diff --git a/logger.go b/logger.go index 50e802d..3fa9f65 100644 --- a/logger.go +++ b/logger.go @@ -16,21 +16,21 @@ import ( ) const ( - //L_INFO log level + // L_INFO log level L_INFO int = iota - //L_WARNING log level + // L_WARNING log level L_WARNING - //L_DEBUG log level + // L_DEBUG log level L_DEBUG - //PRE_INFO log level + // PRE_INFO log level PRE_INFO = "[ INFO]" - //PRE_WARNING log level + // PRE_WARNING log level PRE_WARNING = "[WARNING]" - //PRE_DEBUG log level + // PRE_DEBUG log level PRE_DEBUG = "[ DEBUG]" ) -//Logger struct +// Logger struct type Logger struct { DEV_MODE bool fd *os.File @@ -45,7 +45,7 @@ type Logger struct { log *log.Logger } -//NewLogger returns a new created logger +// NewLogger returns a new created logger func NewLogger(logfile string, size, num int, level int, flushInterval int64, flushSize int) (logger *Logger, err error) { if size < 1 || num < 1 || level < L_INFO || len(logfile) < 1 { err = errors.New("NewLogWriter:param error.") @@ -77,7 +77,7 @@ func NewLogger(logfile string, size, num int, level int, flushInterval int64, fl return } -//InitLogger initialize logger with specified log filename & size +// InitLogger initialize logger with specified log filename & size func InitLogger(logfile string, size, num int) (err error) { logger, err := NewLogger(logfile, size, num, L_INFO, -1, -1) if logger != nil { @@ -86,7 +86,7 @@ func InitLogger(logfile string, size, num int) (err error) { return } -//immplement write +// immplement write func (logger *Logger) Write(p []byte) (n int, err error) { if logger.DEV_MODE { n, err = os.Stdout.Write(p) @@ -181,7 +181,7 @@ func (logger *Logger) saveLog(index int, fbase string, data []byte) (n int, err return } -//Flush buf data to std log +// Flush buf data to std log func (logger *Logger) Flush() { if logger.buf.Len() > 0 { logger.mu.Lock() @@ -194,7 +194,7 @@ func (logger *Logger) Flush() { } } -//Clean prefix and check buf size +// Clean prefix and check buf size func (logger *Logger) clean() { logger.log.SetPrefix("") if logger.buf.Len()/1024 > logger.flushSize { @@ -253,7 +253,7 @@ func (logger *Logger) logPrintf(lv int, format string, args ...interface{}) { logger.clean() } -//Close fd +// Close fd func (logger *Logger) Close() { if logger.fd != nil { logger.Flush() @@ -261,22 +261,22 @@ func (logger *Logger) Close() { } } -//Info output info log +// Info output info log func (logger *Logger) Info(args ...interface{}) { logger.logPrint(L_INFO, args...) } -//Infoln output info log with newline +// Infoln output info log with newline func (logger *Logger) Infoln(args ...interface{}) { logger.logPrintln(L_INFO, args...) } -//Infof output formatted info log +// Infof output formatted info log func (logger *Logger) Infof(format string, args ...interface{}) { logger.logPrintf(L_INFO, format, args...) } -//Warning output warning log +// Warning output warning log func (logger *Logger) Warning(args ...interface{}) { logger.logPrint(L_WARNING, args...) } @@ -286,24 +286,24 @@ func (logger *Logger) Warningln(args ...interface{}) { logger.logPrintln(L_WARNING, args...) } -//Warningf output formatted warning log +// Warningf output formatted warning log func (logger *Logger) Warningf(format string, args ...interface{}) { logger.logPrintf(L_WARNING, format, args...) } -//Debug output debug log +// Debug output debug log func (logger *Logger) Debug(args ...interface{}) { logger.logPrint(L_DEBUG, args...) logger.Flush() } -//Debugln output debug log with newline +// Debugln output debug log with newline func (logger *Logger) Debugln(args ...interface{}) { logger.logPrintln(L_DEBUG, args...) logger.Flush() } -//Debugf output formatted debug log +// Debugf output formatted debug log func (logger *Logger) Debugf(format string, args ...interface{}) { logger.logPrintf(L_DEBUG, format, args...) logger.Flush() From 2f6ed0a2dd4acb03848ba89b24387c777c1305ea Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 17 Aug 2017 13:47:47 +0800 Subject: [PATCH 08/99] Update README.md --- README.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31e9667..a9bcc48 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,22 @@ ██║ ██║██║ ██║██║ ██║██║╚██╗██║╚════██║ ╚██████╔╝╚██████╔╝██████╔╝██║ ╚████║███████║ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ - -Latest release: V1.1 ``` -[![Build Status](https://travis-ci.org/TimothyYe/godns.svg?branch=master)](https://travis-ci.org/TimothyYe/godns) +[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Downloads][5]][6] [![Docker][3]][4] [![Go Report Card][11]][12] + +[1]: https://travis-ci.org/TimothyYe/godns.svg?branch=master +[2]: https://travis-ci.org/TimothyYe/godns +[3]: https://images.microbadger.com/badges/image/timothyye/godns.svg +[4]: https://microbadger.com/images/timothyye/godns +[5]: https://img.shields.io/badge/downloads-1.95MB-brightgreen.svg +[6]: https://github.com/TimothyYe/godns/releases +[7]: https://img.shields.io/badge/release-v1.1-brightgreen.svg +[8]: https://github.com/TimothyYe/godns/releases +[9]: https://img.shields.io/badge/license-Apache-blue.svg +[10]: LICENSE +[11]: https://goreportcard.com/badge/github.com/timothyye/godns +[12]: https://goreportcard.com/report/github.com/timothyye/godns GoDNS is a dynamic DNS (DDNS) tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). From 2a862328f71ea8fd60c660986a8e7d9ded028100 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 17 Aug 2017 17:22:15 +0800 Subject: [PATCH 09/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9bcc48..6829103 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ GoDNS is a dynamic DNS (DDNS) tool, it is based on my early open source project: Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). -## MIPS32 Platform +## MIPS32 platform For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/godns/tree/mips32) branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. From 309158486b09e42c6a1de9a7f0bfd8ea083a488d Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 7 Sep 2017 22:29:58 +0800 Subject: [PATCH 10/99] Update config_sample.json --- config_sample.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config_sample.json b/config_sample.json index 3e1f521..4eb287f 100644 --- a/config_sample.json +++ b/config_sample.json @@ -13,5 +13,6 @@ "ip_url": "http://members.3322.org/dyndns/getip", "log_path":"./godns.log", "log_size":16, - "log_num":3 + "log_num":3, + "socks5_proxy":"" } From ef3faafca7ec4954197385ee7bf71e92e687b754 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Thu, 7 Sep 2017 22:30:52 +0800 Subject: [PATCH 11/99] Update config_sample.json --- config_sample.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config_sample.json b/config_sample.json index 4eb287f..1241d5b 100644 --- a/config_sample.json +++ b/config_sample.json @@ -3,16 +3,16 @@ "password": "", "login_token": "", "domains": [{ - "domain_name":"example.com", - "sub_domains":["www","test"] + "domain_name": "example.com", + "sub_domains": ["www","test"] },{ - "domain_name":"example2.com", - "sub_domains":["www","test"] + "domain_name": "example2.com", + "sub_domains": ["www","test"] } ], "ip_url": "http://members.3322.org/dyndns/getip", - "log_path":"./godns.log", - "log_size":16, - "log_num":3, - "socks5_proxy":"" + "log_path": "./godns.log", + "log_size": 16, + "log_num": 3, + "socks5_proxy": "" } From c302352cc91a10b10a524ca89fd902f889bcb84a Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 15 Sep 2017 16:06:55 +0800 Subject: [PATCH 12/99] refactor run with docker logic --- Dockerfile | 4 ++-- godns.go | 30 +++++------------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5d5bb94..5fe2664 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:latest +FROM timothyye/alpine:3.6-glibc MAINTAINER Timothy RUN apk add --update ca-certificates RUN mkdir -p /usr/local/godns @@ -6,4 +6,4 @@ COPY godns /usr/local/godns RUN chmod +x /usr/local/godns/godns RUN rm -rf /var/cache/apk/* WORKDIR /usr/local/godns -ENTRYPOINT ["./godns", "-d"] +ENTRYPOINT ["./godns", "-c", "/usr/local/godns/config.json"] diff --git a/godns.go b/godns.go index c643472..b687425 100644 --- a/godns.go +++ b/godns.go @@ -20,7 +20,6 @@ const ( var ( configuration Settings optConf = flag.String("c", "./config.json", "Specify a config file") - optDocker = flag.Bool("d", false, "Run it as docker mode") optHelp = flag.Bool("h", false, "Show help") panicCount = 0 ) @@ -32,30 +31,11 @@ func main() { return } - if *optDocker { - // Load settings from ENV - configuration = Settings{ - Email: os.Getenv("EMAIL"), - Password: os.Getenv("PASSWORD"), - LoginToken: os.Getenv("TOKEN"), - IPUrl: "http://members.3322.org/dyndns/getip", - LogPath: "./godns.log", - LogSize: 16, - LogNum: 3, - } - - if err := LoadDomains(os.Getenv("DOMAINS"), &configuration.Domains); err != nil { - fmt.Println(err.Error()) - log.Println(err.Error()) - os.Exit(1) - } - } else { - //Load settings from configurations file - if err := LoadSettings(*optConf, &configuration); err != nil { - fmt.Println(err.Error()) - log.Println(err.Error()) - os.Exit(1) - } + //Load settings from configurations file + if err := LoadSettings(*optConf, &configuration); err != nil { + fmt.Println(err.Error()) + log.Println(err.Error()) + os.Exit(1) } if err := checkSettings(&configuration); err != nil { From 9d1c325e2a238a8bc3aa1300813aca98fa95ae74 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 15 Sep 2017 16:13:08 +0800 Subject: [PATCH 13/99] add Makefile --- .gitignore | 1 + .travis.yml | 3 +++ Makefile | 29 +++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 8b5b812..6682edb 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ _testmain.go config.json *.log *.swp +*.gz godns vendor/* diff --git a/.travis.yml b/.travis.yml index 04220fe..54f9554 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ go: - 1.7 - 1.8 +install: + go get -v + script: - cp ./config_sample.json ./config.json - go test -v ./... diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..66aeb29 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +# Binary name +BINARY=godns +# Builds the project +build: + go build -o ${BINARY} +# Installs our project: copies binaries +install: + go install +release: + # Clean + go clean + rm -rf *.gz + # Build for mac + go build + tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY} + # Build for linux + go clean + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build + tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY} + # Build for win + go clean + CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build + tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe + go clean +# Cleans our projects: deletes binaries +clean: + go clean + +.PHONY: clean build From 52a1005791e5d740437b846662e6ba00ee550aca Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 15 Sep 2017 16:17:05 +0800 Subject: [PATCH 14/99] update README file --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6829103..fdf2a4b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ [4]: https://microbadger.com/images/timothyye/godns [5]: https://img.shields.io/badge/downloads-1.95MB-brightgreen.svg [6]: https://github.com/TimothyYe/godns/releases -[7]: https://img.shields.io/badge/release-v1.1-brightgreen.svg +[7]: https://img.shields.io/badge/release-v1.2-brightgreen.svg [8]: https://github.com/TimothyYe/godns/releases [9]: https://img.shields.io/badge/license-Apache-blue.svg [10]: LICENSE @@ -106,18 +106,14 @@ Now godns supports to run in docker. * Pull godns image from docker hub: ```bash -docker pull timothyye/godns:1.0 +docker pull timothyye/godns:1.2 ``` * Run godns in container and pass config parameters to it via enviroment variables: ```bash docker run -d --name godns --restart=always \ --e EMAIL=your_dnspod_account \ --e PASSWORD=your_dnspod_password \ --e DOMAINS="your_domain1,your_domain2" DOCKER_IMAGE_ID +-v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:1.2 ``` - - ## Enjoy it! From e0dd532cfe4c699039f7658726daca93edbcb98a Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Fri, 15 Sep 2017 16:30:28 +0800 Subject: [PATCH 15/99] Update README.md --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fdf2a4b..ba92598 100644 --- a/README.md +++ b/README.md @@ -100,16 +100,13 @@ sudo systemctl enable godns sudo systemctl start godns ``` -## Run it in docker +## Run it with docker Now godns supports to run in docker. -* Pull godns image from docker hub: -```bash -docker pull timothyye/godns:1.2 -``` - -* Run godns in container and pass config parameters to it via enviroment variables: +* Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github. +* Rename it to **config.json**. +* Run godns with docker: ```bash docker run -d --name godns --restart=always \ From d6fcfcd4f5e08488e9fe7e2521eaaa0e6daba0db Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Fri, 15 Sep 2017 16:32:11 +0800 Subject: [PATCH 16/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba92598..5adaf72 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Now godns supports to run in docker. * Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github. * Rename it to **config.json**. -* Run godns with docker: +* Run GoDNS with docker: ```bash docker run -d --name godns --restart=always \ From 2b60374ac046e44f567b25e4d31623c842bc968f Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Fri, 15 Sep 2017 16:55:03 +0800 Subject: [PATCH 17/99] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 54f9554..1254ad9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: go go: - 1.7 - 1.8 + - 1.9 install: go get -v From 7005b5f17ed5544c8723dce9aec762732b41241c Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Tue, 19 Sep 2017 14:43:41 +0800 Subject: [PATCH 18/99] Delete .gitlab-ci.yml --- .gitlab-ci.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 122cdfb..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,24 +0,0 @@ -before_script: - - export GOPATH=$(pwd) - - export GOBIN=$GOPATH/bin - -stages: - - build - - test - -build-my-project: - image: golang:1.6.2 - stage: build - script: - - mkdir $GOPATH/bin - - go get - - go build - -test-my-project: - image: golang:1.6.2 - stage: test - script: - - mkdir $GOPATH/bin - - go get - - go build - - go test From a4dbb864bf2bce0979575291fc70032dd1b3e6f7 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Sun, 8 Oct 2017 22:21:25 -0500 Subject: [PATCH 19/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5adaf72..aace7fb 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ [11]: https://goreportcard.com/badge/github.com/timothyye/godns [12]: https://goreportcard.com/report/github.com/timothyye/godns -GoDNS is a dynamic DNS (DDNS) tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). +GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). From 9936fbc4e385cbac410718e0e729a32ffb9f5851 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 15:59:09 +0800 Subject: [PATCH 20/99] integrate with he dns --- dns_handler.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ godns.go | 62 ++------------------------------------------------ handler.go | 18 +++++++++++++++ he_handler.go | 6 +++++ settings.go | 1 + 5 files changed, 87 insertions(+), 60 deletions(-) create mode 100644 handler.go create mode 100644 he_handler.go diff --git a/dns_handler.go b/dns_handler.go index 29fb465..eaa2e3d 100644 --- a/dns_handler.go +++ b/dns_handler.go @@ -7,13 +7,73 @@ import ( "log" "net/http" "net/url" + "os" + "runtime/debug" "strconv" "strings" + "time" "github.com/bitly/go-simplejson" "golang.org/x/net/proxy" ) +type DNSPodHandler struct{} + +func (handler *DNSPodHandler) DomainLoop(domain *Domain) { + defer func() { + if err := recover(); err != nil { + panicCount++ + log.Printf("Recovered in %v: %v\n", err, debug.Stack()) + fmt.Println(identifyPanic()) + log.Print(identifyPanic()) + if panicCount < PANIC_MAX { + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go handler.DomainLoop(domain) + } else { + os.Exit(1) + } + } + }() + + for { + + domainID := getDomain(domain.DomainName) + + if domainID == -1 { + continue + } + + currentIP, err := getCurrentIP(configuration.IPUrl) + + if err != nil { + log.Println("get_currentIP:", err) + continue + } + log.Println("currentIp is:", currentIP) + + for _, subDomain := range domain.SubDomains { + + subDomainID, ip := getSubDomain(domainID, subDomain) + + if subDomainID == "" || ip == "" { + log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) + continue + } + + //Continue to check the IP of sub-domain + if len(ip) > 0 && !strings.Contains(currentIP, ip) { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + updateIP(domainID, subDomainID, subDomain, currentIP) + } else { + log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) + } + } + + //Interval is 5 minutes + time.Sleep(time.Minute * INTERVAL) + } +} + func getCurrentIP(url string) (string, error) { response, err := http.Get(url) diff --git a/godns.go b/godns.go index b687425..f92a9d0 100644 --- a/godns.go +++ b/godns.go @@ -5,9 +5,6 @@ import ( "fmt" "log" "os" - "runtime/debug" - "strings" - "time" ) const ( @@ -52,65 +49,10 @@ func main() { } func dnsLoop() { - + handler := createHandler(configuration.Type) for _, domain := range configuration.Domains { - go domainLoop(&domain) + go handler.DomainLoop(&domain) } select {} } - -func domainLoop(domain *Domain) { - defer func() { - if err := recover(); err != nil { - panicCount++ - log.Printf("Recovered in %v: %v\n", err, debug.Stack()) - fmt.Println(identifyPanic()) - log.Print(identifyPanic()) - if panicCount < PANIC_MAX { - log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go domainLoop(domain) - } else { - os.Exit(1) - } - } - }() - - for { - - domainID := getDomain(domain.DomainName) - - if domainID == -1 { - continue - } - - currentIP, err := getCurrentIP(configuration.IPUrl) - - if err != nil { - log.Println("get_currentIP:", err) - continue - } - log.Println("currentIp is:", currentIP) - - for _, subDomain := range domain.SubDomains { - - subDomainID, ip := getSubDomain(domainID, subDomain) - - if subDomainID == "" || ip == "" { - log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) - continue - } - - //Continue to check the IP of sub-domain - if len(ip) > 0 && !strings.Contains(currentIP, ip) { - log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) - updateIP(domainID, subDomainID, subDomain, currentIP) - } else { - log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) - } - } - - //Interval is 5 minutes - time.Sleep(time.Minute * INTERVAL) - } -} diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..13a1aae --- /dev/null +++ b/handler.go @@ -0,0 +1,18 @@ +package main + +type IHandler interface { + DomainLoop(domain *Domain) +} + +func createHandler(provider string) IHandler { + var handler IHandler + + switch provider { + case "DNSPod": + handler = IHandler(&DNSPodHandler{}) + case "HE": + handler = IHandler(&HEHandler{}) + } + + return handler +} diff --git a/he_handler.go b/he_handler.go new file mode 100644 index 0000000..f27e357 --- /dev/null +++ b/he_handler.go @@ -0,0 +1,6 @@ +package main + +type HEHandler struct{} + +func (handler *HEHandler) DomainLoop(domain *Domain) { +} diff --git a/settings.go b/settings.go index e11f333..3c54ba5 100644 --- a/settings.go +++ b/settings.go @@ -15,6 +15,7 @@ type Domain struct { //Settings struct type Settings struct { + Type string `json:"type"` Email string `json:"email"` Password string `json:"password"` LoginToken string `json:"login_token"` From fd0424630aeae6feefd2fda6e592f5c89122c40b Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 16:05:13 +0800 Subject: [PATCH 21/99] rename files --- dns_handler.go => dnspod_handler.go | 14 -------------- utils.go | 16 ++++++++++++++++ dns_handler_test.go => utils_test.go | 0 3 files changed, 16 insertions(+), 14 deletions(-) rename dns_handler.go => dnspod_handler.go (95%) rename dns_handler_test.go => utils_test.go (100%) diff --git a/dns_handler.go b/dnspod_handler.go similarity index 95% rename from dns_handler.go rename to dnspod_handler.go index eaa2e3d..6a13eac 100644 --- a/dns_handler.go +++ b/dnspod_handler.go @@ -74,20 +74,6 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain) { } } -func getCurrentIP(url string) (string, error) { - response, err := http.Get(url) - - if err != nil { - log.Println("Cannot get IP...") - return "", err - } - - defer response.Body.Close() - - body, _ := ioutil.ReadAll(response.Body) - return string(body), nil -} - func generateHeader(content url.Values) url.Values { header := url.Values{} if configuration.LoginToken != "" { diff --git a/utils.go b/utils.go index 106dd58..24bb113 100644 --- a/utils.go +++ b/utils.go @@ -4,11 +4,27 @@ import ( "errors" "flag" "fmt" + "io/ioutil" "log" + "net/http" "runtime" "strings" ) +func getCurrentIP(url string) (string, error) { + response, err := http.Get(url) + + if err != nil { + log.Println("Cannot get IP...") + return "", err + } + + defer response.Body.Close() + + body, _ := ioutil.ReadAll(response.Body) + return string(body), nil +} + func identifyPanic() string { var name, file string var line int diff --git a/dns_handler_test.go b/utils_test.go similarity index 100% rename from dns_handler_test.go rename to utils_test.go From cd3e7e3cb0b101d42c1d7d3b28a6c712ee5031bb Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 16:27:34 +0800 Subject: [PATCH 22/99] refactor DNSPod handler --- dnspod_handler.go | 28 ++++++++++++---------------- godns.go | 6 +++++- handler.go | 4 ++-- settings.go | 2 +- utils.go | 12 ++++++++++-- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/dnspod_handler.go b/dnspod_handler.go index 6a13eac..96aafe9 100644 --- a/dnspod_handler.go +++ b/dnspod_handler.go @@ -37,7 +37,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain) { for { - domainID := getDomain(domain.DomainName) + domainID := handler.GetDomain(domain.DomainName) if domainID == -1 { continue @@ -53,7 +53,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain) { for _, subDomain := range domain.SubDomains { - subDomainID, ip := getSubDomain(domainID, subDomain) + subDomainID, ip := handler.GetSubDomain(domainID, subDomain) if subDomainID == "" || ip == "" { log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) @@ -63,7 +63,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain) { //Continue to check the IP of sub-domain if len(ip) > 0 && !strings.Contains(currentIP, ip) { log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) - updateIP(domainID, subDomainID, subDomain, currentIP) + handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) } else { log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) } @@ -74,7 +74,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain) { } } -func generateHeader(content url.Values) url.Values { +func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { header := url.Values{} if configuration.LoginToken != "" { header.Add("login_token", configuration.LoginToken) @@ -95,11 +95,7 @@ func generateHeader(content url.Values) url.Values { return header } -func apiVersion() { - postData("/Info.Version", nil) -} - -func getDomain(name string) int64 { +func (handler *DNSPodHandler) GetDomain(name string) int64 { var ret int64 values := url.Values{} @@ -107,7 +103,7 @@ func getDomain(name string) int64 { values.Add("offset", "0") values.Add("length", "20") - response, err := postData("/Domain.List", values) + response, err := handler.PostData("/Domain.List", values) if err != nil { log.Println("Failed to get domain list...") @@ -147,7 +143,7 @@ func getDomain(name string) int64 { return ret } -func getSubDomain(domainID int64, name string) (string, string) { +func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, string) { log.Println("debug:", domainID, name) var ret, ip string value := url.Values{} @@ -156,7 +152,7 @@ func getSubDomain(domainID int64, name string) (string, string) { value.Add("length", "1") value.Add("sub_domain", name) - response, err := postData("/Record.List", value) + response, err := handler.PostData("/Record.List", value) if err != nil { log.Println("Failed to get domain list") @@ -191,7 +187,7 @@ func getSubDomain(domainID int64, name string) (string, string) { return ret, ip } -func updateIP(domainID int64, subDomainID string, subDomainName string, ip string) { +func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDomainName string, ip string) { value := url.Values{} value.Add("domain_id", strconv.FormatInt(domainID, 10)) value.Add("record_id", subDomainID) @@ -200,7 +196,7 @@ func updateIP(domainID int64, subDomainID string, subDomainName string, ip strin value.Add("record_line", "默认") value.Add("value", ip) - response, err := postData("/Record.Modify", value) + response, err := handler.PostData("/Record.Modify", value) if err != nil { log.Println("Failed to update record to new IP!") @@ -221,7 +217,7 @@ func updateIP(domainID int64, subDomainID string, subDomainName string, ip strin } -func postData(url string, content url.Values) (string, error) { +func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, error) { client := &http.Client{} if configuration.Socks5Proxy != "" { @@ -239,7 +235,7 @@ func postData(url string, content url.Values) (string, error) { httpTransport.Dial = dialer.Dial } - values := generateHeader(content) + values := handler.GenerateHeader(content) req, _ := http.NewRequest("POST", "https://dnsapi.cn"+url, strings.NewReader(values.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") diff --git a/godns.go b/godns.go index f92a9d0..e22e653 100644 --- a/godns.go +++ b/godns.go @@ -12,6 +12,10 @@ const ( PANIC_MAX = 5 // INTERVAL is minute INTERVAL = 5 + // DNSPod + DNSPOD = "DNSPod" + // HE + HE = "HE" ) var ( @@ -49,7 +53,7 @@ func main() { } func dnsLoop() { - handler := createHandler(configuration.Type) + handler := createHandler(configuration.Provider) for _, domain := range configuration.Domains { go handler.DomainLoop(&domain) } diff --git a/handler.go b/handler.go index 13a1aae..fedd3c1 100644 --- a/handler.go +++ b/handler.go @@ -8,9 +8,9 @@ func createHandler(provider string) IHandler { var handler IHandler switch provider { - case "DNSPod": + case DNSPOD: handler = IHandler(&DNSPodHandler{}) - case "HE": + case HE: handler = IHandler(&HEHandler{}) } diff --git a/settings.go b/settings.go index 3c54ba5..bcefb8b 100644 --- a/settings.go +++ b/settings.go @@ -15,7 +15,7 @@ type Domain struct { //Settings struct type Settings struct { - Type string `json:"type"` + Provider string `json:"provider"` Email string `json:"email"` Password string `json:"password"` LoginToken string `json:"login_token"` diff --git a/utils.go b/utils.go index 24bb113..0995a0e 100644 --- a/utils.go +++ b/utils.go @@ -59,8 +59,16 @@ func usage() { } func checkSettings(config *Settings) error { - if (config.Email == "" || config.Password == "") && config.LoginToken == "" { - return errors.New("Input email/password or login token cannot be empty!") + if config.Provider == DNSPOD { + if (config.Email == "" || config.Password == "") && config.LoginToken == "" { + return errors.New("Email/Password or login token cannot be empty!") + } + } else if config.Provider == HE { + if config.Password == "" { + return errors.New("Password cannot be empty!") + } + } else { + return errors.New("Please provide supported DNS provider: DNSPod/HE") } return nil From c62bb219ccedefaed3043c252c140973f4feafa8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 16:28:45 +0800 Subject: [PATCH 23/99] update config sample file --- config_sample.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config_sample.json b/config_sample.json index 1241d5b..55200b2 100644 --- a/config_sample.json +++ b/config_sample.json @@ -1,4 +1,5 @@ { + "provider": "DNSPod", "email": "example@gmail.com", "password": "", "login_token": "", From ce90fe41efa90e67433142209d0064ea232e1df8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 17:01:39 +0800 Subject: [PATCH 24/99] implement HE dns handler --- he_handler.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/he_handler.go b/he_handler.go index f27e357..0d13e8e 100644 --- a/he_handler.go +++ b/he_handler.go @@ -1,6 +1,72 @@ package main +import ( + "fmt" + "log" + "net/http" + "os" + "runtime/debug" + "time" + + "github.com/parnurzeal/gorequest" +) + +var ( + HEUrl = "https://dyn.dns.he.net/nic/update?hostname=%s.%s&password=%s&myip=%s" +) + type HEHandler struct{} func (handler *HEHandler) DomainLoop(domain *Domain) { + defer func() { + if err := recover(); err != nil { + panicCount++ + log.Printf("Recovered in %v: %v\n", err, debug.Stack()) + fmt.Println(identifyPanic()) + log.Print(identifyPanic()) + if panicCount < PANIC_MAX { + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go handler.DomainLoop(domain) + } else { + os.Exit(1) + } + } + }() + + for { + currentIP, err := getCurrentIP(configuration.IPUrl) + + if err != nil { + log.Println("get_currentIP:", err) + continue + } + log.Println("currentIp is:", 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) + } + + //Interval is 5 minutes + time.Sleep(time.Minute * INTERVAL) + } +} + +func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { + request := gorequest.New() + resp, body, errs := request.Get(fmt.Sprintf(HEUrl, subDomain, domain, configuration.Password, currentIP)).End() + + if len(errs) > 0 { + log.Println("Request error...") + + for _, err := range errs { + log.Println("Err:", err.Error()) + } + } else { + if resp.StatusCode == http.StatusOK { + log.Println("Update IP success:", body) + } else { + log.Println("Update IP failed:", body) + } + } } From 72fc565a9676af9b92f1e2b496525e2041dd82bc Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 17:10:34 +0800 Subject: [PATCH 25/99] add snapshots --- snapshots/he1.png | Bin 0 -> 159140 bytes snapshots/he2.png | Bin 0 -> 117997 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 snapshots/he1.png create mode 100644 snapshots/he2.png diff --git a/snapshots/he1.png b/snapshots/he1.png new file mode 100644 index 0000000000000000000000000000000000000000..9dd40f3cc38244e0b46b866ef731ab9e629f551d GIT binary patch literal 159140 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%0AJ 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≀;h9h_PV|g|4`M7h=qHe{_Bm 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 z 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 literal 0 HcmV?d00001 diff --git a/snapshots/he2.png b/snapshots/he2.png new file mode 100644 index 0000000000000000000000000000000000000000..0163c9610f2f8048adf3814ed5e0bc89eff81331 GIT binary patch literal 117997 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
Z3T58tE9roy$bDp2=4!oXtH@H>Z{Po;; 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%0DKy-*Hx`3(B0hL^A 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 literal 0 HcmV?d00001 From 40a2b9bc9aad3c3c80b99c692e054b24c0bb82a4 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 04:24:57 -0500 Subject: [PATCH 26/99] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aace7fb..92bbf57 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,19 @@ GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source p Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). +## Supported DNS Provider: +* DNSPod ([https://www.dnspod.cn/](https://www.dnspod.cn/)) +* HE(Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/)) + ## MIPS32 platform For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/godns/tree/mips32) branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. ## Pre-condition -* GoDNS relies on [DNSPod](http://dnspod.cn) and its API. +* Register and own a domain. -* To use GoDNS, you need a domain hosted on [DNSPod](http://dnspod.cn). +* Domain's nameserver points to DNSPod or HE. ## Build it From 0bcfd39f41fc500ffd053f24514fa48562d2826f Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 04:34:34 -0500 Subject: [PATCH 27/99] Update README.md --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92bbf57..a3e5ddd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/g * Register and own a domain. -* Domain's nameserver points to DNSPod or HE. +* Domain's nameserver points to [DNSPod](https://www.dnspod.cn/) or [HE](https://dns.he.net/). ## Build it @@ -72,11 +72,61 @@ Usage of ./godns: * Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github. * Rename it to **config.json**. -* Configure your domain/sub-domain info, username and password of DNSPod account. +* Configure your provider, domain/sub-domain info, username and password, etc. * Configure log file path, max size of log file, max count of log file. -* Configure user id, group id for safety. * Save it in the same directory of GoDNS, or use -c=your_conf_path command. +## Config example for DNSPod + +For DNSPod, you need to provide email & password, and config all the domains & subdomains. + +```json +{ + "provider": "DNSPod", + "email": "example@gmail.com", + "password": "YourPassword", + "login_token": "", + "domains": [{ + "domain_name": "example.com", + "sub_domains": ["www","test"] + },{ + "domain_name": "example2.com", + "sub_domains": ["www","test"] + } + ], + "ip_url": "http://members.3322.org/dyndns/getip", + "log_path": "./godns.log", + "log_size": 16, + "log_num": 3, + "socks5_proxy": "" +} +``` +## Config example for HE + +For HE, email is not needed, just fill DDNS key to password, and config all the domains & subdomains. + +```json +{ + "provider": "HE", + "email": "", + "password": "YourPassword", + "login_token": "", + "domains": [{ + "domain_name": "example.com", + "sub_domains": ["www","test"] + },{ + "domain_name": "example2.com", + "sub_domains": ["www","test"] + } + ], + "ip_url": "http://members.3322.org/dyndns/getip", + "log_path":"/users/timothy/workspace/src/godns/godns.log", + "log_size":16, + "log_num":3, + "socks5_proxy": "" +} +``` + ## Run it as a daemon manually ```bash From 39400f628a960ef9af7a9c098d7fbc7b53157dcd Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 04:35:41 -0500 Subject: [PATCH 28/99] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a3e5ddd..c503822 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call i ## Supported DNS Provider: * DNSPod ([https://www.dnspod.cn/](https://www.dnspod.cn/)) -* HE(Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/)) +* HE.net (Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/)) ## MIPS32 platform @@ -38,7 +38,7 @@ For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/g * Register and own a domain. -* Domain's nameserver points to [DNSPod](https://www.dnspod.cn/) or [HE](https://dns.he.net/). +* Domain's nameserver points to [DNSPod](https://www.dnspod.cn/) or [HE.net](https://dns.he.net/). ## Build it @@ -101,7 +101,7 @@ For DNSPod, you need to provide email & password, and config all the domains & "socks5_proxy": "" } ``` -## Config example for HE +## Config example for HE.net For HE, email is not needed, just fill DDNS key to password, and config all the domains & subdomains. From cd6f969bc74c02c936176d59322a06d6a39dfb5f Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 04:43:12 -0500 Subject: [PATCH 29/99] Update README.md --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c503822..d966659 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Usage of ./godns: * Configure log file path, max size of log file, max count of log file. * Save it in the same directory of GoDNS, or use -c=your_conf_path command. -## Config example for DNSPod +### Config example for DNSPod For DNSPod, you need to provide email & password, and config all the domains & subdomains. @@ -101,7 +101,7 @@ For DNSPod, you need to provide email & password, and config all the domains & "socks5_proxy": "" } ``` -## Config example for HE.net +### Config example for HE.net For HE, email is not needed, just fill DDNS key to password, and config all the domains & subdomains. @@ -127,6 +127,16 @@ For HE, email is not needed, just fill DDNS key to password, and config all the } ``` +### HE.net DDNS configuration + +Add a new "A record", make sure that "Enable entry for dynamic dns" is checked: + +![](https://github.com/TimothyYe/godns/blob/he/snapshots/he1.png?raw=true) + +Fill your own DDNS key or generate a random DDNS key for this new created "A record": + +![](https://github.com/TimothyYe/godns/blob/he/snapshots/he2.png?raw=true) + ## Run it as a daemon manually ```bash From 7e9bd7f532e456a9210d43226d3551342d5b58b9 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 04:48:09 -0500 Subject: [PATCH 30/99] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d966659..f0c98f7 100644 --- a/README.md +++ b/README.md @@ -131,11 +131,15 @@ For HE, email is not needed, just fill DDNS key to password, and config all the Add a new "A record", make sure that "Enable entry for dynamic dns" is checked: -![](https://github.com/TimothyYe/godns/blob/he/snapshots/he1.png?raw=true) + Fill your own DDNS key or generate a random DDNS key for this new created "A record": -![](https://github.com/TimothyYe/godns/blob/he/snapshots/he2.png?raw=true) + + +Remember the DDNS key and fill it as password to the config.json. + +__NOTICE__: If you have multiple domains or subdomains, make sure their DDNS key are the same. ## Run it as a daemon manually From 9b458a0d1d0288fa5048c782624be514ab510581 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 20:23:24 +0800 Subject: [PATCH 31/99] Integrate with socks5 proxy --- godns.go | 2 +- he_handler.go | 36 +++++++++++++++++++++++++----------- utils.go | 20 +++++++++++++++++++- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/godns.go b/godns.go index e22e653..e0f637d 100644 --- a/godns.go +++ b/godns.go @@ -12,7 +12,7 @@ const ( PANIC_MAX = 5 // INTERVAL is minute INTERVAL = 5 - // DNSPod + // DNSPOD DNSPOD = "DNSPod" // HE HE = "HE" diff --git a/he_handler.go b/he_handler.go index 0d13e8e..ee6349e 100644 --- a/he_handler.go +++ b/he_handler.go @@ -7,8 +7,8 @@ import ( "os" "runtime/debug" "time" - - "github.com/parnurzeal/gorequest" + "io/ioutil" + "golang.org/x/net/proxy" ) var ( @@ -53,20 +53,34 @@ func (handler *HEHandler) DomainLoop(domain *Domain) { } func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { - request := gorequest.New() - resp, body, errs := request.Get(fmt.Sprintf(HEUrl, subDomain, domain, configuration.Password, currentIP)).End() + client := &http.Client{} - if len(errs) > 0 { - log.Println("Request error...") - - for _, err := range errs { - log.Println("Err:", err.Error()) + if configuration.Socks5Proxy != "" { + + log.Println("use socks5 proxy:" + configuration.Socks5Proxy) + + dialer, err := proxy.SOCKS5("tcp", 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 + } + + resp, err := client.Get(fmt.Sprintf(HEUrl, subDomain, domain, configuration.Password, currentIP)) + + 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:", body) + log.Println("Update IP success:", string(body)) } else { - log.Println("Update IP failed:", body) + log.Println("Update IP failed:", string(body)) } } } diff --git a/utils.go b/utils.go index 0995a0e..f445bf2 100644 --- a/utils.go +++ b/utils.go @@ -9,10 +9,28 @@ import ( "net/http" "runtime" "strings" + "golang.org/x/net/proxy" ) func getCurrentIP(url string) (string, error) { - response, err := http.Get(url) + client := &http.Client{} + + if configuration.Socks5Proxy != "" { + + log.Println("use socks5 proxy:" + configuration.Socks5Proxy) + + dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct) + if err != nil { + fmt.Println("can't connect to the proxy:", err) + return "", err + } + + httpTransport := &http.Transport{} + client.Transport = httpTransport + httpTransport.Dial = dialer.Dial + } + + response, err := client.Get(url) if err != nil { log.Println("Cannot get IP...") From 564ceee22d1816d4d37277d49891835b7355960b Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 9 Oct 2017 20:27:43 +0800 Subject: [PATCH 32/99] add SOCKS5 proxy support. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index f0c98f7..a6c3913 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,16 @@ Remember the DDNS key and fill it as password to the config.json. __NOTICE__: If you have multiple domains or subdomains, make sure their DDNS key are the same. +### SOCKS5 proxy support + +You can also use SOCKS5 proxy, just fill SOCKS5 address to the ```socks5_proxy``` item: + +```json +"socks5_proxy": "127.0.0.1:7070" +``` + +Now all the queries will go through the specified SOCKS5 proxy. + ## Run it as a daemon manually ```bash From ceb8ee8548677e365837b8737917845143244aba Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 10 Oct 2017 09:36:44 +0800 Subject: [PATCH 33/99] refactor update IP logic --- he_handler.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/he_handler.go b/he_handler.go index ee6349e..677567e 100644 --- a/he_handler.go +++ b/he_handler.go @@ -2,17 +2,20 @@ package main import ( "fmt" + "io/ioutil" "log" "net/http" + "net/url" "os" "runtime/debug" + "strings" "time" - "io/ioutil" + "golang.org/x/net/proxy" ) var ( - HEUrl = "https://dyn.dns.he.net/nic/update?hostname=%s.%s&password=%s&myip=%s" + HEUrl = "https://dyn.dns.he.net/nic/update" ) type HEHandler struct{} @@ -53,24 +56,28 @@ func (handler *HEHandler) DomainLoop(domain *Domain) { } func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { + values := url.Values{} + values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) + values.Add("password", configuration.Password) + values.Add("myip", currentIP) + client := &http.Client{} if configuration.Socks5Proxy != "" { - log.Println("use socks5 proxy:" + configuration.Socks5Proxy) - dialer, err := proxy.SOCKS5("tcp", 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 } - resp, err := client.Get(fmt.Sprintf(HEUrl, subDomain, domain, configuration.Password, currentIP)) + req, _ := http.NewRequest("POST", HEUrl, strings.NewReader(values.Encode())) + resp, err := client.Do(req) if err != nil { log.Println("Request error...") From bbf787e6e3be4dbfbd9462d0d3ec72b5176dad1c Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 21:01:19 -0500 Subject: [PATCH 34/99] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a6c3913..974d849 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/g * Domain's nameserver points to [DNSPod](https://www.dnspod.cn/) or [HE.net](https://dns.he.net/). -## Build it +## Get it ### Get & build it from source code @@ -57,6 +57,10 @@ go get go build ``` +## Download from releases + +Download it from [releases](https://github.com/TimothyYe/godns/releases) + ## Get help ```bash From edac8f7f229a68e4e7f118adcc124ac8b8b06d2d Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 21:01:47 -0500 Subject: [PATCH 35/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 974d849..ab1406b 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/g ## Get it -### Get & build it from source code +### Build it from source code * Get source code from Github: From 6559089eae7671d8fae618d1b41f194b2e7fc039 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 21:02:06 -0500 Subject: [PATCH 36/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab1406b..d046cdf 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ go get go build ``` -## Download from releases +### Download from releases Download it from [releases](https://github.com/TimothyYe/godns/releases) From 57f8ad444567f1f57f4d6d83e487598ece78c439 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 21:03:41 -0500 Subject: [PATCH 37/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d046cdf..e46941c 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ go build ### Download from releases -Download it from [releases](https://github.com/TimothyYe/godns/releases) +Download compiled binaries from [releases](https://github.com/TimothyYe/godns/releases) ## Get help From 8743fce0905be7301ec5ef44377e4fe5f2bc7071 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Mon, 9 Oct 2017 21:05:10 -0500 Subject: [PATCH 38/99] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e46941c..24dd8e3 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ [2]: https://travis-ci.org/TimothyYe/godns [3]: https://images.microbadger.com/badges/image/timothyye/godns.svg [4]: https://microbadger.com/images/timothyye/godns -[5]: https://img.shields.io/badge/downloads-1.95MB-brightgreen.svg +[5]: https://img.shields.io/badge/downloads-2.04MB-brightgreen.svg [6]: https://github.com/TimothyYe/godns/releases -[7]: https://img.shields.io/badge/release-v1.2-brightgreen.svg +[7]: https://img.shields.io/badge/release-v1.3-brightgreen.svg [8]: https://github.com/TimothyYe/godns/releases [9]: https://img.shields.io/badge/license-Apache-blue.svg [10]: LICENSE @@ -192,7 +192,7 @@ Now godns supports to run in docker. ```bash docker run -d --name godns --restart=always \ --v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:1.2 +-v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:1.3 ``` ## Enjoy it! From 026200fae91112bd15eff5796bd2bc18d7c99ead Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Tue, 10 Oct 2017 00:24:38 -0500 Subject: [PATCH 39/99] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 24dd8e3..f008607 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,12 @@ Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call i * DNSPod ([https://www.dnspod.cn/](https://www.dnspod.cn/)) * HE.net (Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/)) +## Supported Platforms: +* Linux +* MacOS +* ARM Linux (Raspberry Pi, etc...) +* Windows + ## MIPS32 platform For MIPS32 platform, please checkout the [mips32](https://github.com/TimothyYe/godns/tree/mips32) branch, this branch is contributed by [hguandl](https://github.com/hguandl), in this branch, the support for mips32 is added, which means it could run properly on Openwrt and LEDE. From b5397fb1f3b35f4f126f069f40f7461ffa945e6f Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 10 Oct 2017 13:27:37 +0800 Subject: [PATCH 40/99] add arm platform support --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 66aeb29..2bc942d 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,10 @@ release: go clean CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY} + # Build for arm + go clean + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build + tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY} # Build for win go clean CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build From 5b907f081a9c6e769caadf1e75404f5febd158a6 Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Tue, 10 Oct 2017 00:37:02 -0500 Subject: [PATCH 41/99] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f008607..d0d6768 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,11 @@ For HE, email is not needed, just fill DDNS key to password, and config all the Add a new "A record", make sure that "Enable entry for dynamic dns" is checked: - + Fill your own DDNS key or generate a random DDNS key for this new created "A record": - + Remember the DDNS key and fill it as password to the config.json. From c128dd84db4288b7d4f5447866069138d0b7d98e Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Tue, 10 Oct 2017 22:05:30 +0800 Subject: [PATCH 42/99] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d0d6768..f95c0a9 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,11 @@ GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source p Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). -## Supported DNS Provider: +## Supported DNS Provider * DNSPod ([https://www.dnspod.cn/](https://www.dnspod.cn/)) * HE.net (Hurricane Electric) ([https://dns.he.net/](https://dns.he.net/)) -## Supported Platforms: +## Supported Platforms * Linux * MacOS * ARM Linux (Raspberry Pi, etc...) From ed5b504e5b9d2adcbf2866c08dd89a0bccc7b11f Mon Sep 17 00:00:00 2001 From: George Date: Sat, 14 Oct 2017 11:38:56 +0800 Subject: [PATCH 43/99] block main goroutine with chan communication --- dnspod_handler.go | 11 ++--------- godns.go | 19 ++++++++++++++++--- handler.go | 2 +- he_handler.go | 11 ++--------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/dnspod_handler.go b/dnspod_handler.go index 96aafe9..ab3f24d 100644 --- a/dnspod_handler.go +++ b/dnspod_handler.go @@ -7,7 +7,6 @@ import ( "log" "net/http" "net/url" - "os" "runtime/debug" "strconv" "strings" @@ -19,19 +18,13 @@ import ( type DNSPodHandler struct{} -func (handler *DNSPodHandler) DomainLoop(domain *Domain) { +func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { - panicCount++ log.Printf("Recovered in %v: %v\n", err, debug.Stack()) fmt.Println(identifyPanic()) log.Print(identifyPanic()) - if panicCount < PANIC_MAX { - log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go handler.DomainLoop(domain) - } else { - os.Exit(1) - } + panicChan <- *domain } }() diff --git a/godns.go b/godns.go index e0f637d..0391247 100644 --- a/godns.go +++ b/godns.go @@ -22,7 +22,6 @@ var ( configuration Settings optConf = flag.String("c", "./config.json", "Specify a config file") optHelp = flag.Bool("h", false, "Show help") - panicCount = 0 ) func main() { @@ -53,10 +52,24 @@ func main() { } func dnsLoop() { + panicChan := make(chan Domain) + handler := createHandler(configuration.Provider) for _, domain := range configuration.Domains { - go handler.DomainLoop(&domain) + go handler.DomainLoop(&domain, panicChan) } - select {} + panicCount := 0 + for { + select { + case failDomain := <-panicChan: + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go handler.DomainLoop(&failDomain, panicChan) + } + + panicCount++ + if panicCount >= PANIC_MAX { + os.Exit(1) + } + } } diff --git a/handler.go b/handler.go index fedd3c1..655201d 100644 --- a/handler.go +++ b/handler.go @@ -1,7 +1,7 @@ package main type IHandler interface { - DomainLoop(domain *Domain) + DomainLoop(domain *Domain, panicChan chan<- Domain) } func createHandler(provider string) IHandler { diff --git a/he_handler.go b/he_handler.go index 677567e..83dfc9b 100644 --- a/he_handler.go +++ b/he_handler.go @@ -6,7 +6,6 @@ import ( "log" "net/http" "net/url" - "os" "runtime/debug" "strings" "time" @@ -20,19 +19,13 @@ var ( type HEHandler struct{} -func (handler *HEHandler) DomainLoop(domain *Domain) { +func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { - panicCount++ log.Printf("Recovered in %v: %v\n", err, debug.Stack()) fmt.Println(identifyPanic()) log.Print(identifyPanic()) - if panicCount < PANIC_MAX { - log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go handler.DomainLoop(domain) - } else { - os.Exit(1) - } + panicChan <- *domain } }() From 622b77d431ec428b93caa04893050d00c0cac3ae Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 18:11:38 +0800 Subject: [PATCH 44/99] fix golint warnings --- dnspod_handler.go | 7 +++++++ godns.go | 10 +++++----- handler.go | 1 + he_handler.go | 4 ++++ logger.go | 2 +- utils.go | 15 ++++++++------- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dnspod_handler.go b/dnspod_handler.go index ab3f24d..5240f4d 100644 --- a/dnspod_handler.go +++ b/dnspod_handler.go @@ -16,8 +16,10 @@ import ( "golang.org/x/net/proxy" ) +//DNSPodHandler struct definition type DNSPodHandler struct{} +//DomainLoop the main logic loop func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { @@ -67,6 +69,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain } } +//GenerateHeader generates the request header for DNSPod API func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { header := url.Values{} if configuration.LoginToken != "" { @@ -88,6 +91,7 @@ func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { return header } +//GetDomain returns specific domain by name func (handler *DNSPodHandler) GetDomain(name string) int64 { var ret int64 @@ -136,6 +140,7 @@ func (handler *DNSPodHandler) GetDomain(name string) int64 { return ret } +//GetSubDomain returns subdomain by domain id func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, string) { log.Println("debug:", domainID, name) var ret, ip string @@ -180,6 +185,7 @@ func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, return ret, ip } +//UpdateIP update subdomain with current IP func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDomainName string, ip string) { value := url.Values{} value.Add("domain_id", strconv.FormatInt(domainID, 10)) @@ -210,6 +216,7 @@ func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDo } +//PostData post data and invoke DNSPod API func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, error) { client := &http.Client{} diff --git a/godns.go b/godns.go index 0391247..3c646d4 100644 --- a/godns.go +++ b/godns.go @@ -8,13 +8,13 @@ import ( ) const ( - // PANIC_MAX is the max allowed panic times - PANIC_MAX = 5 + // PanicMax is the max allowed panic times + PanicMax = 5 // INTERVAL is minute INTERVAL = 5 - // DNSPOD + // DNSPOD for dnspod.cn DNSPOD = "DNSPod" - // HE + // HE for he.net HE = "HE" ) @@ -68,7 +68,7 @@ func dnsLoop() { } panicCount++ - if panicCount >= PANIC_MAX { + if panicCount >= PanicMax { os.Exit(1) } } diff --git a/handler.go b/handler.go index 655201d..a805243 100644 --- a/handler.go +++ b/handler.go @@ -1,5 +1,6 @@ package main +//IHandler is the interface for all DNS handlers type IHandler interface { DomainLoop(domain *Domain, panicChan chan<- Domain) } diff --git a/he_handler.go b/he_handler.go index 83dfc9b..6dd89b4 100644 --- a/he_handler.go +++ b/he_handler.go @@ -14,11 +14,14 @@ import ( ) var ( + //HEUrl the API address for he.net HEUrl = "https://dyn.dns.he.net/nic/update" ) +//HEHandler struct type HEHandler struct{} +//DomainLoop the main logic loop func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { @@ -48,6 +51,7 @@ func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { } } +//UpdateIP update subdomain with current IP func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { values := url.Values{} values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) diff --git a/logger.go b/logger.go index 3fa9f65..4d14b9a 100644 --- a/logger.go +++ b/logger.go @@ -48,7 +48,7 @@ type Logger struct { // NewLogger returns a new created logger func NewLogger(logfile string, size, num int, level int, flushInterval int64, flushSize int) (logger *Logger, err error) { if size < 1 || num < 1 || level < L_INFO || len(logfile) < 1 { - err = errors.New("NewLogWriter:param error.") + err = errors.New("newLogWriter:param error") return } logger = &Logger{size: size * 1024, num: num, level: level, DEV_MODE: false} diff --git a/utils.go b/utils.go index f445bf2..6b359b6 100644 --- a/utils.go +++ b/utils.go @@ -9,22 +9,23 @@ import ( "net/http" "runtime" "strings" + "golang.org/x/net/proxy" ) func getCurrentIP(url string) (string, error) { client := &http.Client{} - + if configuration.Socks5Proxy != "" { - + log.Println("use socks5 proxy:" + configuration.Socks5Proxy) - + dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct) if err != nil { fmt.Println("can't connect to the proxy:", err) return "", err } - + httpTransport := &http.Transport{} client.Transport = httpTransport httpTransport.Dial = dialer.Dial @@ -79,14 +80,14 @@ func usage() { func checkSettings(config *Settings) error { if config.Provider == DNSPOD { if (config.Email == "" || config.Password == "") && config.LoginToken == "" { - return errors.New("Email/Password or login token cannot be empty!") + return errors.New("email/password or login token cannot be empty") } } else if config.Provider == HE { if config.Password == "" { - return errors.New("Password cannot be empty!") + return errors.New("password cannot be empty") } } else { - return errors.New("Please provide supported DNS provider: DNSPod/HE") + return errors.New("please provide supported DNS provider: DNSPod/HE") } return nil From 723f4d33227d2f5c57bc516538a145b447917c85 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 09:59:08 +0800 Subject: [PATCH 45/99] fix golint warnings --- logger.go | 66 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/logger.go b/logger.go index 4d14b9a..e40c8d7 100644 --- a/logger.go +++ b/logger.go @@ -16,23 +16,23 @@ import ( ) const ( - // L_INFO log level - L_INFO int = iota - // L_WARNING log level - L_WARNING - // L_DEBUG log level - L_DEBUG - // PRE_INFO log level - PRE_INFO = "[ INFO]" - // PRE_WARNING log level - PRE_WARNING = "[WARNING]" - // PRE_DEBUG log level - PRE_DEBUG = "[ DEBUG]" + // Info log level + Info int = iota + // Warning log level + Warning + // Debug log level + Debug + // PreInfo log level + PreInfo = "[ INFO]" + // PreWarning log level + PreWarning = "[WARNING]" + // PreDebug log level + PreDebug = "[ DEBUG]" ) // Logger struct type Logger struct { - DEV_MODE bool + DevMode bool fd *os.File size int num int @@ -47,11 +47,11 @@ type Logger struct { // NewLogger returns a new created logger func NewLogger(logfile string, size, num int, level int, flushInterval int64, flushSize int) (logger *Logger, err error) { - if size < 1 || num < 1 || level < L_INFO || len(logfile) < 1 { + if size < 1 || num < 1 || level < Info || len(logfile) < 1 { err = errors.New("newLogWriter:param error") return } - logger = &Logger{size: size * 1024, num: num, level: level, DEV_MODE: false} + logger = &Logger{size: size * 1024, num: num, level: level, DevMode: false} logger.fd, err = os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666) if err != nil { logger = nil @@ -79,16 +79,16 @@ func NewLogger(logfile string, size, num int, level int, flushInterval int64, fl // InitLogger initialize logger with specified log filename & size func InitLogger(logfile string, size, num int) (err error) { - logger, err := NewLogger(logfile, size, num, L_INFO, -1, -1) + logger, err := NewLogger(logfile, size, num, Info, -1, -1) if logger != nil { - logger.level = L_INFO - 1 + logger.level = Info - 1 } return } // immplement write func (logger *Logger) Write(p []byte) (n int, err error) { - if logger.DEV_MODE { + if logger.DevMode { n, err = os.Stdout.Write(p) return } @@ -208,12 +208,12 @@ func (logger *Logger) setPrefix(lv int) bool { } switch lv { - case L_INFO: - logger.log.SetPrefix(PRE_INFO) - case L_WARNING: - logger.log.SetPrefix(PRE_WARNING) - case L_DEBUG: - logger.log.SetPrefix(PRE_DEBUG) + case Info: + logger.log.SetPrefix(PreInfo) + case Warning: + logger.log.SetPrefix(PreWarning) + case Debug: + logger.log.SetPrefix(PreDebug) default: return false } @@ -263,48 +263,48 @@ func (logger *Logger) Close() { // Info output info log func (logger *Logger) Info(args ...interface{}) { - logger.logPrint(L_INFO, args...) + logger.logPrint(Info, args...) } // Infoln output info log with newline func (logger *Logger) Infoln(args ...interface{}) { - logger.logPrintln(L_INFO, args...) + logger.logPrintln(Info, args...) } // Infof output formatted info log func (logger *Logger) Infof(format string, args ...interface{}) { - logger.logPrintf(L_INFO, format, args...) + logger.logPrintf(Info, format, args...) } // Warning output warning log func (logger *Logger) Warning(args ...interface{}) { - logger.logPrint(L_WARNING, args...) + logger.logPrint(Warning, args...) } //Warningln output warning log with newline func (logger *Logger) Warningln(args ...interface{}) { - logger.logPrintln(L_WARNING, args...) + logger.logPrintln(Warning, args...) } // Warningf output formatted warning log func (logger *Logger) Warningf(format string, args ...interface{}) { - logger.logPrintf(L_WARNING, format, args...) + logger.logPrintf(Warning, format, args...) } // Debug output debug log func (logger *Logger) Debug(args ...interface{}) { - logger.logPrint(L_DEBUG, args...) + logger.logPrint(Debug, args...) logger.Flush() } // Debugln output debug log with newline func (logger *Logger) Debugln(args ...interface{}) { - logger.logPrintln(L_DEBUG, args...) + logger.logPrintln(Debug, args...) logger.Flush() } // Debugf output formatted debug log func (logger *Logger) Debugf(format string, args ...interface{}) { - logger.logPrintf(L_DEBUG, format, args...) + logger.logPrintf(Debug, format, args...) logger.Flush() } From d46fefa18bf68cc091e5bde708872fae0cfe5555 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 10:22:12 +0800 Subject: [PATCH 46/99] format code --- dnspod_handler.go | 14 +++++++------- godns.go | 2 +- handler.go | 2 +- he_handler.go | 10 +++++----- logger.go | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dnspod_handler.go b/dnspod_handler.go index 5240f4d..ead82a0 100644 --- a/dnspod_handler.go +++ b/dnspod_handler.go @@ -16,10 +16,10 @@ import ( "golang.org/x/net/proxy" ) -//DNSPodHandler struct definition +// DNSPodHandler struct definition type DNSPodHandler struct{} -//DomainLoop the main logic loop +// DomainLoop the main logic loop func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { @@ -69,7 +69,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain } } -//GenerateHeader generates the request header for DNSPod API +// GenerateHeader generates the request header for DNSPod API func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { header := url.Values{} if configuration.LoginToken != "" { @@ -91,7 +91,7 @@ func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { return header } -//GetDomain returns specific domain by name +// GetDomain returns specific domain by name func (handler *DNSPodHandler) GetDomain(name string) int64 { var ret int64 @@ -140,7 +140,7 @@ func (handler *DNSPodHandler) GetDomain(name string) int64 { return ret } -//GetSubDomain returns subdomain by domain id +// GetSubDomain returns subdomain by domain id func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, string) { log.Println("debug:", domainID, name) var ret, ip string @@ -185,7 +185,7 @@ func (handler *DNSPodHandler) GetSubDomain(domainID int64, name string) (string, return ret, ip } -//UpdateIP update subdomain with current IP +// UpdateIP update subdomain with current IP func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDomainName string, ip string) { value := url.Values{} value.Add("domain_id", strconv.FormatInt(domainID, 10)) @@ -216,7 +216,7 @@ func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDo } -//PostData post data and invoke DNSPod API +// PostData post data and invoke DNSPod API func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, error) { client := &http.Client{} diff --git a/godns.go b/godns.go index 3c646d4..3a2bdb2 100644 --- a/godns.go +++ b/godns.go @@ -31,7 +31,7 @@ func main() { return } - //Load settings from configurations file + // Load settings from configurations file if err := LoadSettings(*optConf, &configuration); err != nil { fmt.Println(err.Error()) log.Println(err.Error()) diff --git a/handler.go b/handler.go index a805243..81d8e1d 100644 --- a/handler.go +++ b/handler.go @@ -1,6 +1,6 @@ package main -//IHandler is the interface for all DNS handlers +// IHandler is the interface for all DNS handlers type IHandler interface { DomainLoop(domain *Domain, panicChan chan<- Domain) } diff --git a/he_handler.go b/he_handler.go index 6dd89b4..e72737e 100644 --- a/he_handler.go +++ b/he_handler.go @@ -14,14 +14,14 @@ import ( ) var ( - //HEUrl the API address for he.net + // HEUrl the API address for he.net HEUrl = "https://dyn.dns.he.net/nic/update" ) -//HEHandler struct +// HEHandler struct type HEHandler struct{} -//DomainLoop the main logic loop +// DomainLoop the main logic loop func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { defer func() { if err := recover(); err != nil { @@ -46,12 +46,12 @@ func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { handler.UpdateIP(domain.DomainName, subDomain, currentIP) } - //Interval is 5 minutes + // Interval is 5 minutes time.Sleep(time.Minute * INTERVAL) } } -//UpdateIP update subdomain with current IP +// UpdateIP update subdomain with current IP func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { values := url.Values{} values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) diff --git a/logger.go b/logger.go index e40c8d7..932c28d 100644 --- a/logger.go +++ b/logger.go @@ -86,7 +86,7 @@ func InitLogger(logfile string, size, num int) (err error) { return } -// immplement write +// Write immplement write func (logger *Logger) Write(p []byte) (n int, err error) { if logger.DevMode { n, err = os.Stdout.Write(p) From 4bca24fe97ba851778866b420a532be7c1b593e9 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:12:13 +0800 Subject: [PATCH 47/99] refactor code struct --- godns.go | 75 ------------------- handler.go | 19 ----- .../dnspod_handler.go | 37 +++++---- handler/handler.go | 22 ++++++ he_handler.go => handler/he_handler.go | 30 +++++--- logger.go | 2 +- settings.go | 2 +- settings_test.go | 2 +- utils.go | 23 ++++-- utils_test.go | 2 +- 10 files changed, 84 insertions(+), 130 deletions(-) delete mode 100644 godns.go delete mode 100644 handler.go rename dnspod_handler.go => handler/dnspod_handler.go (84%) create mode 100644 handler/handler.go rename he_handler.go => handler/he_handler.go (68%) diff --git a/godns.go b/godns.go deleted file mode 100644 index 3a2bdb2..0000000 --- a/godns.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "os" -) - -const ( - // PanicMax is the max allowed panic times - PanicMax = 5 - // INTERVAL is minute - INTERVAL = 5 - // DNSPOD for dnspod.cn - DNSPOD = "DNSPod" - // HE for he.net - HE = "HE" -) - -var ( - configuration Settings - optConf = flag.String("c", "./config.json", "Specify a config file") - optHelp = flag.Bool("h", false, "Show help") -) - -func main() { - flag.Parse() - if *optHelp { - flag.Usage() - return - } - - // Load settings from configurations file - if err := LoadSettings(*optConf, &configuration); err != nil { - fmt.Println(err.Error()) - log.Println(err.Error()) - os.Exit(1) - } - - if err := checkSettings(&configuration); err != nil { - log.Println("Settings is invalid! ", err.Error()) - os.Exit(1) - } - - if err := InitLogger(configuration.LogPath, configuration.LogSize, configuration.LogNum); err != nil { - log.Println("InitLogger error:", err.Error()) - os.Exit(1) - } - - dnsLoop() -} - -func dnsLoop() { - panicChan := make(chan Domain) - - handler := createHandler(configuration.Provider) - for _, domain := range configuration.Domains { - go handler.DomainLoop(&domain, panicChan) - } - - panicCount := 0 - for { - select { - case failDomain := <-panicChan: - log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go handler.DomainLoop(&failDomain, panicChan) - } - - panicCount++ - if panicCount >= PanicMax { - os.Exit(1) - } - } -} diff --git a/handler.go b/handler.go deleted file mode 100644 index 81d8e1d..0000000 --- a/handler.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -// IHandler is the interface for all DNS handlers -type IHandler interface { - DomainLoop(domain *Domain, panicChan chan<- Domain) -} - -func createHandler(provider string) IHandler { - var handler IHandler - - switch provider { - case DNSPOD: - handler = IHandler(&DNSPodHandler{}) - case HE: - handler = IHandler(&HEHandler{}) - } - - return handler -} diff --git a/dnspod_handler.go b/handler/dnspod_handler.go similarity index 84% rename from dnspod_handler.go rename to handler/dnspod_handler.go index ead82a0..987bc43 100644 --- a/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -1,4 +1,4 @@ -package main +package handler import ( "encoding/json" @@ -12,20 +12,27 @@ import ( "strings" "time" + "github.com/TimothyYe/godns" "github.com/bitly/go-simplejson" "golang.org/x/net/proxy" ) // DNSPodHandler struct definition -type DNSPodHandler struct{} +type DNSPodHandler struct { + Configuration *godns.Settings +} + +func (handler *DNSPodHandler) SetConfiguration(conf *godns.Settings) { + handler.Configuration = conf +} // DomainLoop the main logic loop -func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { +func (handler *DNSPodHandler) 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()) - fmt.Println(identifyPanic()) - log.Print(identifyPanic()) + fmt.Println(godns.IdentifyPanic()) + log.Print(godns.IdentifyPanic()) panicChan <- *domain } }() @@ -38,7 +45,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain continue } - currentIP, err := getCurrentIP(configuration.IPUrl) + currentIP, err := godns.GetCurrentIP(handler.Configuration) if err != nil { log.Println("get_currentIP:", err) @@ -65,18 +72,18 @@ func (handler *DNSPodHandler) DomainLoop(domain *Domain, panicChan chan<- Domain } //Interval is 5 minutes - time.Sleep(time.Minute * INTERVAL) + time.Sleep(time.Minute * godns.INTERVAL) } } // GenerateHeader generates the request header for DNSPod API func (handler *DNSPodHandler) GenerateHeader(content url.Values) url.Values { header := url.Values{} - if configuration.LoginToken != "" { - header.Add("login_token", configuration.LoginToken) + if handler.Configuration.LoginToken != "" { + header.Add("login_token", handler.Configuration.LoginToken) } else { - header.Add("login_email", configuration.Email) - header.Add("login_password", configuration.Password) + header.Add("login_email", handler.Configuration.Email) + header.Add("login_password", handler.Configuration.Password) } header.Add("format", "json") header.Add("lang", "en") @@ -220,11 +227,11 @@ func (handler *DNSPodHandler) UpdateIP(domainID int64, subDomainID string, subDo func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, error) { client := &http.Client{} - if configuration.Socks5Proxy != "" { + if handler.Configuration.Socks5Proxy != "" { - log.Println("use socks5 proxy:" + configuration.Socks5Proxy) + log.Println("use socks5 proxy:" + handler.Configuration.Socks5Proxy) - dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct) + dialer, err := proxy.SOCKS5("tcp", handler.Configuration.Socks5Proxy, nil, proxy.Direct) if err != nil { fmt.Println("can't connect to the proxy:", err) return "", err @@ -239,7 +246,7 @@ func (handler *DNSPodHandler) PostData(url string, content url.Values) (string, req, _ := http.NewRequest("POST", "https://dnsapi.cn"+url, strings.NewReader(values.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("User-Agent", fmt.Sprintf("GoDNS/0.1 (%s)", configuration.Email)) + req.Header.Set("User-Agent", fmt.Sprintf("GoDNS/0.1 (%s)", handler.Configuration.Email)) response, err := client.Do(req) diff --git a/handler/handler.go b/handler/handler.go new file mode 100644 index 0000000..3fbdfd6 --- /dev/null +++ b/handler/handler.go @@ -0,0 +1,22 @@ +package handler + +import "github.com/TimothyYe/godns" + +// IHandler is the interface for all DNS handlers +type IHandler interface { + SetConfiguration(*godns.Settings) + DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) +} + +func CreateHandler(provider string) IHandler { + var handler IHandler + + switch provider { + case godns.DNSPOD: + handler = IHandler(&DNSPodHandler{}) + case godns.HE: + handler = IHandler(&HEHandler{}) + } + + return handler +} diff --git a/he_handler.go b/handler/he_handler.go similarity index 68% rename from he_handler.go rename to handler/he_handler.go index e72737e..5ce6dd1 100644 --- a/he_handler.go +++ b/handler/he_handler.go @@ -1,4 +1,4 @@ -package main +package handler import ( "fmt" @@ -10,6 +10,8 @@ import ( "strings" "time" + "github.com/TimothyYe/godns" + "golang.org/x/net/proxy" ) @@ -19,21 +21,27 @@ var ( ) // HEHandler struct -type HEHandler struct{} +type HEHandler struct { + Configuration *godns.Settings +} + +func (handler *HEHandler) SetConfiguration(conf *godns.Settings) { + handler.Configuration = conf +} // DomainLoop the main logic loop -func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { +func (handler *HEHandler) 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()) - fmt.Println(identifyPanic()) - log.Print(identifyPanic()) + fmt.Println(godns.IdentifyPanic()) + log.Print(godns.IdentifyPanic()) panicChan <- *domain } }() for { - currentIP, err := getCurrentIP(configuration.IPUrl) + currentIP, err := godns.GetCurrentIP(handler.Configuration) if err != nil { log.Println("get_currentIP:", err) @@ -47,7 +55,7 @@ func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { } // Interval is 5 minutes - time.Sleep(time.Minute * INTERVAL) + time.Sleep(time.Minute * godns.INTERVAL) } } @@ -55,14 +63,14 @@ func (handler *HEHandler) DomainLoop(domain *Domain, panicChan chan<- Domain) { func (handler *HEHandler) UpdateIP(domain, subDomain, currentIP string) { values := url.Values{} values.Add("hostname", fmt.Sprintf("%s.%s", subDomain, domain)) - values.Add("password", configuration.Password) + values.Add("password", handler.Configuration.Password) values.Add("myip", currentIP) client := &http.Client{} - if configuration.Socks5Proxy != "" { - log.Println("use socks5 proxy:" + configuration.Socks5Proxy) - dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct) + 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 diff --git a/logger.go b/logger.go index 932c28d..84f71b5 100644 --- a/logger.go +++ b/logger.go @@ -1,4 +1,4 @@ -package main +package godns import ( "bufio" diff --git a/settings.go b/settings.go index bcefb8b..cd7e532 100644 --- a/settings.go +++ b/settings.go @@ -1,4 +1,4 @@ -package main +package godns import ( "encoding/json" diff --git a/settings_test.go b/settings_test.go index 3c9dd54..da7efb9 100644 --- a/settings_test.go +++ b/settings_test.go @@ -1,4 +1,4 @@ -package main +package godns import ( "testing" diff --git a/utils.go b/utils.go index 6b359b6..9aeea8f 100644 --- a/utils.go +++ b/utils.go @@ -1,4 +1,4 @@ -package main +package godns import ( "errors" @@ -13,7 +13,18 @@ import ( "golang.org/x/net/proxy" ) -func getCurrentIP(url string) (string, error) { +const ( + // PanicMax is the max allowed panic times + PanicMax = 5 + // INTERVAL is minute + INTERVAL = 5 + // DNSPOD for dnspod.cn + DNSPOD = "DNSPod" + // HE for he.net + HE = "HE" +) + +func GetCurrentIP(configuration *Settings) (string, error) { client := &http.Client{} if configuration.Socks5Proxy != "" { @@ -31,7 +42,7 @@ func getCurrentIP(url string) (string, error) { httpTransport.Dial = dialer.Dial } - response, err := client.Get(url) + response, err := client.Get(configuration.IPUrl) if err != nil { log.Println("Cannot get IP...") @@ -44,7 +55,7 @@ func getCurrentIP(url string) (string, error) { return string(body), nil } -func identifyPanic() string { +func IdentifyPanic() string { var name, file string var line int var pc [16]uintptr @@ -72,12 +83,12 @@ func identifyPanic() string { return fmt.Sprintf("pc:%x", pc) } -func usage() { +func Usage() { log.Println("[command] -c=[config file path]") flag.PrintDefaults() } -func checkSettings(config *Settings) error { +func CheckSettings(config *Settings) error { if config.Provider == DNSPOD { if (config.Email == "" || config.Password == "") && config.LoginToken == "" { return errors.New("email/password or login token cannot be empty") diff --git a/utils_test.go b/utils_test.go index 21f3ee1..26a961b 100644 --- a/utils_test.go +++ b/utils_test.go @@ -1,4 +1,4 @@ -package main +package godns import ( "testing" From 05aca524eefc780f0dc6ded012094ad42f803bfb Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:14:22 +0800 Subject: [PATCH 48/99] update testcase --- utils_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils_test.go b/utils_test.go index 26a961b..b723028 100644 --- a/utils_test.go +++ b/utils_test.go @@ -5,7 +5,7 @@ import ( ) func testGetCurrentIP(t *testing.T) { - ip, _ := getCurrentIP("http://members.3322.org/dyndns/getip") + ip, _ := GetCurrentIP("http://members.3322.org/dyndns/getip") if ip == "" { t.Log("IP is empty...") From 790c12ae484b992ccc3659d7fd091f9e0dda9243 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 22:16:09 -0500 Subject: [PATCH 49/99] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f95c0a9..0d18d31 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ``` -[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Downloads][5]][6] [![Docker][3]][4] [![Go Report Card][11]][12] +[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Downloads][5]][6] [![Docker][3]][4] [![Go Report Card][11]][12] [![GoDoc][13]][14] [1]: https://travis-ci.org/TimothyYe/godns.svg?branch=master [2]: https://travis-ci.org/TimothyYe/godns @@ -21,6 +21,8 @@ [10]: LICENSE [11]: https://goreportcard.com/badge/github.com/timothyye/godns [12]: https://goreportcard.com/report/github.com/timothyye/godns +[13]: https://godoc.org/github.com/TimothyYe/godns?status.svg +[14]: https://godoc.org/github.com/TimothyYe/godns GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). From 35bc13e10edacdd5043c22efc951df7a8e0087c0 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 22:17:03 -0500 Subject: [PATCH 50/99] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d18d31..559204c 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,12 @@ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ``` -[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Downloads][5]][6] [![Docker][3]][4] [![Go Report Card][11]][12] [![GoDoc][13]][14] +[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Docker][3]][4] [![Go Report Card][11]][12] [![GoDoc][13]][14] [1]: https://travis-ci.org/TimothyYe/godns.svg?branch=master [2]: https://travis-ci.org/TimothyYe/godns [3]: https://images.microbadger.com/badges/image/timothyye/godns.svg [4]: https://microbadger.com/images/timothyye/godns -[5]: https://img.shields.io/badge/downloads-2.04MB-brightgreen.svg -[6]: https://github.com/TimothyYe/godns/releases [7]: https://img.shields.io/badge/release-v1.3-brightgreen.svg [8]: https://github.com/TimothyYe/godns/releases [9]: https://img.shields.io/badge/license-Apache-blue.svg From 7bf7ae2caa9766233f5a6daa04d3cbfa5a264470 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:26:36 +0800 Subject: [PATCH 51/99] update testcase --- utils_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils_test.go b/utils_test.go index b723028..6e2241e 100644 --- a/utils_test.go +++ b/utils_test.go @@ -5,7 +5,8 @@ import ( ) func testGetCurrentIP(t *testing.T) { - ip, _ := GetCurrentIP("http://members.3322.org/dyndns/getip") + conf := &Settings{IPUrl: "http://members.3322.org/dyndns/getip"} + ip, _ := GetCurrentIP(conf) if ip == "" { t.Log("IP is empty...") From 653ac6bcd8c66483e047c9656e1c07c1364bd8d4 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 22:29:49 -0500 Subject: [PATCH 52/99] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1254ad9..b33370e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ go: install: go get -v + go get -v github.com/bitly/go-simplejson script: - cp ./config_sample.json ./config.json From 4e1084fadaf890fc28b68034c7ab906d651153bd Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 22:30:52 -0500 Subject: [PATCH 53/99] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b33370e..e8ac02a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - 1.7 - - 1.8 - - 1.9 + - 1.7.x + - 1.8.x + - 1.9.x install: go get -v From 2fd1736ac6200e465f4686c419fa1cb631e109dc Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:37:31 +0800 Subject: [PATCH 54/99] add cmd directory --- .gitignore | 2 +- cmd/godns/godns.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 cmd/godns/godns.go diff --git a/.gitignore b/.gitignore index 6682edb..23e40f7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,7 @@ config.json *.log *.swp *.gz -godns +cmd/godns/godns vendor/* /.idea diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go new file mode 100644 index 0000000..956da5a --- /dev/null +++ b/cmd/godns/godns.go @@ -0,0 +1,70 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + + "github.com/TimothyYe/godns" + "github.com/TimothyYe/godns/handler" +) + +const () + +var ( + configuration godns.Settings + optConf = flag.String("c", "./config.json", "Specify a config file") + optHelp = flag.Bool("h", false, "Show help") +) + +func main() { + flag.Parse() + if *optHelp { + flag.Usage() + return + } + + // Load settings from configurations file + if err := godns.LoadSettings(*optConf, &configuration); err != nil { + fmt.Println(err.Error()) + log.Println(err.Error()) + os.Exit(1) + } + + if err := godns.CheckSettings(&configuration); err != nil { + log.Println("Settings is invalid! ", err.Error()) + os.Exit(1) + } + + if err := godns.InitLogger(configuration.LogPath, configuration.LogSize, configuration.LogNum); err != nil { + log.Println("InitLogger error:", err.Error()) + os.Exit(1) + } + + dnsLoop() +} + +func dnsLoop() { + panicChan := make(chan godns.Domain) + + handler := handler.CreateHandler(configuration.Provider) + handler.SetConfiguration(&configuration) + for _, domain := range configuration.Domains { + go handler.DomainLoop(&domain, panicChan) + } + + panicCount := 0 + for { + select { + case failDomain := <-panicChan: + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go handler.DomainLoop(&failDomain, panicChan) + } + + panicCount++ + if panicCount >= godns.PanicMax { + os.Exit(1) + } + } +} From 4280f863620c98ad183316d54daac177945cedba Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:39:44 +0800 Subject: [PATCH 55/99] remove unused code --- settings.go | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/settings.go b/settings.go index cd7e532..196055e 100644 --- a/settings.go +++ b/settings.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "strings" ) //Domain struct @@ -44,35 +43,3 @@ func LoadSettings(configPath string, settings *Settings) error { return nil } - -//LoadDomains -- Load domains from domains string -func LoadDomains(domainsOrginStr string, domains *[]Domain) error { - - domainsMap := make(map[string]*Domain) - domainsArray := strings.Split(domainsOrginStr, ",") - for _, host := range domainsArray { - dotCount := strings.Count(host, ".") - if dotCount < 2 { - continue - } - len := len(host) - pos := strings.Index(host, ".") - subDomain := host[0:pos] - domainName := host[pos+1 : len] - - if d, exist := domainsMap[domainName]; exist { - d.SubDomains = append(d.SubDomains, subDomain) - } else { - d := new(Domain) - d.DomainName = domainName - d.SubDomains = append(d.SubDomains, subDomain) - domainsMap[domainName] = d - } - } - - for _, d := range domainsMap { - *domains = append(*domains, *d) - } - - return nil -} From d4875c1064026a4a7ebffa4532ccf3b1ad4094d1 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 26 Oct 2017 22:42:25 -0500 Subject: [PATCH 56/99] Update .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e8ac02a..bdc4131 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ go: - 1.9.x install: - go get -v - go get -v github.com/bitly/go-simplejson + - go get -v + - go get -v github.com/bitly/go-simplejson script: - cp ./config_sample.json ./config.json From e0bde61c5c1beed879820701a932141c52c72712 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:57:54 +0800 Subject: [PATCH 57/99] fix golint warnings --- handler/dnspod_handler.go | 1 + settings.go | 8 ++++---- utils.go | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index 987bc43..4501cb2 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -22,6 +22,7 @@ type DNSPodHandler struct { Configuration *godns.Settings } +// SetConfiguration pass dns settings and store it to handler instance func (handler *DNSPodHandler) SetConfiguration(conf *godns.Settings) { handler.Configuration = conf } diff --git a/settings.go b/settings.go index 196055e..e648381 100644 --- a/settings.go +++ b/settings.go @@ -6,13 +6,13 @@ import ( "io/ioutil" ) -//Domain struct +// Domain struct type Domain struct { DomainName string `json:"domain_name"` SubDomains []string `json:"sub_domains"` } -//Settings struct +// Settings struct type Settings struct { Provider string `json:"provider"` Email string `json:"email"` @@ -26,9 +26,9 @@ type Settings struct { Socks5Proxy string `json:"socks5_proxy"` } -//LoadSettings -- Load settings from config file +// LoadSettings -- Load settings from config file func LoadSettings(configPath string, settings *Settings) error { - //LoadSettings from config file + // LoadSettings from config file file, err := ioutil.ReadFile(configPath) if err != nil { fmt.Println("Error occurs while reading config file, please make sure config file exists!") diff --git a/utils.go b/utils.go index 9aeea8f..434f96e 100644 --- a/utils.go +++ b/utils.go @@ -24,6 +24,7 @@ const ( HE = "HE" ) +// GetCurrentIP gets public IP from internet func GetCurrentIP(configuration *Settings) (string, error) { client := &http.Client{} @@ -55,6 +56,7 @@ func GetCurrentIP(configuration *Settings) (string, error) { return string(body), nil } +// IdentifyPanic identifies panic and output the detailed panic infomation func IdentifyPanic() string { var name, file string var line int @@ -83,11 +85,13 @@ func IdentifyPanic() string { return fmt.Sprintf("pc:%x", pc) } +// Usage prints the usage of GoDNS func Usage() { log.Println("[command] -c=[config file path]") flag.PrintDefaults() } +// CheckSettings check the format of settings func CheckSettings(config *Settings) error { if config.Provider == DNSPOD { if (config.Email == "" || config.Password == "") && config.LoginToken == "" { From 4472bc9e0e2e234872e4fc41182fc285e89dcfba Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 11:59:57 +0800 Subject: [PATCH 58/99] fix golint warnings --- handler/handler.go | 1 + handler/he_handler.go | 1 + 2 files changed, 2 insertions(+) diff --git a/handler/handler.go b/handler/handler.go index 3fbdfd6..1bc202e 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -8,6 +8,7 @@ type IHandler interface { DomainLoop(domain *godns.Domain, panicChan chan<- godns.Domain) } +// CreateHandler creates dns handler by different providers func CreateHandler(provider string) IHandler { var handler IHandler diff --git a/handler/he_handler.go b/handler/he_handler.go index 5ce6dd1..69a755c 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -25,6 +25,7 @@ type HEHandler struct { Configuration *godns.Settings } +// SetConfiguration pass dns settings and store it to handler instance func (handler *HEHandler) SetConfiguration(conf *godns.Settings) { handler.Configuration = conf } From dbf4bf15bde43ba9c1d757a9e6c4443a345d4ebf Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 12:00:42 +0800 Subject: [PATCH 59/99] fix golint warnings --- utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils.go b/utils.go index 434f96e..37a028d 100644 --- a/utils.go +++ b/utils.go @@ -56,7 +56,7 @@ func GetCurrentIP(configuration *Settings) (string, error) { return string(body), nil } -// IdentifyPanic identifies panic and output the detailed panic infomation +// IdentifyPanic identifies panic and output the detailed panic information func IdentifyPanic() string { var name, file string var line int From 545a546b7b825906c9ae0a76f46989cf75232089 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 12:03:52 +0800 Subject: [PATCH 60/99] remove unused code --- cmd/godns/godns.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 956da5a..3255a77 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -10,8 +10,6 @@ import ( "github.com/TimothyYe/godns/handler" ) -const () - var ( configuration godns.Settings optConf = flag.String("c", "./config.json", "Specify a config file") From 3c916761889986ac0d643bb3b7a254e34d7feb86 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 12:05:33 +0800 Subject: [PATCH 61/99] update logger --- logger.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logger.go b/logger.go index 84f71b5..f15fecf 100644 --- a/logger.go +++ b/logger.go @@ -23,11 +23,11 @@ const ( // Debug log level Debug // PreInfo log level - PreInfo = "[ INFO]" + PreInfo = "[INFO]" // PreWarning log level PreWarning = "[WARNING]" // PreDebug log level - PreDebug = "[ DEBUG]" + PreDebug = "[DEBUG]" ) // Logger struct From 18fdb9818fc918ee015081c7a465d35d0d6146bc Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:07:43 +0800 Subject: [PATCH 62/99] remove logger, use go's official log package --- cmd/godns/godns.go | 21 ++- logger.go | 310 --------------------------------------------- 2 files changed, 16 insertions(+), 315 deletions(-) delete mode 100644 logger.go diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 3255a77..51a59b9 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -3,9 +3,10 @@ package main import ( "flag" "fmt" - "log" "os" + "log" + "github.com/TimothyYe/godns" "github.com/TimothyYe/godns/handler" ) @@ -26,26 +27,36 @@ func main() { // Load settings from configurations file if err := godns.LoadSettings(*optConf, &configuration); err != nil { fmt.Println(err.Error()) - log.Println(err.Error()) os.Exit(1) } if err := godns.CheckSettings(&configuration); err != nil { - log.Println("Settings is invalid! ", err.Error()) + fmt.Println("Settings is invalid! ", err.Error()) os.Exit(1) } - if err := godns.InitLogger(configuration.LogPath, configuration.LogSize, configuration.LogNum); err != nil { - log.Println("InitLogger error:", err.Error()) + if configuration.LogPath == "" { + configuration.LogPath = "./godns.log" + } + + // Init log file + f, err := os.OpenFile(configuration.LogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Failed to create log file:", configuration.LogPath) os.Exit(1) } + defer f.Close() + + log.SetOutput(f) + log.Println("GoDNS started, entering main loop...") dnsLoop() } func dnsLoop() { panicChan := make(chan godns.Domain) + log.Println("Creating DNS handler with provider:", configuration.Provider) handler := handler.CreateHandler(configuration.Provider) handler.SetConfiguration(&configuration) for _, domain := range configuration.Domains { diff --git a/logger.go b/logger.go deleted file mode 100644 index f15fecf..0000000 --- a/logger.go +++ /dev/null @@ -1,310 +0,0 @@ -package godns - -import ( - "bufio" - "bytes" - "errors" - "io" - "io/ioutil" - "log" - "os" - "runtime/debug" - "strconv" - "strings" - "sync" - "time" -) - -const ( - // Info log level - Info int = iota - // Warning log level - Warning - // Debug log level - Debug - // PreInfo log level - PreInfo = "[INFO]" - // PreWarning log level - PreWarning = "[WARNING]" - // PreDebug log level - PreDebug = "[DEBUG]" -) - -// Logger struct -type Logger struct { - DevMode bool - fd *os.File - size int - num int - level int - mu sync.Mutex - muSplit sync.Mutex - flushInterval int64 //Second - flushSize int - buf *bytes.Buffer - log *log.Logger -} - -// NewLogger returns a new created logger -func NewLogger(logfile string, size, num int, level int, flushInterval int64, flushSize int) (logger *Logger, err error) { - if size < 1 || num < 1 || level < Info || len(logfile) < 1 { - err = errors.New("newLogWriter:param error") - return - } - logger = &Logger{size: size * 1024, num: num, level: level, DevMode: false} - logger.fd, err = os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666) - if err != nil { - logger = nil - return - } - log.SetOutput(logger) - if flushInterval > 0 && flushSize > 0 { - logger.buf = new(bytes.Buffer) - logger.log = log.New(logger.buf, "", log.LstdFlags) - - go func(interval int64, logger *Logger) { - defer func() { - if r := recover(); r != nil { - log.Printf("logger Tick, Recovered in %v:\n %s", r, debug.Stack()) - } - }() - c := time.Tick(time.Duration(interval) * time.Second) - for _ = range c { - logger.Flush() - } - }(flushInterval, logger) - } - return -} - -// InitLogger initialize logger with specified log filename & size -func InitLogger(logfile string, size, num int) (err error) { - logger, err := NewLogger(logfile, size, num, Info, -1, -1) - if logger != nil { - logger.level = Info - 1 - } - return -} - -// Write immplement write -func (logger *Logger) Write(p []byte) (n int, err error) { - if logger.DevMode { - n, err = os.Stdout.Write(p) - return - } - n, err = logger.fd.Write(p) - if err == nil { - fi, e := logger.fd.Stat() - if e != nil { - err = e - return - } - if fi.Size() > int64(logger.size) { - logger.muSplit.Lock() - defer logger.muSplit.Unlock() - - fname := fi.Name() - strings.HasSuffix(fname, ".log") - fbase := fname[:len(fname)-3] - - oldBs := make([]byte, 0, logger.size) - newBs := []byte{} - fd, e := os.Open(fname) - if e != nil { - err = e - return - } - rd := bufio.NewReader(fd) - for { - line, e := rd.ReadBytes('\n') - if e == io.EOF { - break - } - if e != nil { - err = e - return - } - if len(oldBs)+len(line) > logger.size { - newBs = append(newBs, line...) - } else { - oldBs = append(oldBs, line...) - } - } - fd.Close() - - _, err = logger.saveLog(1, fbase, oldBs) - if err != nil { - return - } - err = logger.fd.Close() - if err != nil { - return - } - err = os.Remove(fname) - if err != nil { - return - } - logger.fd, err = os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666) - if err != nil { - return - } - _, err = logger.fd.Write(newBs) - if err != nil { - return - } - } - } - return -} - -func (logger *Logger) saveLog(index int, fbase string, data []byte) (n int, err error) { - fn := fbase + strconv.Itoa(index) + ".log" - _, err = os.Stat(fn) - if index < logger.num && err == nil { - var b []byte - b, err = ioutil.ReadFile(fn) - if err != nil { - return - } - n, err = logger.saveLog(index+1, fbase, b) - if err != nil { - return - } - } - - fd, err := os.OpenFile(fn, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm|0666) - if err != nil { - return - } - defer fd.Close() - n, err = fd.Write(data) - return -} - -// Flush buf data to std log -func (logger *Logger) Flush() { - if logger.buf.Len() > 0 { - logger.mu.Lock() - defer logger.mu.Unlock() - - log.SetFlags(0) - log.Print(logger.buf) - log.SetFlags(log.LstdFlags) - logger.buf.Reset() - } -} - -// Clean prefix and check buf size -func (logger *Logger) clean() { - logger.log.SetPrefix("") - if logger.buf.Len()/1024 > logger.flushSize { - go logger.Flush() - } -} - -func (logger *Logger) setPrefix(lv int) bool { - if lv > logger.level { - return false - } - - switch lv { - case Info: - logger.log.SetPrefix(PreInfo) - case Warning: - logger.log.SetPrefix(PreWarning) - case Debug: - logger.log.SetPrefix(PreDebug) - default: - return false - } - return true -} - -func (logger *Logger) logPrint(lv int, args ...interface{}) { - logger.mu.Lock() - defer logger.mu.Unlock() - - if !logger.setPrefix(lv) { - return - } - logger.log.Print(args...) - logger.clean() -} - -func (logger *Logger) logPrintln(lv int, args ...interface{}) { - logger.mu.Lock() - defer logger.mu.Unlock() - - if !logger.setPrefix(lv) { - return - } - logger.log.Println(args...) - logger.clean() -} - -func (logger *Logger) logPrintf(lv int, format string, args ...interface{}) { - logger.mu.Lock() - defer logger.mu.Unlock() - - if !logger.setPrefix(lv) { - return - } - logger.log.Printf(format, args...) - logger.clean() -} - -// Close fd -func (logger *Logger) Close() { - if logger.fd != nil { - logger.Flush() - logger.fd.Close() - } -} - -// Info output info log -func (logger *Logger) Info(args ...interface{}) { - logger.logPrint(Info, args...) -} - -// Infoln output info log with newline -func (logger *Logger) Infoln(args ...interface{}) { - logger.logPrintln(Info, args...) -} - -// Infof output formatted info log -func (logger *Logger) Infof(format string, args ...interface{}) { - logger.logPrintf(Info, format, args...) -} - -// Warning output warning log -func (logger *Logger) Warning(args ...interface{}) { - logger.logPrint(Warning, args...) -} - -//Warningln output warning log with newline -func (logger *Logger) Warningln(args ...interface{}) { - logger.logPrintln(Warning, args...) -} - -// Warningf output formatted warning log -func (logger *Logger) Warningf(format string, args ...interface{}) { - logger.logPrintf(Warning, format, args...) -} - -// Debug output debug log -func (logger *Logger) Debug(args ...interface{}) { - logger.logPrint(Debug, args...) - logger.Flush() -} - -// Debugln output debug log with newline -func (logger *Logger) Debugln(args ...interface{}) { - logger.logPrintln(Debug, args...) - logger.Flush() -} - -// Debugf output formatted debug log -func (logger *Logger) Debugf(format string, args ...interface{}) { - logger.logPrintf(Debug, format, args...) - logger.Flush() -} From fad5b0fa2055a0c7f7c272158e53475ee749bbdc Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 01:12:12 -0500 Subject: [PATCH 63/99] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 559204c..c3b8575 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ git clone https://github.com/timothyye/godns.git * Go into the godns directory, get related library and then build it: ```bash -cd godns -go get +cd cmd/godns +go get -v go build ``` From 62ac21417e318c1fab525e2141d059d694835907 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:34:17 +0800 Subject: [PATCH 64/99] remove unused code, add test cases --- handler/dnspod_handler.go | 2 -- handler/he_handler.go | 2 -- utils.go | 42 +-------------------------------------- utils_test.go | 23 ++++++++++++++++++++- 4 files changed, 23 insertions(+), 46 deletions(-) diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index 4501cb2..f236062 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -32,8 +32,6 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- defer func() { if err := recover(); err != nil { log.Printf("Recovered in %v: %v\n", err, debug.Stack()) - fmt.Println(godns.IdentifyPanic()) - log.Print(godns.IdentifyPanic()) panicChan <- *domain } }() diff --git a/handler/he_handler.go b/handler/he_handler.go index 69a755c..9a34e77 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -35,8 +35,6 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn defer func() { if err := recover(); err != nil { log.Printf("Recovered in %v: %v\n", err, debug.Stack()) - fmt.Println(godns.IdentifyPanic()) - log.Print(godns.IdentifyPanic()) panicChan <- *domain } }() diff --git a/utils.go b/utils.go index 37a028d..1932d78 100644 --- a/utils.go +++ b/utils.go @@ -2,13 +2,9 @@ package godns import ( "errors" - "flag" - "fmt" "io/ioutil" "log" "net/http" - "runtime" - "strings" "golang.org/x/net/proxy" ) @@ -31,10 +27,9 @@ func GetCurrentIP(configuration *Settings) (string, error) { if configuration.Socks5Proxy != "" { log.Println("use socks5 proxy:" + configuration.Socks5Proxy) - dialer, err := proxy.SOCKS5("tcp", configuration.Socks5Proxy, nil, proxy.Direct) if err != nil { - fmt.Println("can't connect to the proxy:", err) + log.Println("can't connect to the proxy:", err) return "", err } @@ -56,41 +51,6 @@ func GetCurrentIP(configuration *Settings) (string, error) { return string(body), nil } -// IdentifyPanic identifies panic and output the detailed panic information -func IdentifyPanic() string { - var name, file string - var line int - var pc [16]uintptr - - n := runtime.Callers(3, pc[:]) - for _, pc := range pc[:n] { - fn := runtime.FuncForPC(pc) - if fn == nil { - continue - } - file, line = fn.FileLine(pc) - name = fn.Name() - if !strings.HasPrefix(name, "runtime.") { - break - } - } - - switch { - case name != "": - return fmt.Sprintf("%v:%v", name, line) - case file != "": - return fmt.Sprintf("%v:%v", file, line) - } - - return fmt.Sprintf("pc:%x", pc) -} - -// Usage prints the usage of GoDNS -func Usage() { - log.Println("[command] -c=[config file path]") - flag.PrintDefaults() -} - // CheckSettings check the format of settings func CheckSettings(config *Settings) error { if config.Provider == DNSPOD { diff --git a/utils_test.go b/utils_test.go index 6e2241e..fcc51b8 100644 --- a/utils_test.go +++ b/utils_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func testGetCurrentIP(t *testing.T) { +func TestGetCurrentIP(t *testing.T) { conf := &Settings{IPUrl: "http://members.3322.org/dyndns/getip"} ip, _ := GetCurrentIP(conf) @@ -14,3 +14,24 @@ func testGetCurrentIP(t *testing.T) { t.Log("IP is:" + ip) } } + +func TestCheckSettings(t *testing.T) { + settingError := &Settings{} + if err := CheckSettings(settingError); err == nil { + t.Error("setting is invalid, should return error") + } + + settingDNSPod := &Settings{Provider: "DNSPod", LoginToken: "aaa"} + if err := CheckSettings(settingDNSPod); err == nil { + t.Log("setting with login token, passed") + } else { + t.Error("setting with login token, should be passed") + } + + settingHE := &Settings{Provider: "HE", Password: ""} + if err := CheckSettings(settingHE); err != nil { + t.Log("HE setting without password, passed") + } else { + t.Error("HE setting without password, should be faild") + } +} From 377d91d969e78060f722cf40d11b159c96fd2b75 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:44:44 +0800 Subject: [PATCH 65/99] add test case --- utils_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils_test.go b/utils_test.go index fcc51b8..bab2979 100644 --- a/utils_test.go +++ b/utils_test.go @@ -13,6 +13,13 @@ func TestGetCurrentIP(t *testing.T) { } else { t.Log("IP is:" + ip) } + + conf = &Settings{Socks5Proxy: "localhost:8899", IPUrl: "http://members.3322.org/dyndns/getip"} + ip, err := GetCurrentIP(conf) + + if ip != "" && err == nil { + t.Error("should return error") + } } func TestCheckSettings(t *testing.T) { From d0dfa698b09fd53a501eb241af8e14e7e7b2b998 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:47:36 +0800 Subject: [PATCH 66/99] add test case --- utils_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils_test.go b/utils_test.go index bab2979..5a77a52 100644 --- a/utils_test.go +++ b/utils_test.go @@ -35,6 +35,11 @@ func TestCheckSettings(t *testing.T) { t.Error("setting with login token, should be passed") } + settingDNSPod = &Settings{Provider: "DNSPod"} + if err := CheckSettings(settingDNSPod); err == nil { + t.Error("setting with invalid parameters, should be failed") + } + settingHE := &Settings{Provider: "HE", Password: ""} if err := CheckSettings(settingHE); err != nil { t.Log("HE setting without password, passed") From 732e97a2944bdb30f8fdd2838674912a87fe0a46 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:50:35 +0800 Subject: [PATCH 67/99] add test case --- settings_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/settings_test.go b/settings_test.go index da7efb9..2f606f4 100644 --- a/settings_test.go +++ b/settings_test.go @@ -13,6 +13,11 @@ func TestLoadSetting(t *testing.T) { } if settings.IPUrl == "" { - t.Error("Cannot load ip_url from config file") + t.Error("cannot load ip_url from config file") + } + + err = LoadSettings("./file/does/not/exists", &settings) + if err == nil { + t.Error("file doesn't exist, should return error") } } From 0b30f52e715c6b083ca6b049fa36dd1af34b685c Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 14:59:52 +0800 Subject: [PATCH 68/99] add cover.run badge --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3b8575..bba1983 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ``` -[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Docker][3]][4] [![Go Report Card][11]][12] [![GoDoc][13]][14] +[![Release][7]][8] [![MIT licensed][9]][10] [![Build Status][1]][2] [![Docker][3]][4] [![Go Report Card][11]][12] [![Cover.Run][15]][16] [![GoDoc][13]][14] [1]: https://travis-ci.org/TimothyYe/godns.svg?branch=master [2]: https://travis-ci.org/TimothyYe/godns @@ -21,6 +21,8 @@ [12]: https://goreportcard.com/report/github.com/timothyye/godns [13]: https://godoc.org/github.com/TimothyYe/godns?status.svg [14]: https://godoc.org/github.com/TimothyYe/godns +[15]: https://cover.run/go/github.com/timothyye/godns.svg +[16]: https://cover.run/go/github.com/timothyye/godns GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). From bccb29ff504ffa4ced62ef8bd178729c35619eb9 Mon Sep 17 00:00:00 2001 From: Timothy Date: Fri, 27 Oct 2017 02:34:32 -0500 Subject: [PATCH 69/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bba1983..a6beabe 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ [12]: https://goreportcard.com/report/github.com/timothyye/godns [13]: https://godoc.org/github.com/TimothyYe/godns?status.svg [14]: https://godoc.org/github.com/TimothyYe/godns -[15]: https://cover.run/go/github.com/timothyye/godns.svg +[15]: https://img.shields.io/badge/cover.run-88.2%25-green.svg [16]: https://cover.run/go/github.com/timothyye/godns GoDNS is a dynamic DNS (DDNS) client tool, it is based on my early open source project: [DynDNS](https://github.com/TimothyYe/DynDNS). From 508aa7321ad923d4773ee48ee41082917f30a894 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 11:04:25 +0800 Subject: [PATCH 70/99] fix #14 Avoid too much api call times by creating a file to store last IP address --- .gitignore | 1 + handler/dnspod_handler.go | 14 ++++++++++++-- handler/he_handler.go | 12 +++++++++++- utils.go | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 23e40f7..f45916b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ vendor/* /godns.iml /godns.ipr /godns.iws +.current_ip diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index f236062..4adce35 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -37,7 +37,6 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- }() for { - domainID := handler.GetDomain(domain.DomainName) if domainID == -1 { @@ -50,7 +49,18 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- log.Println("get_currentIP:", err) continue } - log.Println("currentIp is:", currentIP) + log.Println("currentIP is:", currentIP) + + //Compare currentIP with saved IP + savedIP := godns.LoadCurrentIP() + log.Println("savedIP is:", savedIP) + + if savedIP != "" && strings.TrimRight(currentIP, "\n") == strings.TrimRight(savedIP, "\n") { + log.Printf("Current IP is not changed, no need to update...") + continue + } else { + godns.SaveCurrentIP(currentIP) + } for _, subDomain := range domain.SubDomains { diff --git a/handler/he_handler.go b/handler/he_handler.go index 9a34e77..ac0b286 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -46,7 +46,17 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn log.Println("get_currentIP:", err) continue } - log.Println("currentIp is:", currentIP) + log.Println("currentIP is:", currentIP) + + //Compare currentIP with saved IP + savedIP := godns.LoadCurrentIP() + + if savedIP != "" && currentIP == savedIP { + log.Printf("Current IP is not changed, no need to update...") + continue + } else { + godns.SaveCurrentIP(currentIP) + } for _, subDomain := range domain.SubDomains { log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) diff --git a/utils.go b/utils.go index 1932d78..f85c64c 100644 --- a/utils.go +++ b/utils.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "log" "net/http" + "os" + "strings" "golang.org/x/net/proxy" ) @@ -67,3 +69,17 @@ func CheckSettings(config *Settings) error { return nil } + +func SaveCurrentIP(currentIP string) { + ioutil.WriteFile("./.current_ip", []byte(currentIP), os.FileMode(0644)) +} + +func LoadCurrentIP() string { + content, err := ioutil.ReadFile("./.current_ip") + + if err != nil { + return "" + } + + return strings.Replace(string(content), "\n", "", -1) +} From f8dac9d4e982a90818a188ca3a02d536e119539e Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 11:13:46 +0800 Subject: [PATCH 71/99] add test case --- utils_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/utils_test.go b/utils_test.go index 5a77a52..8a3ac0c 100644 --- a/utils_test.go +++ b/utils_test.go @@ -1,6 +1,8 @@ package godns import ( + "os" + "strings" "testing" ) @@ -47,3 +49,28 @@ func TestCheckSettings(t *testing.T) { t.Error("HE setting without password, should be faild") } } + +func TestSaveCurrentIP(t *testing.T) { + SaveCurrentIP("1.2.3.4") + + if _, err := os.Stat("./.current_ip"); os.IsNotExist(err) { + t.Error(".current_ip file should exists") + } + + savedIP := LoadCurrentIP() + + if strings.TrimRight(savedIP, "\n") != "1.2.3.4" { + t.Error("saved IP should be equal to 1.2.3.4") + } + + //Cleanup + os.Remove("./.current_ip") +} + +func TestLoadCurrentIP(t *testing.T) { + ip := LoadCurrentIP() + + if ip != "" { + t.Error("current ip file should be empth") + } +} From bfb7961229b7c45304da725cc5146839e0977f9c Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:17:18 +0800 Subject: [PATCH 72/99] move Makefile, add program logo --- Makefile => cmd/godns/Makefile | 10 +++++----- cmd/godns/godns.go | 3 +++ utils.go | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) rename Makefile => cmd/godns/Makefile (58%) diff --git a/Makefile b/cmd/godns/Makefile similarity index 58% rename from Makefile rename to cmd/godns/Makefile index 2bc942d..8da0984 100644 --- a/Makefile +++ b/cmd/godns/Makefile @@ -2,7 +2,7 @@ BINARY=godns # Builds the project build: - go build -o ${BINARY} + go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" # Installs our project: copies binaries install: go install @@ -11,19 +11,19 @@ release: go clean rm -rf *.gz # Build for mac - go build + go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" tar czvf ${BINARY}-mac64-${VERSION}.tar.gz ./${BINARY} # Build for linux go clean - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" tar czvf ${BINARY}-linux64-${VERSION}.tar.gz ./${BINARY} # Build for arm go clean - CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY} # Build for win go clean - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build + CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe go clean # Cleans our projects: deletes binaries diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 51a59b9..2cb5b77 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -9,17 +9,20 @@ import ( "github.com/TimothyYe/godns" "github.com/TimothyYe/godns/handler" + "github.com/fatih/color" ) var ( configuration godns.Settings optConf = flag.String("c", "./config.json", "Specify a config file") optHelp = flag.Bool("h", false, "Show help") + Version = "0.1" ) func main() { flag.Parse() if *optHelp { + color.Cyan(godns.Logo, Version) flag.Usage() return } diff --git a/utils.go b/utils.go index f85c64c..908db3f 100644 --- a/utils.go +++ b/utils.go @@ -11,6 +11,22 @@ import ( "golang.org/x/net/proxy" ) +var ( + Logo = ` + + ██████╗ ██████╗ ██████╗ ███╗ ██╗███████╗ +██╔════╝ ██╔═══██╗██╔══██╗████╗ ██║██╔════╝ +██║ ███╗██║ ██║██║ ██║██╔██╗ ██║███████╗ +██║ ██║██║ ██║██║ ██║██║╚██╗██║╚════██║ +╚██████╔╝╚██████╔╝██████╔╝██║ ╚████║███████║ + ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ + +GoDNS V%s +https://github.com/TimothyYe/godns + +` +) + const ( // PanicMax is the max allowed panic times PanicMax = 5 From 49d14783949dffe833b5364206afc282913b54b1 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:21:03 +0800 Subject: [PATCH 73/99] update release version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6beabe..070797f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [2]: https://travis-ci.org/TimothyYe/godns [3]: https://images.microbadger.com/badges/image/timothyye/godns.svg [4]: https://microbadger.com/images/timothyye/godns -[7]: https://img.shields.io/badge/release-v1.3-brightgreen.svg +[7]: https://img.shields.io/badge/release-v1.4-brightgreen.svg [8]: https://github.com/TimothyYe/godns/releases [9]: https://img.shields.io/badge/license-Apache-blue.svg [10]: LICENSE From 4b69c69f34b823765ab0745a65672633126c9c66 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:25:09 +0800 Subject: [PATCH 74/99] update Makefile --- cmd/godns/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/godns/Makefile b/cmd/godns/Makefile index 8da0984..274156f 100644 --- a/cmd/godns/Makefile +++ b/cmd/godns/Makefile @@ -23,11 +23,12 @@ release: tar czvf ${BINARY}-arm64-${VERSION}.tar.gz ./${BINARY} # Build for win go clean - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${BINARY} -ldflags "-X main.Version=${VERSION}" + CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${BINARY}.exe -ldflags "-X main.Version=${VERSION}" tar czvf ${BINARY}-win64-${VERSION}.tar.gz ./${BINARY}.exe go clean # Cleans our projects: deletes binaries clean: go clean + rm -rf *.gz .PHONY: clean build From 9020971add80b393c5296a3cda45196f5a95c52a Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:33:30 +0800 Subject: [PATCH 75/99] bug fix for sleeping --- handler/dnspod_handler.go | 28 ++++++++++++++-------------- handler/he_handler.go | 11 +++++------ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index 4adce35..f2f735b 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -57,30 +57,30 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- if savedIP != "" && strings.TrimRight(currentIP, "\n") == strings.TrimRight(savedIP, "\n") { log.Printf("Current IP is not changed, no need to update...") - continue } else { godns.SaveCurrentIP(currentIP) - } - for _, subDomain := range domain.SubDomains { + for _, subDomain := range domain.SubDomains { - subDomainID, ip := handler.GetSubDomain(domainID, subDomain) + subDomainID, ip := handler.GetSubDomain(domainID, subDomain) - if subDomainID == "" || ip == "" { - log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) - continue - } + if subDomainID == "" || ip == "" { + log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) + continue + } - //Continue to check the IP of sub-domain - if len(ip) > 0 && !strings.Contains(currentIP, ip) { - log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) - handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) - } else { - log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) + //Continue to check the IP of sub-domain + if len(ip) > 0 && !strings.Contains(currentIP, ip) { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) + } else { + log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) + } } } //Interval is 5 minutes + log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL) time.Sleep(time.Minute * godns.INTERVAL) } } diff --git a/handler/he_handler.go b/handler/he_handler.go index ac0b286..e25181b 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -53,17 +53,16 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn if savedIP != "" && currentIP == savedIP { log.Printf("Current IP is not changed, no need to update...") - continue } else { godns.SaveCurrentIP(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) + for _, subDomain := range domain.SubDomains { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(domain.DomainName, subDomain, currentIP) + } } // Interval is 5 minutes + log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL) time.Sleep(time.Minute * godns.INTERVAL) } } From 2d935d704eebf0f581584a10a4c73410666ce229 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 01:39:59 -0500 Subject: [PATCH 76/99] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index bdc4131..9775110 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ go: install: - go get -v - go get -v github.com/bitly/go-simplejson + - go get -v github.com/fatih/color script: - cp ./config_sample.json ./config.json From 661afa0e0da1310f8ad50eb84e494f55e36bc49b Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:44:36 +0800 Subject: [PATCH 77/99] update gitignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f45916b..d62b316 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ vendor/* /godns.ipr /godns.iws .current_ip +.DS_Store From ebb174f604d95110e5c023853a5a6e5fb7e702cf Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 14:53:42 +0800 Subject: [PATCH 78/99] fix golint warnings --- cmd/godns/godns.go | 4 +++- utils.go | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 2cb5b77..655b5cf 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -16,7 +16,9 @@ var ( configuration godns.Settings optConf = flag.String("c", "./config.json", "Specify a config file") optHelp = flag.Bool("h", false, "Show help") - Version = "0.1" + + // Version is current version of GoDNS + Version = "0.1" ) func main() { diff --git a/utils.go b/utils.go index 908db3f..5ec76a3 100644 --- a/utils.go +++ b/utils.go @@ -12,6 +12,7 @@ import ( ) var ( + // Logo for GoDNS Logo = ` ██████╗ ██████╗ ██████╗ ███╗ ██╗███████╗ @@ -86,10 +87,12 @@ func CheckSettings(config *Settings) error { return nil } +// SaveCurrentIP saves current IP into a template file func SaveCurrentIP(currentIP string) { ioutil.WriteFile("./.current_ip", []byte(currentIP), os.FileMode(0644)) } +// LoadCurrentIP loads saved IP from template file func LoadCurrentIP() string { content, err := ioutil.ReadFile("./.current_ip") From eef6c9c1aa3c010adbe881b12a3fb7f3704288e2 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 15:04:10 +0800 Subject: [PATCH 79/99] move Dockerfile --- Dockerfile => cmd/godns/Dockerfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Dockerfile => cmd/godns/Dockerfile (100%) diff --git a/Dockerfile b/cmd/godns/Dockerfile similarity index 100% rename from Dockerfile rename to cmd/godns/Dockerfile From 549a98a48f07c4b39434c7a516d9e4cdef547c0d Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 30 Oct 2017 15:07:55 +0800 Subject: [PATCH 80/99] update README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 070797f..b8b8a5d 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ Now godns supports to run in docker. ```bash docker run -d --name godns --restart=always \ --v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:1.3 +-v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:latest ``` ## Enjoy it! From 281ede607170fbbecadf3d11dd2ec1bac5fb8404 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 2 Nov 2017 14:49:49 +0800 Subject: [PATCH 81/99] remove log size & log num --- config_sample.json | 2 -- settings.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/config_sample.json b/config_sample.json index 55200b2..6f63c3f 100644 --- a/config_sample.json +++ b/config_sample.json @@ -13,7 +13,5 @@ ], "ip_url": "http://members.3322.org/dyndns/getip", "log_path": "./godns.log", - "log_size": 16, - "log_num": 3, "socks5_proxy": "" } diff --git a/settings.go b/settings.go index e648381..6ac9904 100644 --- a/settings.go +++ b/settings.go @@ -21,8 +21,6 @@ type Settings struct { Domains []Domain `json:"domains"` IPUrl string `json:"ip_url"` LogPath string `json:"log_path"` - LogSize int `json:"log_size"` - LogNum int `json:"log_num"` Socks5Proxy string `json:"socks5_proxy"` } From 9d6efbc806fd8cab52e3eaa7f9dceafa479858d8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 2 Nov 2017 14:50:43 +0800 Subject: [PATCH 82/99] update README file --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index b8b8a5d..fb0f8c8 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,6 @@ For DNSPod, you need to provide email & password, and config all the domains & ], "ip_url": "http://members.3322.org/dyndns/getip", "log_path": "./godns.log", - "log_size": 16, - "log_num": 3, "socks5_proxy": "" } ``` @@ -133,8 +131,6 @@ For HE, email is not needed, just fill DDNS key to password, and config all the ], "ip_url": "http://members.3322.org/dyndns/getip", "log_path":"/users/timothy/workspace/src/godns/godns.log", - "log_size":16, - "log_num":3, "socks5_proxy": "" } ``` From ccbdf4e31df9858e8194b33c68e0cdcf3846491f Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 2 Nov 2017 16:45:50 +0800 Subject: [PATCH 83/99] add notify model, add send notify method --- settings.go | 10 ++++++++++ utils.go | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/settings.go b/settings.go index 6ac9904..0d35613 100644 --- a/settings.go +++ b/settings.go @@ -12,6 +12,15 @@ type Domain struct { SubDomains []string `json:"sub_domains"` } +type Notify struct { + Enabled bool `json:"enabled"` + SMTPServer string `json:"smtp_server"` + SendTo string `json:"send_to"` + Port int `json:"port"` + Account string `json:"account"` + Password string `json:"password"` +} + // Settings struct type Settings struct { Provider string `json:"provider"` @@ -22,6 +31,7 @@ type Settings struct { IPUrl string `json:"ip_url"` LogPath string `json:"log_path"` Socks5Proxy string `json:"socks5_proxy"` + Notify Notify `json:"notify"` } // LoadSettings -- Load settings from config file diff --git a/utils.go b/utils.go index 5ec76a3..4e767e7 100644 --- a/utils.go +++ b/utils.go @@ -9,6 +9,7 @@ import ( "strings" "golang.org/x/net/proxy" + "gopkg.in/gomail.v2" ) var ( @@ -102,3 +103,21 @@ func LoadCurrentIP() string { return strings.Replace(string(content), "\n", "", -1) } + +// SendNotify sends mail notify if IP is changed +func SendNotify(configuration *Settings, currentIP string) error { + m := gomail.NewMessage() + + m.SetHeader("From", configuration.Notify.Account) + m.SetHeader("To", configuration.Notify.SendTo) + m.SetHeader("Subject", "GoDNS Notification") + m.SetBody("text/html", "") + + d := gomail.NewPlainDialer(configuration.Notify.SMTPServer, configuration.Notify.Port, configuration.Notify.Account, configuration.Notify.Password) + + // Send the email config by sendlist . + if err := d.DialAndSend(m); err != nil { + return err + } + return nil +} From 4c4f34c55bd08e9a61d31f61af8fca8214f3b778 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 11:32:27 +0800 Subject: [PATCH 84/99] send mail notify if IP is changed --- handler/dnspod_handler.go | 12 +++++++++--- handler/he_handler.go | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index f2f735b..483f11f 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -51,7 +51,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- } log.Println("currentIP is:", currentIP) - //Compare currentIP with saved IP + // Compare currentIP with saved IP savedIP := godns.LoadCurrentIP() log.Println("savedIP is:", savedIP) @@ -69,17 +69,23 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- continue } - //Continue to check the IP of sub-domain + // Continue to check the IP of sub-domain if len(ip) > 0 && !strings.Contains(currentIP, ip) { log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) + + // Send mail notification if notify is enabled + if handler.Configuration.Notify.Enabled { + godns.SendNotify(handler.Configuration, currentIP) + } + } else { log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) } } } - //Interval is 5 minutes + // Interval is 5 minutes log.Printf("Going to sleep, will start next checking in %d minutes...\r\n", godns.INTERVAL) time.Sleep(time.Minute * godns.INTERVAL) } diff --git a/handler/he_handler.go b/handler/he_handler.go index e25181b..ce31dd1 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -58,6 +58,11 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn 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 { + godns.SendNotify(handler.Configuration, currentIP) + } } } From 7a65d4e0ea26a038788057ca6a4210da0c85787b Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 16:48:43 +0800 Subject: [PATCH 85/99] refactor send notify logic --- config_sample.json | 10 +++- handler/dnspod_handler.go | 3 +- handler/he_handler.go | 3 +- settings.go | 12 ++--- template.go | 105 ++++++++++++++++++++++++++++++++++++++ utils.go | 12 +++-- 6 files changed, 132 insertions(+), 13 deletions(-) create mode 100644 template.go diff --git a/config_sample.json b/config_sample.json index 6f63c3f..cbedc6b 100644 --- a/config_sample.json +++ b/config_sample.json @@ -13,5 +13,13 @@ ], "ip_url": "http://members.3322.org/dyndns/getip", "log_path": "./godns.log", - "socks5_proxy": "" + "socks5_proxy": "", + "notify": { + "enabled": false, + "smtp_server": "", + "smtp_username": "", + "smtp_password": "", + "smtp_port": 25, + "send_to": "", + } } diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index 483f11f..cc96816 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -76,7 +76,8 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- // Send mail notification if notify is enabled if handler.Configuration.Notify.Enabled { - godns.SendNotify(handler.Configuration, currentIP) + log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) + godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) } } else { diff --git a/handler/he_handler.go b/handler/he_handler.go index ce31dd1..d11a2ab 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -61,7 +61,8 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn // Send mail notification if notify is enabled if handler.Configuration.Notify.Enabled { - godns.SendNotify(handler.Configuration, currentIP) + log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) + godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) } } } diff --git a/settings.go b/settings.go index 0d35613..fd3cf1f 100644 --- a/settings.go +++ b/settings.go @@ -13,12 +13,12 @@ type Domain struct { } type Notify struct { - Enabled bool `json:"enabled"` - SMTPServer string `json:"smtp_server"` - SendTo string `json:"send_to"` - Port int `json:"port"` - Account string `json:"account"` - Password string `json:"password"` + Enabled bool `json:"enabled"` + SMTPServer string `json:"smtp_server"` + SMTPUsername string `json:"smtp_username"` + SMTPPassword string `json:"smtp_password"` + SMTPPort int `json:"smtp_port"` + SendTo string `json:"send_to"` } // Settings struct diff --git a/template.go b/template.go new file mode 100644 index 0000000..aec9221 --- /dev/null +++ b/template.go @@ -0,0 +1,105 @@ +package godns + +var template = ` + + +
+
+
+
+ +
+ +
+
 
+
+ +
+ +
+
+
+ +
+
+
+ +
+ +
+
 
+
+ +
+
+

+ + Your IP address is changed to + +

+

+ + + %s + + +

+

+ + Domain: %s is updated + +

+
+
+ +
+
 
+
+ +
+
 
+
+ +
+ +
+
+
+ +
 
+ + +
+ +
+
 
+ +
+ +` diff --git a/utils.go b/utils.go index 4e767e7..69d0b6d 100644 --- a/utils.go +++ b/utils.go @@ -2,6 +2,7 @@ package godns import ( "errors" + "fmt" "io/ioutil" "log" "net/http" @@ -105,18 +106,21 @@ func LoadCurrentIP() string { } // SendNotify sends mail notify if IP is changed -func SendNotify(configuration *Settings, currentIP string) error { +func SendNotify(configuration *Settings, domain string, currentIP string) error { m := gomail.NewMessage() - m.SetHeader("From", configuration.Notify.Account) + m.SetHeader("From", configuration.Notify.SMTPUsername) m.SetHeader("To", configuration.Notify.SendTo) m.SetHeader("Subject", "GoDNS Notification") - m.SetBody("text/html", "") + log.Println("currentIP:", currentIP) + log.Println("domain:", domain) + m.SetBody("text/html", fmt.Sprintf(template, currentIP, domain)) - d := gomail.NewPlainDialer(configuration.Notify.SMTPServer, configuration.Notify.Port, configuration.Notify.Account, configuration.Notify.Password) + d := gomail.NewPlainDialer(configuration.Notify.SMTPServer, configuration.Notify.SMTPPort, configuration.Notify.SMTPUsername, configuration.Notify.SMTPPassword) // Send the email config by sendlist . if err := d.DialAndSend(m); err != nil { + log.Println("Send email notification with error:", err.Error()) return err } return nil From 0155dee427ebbfb53c69ff5c2ebffa8581d33ed7 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 17:26:40 +0800 Subject: [PATCH 86/99] compile template --- template.go | 6 +++--- utils.go | 29 ++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/template.go b/template.go index aec9221..d6c433a 100644 --- a/template.go +++ b/template.go @@ -1,6 +1,6 @@ package godns -var template = ` +var MailTemplate = `
@@ -42,14 +42,14 @@ var template = ` lang="x-size-48"> - %s + {{ .CurrentIP }}

- Domain: %s is updated + Domain {{ .Domain }} is updated

diff --git a/utils.go b/utils.go index 69d0b6d..48a2ee4 100644 --- a/utils.go +++ b/utils.go @@ -1,8 +1,9 @@ package godns import ( + "bytes" "errors" - "fmt" + "html/template" "io/ioutil" "log" "net/http" @@ -106,7 +107,7 @@ func LoadCurrentIP() string { } // SendNotify sends mail notify if IP is changed -func SendNotify(configuration *Settings, domain string, currentIP string) error { +func SendNotify(configuration *Settings, domain, currentIP string) error { m := gomail.NewMessage() m.SetHeader("From", configuration.Notify.SMTPUsername) @@ -114,7 +115,7 @@ func SendNotify(configuration *Settings, domain string, currentIP string) error m.SetHeader("Subject", "GoDNS Notification") log.Println("currentIP:", currentIP) log.Println("domain:", domain) - m.SetBody("text/html", fmt.Sprintf(template, currentIP, domain)) + m.SetBody("text/html", buildTemplate(currentIP, domain)) d := gomail.NewPlainDialer(configuration.Notify.SMTPServer, configuration.Notify.SMTPPort, configuration.Notify.SMTPUsername, configuration.Notify.SMTPPassword) @@ -125,3 +126,25 @@ func SendNotify(configuration *Settings, domain string, currentIP string) error } return nil } + +func buildTemplate(currentIP, domain string) string { + t := template.New("notification template") + t.Parse(MailTemplate) + + data := struct { + CurrentIP string + Domain string + }{ + currentIP, + domain, + } + + var tpl bytes.Buffer + if err := t.Execute(&tpl, data); err != nil { + log.Println(err.Error()) + return "" + } + + log.Println("result:", tpl.String()) + return tpl.String() +} From 50a5a8f308bafc67ab9221b66cab8c71b1b46f08 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 17:27:26 +0800 Subject: [PATCH 87/99] remove debug info --- utils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/utils.go b/utils.go index 48a2ee4..737165f 100644 --- a/utils.go +++ b/utils.go @@ -145,6 +145,5 @@ func buildTemplate(currentIP, domain string) string { return "" } - log.Println("result:", tpl.String()) return tpl.String() } From 8e5314ff0944b1a2ebb66994097c3fc64d8d1c07 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 17:37:30 +0800 Subject: [PATCH 88/99] update config sample file --- config_sample.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_sample.json b/config_sample.json index cbedc6b..8749deb 100644 --- a/config_sample.json +++ b/config_sample.json @@ -20,6 +20,6 @@ "smtp_username": "", "smtp_password": "", "smtp_port": 25, - "send_to": "", + "send_to": "" } } From d4bf2ca8d186d7370344b129dccf358a905f7ee8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 17:53:11 +0800 Subject: [PATCH 89/99] fix golint warnings --- settings.go | 1 + template.go | 2 +- utils.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/settings.go b/settings.go index fd3cf1f..c287628 100644 --- a/settings.go +++ b/settings.go @@ -12,6 +12,7 @@ type Domain struct { SubDomains []string `json:"sub_domains"` } +// Notify struct for SMTP notification type Notify struct { Enabled bool `json:"enabled"` SMTPServer string `json:"smtp_server"` diff --git a/template.go b/template.go index d6c433a..9b66792 100644 --- a/template.go +++ b/template.go @@ -1,6 +1,6 @@ package godns -var MailTemplate = ` +var mailTemplate = `
diff --git a/utils.go b/utils.go index 737165f..779241c 100644 --- a/utils.go +++ b/utils.go @@ -129,7 +129,7 @@ func SendNotify(configuration *Settings, domain, currentIP string) error { func buildTemplate(currentIP, domain string) string { t := template.New("notification template") - t.Parse(MailTemplate) + t.Parse(mailTemplate) data := struct { CurrentIP string From 733b2975532f85c2bc609b238a42eae575f04266 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 6 Nov 2017 18:04:44 +0800 Subject: [PATCH 90/99] add snapshots --- snapshots/notify.png | Bin 0 -> 52527 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 snapshots/notify.png diff --git a/snapshots/notify.png b/snapshots/notify.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa5307b89cab6498ae0580d88689c7a7b26fbd6 GIT binary patch literal 52527 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%0D-xaO^LS6F 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 ZgSoU Date: Mon, 6 Nov 2017 18:13:22 +0800 Subject: [PATCH 91/99] remove unused code --- cmd/godns/godns.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 655b5cf..55de35c 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -70,11 +70,9 @@ func dnsLoop() { panicCount := 0 for { - select { - case failDomain := <-panicChan: - log.Println("Got panic in goroutine, will start a new one... :", panicCount) - go handler.DomainLoop(&failDomain, panicChan) - } + failDomain := <-panicChan + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go handler.DomainLoop(&failDomain, panicChan) panicCount++ if panicCount >= godns.PanicMax { From 2a23abbcbd6ebc82cb15dd622005929ff86f61c1 Mon Sep 17 00:00:00 2001 From: Timothy Date: Wed, 6 Dec 2017 11:21:04 +0800 Subject: [PATCH 92/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb0f8c8..3c6ff2d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [2]: https://travis-ci.org/TimothyYe/godns [3]: https://images.microbadger.com/badges/image/timothyye/godns.svg [4]: https://microbadger.com/images/timothyye/godns -[7]: https://img.shields.io/badge/release-v1.4-brightgreen.svg +[7]: http://github-release-version.herokuapp.com/github/timothyye/godns/release.svg?style=flat [8]: https://github.com/TimothyYe/godns/releases [9]: https://img.shields.io/badge/license-Apache-blue.svg [10]: LICENSE From f428da55c8b46b1c635743e0ed01646cafbbcf8d Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Tue, 17 Apr 2018 20:42:17 +0800 Subject: [PATCH 93/99] use stdout as default log output. --- cmd/godns/godns.go | 16 ++-------------- config_sample.json | 37 ++++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 55de35c..836c53b 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -40,20 +40,8 @@ func main() { os.Exit(1) } - if configuration.LogPath == "" { - configuration.LogPath = "./godns.log" - } - - // Init log file - f, err := os.OpenFile(configuration.LogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - fmt.Println("Failed to create log file:", configuration.LogPath) - os.Exit(1) - } - - defer f.Close() - - log.SetOutput(f) + // Init log settings + log.SetPrefix("【GoDNS】") log.Println("GoDNS started, entering main loop...") dnsLoop() } diff --git a/config_sample.json b/config_sample.json index 8749deb..7553c94 100644 --- a/config_sample.json +++ b/config_sample.json @@ -1,25 +1,32 @@ { - "provider": "DNSPod", + "provider": "DNSPod", "email": "example@gmail.com", "password": "", "login_token": "", - "domains": [{ + "domains": [ + { "domain_name": "example.com", - "sub_domains": ["www","test"] - },{ + "sub_domains": [ + "www", + "test" + ] + }, + { "domain_name": "example2.com", - "sub_domains": ["www","test"] + "sub_domains": [ + "www", + "test" + ] } ], "ip_url": "http://members.3322.org/dyndns/getip", - "log_path": "./godns.log", "socks5_proxy": "", - "notify": { - "enabled": false, - "smtp_server": "", - "smtp_username": "", - "smtp_password": "", - "smtp_port": 25, - "send_to": "" - } -} + "notify": { + "enabled": false, + "smtp_server": "", + "smtp_username": "", + "smtp_password": "", + "smtp_port": 25, + "send_to": "" + } +} \ No newline at end of file From 0b7bb3d6b98d213706c27519e0bd8c189172e1e8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 19 Apr 2018 10:56:45 +0800 Subject: [PATCH 94/99] update README file --- README.md | 21 ++++++++++++++++++++- snapshots/mail.png | Bin 0 -> 43335 bytes 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 snapshots/mail.png diff --git a/README.md b/README.md index 3c6ff2d..3e1e709 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Usage of ./godns: * Get [config_sample.json](https://github.com/timothyye/godns/blob/master/config_sample.json) from Github. * Rename it to **config.json**. * Configure your provider, domain/sub-domain info, username and password, etc. -* Configure log file path, max size of log file, max count of log file. +* Configure the SMTP options if you want, a mail notification will sent to your mailbox once the IP is changed. * Save it in the same directory of GoDNS, or use -c=your_conf_path command. ### Config example for DNSPod @@ -149,6 +149,25 @@ Remember the DDNS key and fill it as password to the config.json. __NOTICE__: If you have multiple domains or subdomains, make sure their DDNS key are the same. +### Email notification support + +Update config file and provide your SMTP options, a notification mail will be sent to your mailbox once the IP is changed and updated. + +```json + "notify": { + "enabled": true, + "smtp_server": "smtp.example.com", + "smtp_username": "user", + "smtp_password": "password", + "smtp_port": 25, + "send_to": "my_mail@example.com" + } +``` + +Notification mail example: + + + ### SOCKS5 proxy support You can also use SOCKS5 proxy, just fill SOCKS5 address to the ```socks5_proxy``` item: diff --git a/snapshots/mail.png b/snapshots/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..b3df9b0faac29285c21d2ab7a250ec0072f23ed4 GIT binary patch literal 43335 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%0Du{ACZ6)l08Fx`gnlRLW0^p+e%J_z6fy}fgeUM zLbUEu-r{G-Npv-Z8i<%6GyPLB7KkLc*4&Ny*n9G%CsBA*Wv=@<=9JCt+h07z8yH57DO+u#?epw(Ot+7*SCUk$-Co3{Lg2ZE z?N;i6Y-qjeYc{k^XVhHvOAwk>$_#LU-Gdz0n>i8~2_a)VWU)XRPp-GyM8_N_i9Akh z3_jb=qtv#XjFYBex0)~^^d>vsJ}3j(QQ?q8HDG6)=NKbK8=;+Bkz#6_AQ|0OV?%g_{@Gbe`Q{rBgwELKjE{!r_~+87HoQ8D%a*i0M&Lr*uzjze5JhAVLF1rS#wqewhL75k>HKiQ&Xt=0fD#fXbA8@KJDyTM zN26JPcF0|JoCl-7PRx~7+j~J9uj$DiQyVD@I4ZH#6Z}>pyD$>=2a|kgA2V-X-PIRi?7oR%I9f(UNGHz1?nQy)$B{ zymf4d83G|eec)Z&Oahoay}s9qPs!ya%H(3b0K&`PH=MZe$JXO!k+JWNEK!t$P1CE4 zW0lewP}<>zjrhl;}+2%SY?7&U{T;qnGp{;GW=G`j;9HXV5sP3pQ2ycx_t6O?qfJ8tlO& zq^`x>@ZeoMj><(IHdR`NGhPaQ$kDW$U(RBrXaAKeZ%C`=9C%z9U(w*mqegythmz8w zq7gWro8pYJYB)H1!#g11$~w`zRldLBau%w-o!J(58Y_j5 z6aBKKgJX1cq~l|~N&4%q|DYYE(31Y=z~Xd`f44aS5FWsH zYSuatID+@LQ}-v6LGX;O=nXg${|Q1-{o~orY`k5$OTceMvi`<&Nb8?yzf-gI094(x z{Q$S=7P;Tih0-7(yDp;Y_d8)u>wv0F#x{F`J~TKU$Uh%%EA6Xw2Oy&2;s#^VsY6V2 z`2)f1m{|U*_5a8XueH{%3a3oHG%P+_FE_Ng%$U4}6L1IASuH)ZXve{0(QEov!G3n_ zF|$ybF#a7^4@(8y+!`@Cn(TLiXZtLiin(-Ryi_`Cib8+tzlHqX(+f<$*-a7oct`0~ zt#e6}&Xkuk>G@t{C#g?t;`jgD9LPdO0E$p6>UDnV?RGBhDX%(%yLJbuayLik+j@@6 zxv2)*LlWD8gYNa$XBJ9Ga5U5LJBrU%Yv>=JzvwltpvkHk|A&UZLbkoWcziY;eaw#F>rLrKhEsqR2zusxjqG(t>ETOy9h+Nd0P*fCR3&bIjZ2mzvYu#@!d zv^P5J$vT(OM&68GQv3iHrDTz?DB)8U{x@U*^gydiGb(7DzSRC2uOU~#^5MWNX})<)UGLVa4=%Ei zj^KdXUUoBm#<+Ji&7O{qfb(%>@l3wBRB zif4i^LO?$1N;pc&Gjefr-EkQ-eIm6#Q9nQ)f;y02AHVSKLpJ}rbp)wnQmurTAxHEC zw^HIG#wF+*3A6Wv>3~vKXc%jB*vXEm>@-~#tG$!_Mknkw^Q3JmGV#byVQx z^Tm?PL{edqE`i70te9H7ZpqR$h$Y^rHKbZ2o{~1n|=F zJcs1#zx%Pf=BupcGc%$RPdR=B<_m?+)8u*2+*a-Vy?VB~!L{-b4F8Q+nTPUDP|;m1~6y*YFo7F3>9yw0OF4{cA2>+L&NqL>)qV9SeS zq}Roy)GQXNa&HWzb>IsyFAKmE23yWwsB-+w#Te+-?b-7VSP5#yCx~tOB^Gka;YYbw zJ1!nHHo-~mvqG$w`bqU{P``%+@<7Lp2MKfscySGrVKDv?VxC*CweO8uR
    ;cX1$QV}KuA0x7!Bt{`pvk=`61 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 literal 0 HcmV?d00001 From 4fede061284a4ae589ae83c7947af7deac04dcd7 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 19 Apr 2018 10:57:36 +0800 Subject: [PATCH 95/99] update README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e1e709..49d5ad0 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ Update config file and provide your SMTP options, a notification mail will be se Notification mail example: - + ### SOCKS5 proxy support From cc51388579f0be672a39ae3bf6d67e669ddf2fe3 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 14 May 2018 11:09:24 +0800 Subject: [PATCH 96/99] fix issue #20 --- handler/dnspod_handler.go | 2 +- handler/he_handler.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index cc96816..98fa337 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -70,7 +70,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- } // Continue to check the IP of sub-domain - if len(ip) > 0 && !strings.Contains(currentIP, ip) { + if len(ip) > 0 && strings.TrimRight(currentIP, "\n") != strings.TrimRight(ip, "\n") { log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) diff --git a/handler/he_handler.go b/handler/he_handler.go index d11a2ab..2ac9b13 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -51,7 +51,7 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn //Compare currentIP with saved IP savedIP := godns.LoadCurrentIP() - if savedIP != "" && currentIP == savedIP { + if savedIP != "" && strings.TrimRight(currentIP, "\n") == strings.TrimRight(savedIP, "\n") { log.Printf("Current IP is not changed, no need to update...") } else { godns.SaveCurrentIP(currentIP) From 7d7a616aead7b2830c8baf61e83b1276ad9111da Mon Sep 17 00:00:00 2001 From: Timothy Ye Date: Fri, 15 Jun 2018 22:16:21 +0800 Subject: [PATCH 97/99] fix issue #22 --- cmd/godns/godns.go | 4 ++-- handler/dnspod_handler.go | 43 ++++++++++++++++----------------------- handler/he_handler.go | 22 +++++++------------- utils.go | 19 ----------------- 4 files changed, 26 insertions(+), 62 deletions(-) diff --git a/cmd/godns/godns.go b/cmd/godns/godns.go index 836c53b..6cc795b 100644 --- a/cmd/godns/godns.go +++ b/cmd/godns/godns.go @@ -52,8 +52,8 @@ func dnsLoop() { log.Println("Creating DNS handler with provider:", configuration.Provider) handler := handler.CreateHandler(configuration.Provider) handler.SetConfiguration(&configuration) - for _, domain := range configuration.Domains { - go handler.DomainLoop(&domain, panicChan) + for i, _ := range configuration.Domains { + go handler.DomainLoop(&configuration.Domains[i], panicChan) } panicCount := 0 diff --git a/handler/dnspod_handler.go b/handler/dnspod_handler.go index 98fa337..06a4381 100644 --- a/handler/dnspod_handler.go +++ b/handler/dnspod_handler.go @@ -37,6 +37,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- }() for { + log.Printf("Checking IP for domain %s \r\n", domain.DomainName) domainID := handler.GetDomain(domain.DomainName) if domainID == -1 { @@ -51,38 +52,28 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<- } log.Println("currentIP is:", currentIP) - // Compare currentIP with saved IP - savedIP := godns.LoadCurrentIP() - log.Println("savedIP is:", savedIP) + for _, subDomain := range domain.SubDomains { - if savedIP != "" && strings.TrimRight(currentIP, "\n") == strings.TrimRight(savedIP, "\n") { - log.Printf("Current IP is not changed, no need to update...") - } else { - godns.SaveCurrentIP(currentIP) + subDomainID, ip := handler.GetSubDomain(domainID, subDomain) - for _, subDomain := range domain.SubDomains { + if subDomainID == "" || ip == "" { + log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) + continue + } - subDomainID, ip := handler.GetSubDomain(domainID, subDomain) + // Continue to check the IP of sub-domain + if len(ip) > 0 && strings.TrimRight(currentIP, "\n") != strings.TrimRight(ip, "\n") { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) - if subDomainID == "" || ip == "" { - log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip) - continue + // Send mail notification if notify is enabled + if handler.Configuration.Notify.Enabled { + log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) + godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) } - // Continue to check the IP of sub-domain - if len(ip) > 0 && strings.TrimRight(currentIP, "\n") != strings.TrimRight(ip, "\n") { - log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) - handler.UpdateIP(domainID, subDomainID, subDomain, currentIP) - - // Send mail notification if notify is enabled - if handler.Configuration.Notify.Enabled { - log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) - godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) - } - - } else { - log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) - } + } else { + log.Printf("%s.%s Current IP is same as domain IP, no need to update...\n", subDomain, domain.DomainName) } } diff --git a/handler/he_handler.go b/handler/he_handler.go index 2ac9b13..c34e02c 100644 --- a/handler/he_handler.go +++ b/handler/he_handler.go @@ -48,22 +48,14 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn } log.Println("currentIP is:", currentIP) - //Compare currentIP with saved IP - savedIP := godns.LoadCurrentIP() + for _, subDomain := range domain.SubDomains { + log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName) + handler.UpdateIP(domain.DomainName, subDomain, currentIP) - if savedIP != "" && strings.TrimRight(currentIP, "\n") == strings.TrimRight(savedIP, "\n") { - log.Printf("Current IP is not changed, no need to update...") - } else { - godns.SaveCurrentIP(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) - godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) - } + // Send mail notification if notify is enabled + if handler.Configuration.Notify.Enabled { + log.Print("Sending notification to:", handler.Configuration.Notify.SendTo) + godns.SendNotify(handler.Configuration, fmt.Sprintf("%s.%s", subDomain, domain.DomainName), currentIP) } } diff --git a/utils.go b/utils.go index 779241c..b43f95b 100644 --- a/utils.go +++ b/utils.go @@ -7,9 +7,6 @@ import ( "io/ioutil" "log" "net/http" - "os" - "strings" - "golang.org/x/net/proxy" "gopkg.in/gomail.v2" ) @@ -90,22 +87,6 @@ func CheckSettings(config *Settings) error { return nil } -// SaveCurrentIP saves current IP into a template file -func SaveCurrentIP(currentIP string) { - ioutil.WriteFile("./.current_ip", []byte(currentIP), os.FileMode(0644)) -} - -// LoadCurrentIP loads saved IP from template file -func LoadCurrentIP() string { - content, err := ioutil.ReadFile("./.current_ip") - - if err != nil { - return "" - } - - return strings.Replace(string(content), "\n", "", -1) -} - // SendNotify sends mail notify if IP is changed func SendNotify(configuration *Settings, domain, currentIP string) error { m := gomail.NewMessage() From 7d0ab96fb592d6587ac4e51832cc5681c53dc569 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 16 Jun 2018 14:19:14 +0800 Subject: [PATCH 98/99] Update utils_test.go --- utils_test.go | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/utils_test.go b/utils_test.go index 8a3ac0c..4d6a258 100644 --- a/utils_test.go +++ b/utils_test.go @@ -49,28 +49,3 @@ func TestCheckSettings(t *testing.T) { t.Error("HE setting without password, should be faild") } } - -func TestSaveCurrentIP(t *testing.T) { - SaveCurrentIP("1.2.3.4") - - if _, err := os.Stat("./.current_ip"); os.IsNotExist(err) { - t.Error(".current_ip file should exists") - } - - savedIP := LoadCurrentIP() - - if strings.TrimRight(savedIP, "\n") != "1.2.3.4" { - t.Error("saved IP should be equal to 1.2.3.4") - } - - //Cleanup - os.Remove("./.current_ip") -} - -func TestLoadCurrentIP(t *testing.T) { - ip := LoadCurrentIP() - - if ip != "" { - t.Error("current ip file should be empth") - } -} From b919752145008d658915de7b7d1177b3b93b5909 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 16 Jun 2018 15:49:16 +0800 Subject: [PATCH 99/99] Update utils_test.go --- utils_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils_test.go b/utils_test.go index 4d6a258..5a77a52 100644 --- a/utils_test.go +++ b/utils_test.go @@ -1,8 +1,6 @@ package godns import ( - "os" - "strings" "testing" )