rdns

package module
v0.1.209 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2026 License: BSD-3-Clause Imports: 56 Imported by: 9

README

RouteDNS

Go Reference build license

RouteDNS is a composable DNS stub resolver, proxy and router written in Go. It enables building flexible DNS processing pipelines with support for all modern DNS protocols, query routing, caching, blocklists, DNSSEC validation, Lua scripting, and 30+ other pipeline components — all configured via TOML.

Pipeline Architecture

graph LR
    C[Clients] --> L
    subgraph RouteDNS
        L[Listeners<br/>DNS · DoT · DoH<br/>DoQ · DTLS · ODoH] --> P[Routers / Groups / Modifiers<br/>Router · Cache · Blocklist<br/>Rate Limiter · Load Balancer<br/>DNSSEC Validator · Lua Script<br/>...30+ types]
        P --> R[Resolvers<br/>DNS · DoT · DoH<br/>DoQ · DTLS · ODoH]
    end
    R --> U[Upstream DNS]
    classDef ext fill:#e2e8f0,stroke:#64748b,color:#1e293b
    classDef listen fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef proc fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef resolve fill:#d1fae5,stroke:#10b981,color:#064e3b
    class C,U ext
    class L listen
    class P proc
    class R resolve

Listeners receive queries over any supported protocol. Routers, groups and modifiers form the processing pipeline — routing, filtering, caching, and transforming queries and responses. Resolvers forward queries upstream. Every component implements the same Resolver interface, so they can be composed freely.

Features

Protocols

  • Plain DNS over UDP and TCP, with connection reuse and pipelining
  • DNS-over-TLS (DoT, RFC 7858) — client and server
  • DNS-over-HTTPS (DoH, RFC 8484) — client and server with HTTP/2
  • DNS-over-QUIC (DoQ, RFC 9250) — client and server, with 0-RTT support
  • DNS-over-DTLS (RFC 8094) — client and server
  • DNS-over-HTTPS with QUIC transport — client and server
  • Oblivious DoH (ODoH, RFC 9230) — client, proxy and target
  • Custom CAs and mutual TLS (mTLS)
  • SOCKS5 proxy support

Query Processing

  • DNSSEC validation with IANA trust anchor support
  • DNS64 for NAT64 networks (RFC 6147) — synthesize AAAA from A records
  • Blocklists — domain, regex, hosts-file, wildcard formats with auto-refresh from HTTP/file sources
  • Response blocklists — filter by response name, IP/CIDR, GeoIP country, or ASN
  • MAC address filtering via EDNS0
  • Lua scripting with sandboxed execution for custom query handling logic
  • Query/response modification and name translation
  • Static responses using Go templates
  • EDNS0 Client Subnet (ECS) manipulation (RFC 7871)
  • EDNS0 query and response padding (RFC 7830, RFC 8467)

Routing

  • Route by query name (regex), query type, query class, source IP/CIDR, or EDNS Client Subnet
  • Time-of-day based routing
  • Multiple routes evaluated in order — first match wins

Resilience & Performance

  • Caching with memory or Redis backend, negative-TTL support, and prefetch
  • TTL manipulation (min/max clamping)
  • Multiple load-balancing algorithms: round-robin, fail-rotate, load-balance, fastest, random
  • Request deduplication
  • Rate limiting per client subnet
  • Truncate-retry (automatic TCP fallback on truncated UDP responses)
  • Bootstrap addresses to avoid initial service name lookups

Deployment

  • Linux network namespace support — listen in one netns, resolve in another, via setns or xsocket (no CAP_SYS_ADMIN required); a compatible fd-server is built in (routedns fd-server)
  • Firewall mark (fwmark) and interface binding (SO_BINDTODEVICE) for policy routing and VRF
  • Admin listener with expvar metrics (Prometheus-compatible)
  • Query/response logging, syslog integration
  • Platform independent — written in Go

Installation

Requires Go 1.24+:

go install github.com/folbricht/routedns/cmd/routedns@latest

Or build from source:

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

Pre-built binaries for Linux (amd64, arm64, armv7), macOS (amd64, arm64), FreeBSD, and Windows are available on the GitHub Releases page.

