proxy

package
v0.71.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2024 License: Apache-2.0 Imports: 45 Imported by: 8

Documentation

Overview

Package proxy implements a DNS proxy that supports all known DNS encryption protocols.

Index

Constants

View Source
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
)
View Source
const ErrEmptyHost = errors.Error("host is empty")

ErrEmptyHost is returned by LookupIPAddr when the host is empty and can't be resolved.

View Source
const (

	// NAT64PrefixLength is the length of a NAT64 prefix in bytes.
	NAT64PrefixLength = net.IPv6len - net.IPv4len
)
View Source
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

View Source
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.

View Source
const UnqualifiedNames = "unqualified_names"

UnqualifiedNames is a key for [UpstreamConfig.DomainReservedUpstreams] map to specify the upstreams only used for resolving domain names consisting of a single label.

Variables

This section is empty.

Functions

func CheckDisabledAAAARequest added in v0.20.1

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

func GenEmptyMessage added in v0.20.1

func GenEmptyMessage(request *dns.Msg, rCode int, retry uint32) *dns.Msg

GenEmptyMessage generates empty message with given response code and retry time

func ValidatePrivateConfig added in v0.68.0

func ValidatePrivateConfig(uc *UpstreamConfig, privateSubnets netutil.SubnetSet) (err error)

ValidatePrivateConfig returns an error if uc isn't valid, or, treated as private upstreams configuration, contains specifications for invalid domains.

Types

type BeforeRequestError added in v0.69.0

type BeforeRequestError struct {
	// Err is the error that caused the response.  It must not be nil.
	Err error

	// Response is the response message to be sent to the client.  It must be a
	// valid response message.
	Response *dns.Msg
}

BeforeRequestError is an error that signals that the request should be responded with the given response message.

func (*BeforeRequestError) Error added in v0.69.0

func (e *BeforeRequestError) Error() (msg string)

Error implements the [error] interface for *BeforeRequestError.

func (*BeforeRequestError) Unwrap added in v0.69.0

func (e *BeforeRequestError) Unwrap() (unwrapped error)

Unwrap implements the errors.Wrapper interface for *BeforeRequestError.

type BeforeRequestHandler added in v0.14.0

type BeforeRequestHandler interface {
	// HandleBefore is called before each DNS request is started processing.
	// The passed [DNSContext] contains the Req, Addr, and IsLocalClient fields
	// set accordingly.
	//
	// If returned err is a [BeforeRequestError], the given response message is
	// used.  If err is nil, the request is processed further.  [Proxy] assumes
	// a handler itself doesn't set the [DNSContext.Res] field.
	HandleBefore(p *Proxy, dctx *DNSContext) (err error)
}

BeforeRequestHandler is an object that can handle the request before it's processed by Proxy.

type Config

