rdns

package module
v0.1.51 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2023 License: BSD-3-Clause Imports: 39 Imported by: 6

README

RouteDNS - DNS stub resolver, proxy and router

GoDoc build license

RouteDNS acts as a stub resolver and proxy that offers flexible configuration options with a focus on providing privacy as well as resiliency. It supports several DNS protocols such as plain UDP and TCP, DNS-over-TLS and DNS-over-HTTPS as input and output. In addition it's possible to build complex processing pipelines allowing routing of queries based on query name, type or source address as well as blocklists, caches and name translation. Upstream resolvers can be grouped in various ways to provide failover, load-balancing, or performance.

Features:

  • Support for DNS-over-TLS (DoT, RFC7858), client and server
  • Support for DNS-over-HTTPS (DoH, RFC8484), client and server with HTTP2
  • Support for DNS-over-QUIC (DoQ, RFC9250), client and server
  • Support for DNS-over-DTLS (RFC8094), client and server
  • DNS-over-HTTPS using a QUIC transport, client and server
  • Custom CAs and mutual-TLS
  • Support for plain DNS, UDP and TCP for incoming and outgoing requests
  • Connection reuse and pipelining queries for efficiency
  • Multiple failover and load-balancing algorithms, caching, in-line query/response modification and translation (full list here)
  • Routing of queries based on query type, class, query name, time, or client IP
  • EDNS0 query and response padding (RFC7830, RFC8467)
  • EDNS0 Client Subnet (ECS) manipulation (RFC7871)
  • Support for bootstrap addresses to avoid the initial service name lookup
  • Support for 0-RTT Quic queries if the upstream server supports it
  • SOCKS5 proxy support
  • Optional metrics export (expvar) to support monitoring and graphing
  • Written in Go - Platform independent

Installation

Install Go version 1.19+ then run the following to build the binary. It'll be placed in $HOME/go/bin by default:

GO111MODULE=on go get -v github.com/folbricht/routedns/cmd/routedns

Alternative method using a clone, building from the tip of the master branch.

git clone https://github.com/folbricht/routedns.git
cd routedns/cmd/routedns && go install

Run it:

routedns config.toml

An example systemd service file is provided here

Example configuration files for a number of use-cases can be found here

Docker container

A container is available on Docker Hub. It comes with a very basic configuration which is expected to be overwritten with a custom config file.

Use the default config (simple DNS -> DoT proxy):

docker run -d --rm --network host folbricht/routedns

Override the default configuration (/config.toml) with a config file on the host:

docker run -d --rm --network host -v /path/to/config.toml:/config.toml folbricht/routedns

Listen on non-standard ports:

docker run -d --rm -p 5353:53/udp -p 5353:53/tcp -v /path/to/config.toml:/config.toml folbricht/routedns
Pre-Compiled/Build Binaries

You can also fetch pre-compiled/build binaries for popular/common (router) platforms (Like Raspberry-Pi) here: https://github.com/cbuijs/routedns-binaries.

Configuration

RouteDNS supports building complex DNS processing pipelines. A typically configuration would have one or more listeners to receive queries, several modifiers and routers to process the query (or responses), and then several resolvers that pass the query to upstream DNS services. See the Configuration Guide for details on how to setup a pipeline.

pipeline-overview

QUIC support

Support for the QUIC protocol is still experimental. In the context of DNS, there are two implementations, DNS-over-QUIC (DoQ, RFC9250) as well as DNS-over-HTTPS using QUIC. Both protocols are supported by RouteDNS, client and server implementations. Quic also supports 0-RTT queries if the upstream server supports it.

Use-cases / Examples

Use case 1: Use DNS-over-TLS for all queries locally

In this example, the goal is to send all DNS queries on the local machine encrypted via DNS-over-TLS to Cloudflare's DNS server 1.1.1.1. For this, the nameserver IP in /etc/resolv.conf is changed to 127.0.0.1. To improve query performance a cache is added. Since there is only one upstream resolver, and everything should be sent there, no router is needed. Both listeners are using the loopback device as only the local machine should be able to use RouteDNS.

use-case-1

The full config file for this use-case can be found here

Use case 2: Prefer secure DNS in a corporate environment

In a corporate environment it's necessary to use the potentially slow and insecure company DNS servers. Only these servers are able to resolve some resources hosted in the corporate network. A router can be used to secure DNS whenever possible while still being able to resolve internal hosts over a VPN.

use-case-2

The configuration can be found here

Use case 3: Restrict access to potentially harmful content

The goal here is to single out children's devices on the network and apply a custom blocklist to their DNS resolution. Anything on the (static) blocklist will fail to resolve with an NXDOMAIN response. Names that aren't on the blocklist are then sent on to CleanBrowsing for any further filtering. All other devices on the network will have unfiltered access via Cloudflare's DNS server, and all queries are done using DNS-over-TLS. The config file can also be found here

use-case-3

Use case 4: Replace queries for short names with FQDN in a multi-lab environment

If adding a search list to /etc/resolv.conf is not an option, a replace group can be used to add the correct domain based on the name in the query. It's possible to modify or expand query strings by matching on a regex and replacing it with an alternative expression. The replace string supports expansion like $1 to refer to a match in the regex. The replace can be combined with routers and resolvers as with all the other groups.

In this example, there are multiple lab VPN connections, each with their own DNS server. Queries for short names starting with prod- will have the domain prod-domain.com. appended to them and the prefix removed. Queries for test-* will have test.domain.com. appended and so on. The queries are then routed to the appropriate DNS server and responses to the client will reference the original queries with the response from the lab DNS. More than one replace rule can be defined and they are applied to the query name in order. Any other queries will pass without modification and are routed to Cloudflare.

use-case-4

The configuration can be found here

Use case 5: Proxying out of a restricted or un-trusted location

In this use case the goal is to use get access to unfiltered and unmonitored DNS services in a location that does not offer it normally. Direct access to well-known public DoT or DoH providers may be blocked, forcing plain DNS. It may be possible to setup an instance of RouteDNS in a less restricted location to act as proxy, offering DoH which is harder to detect and block. To prevent unauthorized access to the proxy, the config will enforce mutual-TLS with a client certificate signed by a custom CA.

use-case-5

The server configuration will accept queries over DNS-over-HTTPS from authorized clients (with valid and signed certificate), and forward all queries to Cloudflare using DNS-over-TLS.

The client configuration acts as local DNS resolver, handling all queries from the local OS. Every query is then forwarded to the secure proxy using DoH. The client needs to have a signed certificate as the server is configured to require it.

Use case 6: Protecting the home-network from ads and malware domains using blocklists

In this use-case, a whole internal network can be protected from unwanted content such as ads and malware. This can be achieved by running RouteDNS in the local network, filtering out known-bad domains or networks. There are 3 different types of filters applied:

  • Queries are filtered through a list of bad domains
  • Responses are filtered if they contain names on a blocklist
  • Responses that contain IPs in known-bad networks are blocked, regardless of what query name was used

These blocklists are loaded and refreshed daily by RouteDNS daily over HTTP. Refresh happens transparently and does not impact query performance. In addition, this configuration caches responses and adjusts TTL values to reduce the amount of queries caused by TTL values that are set too low.

use-case-6

The configuration can be found here

Documentation

Overview

Package rdns implements a variety of functionality to make DNS resulution configurable and extensible. It offers DNS resolvers as well as listeners with a number of protcols such as DNS-over-TLS, DNS-over-HTTP, and plain wire format DNS. In addition it is possible to route queries based on the query name or type. There are 4 fundamental types of objects available in this library.

