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

Merge pull request #29 from SadPencil/master

New features
This commit is contained in:
Timothy 2018-12-07 15:56:06 +08:00 committed by GitHub
commit fb5c679bf7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 51 deletions

View File

@ -173,6 +173,19 @@ 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.
### Get an IP address from the interface
For some reasons if you want to get an IP directly from the interface, say `eth0` for Linux or `Local Area Connection` for Windows, update config file like this:
```json
"ip_url": "",
"ip_interface": "eth0",
```
If you set both `ip_url` and `ip_interface`, it first tries to get an IP address online, and if not succeed, gets
an IP address from the interface as a fallback.
Note that IPv6 address will be ignored currently.
### 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.
@ -242,4 +255,10 @@ docker run -d --name godns --restart=always \
-v /path/to/config.json:/usr/local/godns/config.json timothyye/godns:latest
```
## Run it as an Windows service
* Get [birkett/srvany-ng](https://github.com/birkett/srvany-ng/releases) from Github.
* Uncompress and place the executable `srvany-ng.exe` to the same directory where `godns.exe` in.
* Create a service and add registry keys according to the guide [here](https://github.com/birkett/srvany-ng).
## Enjoy it!

View File

@ -19,6 +19,7 @@
}
],
"ip_url": "http://members.3322.org/dyndns/getip",
"ip_interface": "eth0",
"socks5_proxy": "",
"notify": {
"enabled": false,

View File

@ -74,6 +74,7 @@ func (handler *CloudflareHandler) DomainLoop(domain *godns.Domain, panicChan cha
}
}()
var lastIP string
for {
currentIP, err := godns.GetCurrentIP(handler.Configuration)
if err != nil {
@ -81,30 +82,34 @@ func (handler *CloudflareHandler) DomainLoop(domain *godns.Domain, panicChan cha
continue
}
log.Println("Current IP is:", currentIP)
// TODO: check against locally cached IP, if no change, skip update
log.Println("Checking IP for domain", domain.DomainName)
zoneID := handler.getZone(domain.DomainName)
if zoneID != "" {
records := handler.getDNSRecords(zoneID)
// update records
for _, rec := range records {
if recordTracked(domain, &rec) != true {
log.Println("Skiping record:", rec.Name)
continue
}
if rec.IP != currentIP {
log.Printf("IP mismatch: Current(%+v) vs Cloudflare(%+v)\r\n", currentIP, rec.IP)
handler.updateRecord(rec, currentIP)
} else {
log.Printf("Record OK: %+v - %+v\r\n", rec.Name, rec.IP)
}
}
//check against locally cached IP, if no change, skip update
if (currentIP == lastIP){
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
log.Println("Failed to find zone for domain:", domain.DomainName)
}
lastIP = currentIP
log.Println("Checking IP for domain", domain.DomainName)
zoneID := handler.getZone(domain.DomainName)
if zoneID != "" {
records := handler.getDNSRecords(zoneID)
// update records
for _, rec := range records {
if recordTracked(domain, &rec) != true {
log.Println("Skiping record:", rec.Name)
continue
}
if rec.IP != currentIP {
log.Printf("IP mismatch: Current(%+v) vs Cloudflare(%+v)\r\n", currentIP, rec.IP)
handler.updateRecord(rec, currentIP)
} else {
log.Printf("Record OK: %+v - %+v\r\n", rec.Name, rec.IP)
}
}
} else {
log.Println("Failed to find zone for domain:", 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)

View File

@ -36,6 +36,7 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<-
}
}()
var lastIP string
for {
log.Printf("Checking IP for domain %s \r\n", domain.DomainName)
domainID := handler.GetDomain(domain.DomainName)
@ -52,31 +53,37 @@ func (handler *DNSPodHandler) DomainLoop(domain *godns.Domain, panicChan chan<-
}
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
//check against locally cached IP, if no change, skip update
if (currentIP == lastIP){
log.Printf("IP is the same as cached one. Skip update.\n")
}else{
lastIP = currentIP
for _, subDomain := range domain.SubDomains {
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
}
// 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)
if subDomainID == "" || ip == "" {
log.Printf("domain: %s.%s subDomainID: %s ip: %s\n", subDomain, domain.DomainName, subDomainID, ip)
continue
}
} 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.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)
}
}
}
// 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)

View File

@ -39,6 +39,7 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn
}
}()
var lastIP string
for {
currentIP, err := godns.GetCurrentIP(handler.Configuration)
@ -48,21 +49,28 @@ func (handler *HEHandler) DomainLoop(domain *godns.Domain, panicChan chan<- godn
}
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)
//check against locally cached IP, if no change, skip update
if (currentIP == lastIP){
log.Printf("IP is the same as cached one. Skip update.\n")
} else {
lastIP = currentIP
for _, subDomain := range domain.SubDomains {
log.Printf("%s.%s Start to update record IP...\n", subDomain, domain.DomainName)
handler.UpdateIP(domain.DomainName, subDomain, currentIP)
// Send mail notification if notify is enabled
if handler.Configuration.Notify.Enabled {
log.Print("Sending notification to:", handler.Configuration.Notify.SendTo)
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)
}
}
}
// 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)
}
}
// UpdateIP update subdomain with current IP

View File

@ -33,6 +33,9 @@ type Settings struct {
LogPath string `json:"log_path"`
Socks5Proxy string `json:"socks5_proxy"`
Notify Notify `json:"notify"`
IPInterface string `json:"ip_interface"`
//the code is not ready to update AAAA record
//IPType string `json:"ip_type"`
}
// LoadSettings -- Load settings from config file

View File

@ -8,6 +8,7 @@ import (
"log"
"net/http"
"strings"
"net"
"golang.org/x/net/proxy"
"gopkg.in/gomail.v2"
@ -43,8 +44,87 @@ const (
CLOUDFLARE = "Cloudflare"
)
// GetCurrentIP gets public IP from internet
//GetIPFromInterface gets IP address from the specific interface
func GetIPFromInterface(configuration *Settings) (string,error) {
ifaces, err := net.InterfaceByName(configuration.IPInterface)
if err != nil {
log.Println("can't get network device "+configuration.IPInterface+":", err)
return "", err
}
addrs, err :=ifaces.Addrs();
if err != nil {
log.Println("can't get address from "+configuration.IPInterface+":", err)
return "", err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if (ip == nil){
continue;
}
if (!(ip.IsGlobalUnicast() &&!(ip.IsUnspecified()||ip.IsMulticast()||ip.IsLoopback()||ip.IsLinkLocalUnicast()||ip.IsLinkLocalMulticast()||ip.IsInterfaceLocalMulticast()))){
continue;
}
//the code is not ready for updating an AAAA record
/*
if (isIPv4(ip.String())){
if (configuration.IPType=="IPv6"){
continue;
}
}else{
if (configuration.IPType!="IPv6"){
continue;
}
} */
if (!isIPv4(ip.String())){
continue;
}
return ip.String(),nil
}
return "", errors.New("can't get a vaild address from "+configuration.IPInterface)
}
func isIPv4(ip string) bool{
return strings.Count(ip, ":") < 2
}
//GetCurrentIP gets an IP from either internet or specific interface, depending on configuration
func GetCurrentIP(configuration *Settings) (string, error) {
var err error
if (configuration.IPUrl != ""){
ip, err := GetIPOnline(configuration)
if (err != nil){
log.Println("get ip online failed. Fallback to get ip from interface if possible.")
}else{
return ip,nil
}
}
if (configuration.IPInterface != ""){
ip, err := GetIPFromInterface(configuration)
if (err != nil){
log.Println("get ip from interface failed. There is no more ways to try.")
}else{
return ip,nil
}
}
return "", err
}
// GetIPOnline gets public IP from internet
func GetIPOnline(configuration *Settings) (string, error) {
client := &http.Client{}
if configuration.Socks5Proxy != "" {