Support multiple A entries refer: #17
This commit is contained in:
		
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							@ -90,10 +90,6 @@ host-file = "/etc/hosts"
 | 
				
			|||||||
Hosts file format is described in [linux man pages](http://man7.org/linux/man-pages/man5/hosts.5.html). 
 | 
					Hosts file format is described in [linux man pages](http://man7.org/linux/man-pages/man5/hosts.5.html). 
 | 
				
			||||||
More than that , `*.` wildcard is supported additional.
 | 
					More than that , `*.` wildcard is supported additional.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
127.0.0.1 *.example.com
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
__redis hosts__ 
 | 
					__redis hosts__ 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -114,6 +110,18 @@ _Insert hosts records into redis_
 | 
				
			|||||||
redis > hset godns:hosts www.test.com 1.1.1.1
 | 
					redis > hset godns:hosts www.test.com 1.1.1.1
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Compared with file-backend records, redis-backend hosts support two advanced records formatting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. `*.` wildcard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					redis > hset 127.0.0.1 *.example.com
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					2. Multiple A entries, delimited by commas
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					redis > hset www.test.com 1.1.1.1,2.2.2.2
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Benchmark
 | 
					## Benchmark
 | 
				
			||||||
 | 
				
			|||||||
@ -98,7 +98,7 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Query hosts
 | 
						// Query hosts
 | 
				
			||||||
	if settings.Hosts.Enable && IPQuery > 0 {
 | 
						if settings.Hosts.Enable && IPQuery > 0 {
 | 
				
			||||||
		if ip, ok := h.hosts.Get(Q.qname, IPQuery); ok {
 | 
							if ips, ok := h.hosts.Get(Q.qname, IPQuery); ok {
 | 
				
			||||||
			m := new(dns.Msg)
 | 
								m := new(dns.Msg)
 | 
				
			||||||
			m.SetReply(req)
 | 
								m.SetReply(req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -110,8 +110,10 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) {
 | 
				
			|||||||
					Class:  dns.ClassINET,
 | 
										Class:  dns.ClassINET,
 | 
				
			||||||
					Ttl:    settings.Hosts.TTL,
 | 
										Ttl:    settings.Hosts.TTL,
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									for _, ip := range ips {
 | 
				
			||||||
					a := &dns.A{rr_header, ip}
 | 
										a := &dns.A{rr_header, ip}
 | 
				
			||||||
					m.Answer = append(m.Answer, a)
 | 
										m.Answer = append(m.Answer, a)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case _IP6Query:
 | 
								case _IP6Query:
 | 
				
			||||||
				rr_header := dns.RR_Header{
 | 
									rr_header := dns.RR_Header{
 | 
				
			||||||
					Name:   q.Name,
 | 
										Name:   q.Name,
 | 
				
			||||||
@ -119,9 +121,11 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) {
 | 
				
			|||||||
					Class:  dns.ClassINET,
 | 
										Class:  dns.ClassINET,
 | 
				
			||||||
					Ttl:    settings.Hosts.TTL,
 | 
										Ttl:    settings.Hosts.TTL,
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									for _, ip := range ips {
 | 
				
			||||||
					aaaa := &dns.AAAA{rr_header, ip}
 | 
										aaaa := &dns.AAAA{rr_header, ip}
 | 
				
			||||||
					m.Answer = append(m.Answer, aaaa)
 | 
										m.Answer = append(m.Answer, aaaa)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			w.WriteMsg(m)
 | 
								w.WriteMsg(m)
 | 
				
			||||||
			logger.Debug("%s found in hosts file", Q.qname)
 | 
								logger.Debug("%s found in hosts file", Q.qname)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										42
									
								
								hosts.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								hosts.go
									
									
									
									
									
								
							@ -34,29 +34,38 @@ func NewHosts(hs HostsSettings, rs RedisSettings) Hosts {
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
Match local /etc/hosts file first, remote redis records second
 | 
					Match local /etc/hosts file first, remote redis records second
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
func (h *Hosts) Get(domain string, family int) (ip net.IP, ok bool) {
 | 
					func (h *Hosts) Get(domain string, family int) ([]net.IP, bool) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var sip string
 | 
						var sips []string
 | 
				
			||||||
 | 
						var ip net.IP
 | 
				
			||||||
 | 
						var ips []net.IP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if sip, ok = h.fileHosts.Get(domain); !ok {
 | 
						sips, ok := h.fileHosts.Get(domain)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
		if h.redisHosts != nil {
 | 
							if h.redisHosts != nil {
 | 
				
			||||||
			sip, ok = h.redisHosts.Get(domain)
 | 
								sips, ok = h.redisHosts.Get(domain)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if sip == "" {
 | 
						if sips == nil {
 | 
				
			||||||
		return nil, false
 | 
							return nil, false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, sip := range sips {
 | 
				
			||||||
		switch family {
 | 
							switch family {
 | 
				
			||||||
		case _IP4Query:
 | 
							case _IP4Query:
 | 
				
			||||||
			ip = net.ParseIP(sip).To4()
 | 
								ip = net.ParseIP(sip).To4()
 | 
				
			||||||
		case _IP6Query:
 | 
							case _IP6Query:
 | 
				
			||||||
			ip = net.ParseIP(sip).To16()
 | 
								ip = net.ParseIP(sip).To16()
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
		return nil, false
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	return ip, (ip != nil)
 | 
							if ip != nil {
 | 
				
			||||||
 | 
								ips = append(ips, ip)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ips, (ips != nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@ -85,21 +94,21 @@ type RedisHosts struct {
 | 
				
			|||||||
	hosts map[string]string
 | 
						hosts map[string]string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *RedisHosts) Get(domain string) (ip string, ok bool) {
 | 
					func (r *RedisHosts) Get(domain string) ([]string, bool) {
 | 
				
			||||||
	ip, ok = r.hosts[domain]
 | 
						ip, ok := r.hosts[domain]
 | 
				
			||||||
	if ok {
 | 
						if ok {
 | 
				
			||||||
		return
 | 
							return strings.Split(ip, ","), true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for host, ip := range r.hosts {
 | 
						for host, ip := range r.hosts {
 | 
				
			||||||
		if strings.HasPrefix(host, "*.") {
 | 
							if strings.HasPrefix(host, "*.") {
 | 
				
			||||||
			upperLevelDomain := strings.Split(host, "*.")[1]
 | 
								upperLevelDomain := strings.Split(host, "*.")[1]
 | 
				
			||||||
			if strings.HasSuffix(domain, upperLevelDomain) {
 | 
								if strings.HasSuffix(domain, upperLevelDomain) {
 | 
				
			||||||
				return ip, true
 | 
									return strings.Split(ip, ","), true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return
 | 
						return nil, false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *RedisHosts) Set(domain, ip string) (bool, error) {
 | 
					func (r *RedisHosts) Set(domain, ip string) (bool, error) {
 | 
				
			||||||
@ -120,9 +129,12 @@ type FileHosts struct {
 | 
				
			|||||||
	hosts map[string]string
 | 
						hosts map[string]string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *FileHosts) Get(domain string) (ip string, ok bool) {
 | 
					func (f *FileHosts) Get(domain string) ([]string, bool) {
 | 
				
			||||||
	ip, ok = f.hosts[domain]
 | 
						ip, ok := f.hosts[domain]
 | 
				
			||||||
	return
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil, false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return []string{ip}, true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *FileHosts) Refresh() {
 | 
					func (f *FileHosts) Refresh() {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user