1
0
mirror of https://github.com/taigrr/godns synced 2025-01-18 04:03:25 -08:00

forked, modify something

This commit is contained in:
abotoow 2015-02-25 00:06:50 +08:00
parent c1b3cc3f80
commit 26fc929496
6 changed files with 121 additions and 98 deletions

View File

@ -2,9 +2,9 @@
[![Build Status](https://travis-ci.org/TimothyYe/godns.svg?branch=master)](https://travis-ci.org/TimothyYe/godns) [![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 ## 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!

View File

@ -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
} }

View File

@ -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
} }

108
godns.go
View File

@ -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() {
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 { 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) 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
} }

View File

@ -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)
}

View File

@ -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
} }