Host records support wildcard #16

This commit is contained in:
kenshinx 2015-10-14 12:41:08 +08:00
parent a320fe0eb7
commit c5e01db7b5
2 changed files with 38 additions and 19 deletions

View File

@ -87,6 +87,12 @@ can be assigned at godns.conf,default : `/etc/hosts`
[hosts] [hosts]
host-file = "/etc/hosts" 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__ __redis hosts__
@ -105,7 +111,7 @@ redis-key = "godns:hosts"
_Insert hosts records into redis_ _Insert hosts records into redis_
``` ```
redis > hset godns:hosts www.sina.com.cn 1.1.1.1 redis > hset godns:hosts www.test.com 1.1.1.1
``` ```

View File

@ -17,12 +17,12 @@ type Hosts struct {
} }
func NewHosts(hs HostsSettings, rs RedisSettings) Hosts { func NewHosts(hs HostsSettings, rs RedisSettings) Hosts {
fileHosts := &FileHosts{hs.HostsFile, make(map[string]string)} fileHosts := &FileHosts{BaseHosts{make(map[string]string)}, hs.HostsFile}
var redisHosts *RedisHosts var redisHosts *RedisHosts
if hs.RedisEnable { if hs.RedisEnable {
rc := &redis.Client{Addr: rs.Addr(), Db: rs.DB, Password: rs.Password} rc := &redis.Client{Addr: rs.Addr(), Db: rs.DB, Password: rs.Password}
redisHosts = &RedisHosts{rc, hs.RedisKey, make(map[string]string)} redisHosts = &RedisHosts{BaseHosts{make(map[string]string)}, rc, hs.RedisKey}
} }
hosts := Hosts{fileHosts, redisHosts} hosts := Hosts{fileHosts, redisHosts}
@ -32,10 +32,8 @@ func NewHosts(hs HostsSettings, rs RedisSettings) Hosts {
} }
/* /*
1. Match local /etc/hosts file first, remote redis records second Match local /etc/hosts file first, remote redis records second
2. Fetch hosts records from /etc/hosts file and redis per minute
*/ */
func (h *Hosts) Get(domain string, family int) (ip net.IP, ok bool) { func (h *Hosts) Get(domain string, family int) (ip net.IP, ok bool) {
var sip string var sip string
@ -61,6 +59,9 @@ func (h *Hosts) Get(domain string, family int) (ip net.IP, ok bool) {
return ip, (ip != nil) return ip, (ip != nil)
} }
/*
Update hosts records from /etc/hosts file and redis per minute
*/
func (h *Hosts) refresh() { func (h *Hosts) refresh() {
ticker := time.NewTicker(time.Minute) ticker := time.NewTicker(time.Minute)
go func() { go func() {
@ -74,17 +75,34 @@ func (h *Hosts) refresh() {
}() }()
} }
type RedisHosts struct { type BaseHosts struct {
redis *redis.Client
key string
hosts map[string]string hosts map[string]string
} }
func (r *RedisHosts) Get(domain string) (ip string, ok bool) { func (h *BaseHosts) Get(domain string) (ip string, ok bool) {
ip, ok = r.hosts[domain] ip, ok = h.hosts[domain]
if ok {
return return
} }
for host, ip := range h.hosts {
if strings.HasPrefix(host, "*.") {
upperLevelDomain := strings.Split(host, "*.")[1]
if strings.HasSuffix(domain, upperLevelDomain) {
return ip, true
}
}
}
return
}
type RedisHosts struct {
BaseHosts
redis *redis.Client
key string
}
func (r *RedisHosts) Set(domain, ip string) (bool, error) { func (r *RedisHosts) Set(domain, ip string) (bool, error) {
return r.redis.Hset(r.key, domain, []byte(ip)) return r.redis.Hset(r.key, domain, []byte(ip))
} }
@ -99,13 +117,8 @@ func (r *RedisHosts) Refresh() {
} }
type FileHosts struct { type FileHosts struct {
BaseHosts
file string file string
hosts map[string]string
}
func (f *FileHosts) Get(domain string) (ip string, ok bool) {
ip, ok = f.hosts[domain]
return
} }
func (f *FileHosts) Refresh() { func (f *FileHosts) Refresh() {
@ -150,7 +163,7 @@ func (f *FileHosts) isDomain(domain string) bool {
if f.isIP(domain) { if f.isIP(domain) {
return false return false
} }
match, _ := regexp.MatchString(`^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$`, domain) match, _ := regexp.MatchString(`^([a-zA-Z0-9\*]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$`, domain)
return match return match
} }