fastdns

package module
v0.16.7 Latest Latest
Warning

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

Go to latest
Published: Feb 23, 2026 License: MIT Imports: 23 Imported by: 7

README

Fast DNS implementation for Go

godoc release goreport

Features

  • 0 Dependency
  • Similar Interface with net/http
  • Fast DoH Server Co-create with fasthttp
  • Fast DNS Client with rich features
  • Fast eDNS options
  • Compatible metrics with coredns
  • High Performance
    • 0-allocs dns request parser
    • 0-allocs dns records marshaller
    • worker pool + message pool
    • prefork + reuse_port + set_affinity

Getting Started

DNS Server
package main

import (
	"log/slog"
	"net"
	"net/netip"
	"os"

	"github.com/phuslu/fastdns"
)

type DNSHandler struct {
	Debug bool
}

func (h *DNSHandler) ServeDNS(rw fastdns.ResponseWriter, req *fastdns.Message) {
	if h.Debug {
		slog.Info("serve dns request", "domain", req.Domain, "class", req.Question.Class, "type", req.Question.Type)
	}

	switch req.Question.Type {
	case fastdns.TypeA:
		req.SetResponseHeader(fastdns.RcodeNoError, 1)
		req.AppendHOST1(600, netip.AddrFrom4([4]byte{8, 8, 8, 8}))
	case fastdns.TypeAAAA:
		ips := []netip.Addr{netip.MustParseAddr("2001:4860:4860::8888")}
		req.SetResponseHeader(fastdns.RcodeNoError, uint16(len(ips)))
		req.AppendHOST(600, ips)
	case fastdns.TypeCNAME:
		cnames, ips := []string{"dns.google"}, []netip.Addr{netip.MustParseAddr("8.8.8.8")}
		req.SetResponseHeader(fastdns.RcodeNoError, uint16(len(cnames)+len(ips)))
		req.AppendCNAME(600, cnames, ips)
	case fastdns.TypeSRV:
		srvs := []net.SRV{{"www.google.com", 443, 1000, 1000}}
		req.SetResponseHeader(fastdns.RcodeNoError, uint16(len(srvs)))
		req.AppendSRV(600, srvs)
	case fastdns.TypeNS:
		nameservers := []net.NS{{"ns1.google.com"}, {"ns2.google.com"}}
		req.SetResponseHeader(fastdns.RcodeNoError, uint16(len(nameservers)))
		req.AppendNS(600, nameservers)
	case fastdns.TypeSOA:
		mname := net.NS{Host: "ns1.google.com"}
		rname := net.NS{Host: "dns-admin.google.com"}
		req.SetResponseHeader(fastdns.RcodeNoError, 1)
		req.AppendSOA(600, mname, rname, 42, 900, 900, 1800, 60)
	case fastdns.TypeMX:
		mxs := []net.MX{{"mail.gmail.com", 10}, {"smtp.gmail.com", 10}}
		req.SetResponseHeader(fastdns.RcodeNoError, uint16(len(mxs)))
		req.AppendMX(600, mxs)
	case fastdns.TypePTR:
		ptr := "ptr.google.com"
		req.SetResponseHeader(fastdns.RcodeNoError, 1)
		req.AppendPTR(600, ptr)
	case fastdns.TypeTXT:
		txt := "iamatxtrecord"
		req.SetResponseHeader(fastdns.RcodeNoError, 1)
		req.AppendTXT(600, txt)
	default:
		req.SetResponseHeader(fastdns.RcodeFormErr, 0)
	}

	_, _ = rw.Write(req.Raw)
}

func main() {
	addr := ":53"

	server := &fastdns.ForkServer{
		Handler: &DNSHandler{
			Debug: os.Getenv("DEBUG") != "",
		},
		Stats: &fastdns.CoreStats{
			Prefix: "coredns_",
			Family: "1",
			Proto:  "udp",
			Server: "dns://" + addr,
			Zone:   ".",
		},
		ErrorLog: slog.Default(),
	}

	err := server.ListenAndServe(addr)
	if err != nil {
		slog.Error("dnsserver serve failed", "error", err)
	}
}
DoH/eDNS Client
package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"net/netip"
	"net/url"
	"time"

	"github.com/phuslu/fastdns"
)

func main() {
	endpoint, _ := url.Parse("https://8.8.8.8/dns-query")

	client := &fastdns.Client{
		Addr: endpoint.String(),
		Dialer: &fastdns.HTTPDialer{
			Endpoint:  endpoint,
			Header: http.Header{
				"content-type": []string{"application/dns-message"},
				"user-agent":   []string{"fastdns/1.0"},
			},
			Transport: &http.Transport{
				ForceAttemptHTTP2:   true,
				MaxIdleConns:        100,
				IdleConnTimeout:     90 * time.Second,
				TLSHandshakeTimeout: 10 * time.Second,
				TLSClientConfig: &tls.Config{
					NextProtos:         []string{"h2"},
					InsecureSkipVerify: false,
					ServerName:         endpoint.Hostname(),
					ClientSessionCache: tls.NewLRUClientSessionCache(1024),
				},
			},
		},
	}

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	ctx = fastdns.WithClientSubnet(ctx, netip.MustParsePrefix("1.2.4.8/24"))

	fmt.Println(client.LookupNetIP(ctx, "ip4", "www.google.com"))
	fmt.Println(client.LookupHTTPS(ctx, "phus.lu"))
}
DNS/eDNS Client Tool
$ go install github.com/phuslu/fastdns/cmd/fastdig@master
$ fastdig www.google.com @https://8.8.8.8/dns-query +subnet=1.2.3.0/24

