Documentation
¶
Overview ¶
Package proxy implements a DNS proxy that supports all known DNS encryption protocols.
Index ¶
- Constants
- func CheckDisabledAAAARequest(ctx *DNSContext, ipv6Disabled bool) bool
- func GenEmptyMessage(request *dns.Msg, rCode int, retry uint32) *dns.Msg
- type BeforeRequestHandler
- type Config
- type DNSContext
- type DoQVersion
- type Proto
- type Proxy
- func (p *Proxy) Addr(proto Proto) net.Addr
- func (p *Proxy) Addrs(proto Proto) []net.Addr
- func (p *Proxy) ClearCache()
- func (p *Proxy) Init() (err error)
- func (p *Proxy) LookupIPAddr(host string) ([]net.IPAddr, error)
- func (p *Proxy) Resolve(dctx *DNSContext) (err error)
- func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (p *Proxy) Start() (err error)
- func (p *Proxy) Stop() error
- type RequestHandler
- type ResponseHandler
- type UpstreamConfig
- type UpstreamModeType
Constants ¶
const ( // DoQCodeNoError is used when the connection or stream needs to be closed, // but there is no error to signal. DoQCodeNoError quic.ApplicationErrorCode = 0 // DoQCodeInternalError signals that the DoQ implementation encountered // an internal error and is incapable of pursuing the transaction or the // connection. DoQCodeInternalError quic.ApplicationErrorCode = 1 // DoQCodeProtocolError signals that the DoQ implementation encountered // a protocol error and is forcibly aborting the connection. DoQCodeProtocolError quic.ApplicationErrorCode = 2 )
const ErrEmptyHost = errors.Error("host is empty")
ErrEmptyHost is returned by LookupIPAddr when the host is empty and can't be resolved.
const ( // NAT64PrefixLength is the length of a NAT64 prefix in bytes. NAT64PrefixLength = net.IPv6len - net.IPv4len )
const NextProtoDQ = "doq"
NextProtoDQ is the ALPN token for DoQ. During connection establishment, DNS/QUIC support is indicated by selecting the ALPN token "dq" in the crypto handshake. DoQ RFC: https://www.rfc-editor.org/rfc/rfc9250.html
const ServFailMaxCacheTTL = 30
ServFailMaxCacheTTL is the maximum time-to-live value for caching SERVFAIL responses in seconds. It's consistent with the upper constraint of 5 minutes given by RFC 2308.
See https://datatracker.ietf.org/doc/html/rfc2308#section-7.1.
const (
// UnqualifiedNames is reserved name for "unqualified names only", ie names without dots
UnqualifiedNames = "unqualified_names"
)
Variables ¶
This section is empty.
Functions ¶
func CheckDisabledAAAARequest ¶
func CheckDisabledAAAARequest(ctx *DNSContext, ipv6Disabled bool) bool
CheckDisabledAAAARequest checks if AAAA requests should be disabled or not and sets NoError empty response to given DNSContext if needed
Types ¶
type BeforeRequestHandler ¶
type BeforeRequestHandler func(p *Proxy, d *DNSContext) (bool, error)
BeforeRequestHandler is an optional custom handler called before DNS requests If it returns false, the request won't be processed at all
type Config ¶
type Config struct {
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
TLSConfig *tls.Config // necessary for TLS, HTTPS, QUIC
HTTP3 bool // if true, HTTPS server will also support HTTP/3
DNSCryptProviderName string // DNSCrypt provider name
DNSCryptResolverCert *dnscrypt.Cert // DNSCrypt resolver certificate
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
// UpstreamConfig is a general set of DNS servers to forward requests to.
UpstreamConfig *UpstreamConfig
// PrivateRDNSUpstreamConfig is the set of upstream DNS servers for
// resolving private IP addresses. All the requests considered private will
// be resolved via these upstream servers. Such queries will finish with
// [upstream.ErrNoUpstream] if it's empty.
PrivateRDNSUpstreamConfig *UpstreamConfig
// Fallbacks is a list of fallback resolvers. Those will be used if the
// general set fails responding.
Fallbacks *UpstreamConfig
// UpstreamMode determines the logic through which upstreams will be used.
UpstreamMode UpstreamModeType
// 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 is the set of networks used to transform responses into
// NXDOMAIN ones if they contain at least a single IP address within these
// networks. It's 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 is the ECS IP used in request.
EDNSAddr net.IP
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
BeforeRequestHandler BeforeRequestHandler // callback that is called before each request
RequestHandler RequestHandler // callback that can handle incoming DNS requests
ResponseHandler ResponseHandler // response callback
// 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
// UseDNS64 enables DNS64 handling. If true, proxy will translate IPv4
// answers into IPv6 answers using first of DNS64Prefs. Note also that PTR
// requests for addresses within the specified networks are considered
// private and will be forwarded as PrivateRDNSUpstreamConfig specifies.
UseDNS64 bool
// DNS64Prefs is the set of NAT64 prefixes used for DNS64 handling. nil
// value disables the feature. An empty value will be interpreted as the
// default Well-Known Prefix.
DNS64Prefs []netip.Prefix
// PreferIPv6 tells the proxy to prefer IPv6 addresses when bootstrapping
// upstreams that use hostnames.
PreferIPv6 bool
}
Config contains all the fields necessary for proxy configuration
type DNSContext ¶
type DNSContext struct {
Proto Proto
// Req is the request message.
Req *dns.Msg
// Res is the response message.
Res *dns.Msg
// Addr is the address of the client.
Addr net.Addr
// StartTime is the moment when request processing started.
StartTime time.Time
// Upstream is the upstream that resolved the request. In case of cached
// response it's nil.
Upstream upstream.Upstream
// CachedUpstreamAddr is the address of the upstream which the answer was
// cached with. It's empty for responses resolved by the upstream server.
CachedUpstreamAddr string
// CustomUpstreamConfig is only used for current request. The Resolve
// method of Proxy uses it instead of the default servers if it's not nil.
CustomUpstreamConfig *UpstreamConfig
// Conn is the underlying client connection. It is nil if Proto is
// ProtoDNSCrypt, ProtoHTTPS, or ProtoQUIC.
Conn net.Conn
// HTTPRequest - HTTP request (for DoH only)
HTTPRequest *http.Request
// HTTPResponseWriter - HTTP response writer (for DoH only)
HTTPResponseWriter http.ResponseWriter
// DNSCryptResponseWriter - necessary to respond to a DNSCrypt query
DNSCryptResponseWriter dnscrypt.ResponseWriter
// QUICStream is the QUIC stream from which we got the query. For
// ProtoQUIC only.
QUICStream quic.Stream
// QUICConnection is the QUIC session from which we got the query. For
// ProtoQUIC only.
QUICConnection quic.Connection
// DoQVersion is the DoQ protocol version. It can (and should) be read from
// ALPN, but in the current version we also use the way DNS messages are
// encoded as a signal.
DoQVersion DoQVersion
// RequestID is an opaque numerical identifier of this request that is
// guaranteed to be unique across requests processed by a single Proxy
// instance.
RequestID uint64
// ReqECS is the EDNS Client Subnet used in the request.
ReqECS *net.IPNet
// contains filtered or unexported fields
}
DNSContext represents a DNS request message context
type DoQVersion ¶
type DoQVersion int
DoQVersion is an enumeration with supported DoQ versions.
const ( // DoQv1Draft represents old DoQ draft versions that do not send a 2-octet // prefix with the DNS message length. // // TODO(ameshkov): remove in the end of 2024. DoQv1Draft DoQVersion = 0x00 // DoQv1 represents DoQ v1.0: https://www.rfc-editor.org/rfc/rfc9250.html. DoQv1 DoQVersion = 0x01 )
type Proto ¶
type Proto string
Proto is the DNS protocol.
const ( // ProtoUDP is the plain DNS-over-UDP protocol. ProtoUDP Proto = "udp" // ProtoTCP is the plain DNS-over-TCP protocol. ProtoTCP Proto = "tcp" // ProtoTLS is the DNS-over-TLS (DoT) protocol. ProtoTLS Proto = "tls" // ProtoHTTPS is the DNS-over-HTTPS (DoH) protocol. ProtoHTTPS Proto = "https" // ProtoQUIC is the DNS-over-QUIC (DoQ) protocol. ProtoQUIC Proto = "quic" // ProtoDNSCrypt is the DNSCrypt protocol. ProtoDNSCrypt Proto = "dnscrypt" )
Proto values.
type Proxy ¶
type Proxy struct {
// RWMutex protects the whole proxy.
sync.RWMutex
// Config is the proxy configuration.
Config
// contains filtered or unexported fields
}
Proxy combines the proxy server state and configuration
func (*Proxy) Addr ¶
Addr returns the first listen address for the specified proto or null if the proxy does not listen to it proto must be "tcp", "tls", "https", "quic", or "udp"
func (*Proxy) Addrs ¶
Addrs returns all listen addresses for the specified proto or nil if the proxy does not listen to it. proto must be "tcp", "tls", "https", "quic", or "udp"
func (*Proxy) LookupIPAddr ¶
LookupIPAddr resolves the specified host IP addresses It sends two DNS queries (A and AAAA) in parallel and returns both results
func (*Proxy) Resolve ¶
func (p *Proxy) Resolve(dctx *DNSContext) (err error)
Resolve is the default resolving method used by the DNS proxy to query upstream servers.
func (*Proxy) ServeHTTP ¶
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP is the http.Handler implementation that handles DoH queries. Here is what it returns:
- http.StatusBadRequest if there is no DNS request data;
- http.StatusUnsupportedMediaType if request content type is not "application/dns-message";
- http.StatusMethodNotAllowed if request method is not GET or POST.
type RequestHandler ¶
type RequestHandler func(p *Proxy, d *DNSContext) 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 ResponseHandler ¶
type ResponseHandler func(d *DNSContext, err 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 UpstreamConfig ¶
type UpstreamConfig struct {
Upstreams []upstream.Upstream // list of default upstreams
DomainReservedUpstreams map[string][]upstream.Upstream // map of reserved domains and lists of corresponding upstreams
SpecifiedDomainUpstreams map[string][]upstream.Upstream // map of excluded domains and lists of corresponding upstreams
SubdomainExclusions *stringutil.Set // set of domains with sub-domains exclusions
}
UpstreamConfig is a wrapper for list of default upstreams and map of reserved domains and corresponding upstreams
func ParseUpstreamsConfig ¶
func ParseUpstreamsConfig(upstreamConfig []string, options *upstream.Options) (*UpstreamConfig, error)
ParseUpstreamsConfig returns UpstreamConfig and error if upstreams configuration is invalid default upstream syntax: <upstreamString> reserved upstream syntax: [/domain1/../domainN/]<upstreamString> subdomains only upstream syntax: [/*.domain1/../*.domainN]<upstreamString> More specific domains take priority over less specific domains, To exclude more specific domains from reserved upstreams querying you should use the following syntax: [/domain1/../domainN/]# So the following config: ["[/host.com/]1.2.3.4", "[/www.host.com/]2.3.4.5", "[/maps.host.com/]#", "3.4.5.6"] will send queries for *.host.com to 1.2.3.4, except for *.www.host.com, which will go to 2.3.4.5 and *.maps.host.com, which will go to default server 3.4.5.6 with all other domains. To exclude top level domain from reserved upstreams querying you could use the following: [/*.domain.com/]<upstreamString> So the following config: ["[/*.domain.com/]1.2.3.4", "3.4.5.6"] will send queries for all subdomains *.domain.com to 1.2.3.4, but domain.com query will be sent to default server 3.4.5.6 as every other query.
TODO(e.burkov): Refactor this mess.
func (*UpstreamConfig) Close ¶
func (uc *UpstreamConfig) Close() (err error)
Close implements the io.Closer interface for *UpstreamConfig.
type UpstreamModeType ¶
type UpstreamModeType int
UpstreamModeType - upstream mode
const ( // UModeLoadBalance - LoadBalance UModeLoadBalance UpstreamModeType = iota // UModeParallel - parallel queries to all configured upstream servers are enabled UModeParallel // UModeFastestAddr - use Fastest Address algorithm UModeFastestAddr )