Resolvers

Resolvers implement name resolution with upstream resolvers. All of them implement connection reuse as well as pipelining (sending multiple queries and receiving them out-of-order).

Groups

Groups typically wrap multiple resolvers and implement failover or load-balancing algorithms accross all resolvers in the group. Groups too are resolvers and can therefore be nested into other groups for more complex query routing.

Routers

Routers are used to send DNS queries to resolvers, groups, or even other routers based on the query content. As with groups, routers too are resolvers that can be combined to form more advanced configurations.

Listeners

While resolvers handle outgoing queries to upstream servers, listeners are the receivers of queries. Multiple listeners can be started for different protocols and on different ports. Each listener forwards received queries to one resolver, group, or router.

This example starts a stub resolver on the local machine which will forward all queries via DNS-over-TLS to provide privacy.

r := rdns.NewDoTClient("1.1.1.1:853")
l := rdns.NewDNSListener("127.0.0.1:53", "udp", r)
panic(l.Start())
Example (Group)
package main

import (
	"fmt"

	rdns "github.com/folbricht/routedns"
	"github.com/miekg/dns"
)

func main() {
	// Define resolvers
	r1, _ := rdns.NewDNSClient("google1", "8.8.8.8:53", "udp", rdns.DNSClientOptions{})
	r2, _ := rdns.NewDNSClient("google2", "8.8.4.4:53", "udp", rdns.DNSClientOptions{})

	// Combine them int a group that does round-robin over the two resolvers
	g := rdns.NewRoundRobin("test-rr", r1, r2)

	// Build a query
	q := new(dns.Msg)
	q.SetQuestion("google.com.", dns.TypeA)

	// Resolve the query
	a, _ := g.Resolve(q, rdns.ClientInfo{})
	fmt.Println(a)
}
Output:

Example (Resolver)
package main

import (
	"fmt"

	rdns "github.com/folbricht/routedns"
	"github.com/miekg/dns"
)

func main() {
	// Define resolver
	r, _ := rdns.NewDoTClient("test-dot", "dns.google:853", rdns.DoTClientOptions{})

	// Build a query
	q := new(dns.Msg)
	q.SetQuestion("google.com.", dns.TypeA)

	// Resolve the query
	a, _ := r.Resolve(q, rdns.ClientInfo{})
	fmt.Println(a)
}
Output:

Example (Router)
package main

import (
	"fmt"

	rdns "github.com/folbricht/routedns"
	"github.com/miekg/dns"
)

func main() {
	// Define resolvers
	google, _ := rdns.NewDNSClient("g-dns", "8.8.8.8:53", "udp", rdns.DNSClientOptions{})
	cloudflare, _ := rdns.NewDNSClient("cf-dns", "1.1.1.1:53", "udp", rdns.DNSClientOptions{})

	// Build a router that will send all "*.cloudflare.com" to the cloudflare
	// resolver while everything else goes to the google resolver (default)
	route1, _ := rdns.NewRoute(`\.cloudflare\.com\.$`, "", nil, nil, "", "", "", "", "", "", cloudflare)
	route2, _ := rdns.NewRoute("", "", nil, nil, "", "", "", "", "", "", google)
	r := rdns.NewRouter("my-router")
	r.Add(route1, route2)

	// Build a query
	q := new(dns.Msg)
	q.SetQuestion("www.cloudflare.com.", dns.TypeA)

	// Resolve the query
	a, _ := r.Resolve(q, rdns.ClientInfo{})
	fmt.Println(a)
}
Output:

Index

Examples

Constants

View Source
const (
	DOQNoError = 0x00
)
View Source
const QueryPaddingBlockSize = 128

QueryPaddingBlockSize is used to pad queries sent over DoT and DoH according to rfc8467

View Source
const ResponsePaddingBlockSize = 468

ResponsePaddingBlockSize is used to pad responses over DoT and DoH according to rfc8467

Variables

View Source
var (
	DoQPort      string = "8853"
	DohQuicPort  string = "1443"
	DoTPort      string = "853"
	DTLSPort     string = DoTPort
	DoHPort      string = "443"
	PlainDNSPort        = "53"
)
View Source
var (
	BuildVersion string = "v0.1.51"
	BuildTime    string = "Sat Oct 21 08:11:03 UTC 2023"
	BuildNumber  string = "31"
)
View Source
var Log = logrus.New()

Log is a package-global logger used throughout the library. Configuration can be changed directly on this instance or the instance replaced.

Functions

func AddressWithDefault added in v0.1.5

func AddressWithDefault(addr, defaultPort string) string

AddressWithDefault takes an endpoint or a URL and adds a port unless it already has one. If it fails to parse addr, it returns the original value.

func AnswerShuffleRandom added in v0.1.20

func AnswerShuffleRandom(msg *dns.Msg)

Randomly re-order the A/AAAA answer records.

func AnswerShuffleRoundRobin

func AnswerShuffleRoundRobin(msg *dns.Msg)

Shift the answer A/AAAA record order in an answer by one.

func DTLSClientConfig

func DTLSClientConfig(caFile, crtFile, keyFile string) (*dtls.Config, error)

DTLSClientConfig is a convenience function that builds a dtls.Config instance for TLS clients based on common options and certificate+key files.

func DTLSServerConfig

func DTLSServerConfig(caFile, crtFile, keyFile string, mutualTLS bool) (*dtls.Config, error)

DTLSServerConfig is a convenience function that builds a dtls.Config instance for DTLS servers based on common options and certificate+key files.

func ECSModifierDelete

func ECSModifierDelete(id string, q *dns.Msg, ci ClientInfo)

func NewMemoryBackend added in v0.1.51

func NewMemoryBackend(opt MemoryBackendOptions) *memoryBackend

func NewNetDialer

func NewNetDialer(r Resolver) *net.Dialer

func NewNetResolver

func NewNetResolver(r Resolver) *net.Resolver

NewNetResolver returns a new.Resolver that is backed by a RouteDNS resolver instead of the system's.

func NewRedisBackend added in v0.1.51

func NewRedisBackend(opt RedisBackendOptions) *redisBackend

func NewRequestDedup

func NewRequestDedup(id string, resolver Resolver) *requestDedup

func NewRoute

func NewRoute(name, class string, types, weekdays []string, before, after, source, dohPath, listenerID, tlsServerName string, resolver Resolver) (*route, error)

NewRoute initializes a route from string parameters.

func TLSClientConfig

func TLSClientConfig(caFile, crtFile, keyFile, serverName string) (*tls.Config, error)

TLSClientConfig is a convenience function that builds a tls.Config instance for TLS clients based on common options and certificate+key files.

func TLSServerConfig

func TLSServerConfig(caFile, crtFile, keyFile string, mutualTLS bool) (*tls.Config, error)

TLSServerConfig is a convenience function that builds a tls.Config instance for TLS servers based on common options and certificate+key files.

func TTLSelectAverage added in v0.1.20

func TTLSelectAverage(r *TTLModifier, a *dns.Msg) bool

TTLSelectAverage is a function for the TTL Modifier that sets the TTL to the average value of all records.

func TTLSelectFirst added in v0.1.20

func TTLSelectFirst(r *TTLModifier, a *dns.Msg) bool

TTLSelectFirst is a function for the TTL Modifier that sets the TTL to the value of the first record.

func TTLSelectHighest added in v0.1.20

func TTLSelectHighest(r *TTLModifier, a *dns.Msg) bool

TTLSelectHighest is a function for the TTL Modifier that sets the TTL to the highest value of all records.