; <<>> DiG 0.0.1-fastdns-go1.25.0 <<>> www.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 589
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.google.com.                IN      A

;; ANSWER SECTION:
www.google.com. 300     IN      A       142.250.9.147
www.google.com. 300     IN      A       142.250.9.104
www.google.com. 300     IN      A       142.250.9.99
www.google.com. 300     IN      A       142.250.9.105
www.google.com. 300     IN      A       142.250.9.106
www.google.com. 300     IN      A       142.250.9.103

;; Query time: 30 msec
;; SERVER: https://8.8.8.8/dns-query#53(https://8.8.8.8/dns-query)
;; WHEN: Sat Oct 11 00:44:09 +08 2025
;; MSG SIZE  rcvd: 150
DoH Server Example
$ go install github.com/phuslu/fastdns/cmd/fastdoh@master
$ fastdoh :8080

High Performance

A Performance result as below, for daily benchmark results see github actions

# go test -v -run=none -benchmem -bench=.
goos: linux
goarch: amd64
pkg: github.com/phuslu/fastdns
cpu: AMD EPYC 7763 64-Core Processor

BenchmarkMessageParseMessage-4        	80922766	        14.68 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageEncodeDomain-4       	100000000	        12.78 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageSetQuestion-4         	40993672	        30.27 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageSetResponseHeader-4   	320204428	         3.606 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageDecodeName-4          	52074597	        23.07 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendHOST-4          	183561132	         6.544 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendCNAME-4         	42692521	        27.77 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendSRV-4           	50555230	        23.85 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendNS-4            	32065906	        36.33 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendSOA-4           	26630746	        45.05 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendPTR-4           	54242904	        22.74 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendMX-4            	61512556	        19.59 ns/op	       0 B/op	       0 allocs/op
BenchmarkMessageAppendTXT-4           	166240762	         7.213 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerHOST1-4         	152072834	         7.914 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerHOST-4          	130878036	         8.404 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerCNAME-4         	36238018	        33.11 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerSRV-4           	47581225	        25.69 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerNS-4            	30977643	        39.82 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerSOA-4           	22182384	        54.29 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerMX-4            	42502989	        28.91 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerPTR-4           	40598533	        28.77 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerHandlerTXT-4           	100000000	        14.72 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerUpdateStats-4          	39958220	        30.05 ns/op	       0 B/op	       0 allocs/op
BenchmarkServerAppendOpenMetrics-4    	  465868	      2662 ns/op	       0 B/op	       0 allocs/op

PASS
ok  	github.com/phuslu/fastdns

Here is the real-world flamegraph flamegraph when fastdns server reaches 1.4M QPS on a single machine with Xeon 4216 and Intel X710.

Acknowledgment

This dns server is inspired by fasthttp, rawdns and miekg/dns.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidHeader is returned when dns message does not have the expected header size.
	ErrInvalidHeader = errors.New("ErrInvalidHeader")
	// ErrInvalidQuestion is returned when dns message does not have the expected question size.
	ErrInvalidQuestion = errors.New("ErrInvalidQuestion")
	// ErrInvalidAnswer is returned when dns message does not have the expected answer size.
	ErrInvalidAnswer = errors.New("ErrInvalidAnswer")
	// ErrInvalidName is returned when dns message does not have the expected name size.
	ErrInvalidName = errors.New("ErrInvalidName")
	// ErrInvalidOption is returned when dns message does not have the expected option size.
	ErrInvalidOption = errors.New("ErrInvalidOption")
)
View Source
var MaxUDPSize = 1232

Functions

func EncodeDomain added in v0.0.8

func EncodeDomain(dst []byte, domain string) []byte

EncodeDomain encodes domain to dst.

func Error

func Error(rw ResponseWriter, req *Message, rcode Rcode)

Error replies to the request with the specified Rcode.

func ParseMessage added in v0.3.0

func ParseMessage(dst *Message, payload []byte, copying bool) error

ParseMessage parses dns request from payload into dst and returns the error.

func ReleaseMessage added in v0.3.0

func ReleaseMessage(msg *Message)

ReleaseMessage releases the Message back into the pool.

func WithClientCookie added in v0.15.0

func WithClientCookie(ctx context.Context, cookie string) context.Context

WithClientCookie returns a context carrying the client cookie value.

func WithClientPadding added in v0.15.0

func WithClientPadding(ctx context.Context, padding uint16) context.Context