Docker

A container is available on Docker Hub:

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

With a custom config:

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

Quick Start

This minimal config forwards all local DNS queries encrypted via DNS-over-TLS to Cloudflare, with caching. Set your system's nameserver to 127.0.0.1 (e.g. in /etc/resolv.conf).

[resolvers.cloudflare-dot]
address = "1.1.1.1:853"
protocol = "dot"

[groups.cloudflare-cached]
type = "cache"
resolvers = ["cloudflare-dot"]
backend = {type = "memory"}

[listeners.local-udp]
address = "127.0.0.1:53"
protocol = "udp"
resolver = "cloudflare-cached"

[listeners.local-tcp]
address = "127.0.0.1:53"
protocol = "tcp"
resolver = "cloudflare-cached"

Save as config.toml and run:

routedns config.toml

An example systemd service file is provided here.

Use Cases

Corporate split DNS

Route internal queries to company DNS servers while sending everything else securely to Cloudflare via DoH. Company servers are grouped with fail-rotate for resilience.

graph LR
    C[Client] --> L[Listener<br/>UDP/TCP :53]
    L --> RT[Router]
    RT -->|*.mycompany.com| CO[Fail-Rotate<br/>Company DNS A/B]
    RT -->|everything else| CF[Cloudflare DoH]
    classDef ext fill:#e2e8f0,stroke:#64748b,color:#1e293b
    classDef listen fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef proc fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef resolve fill:#d1fae5,stroke:#10b981,color:#064e3b
    class C ext
    class L listen
    class RT proc
    class CO,CF resolve

Configuration: use-case-2.toml

Content filtering for specific devices

Single out devices by IP address and apply a custom blocklist plus a filtered upstream resolver, while giving all other devices unfiltered access.

graph LR
    C[Client] --> L[Listener<br/>UDP/TCP :53]
    L --> RT[Router]
    RT -->|source 192.168.1.123| BL[Blocklist] --> CB[CleanBrowsing DoT]
    RT -->|default| CF[Cloudflare DoT]
    classDef ext fill:#e2e8f0,stroke:#64748b,color:#1e293b
    classDef listen fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef proc fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef resolve fill:#d1fae5,stroke:#10b981,color:#064e3b
    class C ext
    class L listen
    class RT,BL proc
    class CB,CF resolve

Configuration: family-browsing.toml

Home network ad & malware blocking

Protect the whole network with multi-layer blocklists (query names, response names, response IPs), caching, and TTL clamping. Blocklists auto-refresh daily from remote HTTP sources.

graph LR
    C[Clients] --> L[Listener<br/>UDP/TCP :53]
    L --> CA[Cache]
    CA --> TTL[TTL Modifier]
    TTL --> BQ[Query Blocklist]
    BQ --> BR[Response Name<br/>Blocklist]
    BR --> BI[Response IP<br/>Blocklist]
    BI --> CF[Cloudflare DoT<br/>Fail-Rotate]
    classDef ext fill:#e2e8f0,stroke:#64748b,color:#1e293b
    classDef listen fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef proc fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef resolve fill:#d1fae5,stroke:#10b981,color:#064e3b
    class C ext
    class L listen
    class CA,TTL,BQ,BR,BI proc
    class CF resolve

Configuration: use-case-6.toml

DNSSEC validation

Validate DNSSEC signatures on all responses using built-in root trust anchors. Queries with invalid signatures are rejected.

graph LR
    C[Client] --> L[Listener<br/>UDP/TCP :53]
    L --> DV[DNSSEC Validator<br/>IANA Trust Anchor]
    DV --> CF[Cloudflare DoT]
    classDef ext fill:#e2e8f0,stroke:#64748b,color:#1e293b
    classDef listen fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef proc fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef resolve fill:#d1fae5,stroke:#10b981,color:#064e3b
    class C ext
    class L listen
    class DV proc
    class CF resolve
[resolvers.cloudflare-dot]
address = "1.1.1.1:853"
protocol = "dot"

[groups.dnssec-validated]
type = "dnssec-validator"
resolvers = ["cloudflare-dot"]