func TTLSelectLast added in v0.1.20

func TTLSelectLast(r *TTLModifier, a *dns.Msg) bool

TTLSelectLast is a function for the TTL Modifier that sets the TTL to the value of the last record.

func TTLSelectLowest added in v0.1.20

func TTLSelectLowest(r *TTLModifier, a *dns.Msg) bool

TTLSelectLowest is a function for the TTL Modifier that sets the TTL to the lowest value of all records.

func TTLSelectRandom added in v0.1.20

func TTLSelectRandom(r *TTLModifier, a *dns.Msg) bool

TTLSelectRandom is a function for the TTL Modifier that sets the TTL to a random value between ttl-min and ttl-max.

Types

type AdminListener

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

AdminListener is a DNS listener/server for admin services.

func NewAdminListener

func NewAdminListener(id, addr string, opt AdminListenerOptions) (*AdminListener, error)

NewAdminListener returns an instance of an admin service listener.

func (*AdminListener) Start

func (s *AdminListener) Start() error

Start the admin server.

func (*AdminListener) Stop

func (s *AdminListener) Stop() error

Stop the server.

func (*AdminListener) String

func (s *AdminListener) String() string

type AdminListenerOptions

type AdminListenerOptions struct {
	ListenOptions

	// Transport protocol to run HTTPS over. "quic" or "tcp", defaults to "tcp".
	Transport string

	TLSConfig *tls.Config
}

AdminListenerOptions contains options used by the admin service.

type AnswerShuffleFunc

type AnswerShuffleFunc func(*dns.Msg)

Shuffles the order of answer A/AAAA RRs. Used to allow for some control over the records in the cache.

type Blocklist

type Blocklist struct {
	BlocklistOptions
	// contains filtered or unexported fields
}

Blocklist is a resolver that returns NXDOMAIN or a spoofed IP for every query that matches. Everything else is passed through to another resolver.

func NewBlocklist

func NewBlocklist(id string, resolver Resolver, opt BlocklistOptions) (*Blocklist, error)

NewBlocklist returns a new instance of a blocklist resolver.

func (*Blocklist) Resolve

func (r *Blocklist) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first checking the query against the provided matcher. Queries that do not match are passed on to the next resolver.

func (*Blocklist) String

func (r *Blocklist) String() string

type BlocklistDB

type BlocklistDB interface {
	// Reload initializes a new instance of the same database but with
	// a new ruleset loaded.
	Reload() (BlocklistDB, error)

	// Returns true if the question matches a rule. If the IP is not nil,
	// respond with the given IP. NXDOMAIN otherwise. The returned names,
	// if set, are used to answer PTR queries
	Match(q dns.Question) (ip net.IP, names []string, m *BlocklistMatch, matched bool)

	fmt.Stringer
}

type BlocklistLoader

type BlocklistLoader interface {
	// Returns a list of rules that can then be stored into a blocklist DB.
	Load() ([]string, error)
}

type BlocklistMatch added in v0.1.5

type BlocklistMatch struct {
	List string // Identifier or name of the blocklist
	Rule string // Identifier for the rule that matched
}

BlocklistMatch is returned by blocklists when a match is found. It contains information about what rule matched, what list it was from etc. Used mostly for logging.

func (*BlocklistMatch) GetList added in v0.1.51

func (m *BlocklistMatch) GetList() string

func (*BlocklistMatch) GetRule added in v0.1.51

func (m *BlocklistMatch) GetRule() string

type BlocklistMetrics

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

func NewBlocklistMetrics

func NewBlocklistMetrics(id string) *BlocklistMetrics

type BlocklistOptions

type BlocklistOptions struct {
	// Optional, send any blocklist match to this resolver rather
	// than return NXDOMAIN.
	BlocklistResolver Resolver

	BlocklistDB BlocklistDB

	// Refresh period for the blocklist. Disabled if 0.
	BlocklistRefresh time.Duration

	// Optional, send anything that matches the allowlist to an
	// alternative resolver rather than the default upstream one.
	AllowListResolver Resolver

	// Rules that override the blocklist rules, effectively negate them.
	AllowlistDB BlocklistDB

	// Refresh period for the allowlist. Disabled if 0.
	AllowlistRefresh time.Duration
}

type Cache

type Cache struct {
	CacheOptions
	// contains filtered or unexported fields
}

Cache stores results received from its upstream resolver for up to TTL seconds in memory.

func NewCache

func NewCache(id string, resolver Resolver, opt CacheOptions) *Cache

NewCache returns a new instance of a Cache resolver.

func (*Cache) Resolve

func (r *Cache) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first checking an internal cache for existing results

func (*Cache) String

func (r *Cache) String() string

type CacheBackend added in v0.1.51

type CacheBackend interface {
	Store(query *dns.Msg, item *cacheAnswer)

	// Lookup a cached response
	Lookup(q *dns.Msg) (answer *dns.Msg, prefetchEligible bool, ok bool)

	// Return the number of items in the cache
	Size() int

	// Flush all records in the store
	Flush()

	Close() error
}

type CacheMetrics

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

type CacheOptions

type CacheOptions struct {
	// Time period the cache garbage collection runs. Defaults to one minute if set to 0.
	//
	// Deprecated: Pass a configured cache backend instead.
	GCPeriod time.Duration

	// Max number of responses to keep in the cache. Defaults to 0 which means no limit. If
	// the limit is reached, the least-recently used entry is removed from the cache.
	//
	// Deprecated: Pass a configured cache backend instead.
	Capacity int

	// TTL to use for negative responses that do not have an SOA record, default 60
	NegativeTTL uint32

	// Define upper limits on cache TTLs based on RCODE, regardless of SOA. For example this
	// allows settings a limit on how long NXDOMAIN (code 3) responses can be kept in the cache.
	CacheRcodeMaxTTL map[int]uint32

	// Allows control over the order of answer RRs in cached responses. Default is to keep
	// the order if nil.
	ShuffleAnswerFunc AnswerShuffleFunc

	// If enabled, will return NXDOMAIN for every name query under another name that is
	// already cached as NXDOMAIN. For example, if example.com is in the cache with
	// NXDOMAIN, a query for www.example.com will also immediately return NXDOMAIN.
	// See RFC8020.
	HardenBelowNXDOMAIN bool

	// Query name that will trigger a cache flush. Disabled if empty.
	FlushQuery string

	// If a query is received for a record with less that PrefetchTrigger TTL left, the
	// cache will send another query to upstream. The goal is to automatically refresh
	// the record in the cache.
	PrefetchTrigger uint32

	// Only records with at least PrefetchEligible seconds TTL are eligible to be prefetched.
	PrefetchEligible uint32

	// Cache backend used to store records.
	Backend CacheBackend
}

type CidrDB

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

CidrDB holds a list of IP networks that are used to block matching DNS responses. Network ranges are stored in a trie (one for IP4 and one for IP6) to allow for efficient matching

func NewCidrDB

func NewCidrDB(name string, loader BlocklistLoader) (*CidrDB, error)

NewCidrDB returns a new instance of a matcher for a list of networks.

func (*CidrDB) Close

func (m *CidrDB) Close() error

func (*CidrDB) Match

func (m *CidrDB) Match(ip net.IP) (*BlocklistMatch, bool)

func (*CidrDB) Reload

func (m *CidrDB) Reload() (IPBlocklistDB, error)

func (*CidrDB) String

func (m *CidrDB) String() string

type ClientBlocklist

type ClientBlocklist struct {
	ClientBlocklistOptions
	// contains filtered or unexported fields
}

