diff options
Diffstat (limited to 'plugin/hosts/hostsfile.go')
-rw-r--r-- | plugin/hosts/hostsfile.go | 157 |
1 files changed, 66 insertions, 91 deletions
diff --git a/plugin/hosts/hostsfile.go b/plugin/hosts/hostsfile.go index 421f8a77c..f7cc73528 100644 --- a/plugin/hosts/hostsfile.go +++ b/plugin/hosts/hostsfile.go @@ -19,7 +19,8 @@ import ( "github.com/coredns/coredns/plugin" ) -func parseLiteralIP(addr string) net.IP { +// parseIP calls discards any v6 zone info, before calling net.ParseIP. +func parseIP(addr string) net.IP { if i := strings.Index(addr, "%"); i >= 0 { // discard ipv6 zone addr = addr[0:i] @@ -28,10 +29,6 @@ func parseLiteralIP(addr string) net.IP { return net.ParseIP(addr) } -func absDomainName(b string) string { - return plugin.Name(b).Normalize() -} - type options struct { // automatically generate IP to Hostname PTR entries // for host entries we parse @@ -48,48 +45,40 @@ func newOptions() *options { return &options{ autoReverse: true, ttl: 3600, - reload: durationOf5s, + reload: time.Duration(5 * time.Second), } } -type hostsMap struct { - // Key for the list of literal IP addresses must be a host - // name. It would be part of DNS labels, a FQDN or an absolute - // FQDN. - // For now the key is converted to lower case for convenience. - byNameV4 map[string][]net.IP - byNameV6 map[string][]net.IP +// Map contains the IPv4/IPv6 and reverse mapping. +type Map struct { + // Key for the list of literal IP addresses must be a FQDN lowercased host name. + name4 map[string][]net.IP + name6 map[string][]net.IP // Key for the list of host names must be a literal IP address - // including IPv6 address with zone identifier. + // including IPv6 address without zone identifier. // We don't support old-classful IP address notation. - byAddr map[string][]string + addr map[string][]string } -const ( - durationOf0s = time.Duration(0) - durationOf5s = time.Duration(5 * time.Second) -) - -func newHostsMap() *hostsMap { - return &hostsMap{ - byNameV4: make(map[string][]net.IP), - byNameV6: make(map[string][]net.IP), - byAddr: make(map[string][]string), +func newMap() *Map { + return &Map{ + name4: make(map[string][]net.IP), + name6: make(map[string][]net.IP), + addr: make(map[string][]string), } } -// Len returns the total number of addresses in the hostmap, this includes -// V4/V6 and any reverse addresses. -func (h *hostsMap) Len() int { +// Len returns the total number of addresses in the hostmap, this includes V4/V6 and any reverse addresses. +func (h *Map) Len() int { l := 0 - for _, v4 := range h.byNameV4 { + for _, v4 := range h.name4 { l += len(v4) } - for _, v6 := range h.byNameV6 { + for _, v6 := range h.name6 { l += len(v6) } - for _, a := range h.byAddr { + for _, a := range h.addr { l += len(a) } return l @@ -103,11 +92,10 @@ type Hostsfile struct { Origins []string // hosts maps for lookups - hmap *hostsMap + hmap *Map // inline saves the hosts file that is inlined in a Corefile. - // We need a copy here as we want to use it to initialize the maps for parse. - inline *hostsMap + inline *Map // path to the hosts file path string @@ -132,6 +120,7 @@ func (h *Hostsfile) readHosts() { h.RLock() size := h.size h.RUnlock() + if err == nil && h.mtime.Equal(stat.ModTime()) && size == stat.Size() { return } @@ -155,12 +144,11 @@ func (h *Hostsfile) initInline(inline []string) { } h.inline = h.parse(strings.NewReader(strings.Join(inline, "\n"))) - *h.hmap = *h.inline } -// Parse reads the hostsfile and populates the byName and byAddr maps. -func (h *Hostsfile) parse(r io.Reader) *hostsMap { - hmap := newHostsMap() +// Parse reads the hostsfile and populates the byName and addr maps. +func (h *Hostsfile) parse(r io.Reader) *Map { + hmap := newMap() scanner := bufio.NewScanner(r) for scanner.Scan() { @@ -173,73 +161,52 @@ func (h *Hostsfile) parse(r io.Reader) *hostsMap { if len(f) < 2 { continue } - addr := parseLiteralIP(string(f[0])) + addr := parseIP(string(f[0])) if addr == nil { continue } - ver := ipVersion(string(f[0])) + + family := 0 + if addr.To4() != nil { + family = 1 + } else { + family = 2 + } + for i := 1; i < len(f); i++ { - name := absDomainName(string(f[i])) + name := plugin.Name(string(f[i])).Normalize() if plugin.Zones(h.Origins).Matches(name) == "" { // name is not in Origins continue } - switch ver { - case 4: - hmap.byNameV4[name] = append(hmap.byNameV4[name], addr) - case 6: - hmap.byNameV6[name] = append(hmap.byNameV6[name], addr) + switch family { + case 1: + hmap.name4[name] = append(hmap.name4[name], addr) + case 2: + hmap.name6[name] = append(hmap.name6[name], addr) default: continue } if !h.options.autoReverse { continue } - hmap.byAddr[addr.String()] = append(hmap.byAddr[addr.String()], name) + hmap.addr[addr.String()] = append(hmap.addr[addr.String()], name) } } - for name := range h.hmap.byNameV4 { - hmap.byNameV4[name] = append(hmap.byNameV4[name], h.hmap.byNameV4[name]...) - } - for name := range h.hmap.byNameV4 { - hmap.byNameV6[name] = append(hmap.byNameV6[name], h.hmap.byNameV6[name]...) - } - - for addr := range h.hmap.byAddr { - hmap.byAddr[addr] = append(hmap.byAddr[addr], h.hmap.byAddr[addr]...) - } - return hmap } -// ipVersion returns what IP version was used textually -// For why the string is parsed end to start, -// see IPv4-Compatible IPv6 addresses - RFC 4291 section 2.5.5 -func ipVersion(s string) int { - for i := len(s) - 1; i >= 0; i-- { - switch s[i] { - case '.': - return 4 - case ':': - return 6 - } - } - return 0 -} - -// LookupStaticHost looks up the IP addresses for the given host from the hosts file. -func (h *Hostsfile) lookupStaticHost(hmapByName map[string][]net.IP, host string) []net.IP { - fqhost := absDomainName(host) - +// lookupStaticHost looks up the IP addresses for the given host from the hosts file. +func (h *Hostsfile) lookupStaticHost(m map[string][]net.IP, host string) []net.IP { h.RLock() defer h.RUnlock() - if len(hmapByName) == 0 { + if len(m) == 0 { return nil } - ips, ok := hmapByName[fqhost] + ips, ok := m[host] if !ok { return nil } @@ -250,30 +217,38 @@ func (h *Hostsfile) lookupStaticHost(hmapByName map[string][]net.IP, host string // LookupStaticHostV4 looks up the IPv4 addresses for the given host from the hosts file. func (h *Hostsfile) LookupStaticHostV4(host string) []net.IP { - return h.lookupStaticHost(h.hmap.byNameV4, host) + host = strings.ToLower(host) + ip1 := h.lookupStaticHost(h.hmap.name4, host) + ip2 := h.lookupStaticHost(h.inline.name4, host) + return append(ip1, ip2...) } // LookupStaticHostV6 looks up the IPv6 addresses for the given host from the hosts file. func (h *Hostsfile) LookupStaticHostV6(host string) []net.IP { - return h.lookupStaticHost(h.hmap.byNameV6, host) + host = strings.ToLower(host) + ip1 := h.lookupStaticHost(h.hmap.name6, host) + ip2 := h.lookupStaticHost(h.inline.name6, host) + return append(ip1, ip2...) } // LookupStaticAddr looks up the hosts for the given address from the hosts file. func (h *Hostsfile) LookupStaticAddr(addr string) []string { - h.RLock() - defer h.RUnlock() - addr = parseLiteralIP(addr).String() + addr = parseIP(addr).String() if addr == "" { return nil } - if len(h.hmap.byAddr) == 0 { - return nil - } - hosts, ok := h.hmap.byAddr[addr] - if !ok { + + h.RLock() + defer h.RUnlock() + hosts1, _ := h.hmap.addr[addr] + hosts2, _ := h.inline.addr[addr] + + if len(hosts1) == 0 && len(hosts2) == 0 { return nil } - hostsCp := make([]string, len(hosts)) - copy(hostsCp, hosts) + + hostsCp := make([]string, len(hosts1)+len(hosts2)) + copy(hostsCp, hosts1) + copy(hostsCp[len(hosts1):], hosts2) return hostsCp } |