package main import ( "net" "time" "github.com/hoisie/redis" ) type Hosts struct { providers []HostProvider refreshInterval time.Duration } type HostProvider interface { Get(domain string) ([]string, bool) Refresh() } func NewHosts(hs HostsSettings, rs RedisSettings) Hosts { providers := []HostProvider{ NewFileProvider(hs.HostsFile), } if hs.RedisEnable { logger.Info("Redis is enabled: %s", rs.Addr()) rc := &redis.Client{Addr: rs.Addr(), Db: rs.DB, Password: rs.Password} providers = append(providers, NewRedisProvider(rc, hs.RedisKey)) } h := Hosts{providers, time.Second * time.Duration(hs.RefreshInterval)} if h.refreshInterval > 0 { h.refresh() } return h } func (h *Hosts) refresh() { ticker := time.NewTicker(h.refreshInterval) go func() { for { // Force a refresh every refreshInterval for _, provider := range h.providers { provider.Refresh() } <-ticker.C } }() } /* Match local /etc/hosts file first, remote redis records second */ func (h *Hosts) Get(domain string, family int) ([]net.IP, bool) { var sips []string var ok bool var ip net.IP var ips []net.IP for _, provider := range h.providers { sips, ok = provider.Get(domain) if ok { break } } if sips == nil { 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 ips, ips != nil }