type Config struct {
	// TrustedProxies is the trusted list of CIDR networks to detect proxy
	// servers addresses from where the DoH requests should be handled.  The
	// value of nil makes Proxy not trust any address.
	TrustedProxies netutil.SubnetSet

	// PrivateSubnets is the set of private networks.  Client having an address
	// within this set is able to resolve PTR requests for addresses within this
	// set.
	PrivateSubnets netutil.SubnetSet

	// MessageConstructor used to build DNS messages.  If nil, the default
	// constructor will be used.
	MessageConstructor MessageConstructor

	// BeforeRequestHandler is an optional custom handler called before each DNS
	// request is started processing, see [BeforeRequestHandler].  The default
	// no-op implementation is used, if it's nil.
	BeforeRequestHandler BeforeRequestHandler

	// RequestHandler is an optional custom handler for DNS requests.  It's used
	// instead of [Proxy.Resolve] if set.  See [RequestHandler].
	RequestHandler RequestHandler

	// ResponseHandler is an optional custom handler called when DNS query has
	// been processed.  See [ResponseHandler].
	ResponseHandler ResponseHandler

	// 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

	// Userinfo is the sole permitted userinfo for the DoH basic authentication.
	// If Userinfo is set, all DoH queries are required to have this basic
	// authentication information.
	Userinfo *url.Userinfo

	// TLSConfig is the TLS configuration.  Required for DNS-over-TLS,
	// DNS-over-HTTP, and DNS-over-QUIC servers.
	TLSConfig *tls.Config

	// DNSCryptResolverCert is the DNSCrypt resolver certificate.  Required for
	// DNSCrypt server.
	DNSCryptResolverCert *dnscrypt.Cert

	// DNSCryptProviderName is the DNSCrypt provider name.  Required for
	// DNSCrypt server.
	DNSCryptProviderName string

	// HTTPSServerName sets the Server header of the HTTPS server responses, if
	// not empty.
	HTTPSServerName string

	// UDPListenAddr is the set of UDP addresses to listen for plain
	// DNS-over-UDP requests.
	UDPListenAddr []*net.UDPAddr

	// TCPListenAddr is the set of TCP addresses to listen for plain
	// DNS-over-TCP requests.
	TCPListenAddr []*net.TCPAddr

	// HTTPSListenAddr is the set of TCP addresses to listen for DNS-over-HTTPS
	// requests.
	HTTPSListenAddr []*net.TCPAddr

	// TLSListenAddr is the set of TCP addresses to listen for DNS-over-TLS
	// requests.
	TLSListenAddr []*net.TCPAddr

	// QUICListenAddr is the set of UDP addresses to listen for DNS-over-QUIC
	// requests.
	QUICListenAddr []*net.UDPAddr

	// DNSCryptUDPListenAddr is the set of UDP addresses to listen for DNSCrypt
	// requests.
	DNSCryptUDPListenAddr []*net.UDPAddr

	// DNSCryptTCPListenAddr is the set of TCP addresses to listen for DNSCrypt
	// requests.
	DNSCryptTCPListenAddr []*net.TCPAddr

	// 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 []netip.Prefix

	// 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

	// RatelimitWhitelist is a list of IP addresses excluded from rate limiting.
	RatelimitWhitelist []netip.Addr

	// EDNSAddr is the ECS IP used in request.
	EDNSAddr net.IP

	// RatelimitSubnetLenIPv4 is a subnet length for IPv4 addresses used for
	// rate limiting requests.
	RatelimitSubnetLenIPv4 int

	// RatelimitSubnetLenIPv6 is a subnet length for IPv6 addresses used for
	// rate limiting requests.
	RatelimitSubnetLenIPv6 int

	// Ratelimit is a maximum number of requests per second from a given IP (0
	// to disable).
	Ratelimit int

	// CacheSizeBytes is the maximum cache size in bytes.
	CacheSizeBytes int

	// CacheMinTTL is the minimum TTL for cached DNS responses in seconds.
	CacheMinTTL uint32

	// CacheMaxTTL is the maximum TTL for cached DNS responses in seconds.
	CacheMaxTTL uint32

	// 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 uint

	// 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

	// 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

	// RefuseAny makes proxy refuse the requests of type ANY.
	RefuseAny bool

	// HTTP3 enables HTTP/3 support for HTTPS server.
	HTTP3 bool

	// 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

	// CacheEnabled defines if the response cache should be used.
	CacheEnabled bool

	// CacheOptimistic defines if the optimistic cache mechanism should be used.
	CacheOptimistic bool

	// 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.
	// Those will be responded with NXDOMAIN if UsePrivateRDNS is false.
	UseDNS64 bool

	// UsePrivateRDNS defines if the PTR requests for private IP addresses
	// should be resolved via PrivateRDNSUpstreamConfig.  Note that it requires
	// a valid PrivateRDNSUpstreamConfig with at least a single general upstream
	// server.
	UsePrivateRDNS bool

	// 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

TODO(a.garipov): Consider extracting conf blocks for better fieldalignment.

type CustomUpstreamConfig added in v0.59.0

type CustomUpstreamConfig struct {
	// contains filtered or unexported fields
}

CustomUpstreamConfig contains upstreams configuration with an optional cache.

func NewCustomUpstreamConfig added in v0.59.0

func NewCustomUpstreamConfig(
	u *UpstreamConfig,
	cacheEnabled bool,
	cacheSize int,
	enableEDNSClientSubnet bool,
) (c *CustomUpstreamConfig)

NewCustomUpstreamConfig returns new custom upstream configuration.

func (*CustomUpstreamConfig) ClearCache added in v0.59.0

func (c *CustomUpstreamConfig) ClearCache()

ClearCache removes all items from the cache.

func (*CustomUpstreamConfig) Close added in v0.59.0

func (c *CustomUpstreamConfig) Close() (err error)

Close closes the custom upstream config.

type DNSContext

type DNSContext struct {
	// Conn is the underlying client connection.  It is nil if Proto is
	// ProtoDNSCrypt, ProtoHTTPS, or ProtoQUIC.
	Conn net.Conn

	// QUICConnection is the QUIC session from which we got the query.  For
	// ProtoQUIC only.
	QUICConnection quic.Connection

	// QUICStream is the QUIC stream from which we got the query.  For
	// [ProtoQUIC] only.
	QUICStream quic.Stream

	// Upstream is the upstream that resolved the request.  In case of cached
	// response it's nil.
	Upstream upstream.Upstream

	// DNSCryptResponseWriter - necessary to respond to a DNSCrypt query
	DNSCryptResponseWriter dnscrypt.ResponseWriter

	// HTTPResponseWriter - HTTP response writer (for DoH only)
	HTTPResponseWriter http.ResponseWriter

	// HTTPRequest - HTTP request (for DoH only)
	HTTPRequest *http.Request

	// ReqECS is the EDNS Client Subnet used in the request.
	ReqECS *net.IPNet

	// CustomUpstreamConfig is the upstreams configuration used only for current
	// request.  The Resolve method of Proxy uses it instead of the default
	// servers if it's not nil.
	CustomUpstreamConfig *CustomUpstreamConfig

	// Req is the request message.
	Req *dns.Msg
	// Res is the response message.
	Res *dns.Msg

	Proto Proto

	// 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

	// RequestedPrivateRDNS is the subnet extracted from the ARPA domain of
	// request's question if it's a PTR, SOA, or NS query for a private IP
	// address.  It can be a single-address subnet as well as a zero-length one.
	RequestedPrivateRDNS netip.Prefix

	// Addr is the address of the client.
	Addr netip.AddrPort

	// QueryDuration is the duration of a successful query to an upstream
	// server or, if the upstream server is unavailable, to a fallback server.
	QueryDuration time.Duration

	// 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

	// IsPrivateClient is true if the client's address is considered private
	// according to the configured private subnet set.
	IsPrivateClient bool
	// contains filtered or unexported fields
}

DNSContext represents a DNS request message context

type DoQVersion added in v0.43.0

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 MessageConstructor added in v0.66.1

type MessageConstructor interface {
	// NewMsgNXDOMAIN creates a new response message replying to req with the
	// NXDOMAIN code.
	NewMsgNXDOMAIN(req *dns.Msg) (resp *dns.Msg)

	// NewMsgSERVFAIL creates a new response message replying to req with the
	// SERVFAIL code.
	NewMsgSERVFAIL(req *dns.Msg) (resp *dns.Msg)

	// NewMsgNOTIMPLEMENTED creates a new response message replying to req with
	// the NOTIMPLEMENTED code.
	NewMsgNOTIMPLEMENTED(req *dns.Msg) (resp *dns.Msg)
}

MessageConstructor creates DNS messages.

type ParseError added in v0.64.0

type ParseError struct {

	// Idx is an index of the lines.  See [ParseUpstreamsConfig].
	Idx int
	// contains filtered or unexported fields
}

ParseError is an error which contains an index of the line of the upstream list.

func (*ParseError) Error added in v0.64.0

func (e *ParseError) Error() (msg string)

Error implements the [error] interface for *ParseError.

func (*ParseError) Unwrap added in v0.64.0

func (e *ParseError) Unwrap() (unwrapped error)

Unwrap implements the errors.Wrapper interface for *ParseError.

type Proto added in v0.38.0

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 {

	// Config is the proxy configuration.
	//
	// TODO(a.garipov): Remove this embed and create a proper initializer.
	Config

	// RWMutex protects the whole proxy.
	//
	// TODO(e.burkov):  Find out what exactly it protects and name it properly.
	// Also make it a pointer.
	sync.RWMutex
	// contains filtered or unexported fields
}

Proxy combines the proxy server state and configuration. It must not be used until initialized with Proxy.Init.

TODO(a.garipov): Consider extracting conf blocks for better fieldalignment.

func New added in v0.66.0

func New(c *Config) (p *Proxy, err error)

New creates a new Proxy with the specified configuration. c must not be nil.

TODO(e.burkov): Cover with tests.

func (*Proxy) Addr added in v0.9.1

func (p *Proxy) Addr(proto Proto) net.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 added in v0.32.0

func (p *Proxy) Addrs(proto Proto) []net.Addr

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) ClearCache added in v0.46.3

