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).
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

View File

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

View File

@ -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() {