-
Notifications
You must be signed in to change notification settings - Fork 0
/
hostsfile.go
117 lines (108 loc) · 2.49 KB
/
hostsfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Package hosts provides address lookups from local hostfile (usually /etc/hosts).
package hosts
import (
"io/ioutil"
"log"
"net"
"strings"
"sync"
"time"
"github.com/miekg/dns"
)
// Config stores options for hostsfile
type Config struct {
// Positive value enables polling
Poll int
Verbose bool
}
// Hostsfile represents a file containing hosts
type Hostsfile struct {
config *Config
hosts *hostlist
file struct {
size int64
path string
mtime time.Time
}
hostMutex sync.RWMutex
}
// NewHostsfile returns a new Hostsfile object
func NewHostsfile(path string, config *Config) (*Hostsfile, error) {
h := Hostsfile{config: config}
// when no hostfile is given we return an empty hostlist
if path == "" {
h.hosts = new(hostlist)
return &h, nil
}
h.file.path = path
if err := h.loadHostEntries(); err != nil {
return nil, err
}
if h.config.Poll > 0 {
go h.monitorHostEntries(h.config.Poll)
}
log.Printf("Found host:ip pairs in %s:", h.file.path)
for _, hostname := range *h.hosts {
log.Printf("%s -> %s *=%t",
hostname.domain,
hostname.ip.String(),
hostname.wildcard)
}
return &h, nil
}
func (h *Hostsfile) FindHosts(name string) (addrs []net.IP, err error) {
name = strings.TrimSuffix(name, ".")
h.hostMutex.RLock()
defer h.hostMutex.RUnlock()
addrs = h.hosts.FindHosts(name)
return
}
func (h *Hostsfile) FindReverse(name string) (host string, err error) {
h.hostMutex.RLock()
defer h.hostMutex.RUnlock()
for _, hostname := range *h.hosts {
if r, _ := dns.ReverseAddr(hostname.ip.String()); name == r {
host = dns.Fqdn(hostname.domain)
break
}
}
return
}
func (h *Hostsfile) loadHostEntries() error {
data, err := ioutil.ReadFile(h.file.path)
if err != nil {
return err
}
h.hostMutex.Lock()
h.hosts = newHostlist(data)
h.hostMutex.Unlock()
return nil
}
func (h *Hostsfile) monitorHostEntries(poll int) {
hf := h.file
if hf.path == "" {
return
}
t := time.Duration(poll) * time.Second
for _ = range time.Tick(t) {
//log.Printf("go-dnsmasq: checking %q for updates…", hf.path)
mtime, size, err := hostsFileMetadata(hf.path)
if err != nil {
log.Printf("Error stating hostsfile: %s", err)
continue
}
if hf.mtime.Equal(mtime) && hf.size == size {
// no updates
continue
}
if err := h.loadHostEntries(); err != nil {
log.Printf("Error parsing hostsfile: %s", err)
}
log.Printf("Reloaded updated hostsfile")
h.hostMutex.Lock()
h.file.mtime = mtime
h.file.size = size
hf = h.file
h.hostMutex.Unlock()
}
}