func (p *Proxy) ClearCache()

ClearCache clears the DNS cache of p.

func (*Proxy) Init deprecated added in v0.23.0

func (p *Proxy) Init() (err error)

Init populates fields of p but does not start listeners.

Deprecated: Use the New function instead.

func (*Proxy) LookupNetIP added in v0.60.0

func (p *Proxy) LookupNetIP(
	_ context.Context,
	_ string,
	host string,
) (addrs []netip.Addr, err error)

LookupNetIP implements the upstream.Resolver interface for *Proxy. It resolves the specified host IP addresses by sending two DNS queries (A and AAAA) in parallel. It returns both results for those two queries.

func (*Proxy) Resolve added in v0.9.1

func (p *Proxy) Resolve(dctx *DNSContext) (err error)

Resolve is the default resolving method used by the DNS proxy to query upstream servers. It expects dctx is filled with the request, the client's

func (*Proxy) ServeHTTP added in v0.9.11

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.

func (*Proxy) Shutdown added in v0.66.0

func (p *Proxy) Shutdown(_ context.Context) (err error)

Shutdown implements the service.Interface for *Proxy.

TODO(e.burkov): Use the context.

func (*Proxy) Start

func (p *Proxy) Start(ctx context.Context) (err error)

Start implements the service.Interface for *Proxy.