WithClientPadding returns a context carrying the padded EDNS option.

func WithClientSubnet added in v0.15.0

func WithClientSubnet(ctx context.Context, prefix netip.Prefix) context.Context

WithClientSubnet returns a context carrying the client subnet prefix.

Types

type Class

type Class uint16

Class is a DNS class.

const (
	ClassINET   Class = 1
	ClassCSNET  Class = 2
	ClassCHAOS  Class = 3
	ClassHESIOD Class = 4
	ClassNONE   Class = 254
	ClassANY    Class = 255
)

Wire constants and supported types.

func (Class) String

func (c Class) String() string

String returns the textual class identifier.

type Client added in v0.3.4

type Client struct {
	// Addr defines the DNS server's address to which the client will send queries.
	// This field is used if no custom Dialer is provided.
	Addr string

	// Timeout specifies the maximum duration for a query to complete.
	// If a query exceeds this duration, it will result in a timeout error.
	Timeout time.Duration

	// Dialer allows for customizing the way connections are established.
	// If set, Addr and Timeout will be ignore.
	Dialer Dialer
}

Client represents a DNS client that communicates over UDP. It supports sending DNS queries to a specified server.

func (*Client) AppendLookupNetIP added in v0.10.5

func (c *Client) AppendLookupNetIP(dst []netip.Addr, ctx context.Context, network, host string) (_ []netip.Addr, err error)

AppendLookupNetIP looks up host and appends result to dst using the local resolver.

func (*Client) Exchange added in v0.3.4

func (c *Client) Exchange(ctx context.Context, req, resp *Message) (err error)

Exchange executes a DNS transaction and unmarshals the response into resp.

func (*Client) LookupCNAME added in v0.9.5

func (c *Client) LookupCNAME(ctx context.Context, host string) (cname string, err error)

LookupCNAME returns the canonical name for the given host.

func (*Client) LookupHTTPS added in v0.9.3

func (c *Client) LookupHTTPS(ctx context.Context, host string) (https []NetHTTPS, err error)

LookupHTTPS returns the DNS HTTPS records for the given domain name.

func (*Client) LookupMX added in v0.10.3

func (c *Client) LookupMX(ctx context.Context, host string) (mx []*net.MX, err error)

LookupMX returns the DNS MX records for the given domain name sorted by preference.

func (*Client) LookupNS added in v0.10.3

func (c *Client) LookupNS(ctx context.Context, name string) (ns []*net.NS, err error)

LookupNS returns the DNS NS records for the given domain name.

func (*Client) LookupNetIP added in v0.9.0

func (c *Client) LookupNetIP(ctx context.Context, network, host string) (ips []netip.Addr, err error)

LookupNetIP looks up host using the local resolver. It returns a slice of that host's IP addresses of the type specified by network. The network must be one of "ip", "ip4" or "ip6".

func (*Client) LookupPTR added in v0.16.4

func (c *Client) LookupPTR(ctx context.Context, ip string) (ptr string, err error)

LookupPTR returns the Reverse DNS record for the given ip.

func (*Client) LookupSRV added in v0.11.6

func (c *Client) LookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*net.SRV, err error)

LookupSRV resolves SRV records and returns them sorted by priority with weight-based shuffling.

func (*Client) LookupTXT added in v0.9.5

func (c *Client) LookupTXT(ctx context.Context, host string) (txt []string, err error)

LookupTXT returns the DNS TXT records for the given domain name.

type CoreStats added in v0.6.0

