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 ( // 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 []upstream.Upstream // 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 }
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 { sync.RWMutex // protects parallel access to proxy structures Config // proxy configuration // 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.
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 )