diff --git a/README.md b/README.md index 9db13ff..ea5ed64 100644 --- a/README.md +++ b/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). More than that , `*.` wildcard is supported additional. -``` -127.0.0.1 *.example.com -``` - __redis hosts__ @@ -114,6 +110,18 @@ _Insert hosts records into redis_ 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 diff --git a/handler.go b/handler.go index 0b02170..a1acc8e 100644 --- a/handler.go +++ b/handler.go @@ -98,7 +98,7 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { // Query hosts 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.SetReply(req) @@ -110,8 +110,10 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } - a := &dns.A{rr_header, ip} - m.Answer = append(m.Answer, a) + for _, ip := range ips { + a := &dns.A{rr_header, ip} + m.Answer = append(m.Answer, a) + } case _IP6Query: rr_header := dns.RR_Header{ Name: q.Name, @@ -119,8 +121,10 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { Class: dns.ClassINET, Ttl: settings.Hosts.TTL, } - aaaa := &dns.AAAA{rr_header, ip} - m.Answer = append(m.Answer, aaaa) + for _, ip := range ips { + aaaa := &dns.AAAA{rr_header, ip} + m.Answer = append(m.Answer, aaaa) + } } w.WriteMsg(m) diff --git a/hosts.go b/hosts.go index 44a00eb..dd98d7c 100644 --- a/hosts.go +++ b/hosts.go @@ -34,29 +34,38 @@ func NewHosts(hs HostsSettings, rs RedisSettings) Hosts { /* 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 { - sip, ok = h.redisHosts.Get(domain) + sips, ok = h.redisHosts.Get(domain) } } - if sip == "" { + if sips == nil { return nil, false } - switch family { - case _IP4Query: - ip = net.ParseIP(sip).To4() - case _IP6Query: - ip = net.ParseIP(sip).To16() - default: - return nil, false + for _, sip := range sips { + switch family { + case _IP4Query: + ip = net.ParseIP(sip).To4() + case _IP6Query: + ip = net.ParseIP(sip).To16() + default: + continue + } + if ip != nil { + ips = append(ips, ip) + } } - return ip, (ip != nil) + + return ips, (ips != nil) } /* @@ -85,21 +94,21 @@ type RedisHosts struct { hosts map[string]string } -func (r *RedisHosts) Get(domain string) (ip string, ok bool) { - ip, ok = r.hosts[domain] +func (r *RedisHosts) Get(domain string) ([]string, bool) { + ip, ok := r.hosts[domain] if ok { - return + return strings.Split(ip, ","), true } for host, ip := range r.hosts { if strings.HasPrefix(host, "*.") { upperLevelDomain := strings.Split(host, "*.")[1] 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) { @@ -120,9 +129,12 @@ type FileHosts struct { hosts map[string]string } -func (f *FileHosts) Get(domain string) (ip string, ok bool) { - ip, ok = f.hosts[domain] - return +func (f *FileHosts) Get(domain string) ([]string, bool) { + ip, ok := f.hosts[domain] + if !ok { + return nil, false + } + return []string{ip}, true } func (f *FileHosts) Refresh() {