Support multiple A entries refer: #17

This commit is contained in:
kenshinx 2015-10-15 01:08:25 +08:00
parent dcf31e1b22
commit 21448a51e2
3 changed files with 54 additions and 30 deletions

View File

@ -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

View File

@ -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,
} }
a := &dns.A{rr_header, ip} for _, ip := range ips {
m.Answer = append(m.Answer, a) a := &dns.A{rr_header, ip}
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,8 +121,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,
} }
aaaa := &dns.AAAA{rr_header, ip} for _, ip := range ips {
m.Answer = append(m.Answer, aaaa) aaaa := &dns.AAAA{rr_header, ip}
m.Answer = append(m.Answer, aaaa)
}
} }
w.WriteMsg(m) w.WriteMsg(m)

View File

@ -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
} }
switch family { for _, sip := range sips {
case _IP4Query: switch family {
ip = net.ParseIP(sip).To4() case _IP4Query:
case _IP6Query: ip = net.ParseIP(sip).To4()
ip = net.ParseIP(sip).To16() case _IP6Query:
default: ip = net.ParseIP(sip).To16()
return nil, false 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 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() {