type CoreStats struct {
	RequestCountTotal uint64

	RequestDurationSecondsBucket_0_00025 uint64
	RequestDurationSecondsBucket_0_0005  uint64
	RequestDurationSecondsBucket_0_001   uint64
	RequestDurationSecondsBucket_0_002   uint64
	RequestDurationSecondsBucket_0_004   uint64
	RequestDurationSecondsBucket_0_008   uint64
	RequestDurationSecondsBucket_0_016   uint64
	RequestDurationSecondsBucket_0_032   uint64
	RequestDurationSecondsBucket_0_064   uint64
	RequestDurationSecondsBucket_0_128   uint64
	RequestDurationSecondsBucket_0_256   uint64
	RequestDurationSecondsBucket_0_512   uint64
	RequestDurationSecondsBucket_1_024   uint64
	RequestDurationSecondsBucket_2_048   uint64
	RequestDurationSecondsBucket_4_096   uint64
	RequestDurationSecondsBucket_8_192   uint64
	RequestDurationSecondsBucket_Inf     uint64
	RequestDurationSecondsSum            uint64
	RequestDurationSecondsCount          uint64

	RequestSizeBytesBucket_0     uint64
	RequestSizeBytesBucket_100   uint64
	RequestSizeBytesBucket_200   uint64
	RequestSizeBytesBucket_300   uint64
	RequestSizeBytesBucket_400   uint64
	RequestSizeBytesBucket_511   uint64
	RequestSizeBytesBucket_1023  uint64
	RequestSizeBytesBucket_2047  uint64
	RequestSizeBytesBucket_4095  uint64
	RequestSizeBytesBucket_8291  uint64
	RequestSizeBytesBucket_16000 uint64
	RequestSizeBytesBucket_32000 uint64
	RequestSizeBytesBucket_48000 uint64
	RequestSizeBytesBucket_64000 uint64
	RequestSizeBytesBucket_Inf   uint64
	RequestSizeBytesSum          uint64
	RequestSizeBytesCount        uint64

	RequestTypeCountTotal_A     uint64
	RequestTypeCountTotal_AAAA  uint64
	RequestTypeCountTotal_NS    uint64
	RequestTypeCountTotal_PTR   uint64
	RequestTypeCountTotal_SRV   uint64
	RequestTypeCountTotal_CNAME uint64
	RequestTypeCountTotal_SOA   uint64
	RequestTypeCountTotal_MX    uint64
	RequestTypeCountTotal_TXT   uint64

	ResponseRcodeCountTotal_NOERROR  uint64
	ResponseRcodeCountTotal_FORMERR  uint64
	ResponseRcodeCountTotal_SERVFAIL uint64
	ResponseRcodeCountTotal_NOTIMP   uint64
	ResponseRcodeCountTotal_NXDOMAIN uint64
	ResponseRcodeCountTotal_REFUSED  uint64
	ResponseRcodeCountTotal_YXDOMAIN uint64
	ResponseRcodeCountTotal_XRRSET   uint64
	ResponseRcodeCountTotal_NOTAUTH  uint64
	ResponseRcodeCountTotal_NOTZONE  uint64

	ResponseSizeBytesBucket_0     uint64
	ResponseSizeBytesBucket_100   uint64
	ResponseSizeBytesBucket_200   uint64
	ResponseSizeBytesBucket_300   uint64
	ResponseSizeBytesBucket_400   uint64
	ResponseSizeBytesBucket_511   uint64
	ResponseSizeBytesBucket_1023  uint64
	ResponseSizeBytesBucket_2047  uint64
	ResponseSizeBytesBucket_4095  uint64
	ResponseSizeBytesBucket_8291  uint64
	ResponseSizeBytesBucket_16000 uint64
	ResponseSizeBytesBucket_32000 uint64
	ResponseSizeBytesBucket_48000 uint64
	ResponseSizeBytesBucket_64000 uint64
	ResponseSizeBytesBucket_Inf   uint64
	ResponseSizeBytesSum          uint64
	ResponseSizeBytesCount        uint64

	Prefix, Family, Proto, Server, Zone string
}

func (*CoreStats) AppendOpenMetrics added in v0.6.1

func (s *CoreStats) AppendOpenMetrics(dst []byte) []byte

AppendOpenMetrics appends Prometheus-formatted metrics to dst.

func (*CoreStats) UpdateStats added in v0.6.0

func (s *CoreStats) UpdateStats(addr netip.AddrPort, msg *Message, duration time.Duration)

UpdateStats records the request metrics derived from the message and timing data.

type Dialer added in v0.10.0

type Dialer interface {
	DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}

type Flags added in v0.6.2

type Flags uint16

Flags is an arbitrary 16bit represents QR, Opcode, AA, TC, RD, RA, Z and RCODE.

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

func (Flags) AA added in v0.6.2

func (f Flags) AA() byte

AA returns the AA bit in Flags.

func (Flags) Opcode added in v0.6.2

func (f Flags) Opcode() Opcode

Opcode extracts the opcode from Flags.

func (Flags) QR added in v0.6.2

func (f Flags) QR() byte

QR returns the QR bit in Flags.

func (Flags) RA added in v0.6.2

func (f Flags) RA() byte

RA returns the RA bit in Flags.

func (Flags) RD added in v0.6.2

func (f Flags) RD() byte

RD returns the RD bit in Flags.

func (Flags) Rcode added in v0.6.2

func (f Flags) Rcode() Rcode

Rcode extracts the response code from Flags.

func (Flags) TC added in v0.6.2

func (f Flags) TC() byte

TC returns the TC bit in Flags.

func (Flags) Z added in v0.6.2

func (f Flags) Z() byte

Z returns the Z bits in Flags.

type ForkServer

type ForkServer struct {
	// handler to invoke
	Handler Handler

	// stats to invoke
	Stats Stats

	// ErrorLog specifies an optional logger for errors accepting
	// connections, unexpected behavior from handlers, and
	// underlying FileSystem errors.
	// If nil, logging is disabled.
	ErrorLog *slog.Logger

	// The maximum number of procs the server may spawn. use runtime.NumCPU() if empty
	MaxProcs int

	// SetAffinity sets the CPU affinity mask of current process.
	SetAffinity bool

	// The maximum number of concurrent clients the server may serve.
	Concurrency int
}

ForkServer implements a prefork DNS server.

func (*ForkServer) Index

func (s *ForkServer) Index() (index int)

Index indicates the index of Server instances.