[listeners.local-udp]
address = "127.0.0.1:53"
protocol = "udp"
resolver = "dnssec-validated"

[listeners.local-tcp]
address = "127.0.0.1:53"
protocol = "tcp"
resolver = "dnssec-validated"

Documentation

Documentation

Overview

Package rdns implements a variety of functionality to make DNS resolution configurable and extensible. It offers DNS resolvers as well as listeners with a number of protocols 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 across 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 into 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)
}
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)
}
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)
}

Index

Examples

Constants

View Source
const (
	ODOH_PROXY_PATH   = "/proxy"
	ODOH_QUERY_PATH   = "/dns-query"
	ODOH_CONFIG_PATH  = "/.well-known/odohconfigs"
	DOH_CONTENT_TYPE  = "application/dns-message"
	ODOH_CONTENT_TYPE = "application/oblivious-dns-message"
)
View Source
const (
	DOQNoError = 0x00
)
View Source
const IANARootAnchorsURL = "https://data.iana.org/root-anchors/root-anchors.xml"

IANARootAnchorsURL is the URL for the IANA root trust anchors XML.

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.209"
	BuildTime    string = "Tue Jun 16 08:56:42 UTC 2026"
	BuildNumber  string = "189"
)
View Source
var Log = slog.Default()

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 DialInNetNS added in v0.1.141

func DialInNetNS(ns *NetNS, network, address string, dialer *net.Dialer) (net.Conn, error)

DialInNetNS dials a connection in the given network namespace.

func ECSModifierDelete

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

func ListenInNetNS added in v0.1.141

func ListenInNetNS(ctx context.Context, ns *NetNS, network, address string, opts SocketOptions) (net.Listener, error)

ListenInNetNS creates a net.Listener in the given network namespace. Socket options (SO_MARK, SO_BINDTODEVICE) are applied before bind() via net.ListenConfig.Control so that interface binding works correctly.

func ListenPacketInNetNS added in v0.1.141

func ListenPacketInNetNS(ctx context.Context, ns *NetNS, network, address string, opts SocketOptions) (net.PacketConn, error)

ListenPacketInNetNS creates a net.PacketConn in the given network namespace. Socket options (SO_MARK, SO_BINDTODEVICE) are applied before bind() via net.ListenConfig.Control so that interface binding works correctly.

func ListenUDPInNetNS added in v0.1.141

func ListenUDPInNetNS(ctx context.Context, ns *NetNS, network string, laddr *net.UDPAddr, opts SocketOptions) (*net.UDPConn, error)

ListenUDPInNetNS creates a *net.UDPConn in the given network namespace. Socket options (SO_MARK, SO_BINDTODEVICE) are applied before bind() via net.ListenConfig.Control so that interface binding works correctly.

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, ecsSource, dohPath, listenerID, tlsServerName string, resolver Resolver) (*route, error)

NewRoute initializes a route from string parameters.

func RunInNetNS added in v0.1.141

func RunInNetNS(ns *NetNS, fn func() error) error

RunInNetNS executes fn in the given network namespace. If ns is nil or has an empty Name, fn is executed in the current namespace (no-op). The calling goroutine is locked to its OS thread for the duration.

func SubscribeNetNS added in v0.1.189

func SubscribeNetNS(name string) (<-chan NetNSState, func(), error)

SubscribeNetNS returns a channel that receives state changes for the named network namespace, plus a cancel function to unsubscribe. name must be a namespace name under /var/run/netns, not an absolute path. The current state is delivered immediately on subscription; subsequent values reflect changes. It fails if /var/run/netns does not exist: the directory is created by the first "ip netns add" after boot, so routedns must either be started after that or the directory created beforehand (e.g. with "ExecStartPre=+mkdir -p /run/netns" in a systemd unit).

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.

func WaitNetNSReady added in v0.1.193

func WaitNetNSReady(name string, timeout time.Duration) error

WaitNetNSReady blocks until the named network namespace is fully set up and usable, the namespace file disappears, or the timeout expires. name is either a namespace name under /var/run/netns or an absolute path.

