Support multiple A entries refer: #17
This commit is contained in:
parent
dcf31e1b22
commit
21448a51e2
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).
|
||||
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
|
||||
|
14
handler.go
14
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)
|
||||
|
54
hosts.go
54
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() {
|
||||
|
Loading…
Reference in New Issue
Block a user