ClientBlocklist is a resolver that matches the IPs of clients against a blocklist

func NewClientBlocklist

func NewClientBlocklist(id string, resolver Resolver, opt ClientBlocklistOptions) (*ClientBlocklist, error)

NewClientBlocklistIP returns a new instance of a client blocklist resolver.

func (*ClientBlocklist) Resolve

func (r *ClientBlocklist) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query after checking the client's IP against a blocklist. Responds with REFUSED if the client IP is on the blocklist, or sends the query to an alternative resolver if one is configured.

func (*ClientBlocklist) String

func (r *ClientBlocklist) String() string

type ClientBlocklistOptions

type ClientBlocklistOptions struct {
	// Optional, if the client is found to match the blocklist, send the query to this resolver.
	BlocklistResolver Resolver

	BlocklistDB IPBlocklistDB

	// Refresh period for the blocklist. Disabled if 0.
	BlocklistRefresh time.Duration
}

type ClientInfo

type ClientInfo struct {
	SourceIP net.IP

	// DoH query path used by the client. Only populated when
	// the query was received over DoH.
	DoHPath string

	// TLS SNI server name
	TLSServerName string

	// Listener ID of the listener that first received the request. Can be
	// used to route queries.
	Listener string
}

ClientInfo carries information about the client making the request that can be used to route requests.

type DNSClient

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

DNSClient represents a simple DNS resolver for UDP or TCP.

func NewDNSClient

func NewDNSClient(id, endpoint, network string, opt DNSClientOptions) (*DNSClient, error)

NewDNSClient returns a new instance of DNSClient which is a plain DNS resolver that supports pipelining over a single connection.

func (*DNSClient) Resolve