"ip netns add" is not atomic: it first creates a placeholder file (which is what fires the inotify CREATE event the watcher reacts to), then bind-mounts the actual namespace onto it. In the gap between the two, opening the path fails (EACCES on the mode-000 placeholder for a non-root process, EINVAL from setns otherwise). So this waits by checking whether the path is an nsfs mount (statfs) every netnsReadyRecheckInterval.

Types

type ASNDB added in v0.1.97

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

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

func NewASNDB added in v0.1.97

func NewASNDB(name string, loader BlocklistLoader, geoDBFile string) (*ASNDB, error)

NewASN returns a new instance of a matcher for a ASN rules.

func (*ASNDB) Close added in v0.1.97

func (m *ASNDB) Close() error

func (*ASNDB) Match added in v0.1.97

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

func (*ASNDB) Reload added in v0.1.97

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

func (*ASNDB) String added in v0.1.97

func (m *ASNDB) String() string

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(msg *dns.Msg) (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

	// Optional, allows specifying extended errors to be used in the
	// response when blocking.
	EDNS0EDETemplate *EDNS0EDETemplate
}

type ByteCode added in v0.1.134

type ByteCode struct {
	*lua.FunctionProto
}

func LuaCompile added in v0.1.134

func LuaCompile(reader io.Reader, name string) (ByteCode, error)

LuaCompile compiles lua script into bytecode. The returned bytecode can be used to instantiate one or more scripts.

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

	// Use the provided ECS address instead of the real client IP if one was
	// provided. This can be used to "test" blocklists by simulating different
	// client IPs.
	UseECS bool
}

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 DNS64 added in v0.1.154

type DNS64 struct {
	DNS64Options
	// contains filtered or unexported fields
}

DNS64 is a resolver that synthesizes AAAA records from A records for IPv6-only clients using NAT64 (RFC 6147). When an AAAA query returns no AAAA answers, it falls back to an A query and embeds the IPv4 addresses into configurable IPv6 prefixes per RFC 6052.

func NewDNS64 added in v0.1.154

func NewDNS64(id string, resolver Resolver, opt DNS64Options) (*DNS64, error)

NewDNS64 returns a new DNS64 modifier instance.

func (*DNS64) Resolve added in v0.1.154

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

Resolve a DNS query. For AAAA queries without native AAAA answers, synthesizes AAAA records from A records using the configured prefixes.

func (*DNS64) String added in v0.1.154

func (r *DNS64) String() string

type DNS64Options added in v0.1.154

type DNS64Options struct {
	// IPv6 prefixes used for address synthesis per RFC 6052.
	// Each string is a CIDR like "64:ff9b::/96".
	// Only prefix lengths /32, /40, /48, /56, /64, /96 are allowed.
	// Default: ["64:ff9b::/96"] (well-known prefix)
	Prefixes []string
}

DNS64Options contains configuration for the DNS64 modifier.

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
	LocalAddrV4 net.IP
	LocalAddrV6 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

	// Linux network namespace for outbound connections.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

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) Stop added in v0.1.189

func (s DNSListener) Stop() error

func (DNSListener) String

func (s DNSListener) String() string

type DNSSECValidator added in v0.1.152

type DNSSECValidator struct {
	DNSSECValidatorOptions
	// contains filtered or unexported fields
}

DNSSECValidator passes a query to the upstream resolver and validates the response with DNSSEC.

func NewDNSSECValidator added in v0.1.152

func NewDNSSECValidator(id string, resolver Resolver, opt DNSSECValidatorOptions) (*DNSSECValidator, error)

NewDNSSECValidator returns a new instance of a DNSSEC validator.

func (*DNSSECValidator) Resolve added in v0.1.152

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

Resolve a DNS query, then validate the response with DNSSEC.

func (*DNSSECValidator) String added in v0.1.152

func (r *DNSSECValidator) String() string

type DNSSECValidatorOptions added in v0.1.152

type DNSSECValidatorOptions struct {
	TrustAnchors   []TrustAnchor
	TrustAnchorURL string // URL to fetch trust anchors from (e.g. IANA root-anchors.xml)
	LogOnly        bool   // Log validation failures without returning SERVFAIL
}

