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:
		
							parent
							
								
									e91015f051
								
							
						
					
					
						commit
						8a3471ad1c
					
				
							
								
								
									
										97
									
								
								dns_resolver/dns_resolver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								dns_resolver/dns_resolver.go
									
									
									
									
									
										Normal 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 | ||||
| } | ||||
							
								
								
									
										45
									
								
								dns_resolver/dns_resolver_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								dns_resolver/dns_resolver_test.go
									
									
									
									
									
										Normal 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
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -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 | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
| @ -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") | ||||
|  | ||||
							
								
								
									
										18
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								utils.go
									
									
									
									
									
								
							| @ -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>" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user