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

add DNS resolver, update all the handlers

This commit is contained in:
Timothy 2020-05-03 21:32:06 +08:00
parent e91015f051
commit 8a3471ad1c
No known key found for this signature in database
GPG Key ID: DA25A2861AA0F2D1
10 changed files with 162 additions and 12 deletions

View File

@ -0,0 +1,97 @@
// Package dns_resolver is a simple dns resolver
// based on miekg/dns
package dns_resolver
import (
"errors"
"math/rand"
"net"
"os"
"strings"
"time"
"github.com/miekg/dns"
)
// DnsResolver represents a dns resolver
type DnsResolver struct {
Servers []string
RetryTimes int
r *rand.Rand
}
// New initializes DnsResolver.
func New(servers []string) *DnsResolver {
for i := range servers {
servers[i] = net.JoinHostPort(servers[i], "53")
}
return &DnsResolver{servers, len(servers) * 2, rand.New(rand.NewSource(time.Now().UnixNano()))}
}
// NewFromResolvConf initializes DnsResolver from resolv.conf like file.
func NewFromResolvConf(path string) (*DnsResolver, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return &DnsResolver{}, errors.New("no such file or directory: " + path)
}
config, err := dns.ClientConfigFromFile(path)
servers := []string{}
for _, ipAddress := range config.Servers {
servers = append(servers, net.JoinHostPort(ipAddress, "53"))
}
return &DnsResolver{servers, len(servers) * 2, rand.New(rand.NewSource(time.Now().UnixNano()))}, err
}
// LookupHost returns IP addresses of provied host.
// In case of timeout retries query RetryTimes times.
func (r *DnsResolver) LookupHost(host string, dnsType uint16) ([]net.IP, error) {
return r.lookupHost(host, dnsType, r.RetryTimes)
}
func (r *DnsResolver) lookupHost(host string, dnsType uint16, triesLeft int) ([]net.IP, error) {
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
switch dnsType {
case dns.TypeA:
m1.Question[0] = dns.Question{dns.Fqdn(host), dns.TypeA, dns.ClassINET}
case dns.TypeAAAA:
m1.Question[0] = dns.Question{dns.Fqdn(host), dns.TypeAAAA, dns.ClassINET}
}
in, err := dns.Exchange(m1, r.Servers[r.r.Intn(len(r.Servers))])
result := []net.IP{}
if err != nil {
if strings.HasSuffix(err.Error(), "i/o timeout") && triesLeft > 0 {
triesLeft--
return r.lookupHost(host, dnsType, triesLeft)
}
return result, err
}
if in != nil && in.Rcode != dns.RcodeSuccess {
return result, errors.New(dns.RcodeToString[in.Rcode])
}
if dnsType == dns.TypeA {
for _, record := range in.Answer {
if t, ok := record.(*dns.A); ok {
result = append(result, t.A)
}
}
}
if dnsType == dns.TypeAAAA {
for _, record := range in.Answer {
if t, ok := record.(*dns.AAAA); ok {
result = append(result, t.AAAA)
}
}
}
return result, err
}

View File

@ -0,0 +1,45 @@
package dns_resolver
import (
"fmt"
"reflect"
"testing"
"github.com/miekg/dns"
)
func TestNew(t *testing.T) {
servers := []string{"8.8.8.8", "8.8.4.4"}
expectedServers := []string{"8.8.8.8:53", "8.8.4.4:53"}
resolver := New(servers)
if !reflect.DeepEqual(resolver.Servers, expectedServers) {
t.Error("resolver.Servers: ", resolver.Servers, "should be equal to", expectedServers)
}
}
func TestLookupHost_ValidServer(t *testing.T) {
resolver := New([]string{"8.8.8.8", "8.8.4.4"})
result, err := resolver.LookupHost("google-public-dns-a.google.com", dns.TypeA)
if err != nil {
fmt.Println(err.Error())
t.Error("Should succeed dns lookup")
}
if result[0].String() != "8.8.8.8" {
t.Error("google-public-dns-a.google.com should be resolved to 8.8.8.8")
}
}
func TestLookupHostIPv6_ValidServer(t *testing.T) {
resolver := New([]string{"2001:4860:4860::8888", "2001:4860:4860::8844"})
result, err := resolver.LookupHost("google-public-dns-a.google.com", dns.TypeAAAA)
if err != nil {
fmt.Println(err.Error())
t.Error("Should succeed dns lookup")
}
if result[0].String() != "2001:4860:4860::8888" {
t.Error("result shoudl be: 2001:4860:4860::8888")
}
}

2
go.mod
View File

@ -9,7 +9,7 @@ require (
github.com/kr/pretty v0.1.0 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/miekg/dns v1.1.29 // indirect
github.com/miekg/dns v1.1.29
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df

View File

@ -40,7 +40,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -54,7 +54,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -49,7 +49,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -57,7 +57,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -45,7 +45,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
log.Println("currentIP is:", currentIP)
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -50,7 +50,7 @@ func (handler *Handler) DomainLoop(domain *godns.Domain, panicChan chan<- godns.
for _, subDomain := range domain.SubDomains {
hostname := subDomain + "." + domain.DomainName
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver)
lastIP := godns.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
//check against currently known IP, if no change, skip update
if currentIP == lastIP {
log.Printf("IP is the same as cached one. Skip update.\n")

View File

@ -12,7 +12,8 @@ import (
"net/http"
"strings"
"github.com/bogdanovich/dns_resolver"
"github.com/TimothyYe/godns/dns_resolver"
"github.com/miekg/dns"
"golang.org/x/net/proxy"
gomail "gopkg.in/gomail.v2"
)
@ -103,8 +104,9 @@ func GetIPFromInterface(configuration *Settings) (string, error) {
}
}
return ip.String(), nil
if ip.String() != "" {
return ip.String(), nil
}
}
return "", errors.New("can't get a vaild address from " + configuration.IPInterface)
}
@ -356,7 +358,13 @@ func buildTemplate(currentIP, domain string, tplsrc string) string {
}
// ResolveDNS will query DNS for a given hostname.
func ResolveDNS(hostname, resolver string) string {
func ResolveDNS(hostname, resolver, ipType string) string {
var dnsType uint16
if ipType == "" || strings.ToUpper(ipType) == IPV4 {
dnsType = dns.TypeA
} else {
dnsType = dns.TypeAAAA
}
// If no DNS server is set in config file, falls back to default resolver.
if resolver == "" {
@ -373,7 +381,7 @@ func ResolveDNS(hostname, resolver string) string {
// In case of i/o timeout
res.RetryTimes = 5
ip, err := res.LookupHost(hostname)
ip, err := res.LookupHost(hostname, dnsType)
if err != nil {
if strings.HasSuffix(err.Error(), "NXDOMAIN") {
return "<nil>"