DNSSECValidatorOptions holds configuration for the DNSSEC validator.

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 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
	LocalAddrV4 net.IP
	LocalAddrV6 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

	// Linux network namespace for outbound connections.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

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
}

DTLSListenerOptions 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 for 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) 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
	LocalAddrV4 net.IP
	LocalAddrV6 net.IP

	TLSConfig *tls.Config

	QueryTimeout time.Duration

	// IdleTimeout is the maximum amount of time an idle connection will remain
	// open before being closed. For TCP transport, defaults to 30 seconds if not set.
	// For QUIC transport, defaults to the quic-go library default if not set. Note
	// that for QUIC, the actual timeout is the minimum of client and server values.
	IdleTimeout time.Duration

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

	Use0RTT bool

	// Linux network namespace for outbound connections.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

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
	// contains filtered or unexported fields
}

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
	LocalAddrV4 net.IP
	LocalAddrV6 net.IP

	TLSConfig    *tls.Config
	QueryTimeout time.Duration
	Use0RTT      bool

	// Linux network namespace for outbound connections.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

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 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
	LocalAddrV4 net.IP
	LocalAddrV6 net.IP

	TLSConfig *tls.Config

	QueryTimeout time.Duration

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

	// Linux network namespace for outbound connections.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

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, network 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

When includeSubdomains is true, bare entries like "domain.com" are treated as ".domain.com" (apex and all sub-domains). Entries that already use a leading "." or "*." prefix keep their original semantics. This is intended for blocklists where every line is meant to block both the apex and sub-domains (e.g. hagezi's "Wildcard Domains" lists).

func NewDomainDB

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

NewDomainDB returns a new instance of a matcher for a list of domain rules.

func NewDomainSubdomainDB added in v0.1.155

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

NewDomainSubdomainDB is like NewDomainDB but treats bare entries as matching the apex and all sub-domains. See DomainDB for details.

func (*DomainDB) Match

func (m *DomainDB) Match(msg *dns.Msg) ([]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 EDNS0 Client Subnet record

func ECSModifierAdd

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

func ECSModifierAddIfMissing added in v0.1.74

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

func ECSModifierPrivacy

func ECSModifierPrivacy(prefix4, prefix6 uint8) ECSModifierFunc

type EDNS0EDEInput added in v0.1.79

type EDNS0EDEInput struct {
	*dns.Msg
	*BlocklistMatch
}

type EDNS0EDETemplate added in v0.1.71

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

func NewEDNS0EDETemplate added in v0.1.71

func NewEDNS0EDETemplate(infoCode uint16, extraText string) (*EDNS0EDETemplate, error)

func (*EDNS0EDETemplate) Apply added in v0.1.71

func (t *EDNS0EDETemplate) Apply(msg *dns.Msg, in EDNS0EDEInput) error

Apply executes the template for the EDNS0-EDE record text, e.g. replacing placeholders in the Text with Query names, then adding the EDE record to the given msg.

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

	// Determines if an empty response returned by a resolver should be considered an
	// error response and trigger a failover.
	EmptyError 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

	// Determines if an empty response returned by a resolver should be considered an
	// error response and trigger a failover.
	EmptyError 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
	LocalAddrV4   net.IP
	LocalAddrV6   net.IP
	Timeout       time.Duration
	NetNS         *NetNS
	SocketOptions SocketOptions
}

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 block 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(msg *dns.Msg) ([]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

	// Linux network namespace for the listening socket.
	NetNS *NetNS

	// Linux socket options for fwmark and interface binding.
	SocketOptions SocketOptions
}

type Listener

type Listener interface {
	Start() error
	Stop() 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 LoadBalance added in v0.1.190

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

LoadBalance is a resolver group that prefers resolvers with lower average response times and penalizes resolvers that fail.

func NewLoadBalance added in v0.1.190

func NewLoadBalance(id string, opt LoadBalanceOptions, resolvers ...Resolver) *LoadBalance

NewLoadBalance returns a new instance of a load-balancing resolver group.

func (*LoadBalance) Resolve added in v0.1.190

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

Resolve a DNS query using a weighted random resolver selection. Resolvers with lower average response times receive more traffic. Failed resolvers are penalized and the request is retried with another resolver.

func (*LoadBalance) String added in v0.1.190

func (r *LoadBalance) String() string

type LoadBalanceOptions added in v0.1.190

type LoadBalanceOptions struct {
	// Duration recorded as the RTT penalty for persistently failing resolvers
	// (after loadBalancePenaltyThreshold consecutive failures). 0 disables the
	// penalty; without it fast-failing resolvers are still prevented from
	// gaining weight via the upward-only EMA update on failure.
	FailurePenalty time.Duration

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

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

LoadBalanceOptions contain settings for the load-balancing resolver group.

type LogFormat added in v0.1.92

type LogFormat string
const (
	LogFormatText LogFormat = "text"
	LogFormatJSON LogFormat = "json"
)

type Lua added in v0.1.134

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

func NewLua added in v0.1.134

func NewLua(id string, opt LuaOptions, resolvers ...Resolver) (*Lua, error)

func (*Lua) Close added in v0.1.134

func (r *Lua) Close()

func (*Lua) Resolve added in v0.1.134

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

func (*Lua) String added in v0.1.134

func (r *Lua) String() string

type LuaOptions added in v0.1.134

type LuaOptions struct {
	Script      string
	Concurrency uint
	NoSandbox   bool // Disables the sandbox. When false (default), scripts cannot access os/io/debug/etc.
}

type LuaScript added in v0.1.134

type LuaScript struct {
	L *lua.LState
}

func NewScriptFromByteCode added in v0.1.134

func NewScriptFromByteCode(b ByteCode, sandbox bool) (*LuaScript, error)

NewScriptFromByteCode creates a new lua script from bytecode. When sandbox is true, only safe libraries are loaded (no io, os, debug, package, channel).

func (*LuaScript) Call added in v0.1.134

func (s *LuaScript) Call(fnName string, nret int, params ...any) ([]any, error)

func (*LuaScript) HasFunction added in v0.1.134

func (s *LuaScript) HasFunction(name string) bool

func (*LuaScript) InjectResolvers added in v0.1.134

func (s *LuaScript) InjectResolvers(resolvers []Resolver)

func (*LuaScript) RegisterClientInfoType added in v0.1.137

func (s *LuaScript) RegisterClientInfoType()

func (*LuaScript) RegisterConstants added in v0.1.134

func (s *LuaScript) RegisterConstants()

func (*LuaScript) RegisterEDNS0Types added in v0.1.134

func (s *LuaScript) RegisterEDNS0Types()

func (*LuaScript) RegisterErrorType added in v0.1.134

func (s *LuaScript) RegisterErrorType()

func (*LuaScript) RegisterMessageType added in v0.1.134

func (s *LuaScript) RegisterMessageType()

func (*LuaScript) RegisterOPTType added in v0.1.134

func (s *LuaScript) RegisterOPTType()

func (*LuaScript) RegisterQuestionType added in v0.1.134

func (s *LuaScript) RegisterQuestionType()

func (*LuaScript) RegisterRRTypes added in v0.1.134

func (s *LuaScript) RegisterRRTypes()

type MACDB added in v0.1.94

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

MACDB holds a list of MAC addresses used to match clients with the given MAC (as per EDNS0 option 65001).

func NewMACDB added in v0.1.94

func NewMACDB(name string, loader BlocklistLoader) (*MACDB, error)

NewMACDB returns a new instance of a matcher for a list of MAC addresses.

func (*MACDB) Close added in v0.1.94

func (m *MACDB) Close() error

func (*MACDB) Match added in v0.1.94

func (m *MACDB) Match(msg *dns.Msg) ([]net.IP, []string, *BlocklistMatch, bool)

func (*MACDB) Reload added in v0.1.94

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

func (*MACDB) String added in v0.1.94

func (m *MACDB) String() string

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.Msg) ([]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 NetNS added in v0.1.141

type NetNS struct {
	Name    string
	XSocket string
}

NetNS represents a target Linux network namespace and how to reach it.

Name selects the namespace via setns(2) (requires CAP_SYS_ADMIN). XSocket instead points at the Unix socket of an xsocket-server running inside the target namespace, which hands back sockets created in that namespace via SCM_RIGHTS - avoiding the need for elevated privileges. The two are mutually exclusive.

type NetNSState added in v0.1.189

type NetNSState int

NetNSState represents whether a Linux network namespace is currently present in the filesystem.

const (
	NetNSAbsent NetNSState = iota
	NetNSPresent
)

type ODoHClient added in v0.1.86

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

ODoHClient is a Oblivious DNS client.

func NewODoHClient added in v0.1.86

func NewODoHClient(id, proxy, target, targetConfig string, opt DoHClientOptions) (*ODoHClient, error)

func (*ODoHClient) Resolve added in v0.1.86

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

Resolve a DNS query.

func (*ODoHClient) String added in v0.1.86

func (d *ODoHClient) String() string

type ODoHListener added in v0.1.100

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

ODoHListener is an Oblivious DNS over HTTPS listener.

func NewODoHListener added in v0.1.100

func NewODoHListener(id, addr string, opt ODoHListenerOptions, resolver Resolver) (*ODoHListener, error)

NewODoHListener returns an instance of an oblivious DNS-over-HTTPS listener.

func (*ODoHListener) ODoHproxyHandler added in v0.1.100

func (s *ODoHListener) ODoHproxyHandler(w http.ResponseWriter, r *http.Request)

func (*ODoHListener) ODoHqueryHandler added in v0.1.100

func (s *ODoHListener) ODoHqueryHandler(w http.ResponseWriter, r *http.Request)

func (*ODoHListener) Start added in v0.1.100

func (s *ODoHListener) Start() error

func (*ODoHListener) Stop added in v0.1.100

func (s *ODoHListener) Stop() error

func (*ODoHListener) String added in v0.1.100

func (s *ODoHListener) String() string

type ODoHListenerOptions added in v0.1.100

type ODoHListenerOptions struct {
	ListenOptions

	OdohMode  string
	AllowDoH  bool
	KeySeed   string
	TLSConfig *tls.Config
}

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 Prefetch added in v0.1.119

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

Prefetch monitors queries and initiates queries for any that are requested frequently by the client. Requires a cache behind it to be meaningful.

func NewPrefetch added in v0.1.119

func NewPrefetch(id string, resolver Resolver, opt PrefetchOptions) *Prefetch

func (*Prefetch) Resolve added in v0.1.119

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

func (*Prefetch) String added in v0.1.119

func (r *Prefetch) String() string

type PrefetchOptions added in v0.1.119

type PrefetchOptions struct {
	PrefetchWindow    time.Duration
	PrefetchThreshold uint64
	PrefetchCacheSize int
	PrefetchMaxItems  int
}

type QueryLogResolver added in v0.1.92

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

QueryLogResolver logs requests to STDOUT or file.

func NewQueryLogResolver added in v0.1.92

func NewQueryLogResolver(id string, resolver Resolver, opt QueryLogResolverOptions) (*QueryLogResolver, error)

NewQueryLogResolver returns a new instance of a QueryLogResolver.

func (*QueryLogResolver) Resolve added in v0.1.92

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

Resolve logs the query details and passes the query to the next resolver.

func (*QueryLogResolver) String added in v0.1.92

func (r *QueryLogResolver) String() string

type QueryLogResolverOptions added in v0.1.92

type QueryLogResolverOptions struct {
	OutputFile   string // Output filename, leave blank for STDOUT
	OutputFormat LogFormat
}

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

	// Determines if an empty response returned by a resolver should be considered an
	// error response and trigger a failover.
	EmptyError 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 allowed 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
	SyncSet      bool // When true, perform Redis SET synchronously. Default is false (async writes).
}

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(msg *dns.Msg) ([]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 blocklist-resolver
	Filter bool

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

	// Optional, allows specifying extended errors to be used in the
	// response when blocking.
	EDNS0EDETemplate *EDNS0EDETemplate
}

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

	// Optional, allows specifying extended errors to be used in the
	// response when blocking.
	EDNS0EDETemplate *EDNS0EDETemplate
}

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 SocketOptions added in v0.1.145

type SocketOptions struct {
	// Firewall mark (SO_MARK) to set on the socket. 0 means unset.
	FWMark uint32

	// Network interface to bind the socket to (SO_BINDTODEVICE). Empty means unset.
	BindInterface string
}

SocketOptions contains Linux-specific socket options for controlling packet routing and interface binding. These options map to the SO_MARK and SO_BINDTODEVICE socket options.

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
	LocalAddrV4 net.IP
	LocalAddrV6 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

	// Linux network namespace for the connection to the SOCKS5 proxy. Only the
	// xsocket mechanism is handled here; setns-based namespaces are entered by
	// the caller (which wraps Dial in RunInNetNS). A nil or empty value reaches
	// the proxy from the current namespace.
	NetNS *NetNS

	// Linux socket options (fwmark, interface binding) applied to the socket
	// used to reach the proxy. Only honoured when dialing the proxy via xsocket;
	// other paths apply them around Dial.
	SocketOptions SocketOptions
}

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
	// Optional, allows specifying extended errors to be used in the
	// response when blocking.
	EDNS0EDETemplate *EDNS0EDETemplate
}