func (*ForkServer) ListenAndServe

func (s *ForkServer) ListenAndServe(addr string) error

ListenAndServe serves DNS requests from the given UDP addr.

type HTTPDialer added in v0.9.1

type HTTPDialer struct {
	// Endpoint specifies the HTTP server's URL that the dialer will connect to.
	// This is the base address used for sending HTTP requests.
	Endpoint *url.URL

	// Transport allows for customizing the underlying transport mechanism used
	// for making HTTP requests. If set, it overrides the default RoundTripper behavior.
	Transport http.RoundTripper

	// Header defines the request header that will be sent in the HTTP requests.
	// It can be customized for specific needs, E.g. User-Agent.
	Header http.Header
	// contains filtered or unexported fields
}

HTTPDialer is a custom dialer for creating HTTP connections. It allows sending HTTP requests with a specified endpoint, user agent, and transport configuration.

func (*HTTPDialer) DialContext added in v0.9.1

func (d *HTTPDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error)

DialContext returns an HTTP connection wrapper for DNS-over-HTTPS queries.

func (*HTTPDialer) Put added in v0.10.0

func (d *HTTPDialer) Put(conn net.Conn)

Put releases the HTTP connection wrapper back to the pool.

type Handler

type Handler interface {
	ServeDNS(rw ResponseWriter, req *Message)
}

Handler is implemented by any value that implements ServeDNS.

type MemResponseWriter added in v0.6.3

type MemResponseWriter struct {
	Data  []byte
	Raddr netip.AddrPort
	Laddr netip.AddrPort
}

MemResponseWriter is an implementation of ResponseWriter that supports write response to memory.

func (*MemResponseWriter) LocalAddr added in v0.6.3

func (rw *MemResponseWriter) LocalAddr() netip.AddrPort

LocalAddr returns the netip.AddrPort of the server

func (*MemResponseWriter) RemoteAddr added in v0.6.3

func (rw *MemResponseWriter) RemoteAddr() netip.AddrPort

RemoteAddr returns the netip.AddrPort of the client that sent the current request.

func (*MemResponseWriter) Write added in v0.6.3

func (rw *MemResponseWriter) Write(p []byte) (n int, err error)

Write writes a raw buffer back to the memory buffer.

type Message added in v0.3.0

type Message struct {
	// Raw refers to the raw query packet.
	Raw []byte

	// Domain represents to the parsed query domain in the query.
	Domain []byte

	// Header encapsulates the construct of the header part of the DNS query message.
	// It follows the conventions stated at RFC1035 section 4.1.1.
	Header struct {
		// ID is an arbitrary 16bit request identifier that is
		// forwarded back in the response so that we can match them up.
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                      ID                       |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		ID uint16

		// Flags is an arbitrary 16bit represents QR, Opcode, AA, TC, RD, RA, Z and RCODE.
		//
		//   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		Flags Flags

		// QDCOUNT specifies the number of entries in the question section
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                    QDCOUNT                    |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		QDCount uint16

		// ANCount specifies the number of resource records (RR) in the answer section
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                    ANCOUNT                    |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		ANCount uint16

		// NSCount specifies the number of name server resource records in the authority section
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                    NSCOUNT                    |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		NSCount uint16

		// ARCount specifies the number of resource records in the additional records section
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                    ARCOUNT                    |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		ARCount uint16
	}

	// Question encapsulates the construct of the question part of the DNS query message.
	// It follows the conventions stated at RFC1035 section 4.1.2.
	Question struct {
		// Name refers to the raw query name to be resolved in the query.
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                                               |
		// /                     QNAME                     /
		// /                                               /
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		Name []byte

		// Type specifies the type of the query to perform.
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                     QTYPE                     |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		Type Type

		// Class specifies the class of the query to perform.
		//
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		// |                     QCLASS                    |
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		Class Class
	}
}

Message represents an DNS request received by a server or to be sent by a client.

func AcquireMessage added in v0.3.0

func AcquireMessage() *Message

AcquireMessage retrieves a reusable Message from the pool.

func (*Message) AppendCNAME added in v0.15.2

func (msg *Message) AppendCNAME(ttl uint32, cnames []string, ips []netip.Addr)

AppendCNAME appends the CNAME and Host records to msg.

func (*Message) AppendHOST added in v0.15.2

func (msg *Message) AppendHOST(ttl uint32, ips []netip.Addr)

AppendHOST appends the Host records to msg.

func (*Message) AppendHOST1 added in v0.15.2

func (msg *Message) AppendHOST1(ttl uint32, ip netip.Addr)

AppendHOST1 appends a Host records to msg.

func (*Message) AppendMX added in v0.15.2

func (msg *Message) AppendMX(ttl uint32, mxs []net.MX)

AppendMX appends the MX records to msg.

func (*Message) AppendNS added in v0.15.2

func (msg *Message) AppendNS(ttl uint32, nameservers []net.NS)

AppendNS appends the NS records to msg.

func (*Message) AppendPTR added in v0.15.2