func (d *DNSClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query.

func (*DNSClient) String

func (d *DNSClient) String() string

type DNSClientOptions

type DNSClientOptions struct {
	// Local IP to use for outbound connections. If nil, a local address is chosen.
	LocalAddr net.IP

	// Sets the EDNS0 UDP size for all queries sent upstream. If set to 0, queries
	// are not changed.
	UDPSize uint16

	QueryTimeout time.Duration

	// Optional dialer, e.g. proxy
	Dialer Dialer
}

type DNSDialer

type DNSDialer interface {
	Dial(address string) (*dns.Conn, error)
}

DNSDialer is an abstraction for a dns.Client that returns a *dns.Conn.

type DNSListener

type DNSListener struct {
	*dns.Server
	// contains filtered or unexported fields
}

DNSListener is a standard DNS listener for UDP or TCP.

func NewDNSListener

func NewDNSListener(id, addr, net string, opt ListenOptions, resolver Resolver) *DNSListener

NewDNSListener returns an instance of either a UDP or TCP DNS listener.

func (DNSListener) Start

func (s DNSListener) Start() error

Start the DNS listener.

func (DNSListener) String

func (s DNSListener) String() string

type DTLSClient

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

DTLSClient is a DNS-over-DTLS resolver.

func NewDTLSClient

func NewDTLSClient(id, endpoint string, opt DTLSClientOptions) (*DTLSClient, error)

NewDTLSClient instantiates a new DNS-over-TLS resolver.

func (*DTLSClient) Resolve

func (d *DTLSClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query.

func (*DTLSClient) String

func (d *DTLSClient) String() string

type DTLSClientOptions

type DTLSClientOptions struct {
	// Bootstrap address - IP to use for the serivce instead of looking up
	// the service's hostname with potentially plain DNS.
	BootstrapAddr string

	// Local IP to use for outbound connections. If nil, a local address is chosen.
	LocalAddr net.IP

	// Sets the EDNS0 UDP size for all queries sent upstream. If set to 0, queries
	// are not changed.
	UDPSize uint16

	DTLSConfig *dtls.Config

	QueryTimeout time.Duration
}

DTLSClientOptions contains options used by the DNS-over-DTLS resolver.

type DTLSListener

type DTLSListener struct {
	*dns.Server
	// contains filtered or unexported fields
}

DTLSListener is a DNS listener/server for DNS-over-DTLS.

func NewDTLSListener

func NewDTLSListener(id, addr string, opt DTLSListenerOptions, resolver Resolver) *DTLSListener

NewDTLSListener returns an instance of a DNS-over-DTLS listener.

func (*DTLSListener) Start

func (s *DTLSListener) Start() error

Start the DTLS server.

func (*DTLSListener) Stop

func (s *DTLSListener) Stop() error

Stop the server.

func (*DTLSListener) String

func (s *DTLSListener) String() string

type DTLSListenerOptions

type DTLSListenerOptions struct {
	ListenOptions

	DTLSConfig *dtls.Config
}

DoTListenerOptions contains options used by the DNS-over-DTLS server.

type Dialer added in v0.1.51

type Dialer interface {
	Dial(net string, address string) (net.Conn, error)
}

type DoHClient

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

DoHClient is a DNS-over-HTTP resolver with support fot HTTP/2.

func NewDoHClient

func NewDoHClient(id, endpoint string, opt DoHClientOptions) (*DoHClient, error)

func (*DoHClient) Resolve

func (d *DoHClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query.

func (*DoHClient) ResolveGET

func (d *DoHClient) ResolveGET(q *dns.Msg) (*dns.Msg, error)

ResolveGET resolves a DNS query via DNS-over-HTTP using the GET method.

func (*DoHClient) ResolvePOST

func (d *DoHClient) ResolvePOST(q *dns.Msg) (*dns.Msg, error)

ResolvePOST resolves a DNS query via DNS-over-HTTP using the POST method.

func (*DoHClient) String

func (d *DoHClient) String() string

type DoHClientOptions

type DoHClientOptions struct {
	// Query method, either GET or POST. If empty, POST is used.
	Method string

	// Bootstrap address - IP to use for the service instead of looking up
	// the service's hostname with potentially plain DNS.
	BootstrapAddr string

	// Transport protocol to run HTTPS over. "quic" or "tcp", defaults to "tcp".
	Transport string

	// Local IP to use for outbound connections. If nil, a local address is chosen.
	LocalAddr net.IP

	TLSConfig *tls.Config

	QueryTimeout time.Duration

	// Optional dialer, e.g. proxy
	Dialer Dialer
}

DoHClientOptions contains options used by the DNS-over-HTTP resolver.

type DoHListener

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

DoHListener is a DNS listener/server for DNS-over-HTTPS.

func NewDoHListener

func NewDoHListener(id, addr string, opt DoHListenerOptions, resolver Resolver) (*DoHListener, error)

NewDoHListener returns an instance of a DNS-over-HTTPS listener.

func (*DoHListener) Start

func (s *DoHListener) Start() error

Start the DoH server.

func (*DoHListener) Stop

func (s *DoHListener) Stop() error

Stop the server.

func (*DoHListener) String

func (s *DoHListener) String() string

type DoHListenerMetrics

type DoHListenerMetrics struct {
	ListenerMetrics
	// contains filtered or unexported fields
}

func NewDoHListenerMetrics

func NewDoHListenerMetrics(id string) *DoHListenerMetrics

type DoHListenerOptions

type DoHListenerOptions struct {
	ListenOptions

	// Transport protocol to run HTTPS over. "quic" or "tcp", defaults to "tcp".
	Transport string

	TLSConfig *tls.Config

	// IP(v4/v6) subnet of known reverse proxies in front of this server.
	HTTPProxyNet *net.IPNet

	// Disable TLS on the server (insecure, for testing purposes only).
	NoTLS bool
}

DoHListenerOptions contains options used by the DNS-over-HTTPS server.

type DoQClient

type DoQClient struct {
	DoQClientOptions
	// contains filtered or unexported fields
}

DoQClient is a DNS-over-QUIC resolver.

func NewDoQClient

func NewDoQClient(id, endpoint string, opt DoQClientOptions) (*DoQClient, error)

NewDoQClient instantiates a new DNS-over-QUIC resolver.

func (*DoQClient) Resolve

func (d *DoQClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query.

func (*DoQClient) String

func (d *DoQClient) String() string

type DoQClientOptions

type DoQClientOptions struct {
	// Bootstrap address - IP to use for the service instead of looking up
	// the service's hostname with potentially plain DNS.
	BootstrapAddr string

	// Local IP to use for outbound connections. If nil, a local address is chosen.
	LocalAddr net.IP

	TLSConfig *tls.Config

	QueryTimeout time.Duration
}

DoQClientOptions contains options used by the DNS-over-QUIC resolver.

type DoQListener

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

DoQListener is a DNS listener/server for QUIC.

func NewQUICListener

func NewQUICListener(id, addr string, opt DoQListenerOptions, resolver Resolver) *DoQListener

NewQuicListener returns an instance of a QUIC listener.

func (DoQListener) Start

func (s DoQListener) Start() error

Start the QUIC server.

func (DoQListener) Stop

func (s DoQListener) Stop() error

Stop the server.

func (DoQListener) String

func (s DoQListener) String() string

type DoQListenerMetrics

type DoQListenerMetrics struct {
	ListenerMetrics
	// contains filtered or unexported fields
}

func NewDoQListenerMetrics

func NewDoQListenerMetrics(id string) *DoQListenerMetrics

type DoQListenerOptions

type DoQListenerOptions struct {
	ListenOptions

	TLSConfig *tls.Config
}

DoQListenerOptions contains options used by the QUIC server.

type DoTClient

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

DoTClient is a DNS-over-TLS resolver.

func NewDoTClient

func NewDoTClient(id, endpoint string, opt DoTClientOptions) (*DoTClient, error)

NewDoTClient instantiates a new DNS-over-TLS resolver.

func (*DoTClient) Resolve

func (d *DoTClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query.

func (*DoTClient) String

func (d *DoTClient) String() string

type DoTClientOptions

type DoTClientOptions struct {
	// Bootstrap address - IP to use for the serivce instead of looking up
	// the service's hostname with potentially plain DNS.
	BootstrapAddr string

	// Local IP to use for outbound connections. If nil, a local address is chosen.
	LocalAddr net.IP

	TLSConfig *tls.Config

	QueryTimeout time.Duration

	// Optional dialer, e.g. proxy
	Dialer Dialer
}

DoTClientOptions contains options used by the DNS-over-TLS resolver.

type DoTListener

type DoTListener struct {
	*dns.Server
	// contains filtered or unexported fields
}

DoTListener is a DNS listener/server for DNS-over-TLS.

func NewDoTListener

func NewDoTListener(id, addr string, opt DoTListenerOptions, resolver Resolver) *DoTListener

NewDoTListener returns an instance of a DNS-over-TLS listener.

func (DoTListener) Start

func (s DoTListener) Start() error

Start the Dot server.

func (DoTListener) Stop

func (s DoTListener) Stop() error

Stop the server.

func (DoTListener) String

func (s DoTListener) String() string

type DoTListenerOptions

type DoTListenerOptions struct {
	ListenOptions

	TLSConfig *tls.Config
}

DoTListenerOptions contains options used by the DNS-over-TLS server.

type DomainDB

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

DomainDB holds a list of domain strings (potentially with wildcards). Matching logic: domain.com: matches just domain.com and not subdomains .domain.com: matches domain.com and all subdomains *.domain.com: matches all subdomains but not domain.com

func NewDomainDB

func NewDomainDB(name string, loader BlocklistLoader) (*DomainDB, error)

NewDomainDB returns a new instance of a matcher for a list of regular expressions.

func (*DomainDB) Match

func (m *DomainDB) Match(q dns.Question) (net.IP, []string, *BlocklistMatch, bool)

func (*DomainDB) Reload

func (m *DomainDB) Reload() (BlocklistDB, error)

func (*DomainDB) String

func (m *DomainDB) String() string

type DropResolver

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

DropResolver is a resolver that returns nil for every query which then causes any listeners to close the connection on the client.

func NewDropResolver

func NewDropResolver(id string) *DropResolver

NewDropResolver returns a new instance of a DropResolver resolver.

func (*DropResolver) Resolve

func (r *DropResolver) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by returning nil to signal to the listener to drop this request.

func (*DropResolver) String

func (r *DropResolver) String() string

type ECSModifier

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

ECSModifier manipulates EDNS0 Client Subnet in queries.

func NewECSModifier

func NewECSModifier(id string, resolver Resolver, f ECSModifierFunc) (*ECSModifier, error)

NewECSModifier initializes an ECS modifier.

func (*ECSModifier) Resolve

func (r *ECSModifier) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve modifies the OPT EDNS0 record and passes it to the next resolver.

func (*ECSModifier) String

func (r *ECSModifier) String() string

type ECSModifierFunc

type ECSModifierFunc func(id string, q *dns.Msg, ci ClientInfo)

ECSModifierFunc takes a DNS query and modifies its EDN0 Client Subdomain record

func ECSModifierAdd

func ECSModifierAdd(addr net.IP, prefix4, prefix6 uint8) ECSModifierFunc

func ECSModifierPrivacy

func ECSModifierPrivacy(prefix4, prefix6 uint8) ECSModifierFunc

type EDNS0Modifier

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

EDNS0Modifier manipulates EDNS0 options, typically for codes in the 65001-65534 range.

func NewEDNS0Modifier

func NewEDNS0Modifier(id string, resolver Resolver, f EDNS0ModifierFunc) (*EDNS0Modifier, error)

NewEDNS0Modifier initializes an EDNS0 modifier.

func (*EDNS0Modifier) Resolve

func (r *EDNS0Modifier) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve modifies the OPT EDNS0 record and passes it to the next resolver.

func (*EDNS0Modifier) String

func (r *EDNS0Modifier) String() string

type EDNS0ModifierFunc

type EDNS0ModifierFunc func(q *dns.Msg, ci ClientInfo)

EDNS0ModifierFunc takes a DNS query and modifies its EDN0 records

func EDNS0ModifierAdd

func EDNS0ModifierAdd(code uint16, data []byte) EDNS0ModifierFunc

func EDNS0ModifierDelete

func EDNS0ModifierDelete(code uint16) EDNS0ModifierFunc

type FailBack

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

FailBack is a resolver group that queries the same resolver unless that returns a failure in which case the request is retried on the next one for up to N times (with N the number of resolvers in the group). If the last resolver fails, the first one in the list becomes the active one. After the reset timer expired without any further failures, the first resolver becomes active again. This group prefers the resolvers in the order they were added but fails over as necessary with regular retry of the higher-priority ones.

func NewFailBack

func NewFailBack(id string, opt FailBackOptions, resolvers ...Resolver) *FailBack

NewFailBack returns a new instance of a failover resolver group.

func (*FailBack) Resolve

func (r *FailBack) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query using a failover resolver group that switches to the next resolver on error.

func (*FailBack) String

func (r *FailBack) String() string

type FailBackOptions

type FailBackOptions struct {
	// Switch back to the first resolver in the group after no further failures
	// for this amount of time. Default 1 minute.
	ResetAfter time.Duration

	// Determines if a SERVFAIL returned by a resolver should be considered an
	// error response and trigger a failover.
	ServfailError bool
}

FailBackOptions contain group-specific options.

type FailRotate

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

FailRotate is a resolver group that queries the same resolver unless that returns a failure in which case the request is retried on the next one for up to N times (with N the number of resolvers in the group). If the last resolver fails, the first one in the list becomes the active one. This group does not fail back automatically.

func NewFailRotate

func NewFailRotate(id string, opt FailRotateOptions, resolvers ...Resolver) *FailRotate

NewFailRotate returns a new instance of a failover resolver group.

func (*FailRotate) Resolve

func (r *FailRotate) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query using a failover resolver group that switches to the next resolver on error.

func (*FailRotate) String

func (r *FailRotate) String() string

type FailRotateOptions

type FailRotateOptions struct {
	// Determines if a SERVFAIL returned by a resolver should be considered an
	// error response and trigger a failover.
	ServfailError bool
}

FailRotateOptions contain group-specific options.

type FailRouterMetrics

type FailRouterMetrics struct {
	RouterMetrics
	// contains filtered or unexported fields
}

func NewFailRouterMetrics

func NewFailRouterMetrics(id string, available int) *FailRouterMetrics

type Fastest

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

Fastest is a resolver group that queries all resolvers concurrently for the same query, then returns the fastest response only.

func NewFastest

func NewFastest(id string, resolvers ...Resolver) *Fastest

NewFastest returns a new instance of a resolver group that returns the fastest response from all its resolvers.

func (*Fastest) Resolve

func (r *Fastest) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by sending it to all resolvers and returning the fastest non-error response

func (*Fastest) String

func (r *Fastest) String() string

type FastestTCP

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

FastestTCP first resolves the query with the upstream resolver, then performs TCP connection tests with the response IPs to determine which IP responds the fastest. This IP is then returned in the response as first A/AAAA record. This should be used in combination with a Cache to avoid the TCP connection overhead on every query.

func NewFastestTCP

func NewFastestTCP(id string, resolver Resolver, opt FastestTCPOptions) *FastestTCP

NewFastestTCP returns a new instance of a TCP probe resolver.

func (*FastestTCP) Resolve

func (r *FastestTCP) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query and order the response based on which IP was able to establish a TCP connection the fastest.

func (*FastestTCP) String

func (r *FastestTCP) String() string

type FastestTCPOptions

type FastestTCPOptions struct {
	// Port number to use for TCP probes, default 443
	Port int

	// Wait for all connection probes and sort the responses based on time
	// (fastest first). This is generally slower than just waiting for the
	// fastest, since the response time is determined by the slowest probe.
	WaitAll bool

	// TTL set on all RRs when TCP probing was successful. Can be used to
	// ensure these are kept for longer in a cache and improve performance.
	SuccessTTLMin uint32
}

FastestTCPOptions contain settings for a resolver that filters responses based on TCP connection probes.

type FileLoader

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

FileLoader reads blocklist rules from a local file. Used to refresh blocklists from a file on the local machine.

func NewFileLoader

func NewFileLoader(filename string, opt FileLoaderOptions) *FileLoader

func (*FileLoader) Load

func (l *FileLoader) Load() (rules []string, err error)

type FileLoaderOptions added in v0.1.51

type FileLoaderOptions struct {
	// Don't fail when trying to load the list
	AllowFailure bool
}

FileLoaderOptions holds options for file blocklist loaders.

type GenericDNSClient added in v0.1.51

type GenericDNSClient struct {
	Dialer    Dialer
	Net       string
	TLSConfig *tls.Config
	LocalAddr net.IP
	Timeout   time.Duration
}

GenericDNSClient is a workaround for dns.Client not supporting custom dialers (only *net.Dialer) which prevents the use of proxies. It implements the same Dial functionality, while supporting custom dialers.

func (GenericDNSClient) Dial added in v0.1.51

func (d GenericDNSClient) Dial(address string) (*dns.Conn, error)

type GeoIPDB

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

GeoIPDB holds blocklist rules based on location. When an IP is queried, its location is looked up in a database and the result is compared to the blocklist rules.

func NewGeoIPDB

func NewGeoIPDB(name string, loader BlocklistLoader, geoDBFile string) (*GeoIPDB, error)

NewGeoIPDB returns a new instance of a matcher for a location rules.

func (*GeoIPDB) Close

func (m *GeoIPDB) Close() error

func (*GeoIPDB) Match

func (m *GeoIPDB) Match(ip net.IP) (*BlocklistMatch, bool)

func (*GeoIPDB) Reload

func (m *GeoIPDB) Reload() (IPBlocklistDB, error)

func (*GeoIPDB) String

func (m *GeoIPDB) String() string

type HTTPLoader

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

HTTPLoader reads blocklist rules from a server via HTTP(S).

func NewHTTPLoader

func NewHTTPLoader(url string, opt HTTPLoaderOptions) *HTTPLoader

func (*HTTPLoader) Load

func (l *HTTPLoader) Load() (rules []string, err error)

type HTTPLoaderOptions

type HTTPLoaderOptions struct {
	CacheDir string

	// Don't fail when trying to load the list
	AllowFailure bool
}

HTTPLoaderOptions holds options for HTTP blocklist loaders.

type HostsDB

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

HostsDB holds a list of hosts-file entries that are used in blocklists to spoof or bloc requests. IP4 and IP6 records can be spoofed independently, however it's not possible to block only one type. If IP4 is given but no IP6, then a domain match will still result in an NXDOMAIN for the IP6 address.

func NewHostsDB

func NewHostsDB(name string, loader BlocklistLoader) (*HostsDB, error)

NewHostsDB returns a new instance of a matcher for a list of regular expressions.

func (*HostsDB) Match

func (m *HostsDB) Match(q dns.Question) (net.IP, []string, *BlocklistMatch, bool)

func (*HostsDB) Reload

func (m *HostsDB) Reload() (BlocklistDB, error)

func (*HostsDB) String

func (m *HostsDB) String() string

type IPBlocklistDB

type IPBlocklistDB interface {
	Reload() (IPBlocklistDB, error)
	Match(ip net.IP) (*BlocklistMatch, bool)
	Close() error
	fmt.Stringer
}

IPBlocklistDB is a database containing IPs used in blocklists.

type ListenOptions

type ListenOptions struct {
	// Network allowed to query this listener.
	AllowedNet []*net.IPNet
}

type Listener

type Listener interface {
	Start() error
	fmt.Stringer
}

Listener is an interface for a DNS listener.

type ListenerMetrics

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

Metrics that are available from listeners and clients.

func NewListenerMetrics

func NewListenerMetrics(base string, id string) *ListenerMetrics

type MemoryBackendOptions added in v0.1.51

type MemoryBackendOptions struct {
	// Total capacity of the cache, default unlimited
	Capacity int

	// How often to run garbage collection, default 1 minute
	GCPeriod time.Duration

	// Load the cache from file on startup and write it on close
	Filename string

	// Write the file in an interval. Only write on shutdown if not set
	SaveInterval time.Duration
}

type MultiDB

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

MultiDB wraps multiple blocklist DBs and performs queries over all of them.

func NewMultiDB

func NewMultiDB(dbs ...BlocklistDB) (MultiDB, error)

NewMultiDB returns a new instance of a wrapper for blocklists

func (MultiDB) Match

func (m MultiDB) Match(q dns.Question) (net.IP, []string, *BlocklistMatch, bool)

func (MultiDB) Reload

func (m MultiDB) Reload() (BlocklistDB, error)

func (MultiDB) String

func (m MultiDB) String() string

type MultiIPDB

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

MultiIPDB wraps multiple blocklist CIDR DBs and performs queries over all of them.

func NewMultiIPDB

func NewMultiIPDB(dbs ...IPBlocklistDB) (MultiIPDB, error)

NewMultiIPDB returns a new instance of a wrapper for blocklists

func (MultiIPDB) Close

func (m MultiIPDB) Close() error

func (MultiIPDB) Match

func (m MultiIPDB) Match(ip net.IP) (*BlocklistMatch, bool)

func (MultiIPDB) Reload

func (m MultiIPDB) Reload() (IPBlocklistDB, error)

func (MultiIPDB) String

func (m MultiIPDB) String() string

type Pipeline

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

Pipeline is a DNS client that is able to use pipelining for multiple requests over one connection, handle out-of-order responses and deals with disconnects gracefully. It opens a single connection on demand and uses it for all queries. It can manage UDP, TCP, DNS-over-TLS, and DNS-over-DTLS connections.

func NewPipeline

func NewPipeline(id string, addr string, client DNSDialer, timeout time.Duration) *Pipeline

NewPipeline returns an initialized (and running) DNS connection manager.

func (*Pipeline) Resolve

func (c *Pipeline) Resolve(q *dns.Msg) (*dns.Msg, error)

Resolve a single query using this connection.

type QueryTimeoutError

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

QueryTimeoutError is returned when a query times out.

func (QueryTimeoutError) Error

func (e QueryTimeoutError) Error() string

type Random

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

Random is a resolver group that randomly picks a resolver from it's list of resolvers. If one resolver fails, it is removed from the list of active resolvers for a period of time and the query retried.

func NewRandom

func NewRandom(id string, opt RandomOptions, resolvers ...Resolver) *Random

NewRandom returns a new instance of a random resolver group.

func (*Random) Resolve

func (r *Random) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query using a random resolver.

func (*Random) String

func (r *Random) String() string

type RandomOptions

type RandomOptions struct {
	// Re-enable resolvers after this time after a failure
	ResetAfter time.Duration

	// Determines if a SERVFAIL returned by a resolver should be considered an
	// error response and cause the resolver to be removed from the group temporarily.
	ServfailError bool
}

RandomOptions contain settings for the random resolver group.

type RateLimiter

type RateLimiter struct {
	RateLimiterOptions
	// contains filtered or unexported fields
}

RateLimiter is a resolver that limits the number of queries by a client (network) that are passed to the upstream resolver per timeframe.

func NewRateLimiter

func NewRateLimiter(id string, resolver Resolver, opt RateLimiterOptions) *RateLimiter

NewRateLimiterIP returns a new instance of a query rate limiter.

func (*RateLimiter) Resolve

func (r *RateLimiter) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query while limiting the query rate per time period.

func (*RateLimiter) String

func (r *RateLimiter) String() string

type RateLimiterMetrics

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

type RateLimiterOptions

type RateLimiterOptions struct {
	Requests      uint     // Number of requests allwed per time period
	Window        uint     // Time period in seconds
	Prefix4       uint8    // Netmask to identify IP4 clients
	Prefix6       uint8    // Netmask to identify IP6 clients
	LimitResolver Resolver // Alternate resolver for rate-limited requests
}

type RedisBackendOptions added in v0.1.51

type RedisBackendOptions struct {
	RedisOptions redis.Options
	KeyPrefix    string
}

type RegexpDB

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

RegexpDB holds a list of regular expressions against which it evaluates DNS queries.

func NewRegexpDB

func NewRegexpDB(name string, loader BlocklistLoader) (*RegexpDB, error)

NewRegexpDB returns a new instance of a matcher for a list of regular expressions.

func (*RegexpDB) Match

func (m *RegexpDB) Match(q dns.Question) (net.IP, []string, *BlocklistMatch, bool)

func (*RegexpDB) Reload

func (m *RegexpDB) Reload() (BlocklistDB, error)

func (*RegexpDB) String

func (m *RegexpDB) String() string

type Replace

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

Replace is a resolver that modifies queries according to regular expressions and forwards the modified queries to another resolver. Responses are then mapped back to the original query string.

func NewReplace

func NewReplace(id string, resolver Resolver, list ...ReplaceOperation) (*Replace, error)

NewReplace returns a new instance of a Replace resolver.

func (*Replace) Resolve

func (r *Replace) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first replacing the query string with another sending the query upstream and replace the name in the response with the original query string again.

func (*Replace) String

func (r *Replace) String() string

type ReplaceOperation

type ReplaceOperation struct {
	From string
	To   string
}

type Resolver

type Resolver interface {
	Resolve(*dns.Msg, ClientInfo) (*dns.Msg, error)
	fmt.Stringer
}

Resolver is an interface to resolve DNS queries.

type ResponseBlocklistIP

type ResponseBlocklistIP struct {
	ResponseBlocklistIPOptions
	// contains filtered or unexported fields
}

ResponseBlocklistIP is a resolver that filters by matching the IPs in the response against a blocklist.

func NewResponseBlocklistIP

func NewResponseBlocklistIP(id string, resolver Resolver, opt ResponseBlocklistIPOptions) (*ResponseBlocklistIP, error)

NewResponseBlocklistIP returns a new instance of a response blocklist resolver.

func (*ResponseBlocklistIP) Resolve

func (r *ResponseBlocklistIP) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first querying the upstream resolver, then checking any IP responses against a blocklist. Responds with NXDOMAIN if the response IP is in the filter-list.

func (*ResponseBlocklistIP) String

func (r *ResponseBlocklistIP) String() string

type ResponseBlocklistIPOptions

type ResponseBlocklistIPOptions struct {
	// Optional, if the response is found to match the blocklist, send the query to this resolver.
	BlocklistResolver Resolver

	BlocklistDB IPBlocklistDB

	// Refresh period for the blocklist. Disabled if 0.
	BlocklistRefresh time.Duration

	// If true, removes matching records from the response rather than replying with NXDOMAIN. Can
	// not be combined with alternative blockist-resolver
	Filter bool

	// Inverted behavior, only allow responses that can be found on at least one list.
	Inverted bool
}

type ResponseBlocklistName

type ResponseBlocklistName struct {
	ResponseBlocklistNameOptions
	// contains filtered or unexported fields
}

ResponseBlocklistName is a resolver that filters by matching the strings in CNAME, MX, NS, PTR and SRV response records against a blocklist.

func NewResponseBlocklistName

func NewResponseBlocklistName(id string, resolver Resolver, opt ResponseBlocklistNameOptions) (*ResponseBlocklistName, error)

NewResponseBlocklistName returns a new instance of a response blocklist resolver.

func (*ResponseBlocklistName) Resolve

func (r *ResponseBlocklistName) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first querying the upstream resolver, then checking any responses with strings against a blocklist. Responds with NXDOMAIN if the response matches the filter.

func (*ResponseBlocklistName) String

func (r *ResponseBlocklistName) String() string

type ResponseBlocklistNameOptions

type ResponseBlocklistNameOptions struct {
	// Optional, if the response is found to match the blocklist, send the query to this resolver.
	BlocklistResolver Resolver

	BlocklistDB BlocklistDB

	// Refresh period for the blocklist. Disabled if 0.
	BlocklistRefresh time.Duration

	// Inverted behavior, only allow responses that can be found on at least one list.
	Inverted bool
}

type ResponseCollapse

type ResponseCollapse struct {
	ResponseCollapseOptions
	// contains filtered or unexported fields
}

ResponseCollapse is a resolver that collapses response records to just the type of the query, eliminating answer chains.

func NewResponseCollapse

func NewResponseCollapse(id string, resolver Resolver, opt ResponseCollapseOptions) *ResponseCollapse

NewResponseMinimize returns a new instance of a response minimizer.

func (*ResponseCollapse) Resolve

func (r *ResponseCollapse) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query, then collapse the response to remove anything from the answer that wasn't asked for.

func (*ResponseCollapse) String

func (r *ResponseCollapse) String() string

type ResponseCollapseOptions added in v0.1.20

type ResponseCollapseOptions struct {
	NullRCode int // Response code when there's nothing left after collapsing the response
}

type ResponseMinimize

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

ResponseMinimize is a resolver that strips Extra and Authority records from responses, leaving just the answer records.

func NewResponseMinimize

func NewResponseMinimize(id string, resolver Resolver) *ResponseMinimize

NewResponseMinimize returns a new instance of a response minimizer.

func (*ResponseMinimize) Resolve

func (r *ResponseMinimize) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query with the upstream resolver and strip out any extra or NS records in the response.

func (*ResponseMinimize) String

func (r *ResponseMinimize) String() string

type RoundRobin

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

RoundRobin is a group of resolvers that will receive equal amounts of queries. Failed queries are not retried.

func NewRoundRobin

func NewRoundRobin(id string, resolvers ...Resolver) *RoundRobin

NewRoundRobin returns a new instance of a round-robin resolver group.

func (*RoundRobin) Resolve

func (r *RoundRobin) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query using a round-robin resolver group.

func (*RoundRobin) String

func (r *RoundRobin) String() string

type Router

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

Router for DNS requests based on query type and/or name. Implements the Resolver interface.

func NewRouter

func NewRouter(id string) *Router

NewRouter returns a new router instance. The router won't have any routes and can only be used once Add() is called to setup a route.

func (*Router) Add

func (r *Router) Add(routes ...*route)

Add a new route to the router. New routes are appended to the existing ones and are evaluated in the same order they're added. The default route (no name, no type) should be added last since subsequently added routes won't have any impact. Name is a regular expression that is applied to the name in the first question section of the DNS message. Source is an IP or network in CIDR format.

func (*Router) Resolve

func (r *Router) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a request by routing it to the right resolved based on the routes setup in the router.

func (*Router) String

func (r *Router) String() string

type RouterMetrics

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

func NewRouterMetrics

func NewRouterMetrics(id string, available int) *RouterMetrics

type Socks5Dialer added in v0.1.51

type Socks5Dialer struct {
	*socks5.Client
	// contains filtered or unexported fields
}

func NewSocks5Dialer added in v0.1.51

func NewSocks5Dialer(addr string, opt Socks5DialerOptions) *Socks5Dialer

func (*Socks5Dialer) Dial added in v0.1.51

func (d *Socks5Dialer) Dial(network string, address string) (net.Conn, error)

type Socks5DialerOptions added in v0.1.51

type Socks5DialerOptions struct {
	Username   string
	Password   string
	UDPTimeout time.Duration
	TCPTimeout time.Duration
	LocalAddr  net.IP

	// When the resolver is configured with a name, not an IP, e.g. one.one.one.one:53
	// this setting will resolve that name locally rather than on the SOCKS proxy. The
	// name will be resolved either on the local system, or via the bootstrap-resolver
	// if one is setup.
	ResolveLocal bool
}

type StaticLoader

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

StaticLoader holds a fixed ruleset in memory. It's used for loading fixed blocklists from configuration that doesn't get refreshed.

func NewStaticLoader

func NewStaticLoader(rules []string) *StaticLoader

func (*StaticLoader) Load

func (l *StaticLoader) Load() ([]string, error)

type StaticResolver

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

StaticResolver is a resolver that always returns the same answer, to any question. Typically used in combination with a blocklist to define fixed block responses or with a router when building a walled garden.

func NewStaticResolver

func NewStaticResolver(id string, opt StaticResolverOptions) (*StaticResolver, error)

NewStaticResolver returns a new instance of a StaticResolver resolver.

func (*StaticResolver) Resolve

func (r *StaticResolver) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by returning a fixed response.

func (*StaticResolver) String

func (r *StaticResolver) String() string

type StaticResolverOptions

type StaticResolverOptions struct {
	// Records in zone-file format
	Answer   []string
	NS       []string
	Extra    []string
	RCode    int
	Truncate bool
}

type Syslog added in v0.1.5

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

Syslog forwards every query unmodified and logs the content to syslog

func NewSyslog added in v0.1.5

func NewSyslog(id string, resolver Resolver, opt SyslogOptions) *Syslog

NewSyslog returns a new instance of a Syslog generator.

func (*Syslog) Resolve added in v0.1.5

func (r *Syslog) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve passes a DNS query through unmodified. Query details are sent via syslog.

func (*Syslog) String added in v0.1.5

func (r *Syslog) String() string

type SyslogOptions added in v0.1.5

type SyslogOptions struct {
	// "udp", "tcp", "unix". Defaults to "udp"
	Network string

	// Remote address, defaults to local syslog server
	Address string

	// Priority value as per https://pkg.go.dev/log/syslog#Priority
	Priority int

	// Syslog tag
	Tag string

	// Log requests and/or responses
	LogRequest  bool
	LogResponse bool

	// Log all response records, including those that do not match the query type
	Verbose bool
}

type TTLModifier

type TTLModifier struct {
	TTLModifierOptions
	// contains filtered or unexported fields
}

TTLModifier passes queries to upstream resolvers and then modifies the TTL in response RRs according to limits.

func NewTTLModifier

func NewTTLModifier(id string, resolver Resolver, opt TTLModifierOptions) *TTLModifier

NewTTLModifier returns a new instance of a TTL modifier.

func (*TTLModifier) Resolve

func (r *TTLModifier) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first resoling it upstream, then applying TTL limits on the response.

func (*TTLModifier) String

func (r *TTLModifier) String() string

type TTLModifierOptions

type TTLModifierOptions struct {
	// Function performing the initial modifications (min/max are applied after).
	// Returns true if at least one value was modified.
	SelectFunc TTLSelectFunc

	// Minimum TTL, any RR with a TTL below will be updated to this value.
	MinTTL uint32

	// Maximum TTL, any RR with a TTL higher than this will have their value
	// set to the max. A value of 0 disables the limit. Default 0.
	MaxTTL uint32
}

type TTLSelectFunc added in v0.1.20

type TTLSelectFunc func(*TTLModifier, *dns.Msg) bool

type TimeOfDay

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

func (*TimeOfDay) String added in v0.1.20

func (t *TimeOfDay) String() string

type TruncateRetry

type TruncateRetry struct {
	TruncateRetryOptions
	// contains filtered or unexported fields
}

TruncateRetry retries truncated responses with an alternative resolver. This is typically used when using UDP/DTLS transports, to fail over to a stream- based protocol.

func NewTruncateRetry

func NewTruncateRetry(id string, resolver, retryResolver Resolver, opt TruncateRetryOptions) *TruncateRetry

NewTruncateRetry returns a new instance of a truncate-retry router.

func (*TruncateRetry) Resolve

func (r *TruncateRetry) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error)

Resolve a DNS query by first resoling it upstream, if the response is truncated, the retry resolver is used to resolve the same query again.

func (*TruncateRetry) String

func (r *TruncateRetry) String() string

type TruncateRetryOptions

type TruncateRetryOptions struct {
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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