type StaticTemplateResolver added in v0.1.75

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

StaticTemplateResolver is a resolver that always returns a predefined set of records which can be customized with information from the question. It is similar to StaticResolver but allows the use of templates with placeholders as input.

func NewStaticTemplateResolver added in v0.1.75

func NewStaticTemplateResolver(id string, opt StaticResolverOptions) (*StaticTemplateResolver, error)

NewStaticTemplateResolver returns a new instance of a StaticTemplateResolver resolver.

func (*StaticTemplateResolver) Resolve added in v0.1.75

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

Resolve a DNS query by incorporating data from the query into a fixed response.

func (*StaticTemplateResolver) String added in v0.1.75

func (r *StaticTemplateResolver) String() string

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 resolving 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 Template added in v0.1.75

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

func NewTemplate added in v0.1.75

func NewTemplate(text string) (*Template, error)

func (*Template) Apply added in v0.1.75

func (t *Template) Apply(input templateInput) (string, error)

Apply executes the template, e.g. replacing placeholders in the text with values from the Query.

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 resolving 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 {
}

type TrustAnchor added in v0.1.152

type TrustAnchor struct {
	Owner      string
	Digest     string
	KeyTag     uint16
	Algorithm  uint8
	DigestType uint8
}

TrustAnchor represents a DNSSEC trust anchor (typically the root KSK).

