forked from AdguardTeam/dnsproxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.go
229 lines (186 loc) · 7.88 KB
/
config.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package proxy
import (
"crypto/tls"
"net"
"time"
"github.com/AdguardTeam/dnsproxy/upstream"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/ameshkov/dnscrypt/v2"
)
// UpstreamModeType - upstream mode
type UpstreamModeType int
const (
// UModeLoadBalance - LoadBalance
UModeLoadBalance UpstreamModeType = iota
// UModeParallel - parallel queries to all configured upstream servers are enabled
UModeParallel
// UModeFastestAddr - use Fastest Address algorithm
UModeFastestAddr
)
// BeforeRequestHandler is an optional custom handler called before DNS requests
// If it returns false, the request won't be processed at all
type BeforeRequestHandler func(p *Proxy, d *DNSContext) (bool, error)
// RequestHandler is an optional custom handler for DNS requests
// It is called instead of the default method (Proxy.Resolve())
// See handler_test.go for examples
type RequestHandler func(p *Proxy, d *DNSContext) error
// ResponseHandler is a callback method that is called when DNS query has been processed
// d -- current DNS query context (contains response if it was successful)
// err -- error (if any)
type ResponseHandler func(d *DNSContext, err error)
// Config contains all the fields necessary for proxy configuration
type Config struct {
// Listeners
// --
UDPListenAddr []*net.UDPAddr // if nil, then it does not listen for UDP
TCPListenAddr []*net.TCPAddr // if nil, then it does not listen for TCP
HTTPSListenAddr []*net.TCPAddr // if nil, then it does not listen for HTTPS (DoH)
TLSListenAddr []*net.TCPAddr // if nil, then it does not listen for TLS (DoT)
QUICListenAddr []*net.UDPAddr // if nil, then it does not listen for QUIC (DoQ)
DNSCryptUDPListenAddr []*net.UDPAddr // if nil, then it does not listen for DNSCrypt
DNSCryptTCPListenAddr []*net.TCPAddr // if nil, then it does not listen for DNSCrypt
// Encryption configuration
// --
TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC
DNSCryptProviderName string // DNSCrypt provider name
DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate
// Rate-limiting and anti-DNS amplification measures
// --
Ratelimit int // max number of requests per second from a given IP (0 to disable)
RatelimitWhitelist []string // a list of whitelisted client IP addresses
RefuseAny bool // if true, refuse ANY requests
// TrustedProxies is the list of IP addresses and CIDR networks to
// detect proxy servers addresses the DoH requests from which should be
// handled. The value of nil or an empty slice for this field makes
// Proxy not trust any address.
TrustedProxies []string
// Upstream DNS servers and their settings
// --
UpstreamConfig *UpstreamConfig // Upstream DNS servers configuration
Fallbacks []upstream.Upstream // list of fallback resolvers (which will be used if regular upstream failed to answer)
UpstreamMode UpstreamModeType // How to request the upstream servers
// FastestPingTimeout is the timeout for waiting the first successful
// dialing when the UpstreamMode is set to UModeFastestAddr.
// Non-positive value will be replaced with the default one.
FastestPingTimeout time.Duration
// BogusNXDomain - transforms responses that contain at least one of the given IP addresses into NXDOMAIN
// Similar to dnsmasq's "bogus-nxdomain"
BogusNXDomain []*net.IPNet
// Enable EDNS Client Subnet option DNS requests to the upstream server will
// contain an OPT record with Client Subnet option. If the original request
// already has this option set, we pass it through as is. Otherwise, we set
// it ourselves using the client IP with subnet /24 (for IPv4) and /56 (for
// IPv6).
//
// If the upstream server supports ECS, it sets subnet number in the
// response. This subnet number along with the client IP and other data is
// used as a cache key. Next time, if a client from the same subnet
// requests this host name, we get the response from cache. If another
// client from a different subnet requests this host name, we pass his
// request to the upstream server.
//
// If the upstream server doesn't support ECS (there's no subnet number in
// response), this response will be cached for all clients.
//
// If client IP is private (i.e. not public), we don't add EDNS record into
// a request. And so there will be no EDNS record in response either. We
// store these responses in general cache (without subnet) so they will
// never be used for clients with public IP addresses.
EnableEDNSClientSubnet bool
EDNSAddr net.IP // ECS IP used in request
// Cache settings
// --
CacheEnabled bool // cache status
CacheSizeBytes int // Cache size (in bytes). Default: 64k
CacheMinTTL uint32 // Minimum TTL for DNS entries (in seconds).
CacheMaxTTL uint32 // Maximum TTL for DNS entries (in seconds).
// CacheOptimistic defines if the optimistic cache mechanism should be
// used.
CacheOptimistic bool
// Handlers (for the case when dnsproxy is used as a library)
// --
BeforeRequestHandler BeforeRequestHandler // callback that is called before each request
RequestHandler RequestHandler // callback that can handle incoming DNS requests
ResponseHandler ResponseHandler // response callback
// Other settings
// --
// MaxGoroutines is the maximum number of goroutines processing DNS
// requests. Important for mobile users.
//
// TODO(a.garipov): Rename this to something like
// “MaxDNSRequestGoroutines” in a later major version, as it doesn't
// actually limit all goroutines.
MaxGoroutines int
// The size of the read buffer on the underlying socket. Larger read buffers can handle
// larger bursts of requests before packets get dropped.
UDPBufferSize int
}
// validateConfig verifies that the supplied configuration is valid and returns an error if it's not
func (p *Proxy) validateConfig() error {
if p.started {
return errors.Error("server has been already started")
}
err := p.validateListenAddrs()
if err != nil {
return err
}
if p.UpstreamConfig == nil {
return errors.Error("no default upstreams specified")
}
if len(p.UpstreamConfig.Upstreams) == 0 {
if len(p.UpstreamConfig.DomainReservedUpstreams) == 0 {
return errors.Error("no upstreams specified")
}
return errors.Error("no default upstreams specified")
}
if p.CacheMinTTL > 0 || p.CacheMaxTTL > 0 {
log.Info("Cache TTL override is enabled. Min=%d, Max=%d", p.CacheMinTTL, p.CacheMaxTTL)
}
if p.Ratelimit > 0 {
log.Info("Ratelimit is enabled and set to %d rps", p.Ratelimit)
}
if p.RefuseAny {
log.Info("The server is configured to refuse ANY requests")
}
if len(p.BogusNXDomain) > 0 {
log.Info("%d bogus-nxdomain IP specified", len(p.BogusNXDomain))
}
return nil
}
// validateListenAddrs returns an error if the addressses are not configured
// properly.
func (p *Proxy) validateListenAddrs() error {
if !p.hasListenAddrs() {
return errors.Error("no listen address specified")
}
if p.TLSConfig == nil {
if p.TLSListenAddr != nil {
return errors.Error("cannot create tls listener without tls config")
}
if p.HTTPSListenAddr != nil {
return errors.Error("cannot create https listener without tls config")
}
if p.QUICListenAddr != nil {
return errors.Error("cannot create quic listener without tls config")
}
}
if (p.DNSCryptTCPListenAddr != nil || p.DNSCryptUDPListenAddr != nil) &&
(p.DNSCryptResolverCert == nil || p.DNSCryptProviderName == "") {
return errors.Error("cannot create dnscrypt listener without dnscrypt config")
}
return nil
}
// hasListenAddrs - is there any addresses to listen to?
func (p *Proxy) hasListenAddrs() bool {
if p.UDPListenAddr == nil &&
p.TCPListenAddr == nil &&
p.TLSListenAddr == nil &&
p.HTTPSListenAddr == nil &&
p.QUICListenAddr == nil &&
p.DNSCryptUDPListenAddr == nil &&
p.DNSCryptTCPListenAddr == nil {
return false
}
return true
}