proxy

package
v0.0.0-...-96e514c Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2023 License: Apache-2.0 Imports: 37 Imported by: 0

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 (

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

func GenEmptyMessage

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

GenEmptyMessage generates empty message with given response code and retry time

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

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

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

func (p *Proxy) ClearCache()

ClearCache clears the DNS cache of p.

func (*Proxy) Init

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

Init populates fields of p but does not start listeners.

func (*Proxy) LookupIPAddr

func (p *Proxy) LookupIPAddr(host string) ([]net.IPAddr, error)

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.

func (*Proxy) Start

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

Start initializes the proxy server and starts listening

func (*Proxy) Stop

func (p *Proxy) Stop() error

Stop stops the proxy server including all its listeners

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
)

Jump to

Keyboard shortcuts

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