type RequestHandler added in v0.14.0

type RequestHandler func(p *Proxy, dctx *DNSContext) (err error)

RequestHandler is an optional custom handler for DNS requests. It's used instead of Proxy.Resolve if set. The resulting error doesn't affect the request processing. The custom handler is responsible for calling ResponseHandler, if it doesn't call Proxy.Resolve.

TODO(e.burkov): Use the same interface-based approach as BeforeRequestHandler.

type ResponseHandler added in v0.13.0

type ResponseHandler func(dctx *DNSContext, err error)

ResponseHandler is an optional custom handler called when DNS query has been processed. When called from Proxy.Resolve, dctx will contain the response message if the upstream or cache succeeded. err is only not nil if the upstream failed to respond.

TODO(e.burkov): Use the same interface-based approach as BeforeRequestHandler.

type UpstreamConfig added in v0.12.0

type UpstreamConfig struct {
	// DomainReservedUpstreams maps the domains to the upstreams.
	DomainReservedUpstreams map[string][]upstream.Upstream

	// SpecifiedDomainUpstreams maps the specific domain names to the upstreams.
	SpecifiedDomainUpstreams map[string][]upstream.Upstream

	// SubdomainExclusions is set of domains with subdomains exclusions.
	SubdomainExclusions *container.MapSet[string]

	// Upstreams is a list of default upstreams.
	Upstreams []upstream.Upstream
}

UpstreamConfig maps domain names to upstreams.

func ParseUpstreamsConfig added in v0.12.0

func ParseUpstreamsConfig(
	lines []string,
	opts *upstream.Options,
) (conf *UpstreamConfig, err error)

ParseUpstreamsConfig returns an UpstreamConfig and nil error if the upstream configuration is valid. Otherwise returns a partially filled UpstreamConfig and wrapped error containing lines with errors. It also skips empty lines and comments (lines starting with "#").

Simple upstreams

Single upstream per line. For example:

1.2.3.4
3.4.5.6

Domain specific upstreams

  • reserved upstreams: [/domain1/../domainN/]<upstreamString>
  • subdomains only upstreams: [/*.domain1/../*.domainN]<upstreamString>

Where <upstreamString> is one or many upstreams separated by space (e.g. `1.1.1.1` or `1.1.1.1 2.2.2.2`).

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/news.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 or *.news.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): Consider supporting multiple upstreams in a single line for default upstream syntax.

func (*UpstreamConfig) Close added in v0.46.0

func (uc *UpstreamConfig) Close() (err error)

Close implements the io.Closer interface for *UpstreamConfig.

type UpstreamModeType added in v0.29.0

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
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL