-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathserver.go
106 lines (91 loc) · 2.21 KB
/
server.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
package dnsp
import (
"regexp"
"sync"
"time"
"github.com/miekg/dns"
)
// Server implements a DNS server.
type Server struct {
c *dns.Client
s *dns.Server
// White, when set to true, causes the server to work in white-listing mode.
// It will only resolve queries that have been white-listed.
//
// When set to false, it will resolve anything that is not blacklisted.
white bool
// Protect access to the hosts file with a mutex.
m sync.RWMutex
// A combined whitelist/blacklist. It contains both whitelist and blacklist entries.
hosts hosts
// Regex based whitelist and blacklist, depending on the value of `white`.
hostsRX hostsRX
privateHosts map[string]struct{}
privateHostsRX map[string]*regexp.Regexp
// Information about the hosts file, used for polling:
hostsFile struct {
size int64
path string
mtime time.Time
}
}
// NewServer creates a new Server with the given options.
func NewServer(o Options) (*Server, error) {
if err := o.validate(); err != nil {
return nil, err
}
s := Server{
c: &dns.Client{},
s: &dns.Server{
Net: o.Net,
Addr: o.Bind,
},
white: o.Whitelist != "",
hosts: hosts{},
hostsRX: hostsRX{},
privateHosts: map[string]struct{}{},
privateHostsRX: map[string]*regexp.Regexp{},
}
hostListPath := o.Whitelist
if hostListPath == "" {
hostListPath = o.Blacklist
}
s.hostsFile.path = hostListPath
if err := s.loadHostEntries(); err != nil {
return nil, err
}
if o.Poll != 0 {
go s.monitorHostEntries(o.Poll)
}
s.s.Handler = dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
// If no upstream proxy is present, drop the query:
if len(o.Resolve) == 0 {
dns.HandleFailed(w, r)
return
}
// Filter Questions:
if r.Question = s.filter(r.Question); len(r.Question) == 0 {
w.WriteMsg(r)
return
}
// Proxy Query:
for _, addr := range o.Resolve {
in, _, err := s.c.Exchange(r, addr)
if err != nil {
continue
}
w.WriteMsg(in)
return
}
dns.HandleFailed(w, r)
})
return &s, nil
}
// ListenAndServe runs the server
func (s *Server) ListenAndServe() error {
return s.s.ListenAndServe()
}
// Shutdown stops the server, closing its connection.
func (s *Server) Shutdown() error {
return s.s.Shutdown()
}