func FetchTrustAnchorsFromURL added in v0.1.152

func FetchTrustAnchorsFromURL(url string) ([]TrustAnchor, error)

FetchTrustAnchorsFromURL fetches and parses IANA-format trust anchor XML from the given URL. Entries past their validUntil date are filtered out.

type XSocketServer added in v0.1.209

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

XSocketServer implements the server side of the xsocket protocol, see https://github.com/koro666/xsocket. It listens on an AF_UNIX/SOCK_SEQPACKET socket and returns socket file descriptors created in its own network namespace to clients via SCM_RIGHTS. It can be used in place of xsocket-server, typically started inside a network namespace with "ip netns exec". A leading '@' in the path denotes an abstract socket.

func NewXSocketServer added in v0.1.209

func NewXSocketServer(path string, opt XSocketServerOptions) *XSocketServer

func (*XSocketServer) Start added in v0.1.209

func (s *XSocketServer) Start() error

Start creates the Unix socket and serves requests until Stop is called.

func (*XSocketServer) Stop added in v0.1.209

func (s *XSocketServer) Stop() error

Stop closes the listening socket, removing it from the filesystem.

func (*XSocketServer) String added in v0.1.209

func (s *XSocketServer) String() string

type XSocketServerOptions added in v0.1.209

type XSocketServerOptions struct {
	// Hand out any socket the client asks for rather than just the
	// IPv4/IPv6 stream and datagram sockets RouteDNS itself uses.
	Unrestricted bool

	// Permissions applied to the Unix socket after it is created. Zero
	// leaves the permissions at what the process umask produces. Has no
	// effect on abstract sockets.
	SocketMode fs.FileMode
}

XSocketServerOptions contain settings for the xsocket fd-server.

Directories

Path Synopsis
cmd
routedns command

Jump to

Keyboard shortcuts

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