func (msg *Message) AppendPTR(ttl uint32, ptr string)

AppendPTR appends the PTR records to msg.

func (*Message) AppendSOA added in v0.15.2

func (msg *Message) AppendSOA(ttl uint32, mname, rname net.NS, serial, refresh, retry, expire, minimum uint32)

AppendSOA appends the SOA records to msg.

func (*Message) AppendSRV added in v0.15.2

func (msg *Message) AppendSRV(ttl uint32, srvs []net.SRV)

AppendSRV appends the SRV records to msg.

func (*Message) AppendTXT added in v0.15.2

func (msg *Message) AppendTXT(ttl uint32, txt string)

AppendTXT appends the TXT records to msg.

func (*Message) DecodeName added in v0.3.3

func (msg *Message) DecodeName(dst []byte, name []byte) ([]byte, error)

DecodeName decodes dns labels to dst.

func (*Message) OptionsAppender added in v0.14.0

func (msg *Message) OptionsAppender() (moa MessageOptionsAppender, err error)

OptionsAppender constructs an EDNS options appender for the message.

func (*Message) Records added in v0.11.0

func (msg *Message) Records() (records MessageRecords)

Records returns the message records in their original wire order.

func (*Message) SetRequestQuestion added in v0.8.2

func (msg *Message) SetRequestQuestion(domain string, typ Type, class Class)

SetRequestQuestion primes the message with a standard DNS query header and question.

func (*Message) SetResponseHeader added in v0.6.2

func (msg *Message) SetResponseHeader(rcode Rcode, ancount uint16)

SetResponseHeader sets QR=1, RCODE=rcode, ANCount=ancount then updates Raw.

type MessageOption added in v0.14.0

type MessageOption struct {
	Code OptionCode
	Data []byte
}

func (MessageOption) AsCookie added in v0.15.0

func (o MessageOption) AsCookie(dst []byte) ([]byte, error)

AsCookie decodes a COOKIE option payload.

func (MessageOption) AsPadding added in v0.15.0

func (o MessageOption) AsPadding(dst []byte) ([]byte, error)

AsPadding returns the padding option payload.

func (MessageOption) AsSubnet added in v0.15.0

func (o MessageOption) AsSubnet() (netip.Prefix, error)

AsSubnet decodes an ECS option into a subnet prefix.

type MessageOptions added in v0.14.0

type MessageOptions struct {
	Type    Type
	UDPSize uint16
	Rcode   Rcode
	Version byte
	Flags   uint16
	// contains filtered or unexported fields
}

func (*MessageOptions) Err added in v0.14.0

func (o *MessageOptions) Err() error

Err reports the iteration error.

func (*MessageOptions) Item added in v0.14.0

func (o *MessageOptions) Item() MessageOption

Item returns the current option.

func (*MessageOptions) Next added in v0.14.0

func (o *MessageOptions) Next() bool

Next advances to the next available option.

type MessageOptionsAppender added in v0.14.0

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

func (*MessageOptionsAppender) AppendCookie added in v0.15.0

func (a *MessageOptionsAppender) AppendCookie(cookie string)

AppendCookie adds a COOKIE option to the message.

func (*MessageOptionsAppender) AppendPadding added in v0.14.0

func (a *MessageOptionsAppender) AppendPadding(padding uint16)

AppendPadding grows the message with a padding option.

func (*MessageOptionsAppender) AppendSubnet added in v0.15.0

func (a *MessageOptionsAppender) AppendSubnet(prefix netip.Prefix)

AppendSubnet adds an ECS option for the given prefix.

type MessageRecord added in v0.11.1

type MessageRecord struct {
	Name  []byte
	Type  Type
	Class Class
	TTL   uint32
	Data  []byte
}

func (*MessageRecord) AsOptions added in v0.15.0

func (r *MessageRecord) AsOptions() (options MessageOptions, err error)

AsOptions converts an OPT record into message options.

type MessageRecords added in v0.13.0

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

func (*MessageRecords) Err added in v0.13.1

func (r *MessageRecords) Err() error

Err reports the first error encountered during iteration.

func (*MessageRecords) Item added in v0.13.0

func (r *MessageRecords) Item() MessageRecord

Item returns the current resource record.

func (*MessageRecords) Next added in v0.13.0

func (r *MessageRecords) Next() bool

Next advances to the next resource record and reports whether one exists.

type NetHTTPS added in v0.9.3

type NetHTTPS struct {
	ALPN          []string
	NoDefaultALPN bool
	Port          uint32
	IPv4Hint      []netip.Addr
	IPv6Hint      []netip.Addr
	ECH           []byte
}

type Opcode

type Opcode byte

Opcode denotes a 4bit field that specified the query type.

const (
	OpcodeQuery  Opcode = 0
	OpcodeIQuery Opcode = 1
	OpcodeStatus Opcode = 2
	OpcodeNotify Opcode = 4
	OpcodeUpdate Opcode = 5
)

Wire constants and supported types.

func (Opcode) String

func (c Opcode) String() string

