dnsclient

package
v1.7.2 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package dnsclient owns SDNS's upstream DNS transport: wire framing, buffer pooling, dialing, deadlines and exchange policy (ID match, question-section guard, UDP->TCP truncation fallback). It is written clean-room and depends on github.com/miekg/dns only as the message codec (dns.Msg / Pack / Unpack), not as a transport.

Index

Constants

This section is empty.

Variables

View Source
var ErrQuestion = errors.New("dns: response question did not match request")

ErrQuestion is returned by (*Conn).Exchange when the response's question section does not match the outstanding request. Accepting a mismatched question lets a malicious upstream plant a cache entry under an unrelated name (issue #469).

Functions

func AcquireBuf

func AcquireBuf(size uint16) []byte

AcquireBuf returns a buffer from the appropriate pool.

func QuestionMatches

func QuestionMatches(req dns.Question, resp []dns.Question) bool

QuestionMatches reports whether the response's question section answers the outstanding request question. DNS names are compared case-insensitively because they are not case-sensitive on the wire.

func ReleaseBuf

func ReleaseBuf(buf []byte)

ReleaseBuf returns buf to the appropriate pool.

Types

type Client

type Client struct {
	Proto     string        // "udp" | "tcp" | "tcp-tls" | "doh"; empty means "udp"
	Timeout   time.Duration // per-exchange dial+read+write budget; 0 means none
	TLSConfig *tls.Config   // DoT (tcp-tls) server config
	DoHURL    string        // DoH endpoint URL
	DoHClient *http.Client  // DoH HTTP client (reused transport / HTTP2 pool)

	// SkipQuestionCheck disables the response question-section guard.
	// The guard is on by default; leave this false unless a caller has
	// a specific reason to accept mismatched questions.
	SkipQuestionCheck bool
}

Client is a high-level, dial-per-Exchange DNS client for callers that don't maintain their own connection pool — the forwarder, failover, and the config IPv6 probe. The resolver hot path uses Conn directly so it keeps its own pooling, circuit breaker and retry policy.

The zero value with Proto unset behaves as plain UDP. The question- section guard is on by default; the response transaction ID is always validated.

func (*Client) Exchange

func (c *Client) Exchange(ctx context.Context, req *dns.Msg, addr string) (*dns.Msg, time.Duration, error)

Exchange sends req to addr over c.Proto and returns the validated response. A truncated UDP answer transparently retries over TCP.

type Conn

type Conn struct {
	net.Conn        // underlying connection
	UDPSize  uint16 // minimum receive buffer for UDP messages
}

Conn represents a connection to a DNS server. It wraps a net.Conn (either a connected UDP socket or a TCP/TLS stream) and tracks the negotiated UDP receive size.

func (*Conn) Exchange

func (co *Conn) Exchange(m *dns.Msg) (r *dns.Msg, rtt time.Duration, err error)

Exchange performs a synchronous query over co: it writes m, reads the response, and validates the transaction ID and question section. The caller is responsible for dialing co and setting any deadline before calling Exchange.

func (*Conn) Read

func (co *Conn) Read(p []byte) (n int, err error)

Read implements net.Conn. For a UDP connection it reads a single datagram. For a stream connection it reads the 2-byte length prefix (RFC 1035 §4.2.2) and then exactly that many bytes into p.

func (*Conn) ReadMsg

func (co *Conn) ReadMsg() (*dns.Msg, error)

ReadMsg reads a single DNS message from co. The buffer is always returned to the pool, even on a timed-out UDP read or a truncated TCP read, so failed upstream reads never leak the buffer. On success only the bytes actually read are unpacked — feeding Unpack the trailing capacity of a pooled UDP buffer would let stale bytes from a previous use bleed into the parsed message.

func (*Conn) Write

func (co *Conn) Write(p []byte) (int, error)

Write implements net.Conn. For UDP it writes p as a single datagram. For a stream connection it prefixes p with its 2-byte length.

func (*Conn) WriteMsg

func (co *Conn) WriteMsg(m *dns.Msg) (err error)

WriteMsg packs m into a pooled buffer and writes it to co.

Jump to

Keyboard shortcuts

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