diff --git a/README.md b/README.md index 8f8320a..4642ce1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![Build Status](https://travis-ci.org/TimothyYe/godns.svg?branch=master)](https://travis-ci.org/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) tool, it is fork from: [GoDNS](https://github.com/TimothyYe/godns). -Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call it [GoDNS](https://github.com/TimothyYe/godns). +Modify something. ## Pre-condition @@ -19,7 +19,7 @@ Now I rewrite [DynDNS](https://github.com/TimothyYe/DynDNS) by Golang and call i * Get source code from Github: ```bash -git clone https://github.com/TimothyYe/godns.git +git clone https://github.com/abotoo/godns.git ``` * Go into the godns directory, get related library and then build it: @@ -30,21 +30,17 @@ go build ``` * Then you get GoDNS. -### Build godns from the 3rd party - -* Visit this URL provided by [GoBuild](http://gobuild.io/download/github.com/TimothyYe/godns). -* Select the platform you need. -* Input the build type and branch name. -* Build and download GoDNS. - ## Run it -* Get [config_sample.json](https://github.com/TimothyYe/godns/blob/master/config_sample.json) from Github. +* Get [config_sample.json](https://github.com/abotoo/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. -* Save it in the same directory of GoDNS. +* Configure log file path, max size of log file, max count of log file. +* Configure user id, group id for safty. +* Save it in the same directory of GoDNS, or use -c=your_conf_path command. * The last step, run godns: + ```bash -nohup ./godns & +./godns ``` * Enjoy it! diff --git a/config_sample.json b/config_sample.json index bc40a8f..a3090af 100644 --- a/config_sample.json +++ b/config_sample.json @@ -3,5 +3,10 @@ "password": "", "domain": "", "sub_domain": "", - "ip_url": "http://members.3322.org/dyndns/getip" + "ip_url": "http://members.3322.org/dyndns/getip", + "log_path":"./godns.log", + "log_size":16, + "log_num":3, + "user":0, + "group":0 } \ No newline at end of file diff --git a/dns_handler.go b/dns_handler.go index 7ff07c6..f84889f 100644 --- a/dns_handler.go +++ b/dns_handler.go @@ -3,21 +3,21 @@ package main import ( "encoding/json" "fmt" - "github.com/bitly/go-simplejson" - log "github.com/cihub/seelog" "io/ioutil" + "log" "net/http" "net/url" "strconv" "strings" + + "github.com/bitly/go-simplejson" ) func get_currentIP(url string) (string, error) { response, err := http.Get(url) if err != nil { - fmt.Println("Cannot get IP...") - log.Error("Cannot get IP...") + log.Println("Cannot get IP...") return "", err } @@ -60,16 +60,14 @@ func get_domain(name string) int64 { response, err := post_data("/Domain.List", values) if err != nil { - fmt.Println("Failed to get domain list...") - log.Error("Failed to get domain list...") + log.Println("Failed to get domain list...") return -1 } sjson, parse_err := simplejson.NewJson([]byte(response)) if parse_err != nil { - fmt.Println(parse_err.Error()) - log.Error(parse_err.Error()) + log.Println(parse_err) return -1 } @@ -89,12 +87,18 @@ func get_domain(name string) int64 { break } } + if len(domains) == 0 { + log.Println("domains slice is empty.") + } + } else { + log.Println("get_domain:status code:", sjson.Get("status").Get("code").MustString()) } return ret } func get_subdomain(domain_id int64, name string) (string, string) { + log.Println("debug:", domain_id, name) var ret, ip string value := url.Values{} value.Add("domain_id", strconv.FormatInt(domain_id, 10)) @@ -105,16 +109,14 @@ func get_subdomain(domain_id int64, name string) (string, string) { response, err := post_data("/Record.List", value) if err != nil { - fmt.Println("Failed to get domain list...") - log.Error("Failed to get domain list") + log.Println("Failed to get domain list") return "", "" } sjson, parse_err := simplejson.NewJson([]byte(response)) if parse_err != nil { - fmt.Println(parse_err.Error()) - log.Error(parse_err.Error()) + log.Println(parse_err) return "", "" } @@ -129,6 +131,11 @@ func get_subdomain(domain_id int64, name string) (string, string) { break } } + if len(records) == 0 { + log.Println("records slice is empty.") + } + } else { + log.Println("get_subdomain:status code:", sjson.Get("status").Get("code").MustString()) } return ret, ip @@ -146,25 +153,20 @@ func update_ip(domain_id int64, sub_domain_id string, sub_domain_name string, ip response, err := post_data("/Record.Modify", value) if err != nil { - fmt.Println("Failed to update record to new IP!") - fmt.Println(err.Error()) - - log.Error("Failed to update record to new IP!") - log.Error(err.Error()) + log.Println("Failed to update record to new IP!") + log.Println(err) return } sjson, parse_err := simplejson.NewJson([]byte(response)) if parse_err != nil { - fmt.Println(parse_err.Error()) - log.Error(parse_err.Error()) + log.Println(parse_err) return } if sjson.Get("status").Get("code").MustString() == "1" { - fmt.Println("New IP updated!") - log.Info("New IP updated!") + log.Println("New IP updated!") } } @@ -181,11 +183,8 @@ func post_data(url string, content url.Values) (string, error) { defer response.Body.Close() if err != nil { - fmt.Println("Post failed...") - fmt.Println(err.Error()) - - log.Error("Post failed...") - log.Error(err.Error()) + log.Println("Post failed...") + log.Println(err) return "", err } diff --git a/godns.go b/godns.go index 6b4534c..6ab13e3 100644 --- a/godns.go +++ b/godns.go @@ -1,51 +1,87 @@ package main import ( - "fmt" - log "github.com/cihub/seelog" - "os" + "flag" + "log" "runtime/debug" "strings" + "syscall" "time" + + "bitbucket.org/abotoo/gonohup" ) -var Configuration Settings +const ( + PANIC_MAX = 5 + INTERVAL = 5 //Minute +) +var ( + Configuration Settings + optConf = flag.String("c", "./config.json", "config file") + optCommand = flag.String("s", "", "send signal to a master process: stop, quit, reopen, reload") + optHelp = flag.Bool("h", false, "this help") + panicCount = 0 +) + +func usage() { + log.Println("[command] -c=[config file path]") + flag.PrintDefaults() +} func main() { - initLog() + flag.Parse() + if *optHelp { + usage() + return + } - fmt.Println("Starting...") - log.Info("Starting...") + Configuration = LoadSettings(*optConf) - Configuration = LoadSettings() + ctx := gonohup.Context{ + Hash: "godns", + User: Configuration.User, + Group: Configuration.Group, + Command: *optCommand, + } + sig, err := gonohup.Daemonize(ctx) + if err != nil { + log.Println("Daemonize:", err) + return + } - loop := make(chan bool) - go dns_loop(loop) + err = gonohup.InitLogger(Configuration.Log_Path, Configuration.Log_Size, Configuration.Log_Num) + if err != nil { + log.Println("InitLogger error:", err) + return + } - ret := <-loop + go dns_loop() - if !ret { - fmt.Println("Dns loop exited...") - log.Error("Dns loop exited...") - close(loop) - - os.Exit(1) + for s := range sig { + switch s { + case syscall.SIGHUP, syscall.SIGUSR2: + // do some custom jobs while reload/hotupdate + case syscall.SIGTERM: + // do some clean up and exit + return + } } } -func dns_loop(loop chan bool) { +func dns_loop() { + defer func() { + if err := recover(); err != nil { + panicCount++ + log.Printf("Recovered in %v: %v\n", err, debug.Stack()) + if panicCount < PANIC_MAX { + log.Println("Got panic in goroutine, will start a new one... :", panicCount) + go dns_loop() + } + } + }() for { - defer func() { - if err := recover(); err != nil { - log.Error(err) - log.Info("Stack trace:\n" + string(debug.Stack())) - log.Info("Got panic in goroutine, will start a new one...") - go dns_loop(loop) - } - }() - domain_id := get_domain(Configuration.Domain) if domain_id == -1 { @@ -55,34 +91,30 @@ func dns_loop(loop chan bool) { currentIP, err := get_currentIP(Configuration.IP_Url) if err != nil { + log.Println("get_currentIP:", err) continue } sub_domain_id, ip := get_subdomain(domain_id, Configuration.Sub_domain) if sub_domain_id == "" || ip == "" { + log.Println("sub_domain:", sub_domain_id, ip) continue } - fmt.Printf("currentIp is:%s\n", currentIP) - log.Infof("currentIp is:%s\n", currentIP) + log.Println("currentIp is:", currentIP) //Continue to check the IP of sub-domain if len(ip) > 0 && !strings.Contains(currentIP, ip) { - - fmt.Println("Start to update record IP...") - log.Info("Start to update record IP...") + log.Println("Start to update record IP...") update_ip(domain_id, sub_domain_id, Configuration.Sub_domain, currentIP) - } else { - fmt.Println("Current IP is same as domain IP, no need to update...") - log.Info("Current IP is same as domain IP, no need to update...") + log.Println("Current IP is same as domain IP, no need to update...") } //Interval is 5 minutes - time.Sleep(time.Second * 60 * 5) + time.Sleep(time.Minute * INTERVAL) } - log.Info("Loop exited...") - loop <- false + log.Printf("Loop %d exited...\n", panicCount) } diff --git a/logger.go b/logger.go deleted file mode 100644 index beac2d2..0000000 --- a/logger.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import log "github.com/cihub/seelog" - -func initLog() { - testConfig := ` - - - - - -` - logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig)) - log.ReplaceLogger(logger) -} diff --git a/settings.go b/settings.go index de07d0d..dbb2198 100644 --- a/settings.go +++ b/settings.go @@ -7,26 +7,32 @@ import ( "os" ) -const config_path string = "config.json" - type Settings struct { Email string Password string Domain string Sub_domain string IP_Url string + Log_Path string + Log_Size int + Log_Num int + User int + Group int } -func LoadSettings() Settings { +func LoadSettings(config_path string) Settings { file, err := ioutil.ReadFile(config_path) - if err != nil { fmt.Println("Error occurs while reading config file, please make sure config file exists!") os.Exit(1) } var setting Settings - json.Unmarshal(file, &setting) + err = json.Unmarshal(file, &setting) + if err != nil { + fmt.Println("Error occurs while unmarshal config file, please make sure config file correct!") + os.Exit(1) + } return setting }