String returns the textual opcode name.

type OptionCode added in v0.14.0

type OptionCode uint16
const (
	OptionCodeNSID      OptionCode = 3
	OptionCodeDAU       OptionCode = 5
	OptionCodeDHU       OptionCode = 6
	OptionCodeN3U       OptionCode = 7
	OptionCodeECS       OptionCode = 8
	OptionCodeEXPIRE    OptionCode = 9
	OptionCodeCOOKIE    OptionCode = 10
	OptionCodeKeepalive OptionCode = 11
	OptionCodePadding   OptionCode = 12
)

type Rcode

type Rcode byte

Rcode denotes a 4bit field that specifies the response code for a query.

const (
	RcodeNoError   Rcode = 0  // No Error                          [DNS]
	RcodeFormErr   Rcode = 1  // Format Error                      [DNS]
	RcodeServFail  Rcode = 2  // Server Failure                    [DNS]
	RcodeNXDomain  Rcode = 3  // Non-Existent Domain               [DNS]
	RcodeNotImp    Rcode = 4  // Not Implemented                   [DNS]
	RcodeRefused   Rcode = 5  // Query Refused                     [DNS]
	RcodeYXDomain  Rcode = 6  // Name Exists when it should not    [DNS Update]
	RcodeYXRRSet   Rcode = 7  // RR Set Exists when it should not  [DNS Update]
	RcodeNXRRSet   Rcode = 8  // RR Set that should exist does not [DNS Update]
	RcodeNotAuth   Rcode = 9  // Server Not Authoritative for zone [DNS Update]
	RcodeNotZone   Rcode = 10 // Name not contained in zone        [DNS Update/TSIG]
	RcodeBADSIG    Rcode = 16 // TSIG Signature Failure            [TSIG]
	RcodeBADVERS   Rcode = 16 // Bad OPT Version                   [EDNS0]
	RcodeBADKEY    Rcode = 17 // Key not recognized                [TSIG]
	RcodeBADTIME   Rcode = 18 // Signature out of time window      [TSIG]
	RcodeBADMODE   Rcode = 19 // Bad TKEY Mode                     [TKEY]
	RcodeBADNAME   Rcode = 20 // Duplicate key name                [TKEY]
	RcodeBADALG    Rcode = 21 // Algorithm not supported           [TKEY]
	RcodeBADTRUNC  Rcode = 22 // Bad Truncation                    [TSIG]
	RcodeBADCOOKIE Rcode = 23 // Bad/missing Server Cookie         [DNS Cookies]
)

Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml

func ParseRcode added in v0.12.3

func ParseRcode(rcode string) (Rcode, error)

ParseRcode maps the provided text to a defined Rcode.

func (Rcode) String

func (c Rcode) String() string

String returns the canonical text form of the Rcode value.

type ResponseWriter

type ResponseWriter interface {
	// LocalAddr returns the netip.AddrPort of the server
	LocalAddr() netip.AddrPort

	// RemoteAddr returns the netip.AddrPort of the client that sent the current request.
	RemoteAddr() netip.AddrPort

	// Write writes a raw buffer back to the client.
	Write([]byte) (int, error)
}

A ResponseWriter interface is used by an DNS handler to construct an DNS response.

type Server

type Server struct {
	// handler to invoke
	Handler Handler

	// Stats to invoke
	Stats Stats

	// ErrorLog specifies an optional logger for errors accepting
	// connections, unexpected behavior from handlers, and
	// underlying FileSystem errors.
	// If nil, logging is disabled.
	ErrorLog *slog.Logger

	// The maximum number of procs the server may spawn. use runtime.NumCPU() if empty
	MaxProcs int

	// The maximum number of concurrent clients the server may serve.
	Concurrency int
	// contains filtered or unexported fields
}

Server implements a mutli-listener DNS server.

func (*Server) Index

func (s *Server) Index() (index int)

Index indicates the index of Server instances.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(addr string) error

ListenAndServe serves DNS requests from the given UDP addr.

func (*Server) Serve added in v0.12.1

func (s *Server) Serve(conn *net.UDPConn) error

Serve serves DNS requests from the given UDP addr.

type Stats added in v0.6.0

type Stats interface {
	UpdateStats(addr netip.AddrPort, msg *Message, duration time.Duration)
	AppendOpenMetrics(dst []byte) []byte
}

type TCPDialer added in v0.12.0

type TCPDialer struct {
	// Addr specifies the remote TLS address that the dialer will connect to.
	Addr *net.TCPAddr

	// TLSConfig specifies the *tls.Config for TLS handshakes.
	// If set, use DoT instead of TCP protocol.
	TLSConfig *tls.Config

	// Timeout specifies the maximum duration for a query to complete.
	// If a query exceeds this duration, it will result in a timeout error.
	Timeout time.Duration

	// MaxConns limits the maximum number of TLS connections that can be created
	// and reused. Once this limit is reached, no new connections will be made.
	// If not set, use 8 as default.
	MaxConns uint16
	// contains filtered or unexported fields
}

