mirror of
https://github.com/taigrr/godns
synced 2025-01-18 04:03:25 -08:00
Merge pull request #2 from abotoo/master
daemonize it using code instead of using nohup command
This commit is contained in:
commit
b9780b7566
22
README.md
22
README.md
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
[](https://travis-ci.org/TimothyYe/godns)
|
[](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
|
## 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:
|
* Get source code from Github:
|
||||||
|
|
||||||
```bash
|
```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:
|
* Go into the godns directory, get related library and then build it:
|
||||||
|
|
||||||
@ -30,21 +30,17 @@ go build
|
|||||||
```
|
```
|
||||||
* Then you get GoDNS.
|
* 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
|
## 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**.
|
* Rename it to **config.json**.
|
||||||
* Configure your domain/sub-domain info, username and password of DNSPod account.
|
* 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:
|
* The last step, run godns:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nohup ./godns &
|
./godns
|
||||||
```
|
```
|
||||||
* Enjoy it!
|
* Enjoy it!
|
||||||
|
@ -3,5 +3,10 @@
|
|||||||
"password": "",
|
"password": "",
|
||||||
"domain": "",
|
"domain": "",
|
||||||
"sub_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
|
||||||
}
|
}
|
@ -3,21 +3,21 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bitly/go-simplejson"
|
|
||||||
log "github.com/cihub/seelog"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bitly/go-simplejson"
|
||||||
)
|
)
|
||||||
|
|
||||||
func get_currentIP(url string) (string, error) {
|
func get_currentIP(url string) (string, error) {
|
||||||
response, err := http.Get(url)
|
response, err := http.Get(url)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Cannot get IP...")
|
log.Println("Cannot get IP...")
|
||||||
log.Error("Cannot get IP...")
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,16 +60,14 @@ func get_domain(name string) int64 {
|
|||||||
response, err := post_data("/Domain.List", values)
|
response, err := post_data("/Domain.List", values)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to get domain list...")
|
log.Println("Failed to get domain list...")
|
||||||
log.Error("Failed to get domain list...")
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
sjson, parse_err := simplejson.NewJson([]byte(response))
|
sjson, parse_err := simplejson.NewJson([]byte(response))
|
||||||
|
|
||||||
if parse_err != nil {
|
if parse_err != nil {
|
||||||
fmt.Println(parse_err.Error())
|
log.Println(parse_err)
|
||||||
log.Error(parse_err.Error())
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,12 +87,18 @@ func get_domain(name string) int64 {
|
|||||||
break
|
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
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_subdomain(domain_id int64, name string) (string, string) {
|
func get_subdomain(domain_id int64, name string) (string, string) {
|
||||||
|
log.Println("debug:", domain_id, name)
|
||||||
var ret, ip string
|
var ret, ip string
|
||||||
value := url.Values{}
|
value := url.Values{}
|
||||||
value.Add("domain_id", strconv.FormatInt(domain_id, 10))
|
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)
|
response, err := post_data("/Record.List", value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to get domain list...")
|
log.Println("Failed to get domain list")
|
||||||
log.Error("Failed to get domain list")
|
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
sjson, parse_err := simplejson.NewJson([]byte(response))
|
sjson, parse_err := simplejson.NewJson([]byte(response))
|
||||||
|
|
||||||
if parse_err != nil {
|
if parse_err != nil {
|
||||||
fmt.Println(parse_err.Error())
|
log.Println(parse_err)
|
||||||
log.Error(parse_err.Error())
|
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +131,11 @@ func get_subdomain(domain_id int64, name string) (string, string) {
|
|||||||
break
|
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
|
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)
|
response, err := post_data("/Record.Modify", value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed to update record to new IP!")
|
log.Println("Failed to update record to new IP!")
|
||||||
fmt.Println(err.Error())
|
log.Println(err)
|
||||||
|
|
||||||
log.Error("Failed to update record to new IP!")
|
|
||||||
log.Error(err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sjson, parse_err := simplejson.NewJson([]byte(response))
|
sjson, parse_err := simplejson.NewJson([]byte(response))
|
||||||
|
|
||||||
if parse_err != nil {
|
if parse_err != nil {
|
||||||
fmt.Println(parse_err.Error())
|
log.Println(parse_err)
|
||||||
log.Error(parse_err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if sjson.Get("status").Get("code").MustString() == "1" {
|
if sjson.Get("status").Get("code").MustString() == "1" {
|
||||||
fmt.Println("New IP updated!")
|
log.Println("New IP updated!")
|
||||||
log.Info("New IP updated!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -181,11 +183,8 @@ func post_data(url string, content url.Values) (string, error) {
|
|||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Post failed...")
|
log.Println("Post failed...")
|
||||||
fmt.Println(err.Error())
|
log.Println(err)
|
||||||
|
|
||||||
log.Error("Post failed...")
|
|
||||||
log.Error(err.Error())
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
104
godns.go
104
godns.go
@ -1,51 +1,87 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"flag"
|
||||||
log "github.com/cihub/seelog"
|
"log"
|
||||||
"os"
|
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"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() {
|
func main() {
|
||||||
initLog()
|
flag.Parse()
|
||||||
|
if *optHelp {
|
||||||
|
usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Starting...")
|
Configuration = LoadSettings(*optConf)
|
||||||
log.Info("Starting...")
|
|
||||||
|
|
||||||
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)
|
err = gonohup.InitLogger(Configuration.Log_Path, Configuration.Log_Size, Configuration.Log_Num)
|
||||||
go dns_loop(loop)
|
if err != nil {
|
||||||
|
log.Println("InitLogger error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ret := <-loop
|
go dns_loop()
|
||||||
|
|
||||||
if !ret {
|
for s := range sig {
|
||||||
fmt.Println("Dns loop exited...")
|
switch s {
|
||||||
log.Error("Dns loop exited...")
|
case syscall.SIGHUP, syscall.SIGUSR2:
|
||||||
close(loop)
|
// do some custom jobs while reload/hotupdate
|
||||||
|
case syscall.SIGTERM:
|
||||||
os.Exit(1)
|
// do some clean up and exit
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dns_loop(loop chan bool) {
|
func dns_loop() {
|
||||||
|
|
||||||
for {
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
log.Error(err)
|
panicCount++
|
||||||
log.Info("Stack trace:\n" + string(debug.Stack()))
|
log.Printf("Recovered in %v: %v\n", err, debug.Stack())
|
||||||
log.Info("Got panic in goroutine, will start a new one...")
|
if panicCount < PANIC_MAX {
|
||||||
go dns_loop(loop)
|
log.Println("Got panic in goroutine, will start a new one... :", panicCount)
|
||||||
|
go dns_loop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
domain_id := get_domain(Configuration.Domain)
|
domain_id := get_domain(Configuration.Domain)
|
||||||
|
|
||||||
if domain_id == -1 {
|
if domain_id == -1 {
|
||||||
@ -55,34 +91,30 @@ func dns_loop(loop chan bool) {
|
|||||||
currentIP, err := get_currentIP(Configuration.IP_Url)
|
currentIP, err := get_currentIP(Configuration.IP_Url)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("get_currentIP:", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_domain_id, ip := get_subdomain(domain_id, Configuration.Sub_domain)
|
sub_domain_id, ip := get_subdomain(domain_id, Configuration.Sub_domain)
|
||||||
|
|
||||||
if sub_domain_id == "" || ip == "" {
|
if sub_domain_id == "" || ip == "" {
|
||||||
|
log.Println("sub_domain:", sub_domain_id, ip)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("currentIp is:%s\n", currentIP)
|
log.Println("currentIp is:", currentIP)
|
||||||
log.Infof("currentIp is:%s\n", currentIP)
|
|
||||||
|
|
||||||
//Continue to check the IP of sub-domain
|
//Continue to check the IP of sub-domain
|
||||||
if len(ip) > 0 && !strings.Contains(currentIP, ip) {
|
if len(ip) > 0 && !strings.Contains(currentIP, ip) {
|
||||||
|
log.Println("Start to update record IP...")
|
||||||
fmt.Println("Start to update record IP...")
|
|
||||||
log.Info("Start to update record IP...")
|
|
||||||
update_ip(domain_id, sub_domain_id, Configuration.Sub_domain, currentIP)
|
update_ip(domain_id, sub_domain_id, Configuration.Sub_domain, currentIP)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Current IP is same as domain IP, no need to update...")
|
log.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...")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Interval is 5 minutes
|
//Interval is 5 minutes
|
||||||
time.Sleep(time.Second * 60 * 5)
|
time.Sleep(time.Minute * INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Loop exited...")
|
log.Printf("Loop %d exited...\n", panicCount)
|
||||||
loop <- false
|
|
||||||
}
|
}
|
||||||
|
15
logger.go
15
logger.go
@ -1,15 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import log "github.com/cihub/seelog"
|
|
||||||
|
|
||||||
func initLog() {
|
|
||||||
testConfig := `
|
|
||||||
<seelog>
|
|
||||||
<outputs>
|
|
||||||
<rollingfile type="size" filename="./run.log" maxsize="10000" maxrolls="5" />
|
|
||||||
</outputs>
|
|
||||||
</seelog>
|
|
||||||
`
|
|
||||||
logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
|
|
||||||
log.ReplaceLogger(logger)
|
|
||||||
}
|
|
16
settings.go
16
settings.go
@ -7,26 +7,32 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
const config_path string = "config.json"
|
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
Email string
|
Email string
|
||||||
Password string
|
Password string
|
||||||
Domain string
|
Domain string
|
||||||
Sub_domain string
|
Sub_domain string
|
||||||
IP_Url 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)
|
file, err := ioutil.ReadFile(config_path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error occurs while reading config file, please make sure config file exists!")
|
fmt.Println("Error occurs while reading config file, please make sure config file exists!")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var setting Settings
|
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
|
return setting
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user