TCPDialer is a custom dialer for creating TLS connections. It manages a pool of connections to optimize performance in scenarios where multiple TLS connections to the same server are required.

func (*TCPDialer) DialContext added in v0.12.0

func (d *TCPDialer) DialContext(ctx context.Context, network, addr string) (conn net.Conn, err error)

DialContext returns a pooled TCP or TLS connection based on the dialer settings.

func (*TCPDialer) Put added in v0.12.2

func (d *TCPDialer) Put(conn net.Conn)

Put returns the TCP connection wrapper to the pool.

type Type

type Type uint16

Type is a DNS type.

const (
	TypeNone       Type = 0
	TypeA          Type = 1
	TypeNS         Type = 2
	TypeMD         Type = 3
	TypeMF         Type = 4
	TypeCNAME      Type = 5
	TypeSOA        Type = 6
	TypeMB         Type = 7
	TypeMG         Type = 8
	TypeMR         Type = 9
	TypeNULL       Type = 10
	TypePTR        Type = 12
	TypeHINFO      Type = 13
	TypeMINFO      Type = 14
	TypeMX         Type = 15
	TypeTXT        Type = 16
	TypeRP         Type = 17
	TypeAFSDB      Type = 18
	TypeX25        Type = 19
	TypeISDN       Type = 20
	TypeRT         Type = 21
	TypeNSAPPTR    Type = 23
	TypeSIG        Type = 24
	TypeKEY        Type = 25
	TypePX         Type = 26
	TypeGPOS       Type = 27
	TypeAAAA       Type = 28
	TypeLOC        Type = 29
	TypeNXT        Type = 30
	TypeEID        Type = 31
	TypeNIMLOC     Type = 32
	TypeSRV        Type = 33
	TypeATMA       Type = 34
	TypeNAPTR      Type = 35
	TypeKX         Type = 36
	TypeCERT       Type = 37
	TypeDNAME      Type = 39
	TypeOPT        Type = 41 // EDNS
	TypeAPL        Type = 42
	TypeDS         Type = 43
	TypeSSHFP      Type = 44
	TypeRRSIG      Type = 46
	TypeNSEC       Type = 47
	TypeDNSKEY     Type = 48
	TypeDHCID      Type = 49
	TypeNSEC3      Type = 50
	TypeNSEC3PARAM Type = 51
	TypeTLSA       Type = 52
	TypeSMIMEA     Type = 53
	TypeHIP        Type = 55
	TypeNINFO      Type = 56
	TypeRKEY       Type = 57
	TypeTALINK     Type = 58
	TypeCDS        Type = 59
	TypeCDNSKEY    Type = 60
	TypeOPENPGPKEY Type = 61
	TypeCSYNC      Type = 62
	TypeZONEMD     Type = 63
	TypeSVCB       Type = 64
	TypeHTTPS      Type = 65
	TypeSPF        Type = 99
	TypeUINFO      Type = 100
	TypeUID        Type = 101
	TypeGID        Type = 102
	TypeUNSPEC     Type = 103
	TypeNID        Type = 104
	TypeL32        Type = 105
	TypeL64        Type = 106
	TypeLP         Type = 107
	TypeEUI48      Type = 108
	TypeEUI64      Type = 109
	TypeURI        Type = 256
	TypeCAA        Type = 257
	TypeAVC        Type = 258
	TypeTKEY       Type = 249
	TypeTSIG       Type = 250
	TypeIXFR       Type = 251
	TypeAXFR       Type = 252
	TypeMAILB      Type = 253
	TypeMAILA      Type = 254
	TypeANY        Type = 255
	TypeTA         Type = 32768
	TypeDLV        Type = 32769
	TypeReserved   Type = 65535
)

Wire constants and supported types.

func ParseType added in v0.4.1

func ParseType(s string) (t Type)

ParseType converts a question type string into a question type value.

func (Type) String

func (t Type) String() string

String returns the mnemonic for the DNS record type.

type UDPDialer added in v0.10.1

type UDPDialer struct {
	// Addr specifies the remote UDP address that the dialer will connect to.
	Addr *net.UDPAddr

	// MaxConns limits the maximum number of UDP connections that can be created
	// and reused. Once this limit is reached, no new connections will be made.
	// If not set, use 64 as default.
	MaxConns uint16
	// contains filtered or unexported fields
}

UDPDialer is a custom dialer for creating UDP connections. It manages a pool of connections to optimize performance in scenarios where multiple UDP connections to the same server are required.

func (*UDPDialer) DialContext added in v0.10.1

func (d *UDPDialer) DialContext(ctx context.Context, network, addr string) (conn net.Conn, err error)

DialContext returns a pooled UDP connection for the requested network.

func (*UDPDialer) Put added in v0.10.1

func (d *UDPDialer) Put(conn net.Conn)

Put returns the UDP connection to the pool for reuse.

Directories

Path Synopsis
cmd
fastdig command
fastdoh module
fastdoh module

Jump to

Keyboard shortcuts

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