dns

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: May 22, 2026 License: CC0-1.0 Imports: 16 Imported by: 0

Documentation

Overview

Package dns provides a channel-based DNS message interface and adapters for composing DNS providers, consumers, and middleware.

The central contract is Interface. Implementations expose a request channel; every Request carries its own context and reply channel, so callers can cancel one request without closing the whole provider. Providers and middleware are safe for concurrent consumers unless a concrete type documents otherwise.

The package includes detached middleware, a request router, resolver adapters, an in-memory cache middleware, a simple UDP/TCP DNS client, and a simple UDP DNS server. These pieces are intentionally small and composable so callers can build chains or trees such as resolver adapters feeding shared cache middleware that fans out to local or remote DNS transports.

Index

Constants

View Source
const (
	TypeA     uint16 = 1
	TypeNS    uint16 = 2
	TypeCNAME uint16 = 5
	TypeSOA   uint16 = 6
	TypePTR   uint16 = 12
	TypeMX    uint16 = 15
	TypeTXT   uint16 = 16
	TypeAAAA  uint16 = 28
	TypeSRV   uint16 = 33

	ClassIN uint16 = 1

	OpcodeQuery uint8 = 0

	RCodeSuccess        uint8 = 0
	RCodeFormatError    uint8 = 1
	RCodeServerFailure  uint8 = 2
	RCodeNameError      uint8 = 3
	RCodeNotImplemented uint8 = 4
)

Variables

View Source
var (
	// ErrNoUpstream is returned when middleware has no wrapped DNS interface.
	ErrNoUpstream = errors.New("dns: no upstream attached")
	// ErrClosed is returned by providers and middleware after Close.
	ErrClosed = net.ErrClosed
)
View Source
var ErrInvalidBackendName = errors.New("dns: invalid backend name")

ErrInvalidBackendName is returned when a backend mutation uses an empty name.

Functions

func NextID

func NextID() uint16

NextID returns the next value of a process-wide cycling DNS message ID counter. The counter is safe for concurrent use. It is intended for correlation, not for cryptographic randomness.

func Pack

func Pack(m *Message) ([]byte, error)

Pack converts m to a DNS wire-format packet.

Types

type Cache

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

Cache is a DNS middleware that caches successful responses and forwards misses to an attachable upstream. Detach cancels requests that are currently waiting on the old upstream. Cached responses remain available across attach, detach, and reattach operations.

func NewCache

func NewCache(upstream Interface, storage CacheStorage) *Cache

NewCache creates a cache using storage. If storage is nil, a new MemoryStorage is used.

func (*Cache) Attach

func (c *Cache) Attach(upstream Interface)

Attach replaces the upstream DNS interface. Existing requests going through a previous upstream are canceled before the new upstream is installed.

func (*Cache) Close

func (c *Cache) Close() error

func (*Cache) Detach

func (c *Cache) Detach()

Detach removes the upstream and cancels in-flight miss lookups. Cached hits continue to be served.

func (*Cache) Requests

func (c *Cache) Requests() chan<- Request

type CacheStorage

type CacheStorage interface {
	Get(key string, now time.Time) (*Message, bool)
	Set(key string, msg *Message, now time.Time)
	Delete(key string)
}

CacheStorage stores DNS messages by cache key. Implementations must be safe for concurrent callers when shared by multiple Cache values.

type Client

type Client struct {
	// TLSConfig configures TLS for dot:// upstreams. The config is cloned for
	// each connection. If ServerName is empty, the URL host is used.
	TLSConfig *tls.Config
	// contains filtered or unexported fields
}

Client is a simple DNS client for udp://, tcp://, and dot:// servers.

It sends supported DNS query messages to the configured servers and returns the first successful wire response. The client allocates a fresh wire ID for every upstream request and maps the response ID back to the caller's message ID before replying.

func NewClient

func NewClient(dial gonnect.Dial, servers ...string) *Client

NewClient creates a DNS client using dial and server URLs. If dial is nil, net.Dialer.DialContext is used. Supported schemes are udp, tcp, and dot.

func (*Client) Close

func (c *Client) Close() error

func (*Client) Requests

func (c *Client) Requests() chan<- Request

type Detached

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

Detached is an independently closable wrapper around another DNS Interface.

Closing the detached wrapper cancels requests that are currently passing through it but does not close the wrapped interface. Other users of the wrapped interface continue to operate normally.

func Detach

func Detach(upstream Interface) *Detached

Detach wraps upstream with independent close and cancellation state.

func (*Detached) Close

func (d *Detached) Close() error

func (*Detached) Requests

func (d *Detached) Requests() chan<- Request

type Interface

type Interface interface {
	Requests() chan<- Request
	Close() error
}

Interface is a concurrent, channel based DNS message transport.

Implementations accept request messages through Requests and respond through the per-request Reply channel. Close terminates the implementation and cancels in-flight work owned by that implementation. Callers may share one Interface between multiple goroutines.

type MemoryStorage

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

MemoryStorage is a simple map-backed CacheStorage implementation.

func NewMemoryStorage

func NewMemoryStorage() *MemoryStorage

NewMemoryStorage returns an empty in-memory cache storage.

func (*MemoryStorage) Delete

func (s *MemoryStorage) Delete(key string)

func (*MemoryStorage) Get

func (s *MemoryStorage) Get(key string, now time.Time) (*Message, bool)

func (*MemoryStorage) Set

func (s *MemoryStorage) Set(key string, msg *Message, now time.Time)

type Message

type Message struct {
	ID       uint16
	Response bool

	Opcode uint8
	RCode  uint8

	Authoritative      bool
	Truncated          bool
	RecursionDesired   bool
	RecursionAvailable bool
	AuthenticatedData  bool
	CheckingDisabled   bool

	Questions   []Question
	Answers     []Resource
	Authorities []Resource
	Additionals []Resource
}

Message is the package-level representation of a DNS message.

It intentionally models the message header and the four standard sections without tying callers to a concrete wire codec. Name values are regular DNS names; callers may use either absolute names with a trailing dot or relative presentation names.

func Query

func Query(ctx context.Context, d Interface, req *Message) (*Message, error)

Query sends req through d and waits for one response or cancellation.

func Unpack

func Unpack(pkt []byte) (*Message, error)

Unpack parses a DNS wire-format packet.

func (*Message) Copy

func (m *Message) Copy() *Message

Copy returns a deep copy of m. Nil receivers return nil.

type Question

type Question struct {
	Name  string
	Type  uint16
	Class uint16
}

Question identifies one DNS question.

type Request

type Request struct {
	Context RequestContext
	Message *Message
	Reply   chan<- Response
}

Request is the channel envelope used by DNS implementations. Context cancels only this request. Reply receives exactly one Response unless the provider has already been closed before it can accept the request.

type RequestContext

type RequestContext interface {
	context.Context
}

RequestContext is the subset of context.Context carried by a Request.

type Resolver

type Resolver struct {
	DNS Interface
}

Resolver adapts a DNS Interface into a full gonnect.Resolver.

func NewResolver

func NewResolver(d Interface) *Resolver

func (*Resolver) LookupAddr

func (r *Resolver) LookupAddr(
	ctx context.Context,
	addr string,
) ([]string, error)

func (*Resolver) LookupCNAME

func (r *Resolver) LookupCNAME(
	ctx context.Context,
	host string,
) (string, error)

func (*Resolver) LookupHost

func (r *Resolver) LookupHost(
	ctx context.Context,
	host string,
) ([]string, error)

func (*Resolver) LookupIP

func (r *Resolver) LookupIP(
	ctx context.Context,
	network, host string,
) ([]net.IP, error)

func (*Resolver) LookupIPAddr

func (r *Resolver) LookupIPAddr(
	ctx context.Context,
	host string,
) ([]net.IPAddr, error)

func (*Resolver) LookupMX

func (r *Resolver) LookupMX(
	ctx context.Context,
	name string,
) ([]*net.MX, error)

func (*Resolver) LookupNS

func (r *Resolver) LookupNS(
	ctx context.Context,
	name string,
) ([]*net.NS, error)

func (*Resolver) LookupNetIP

func (r *Resolver) LookupNetIP(
	ctx context.Context,
	network, host string,
) ([]netip.Addr, error)

func (*Resolver) LookupPort

func (r *Resolver) LookupPort(
	ctx context.Context,
	network, service string,
) (int, error)

func (*Resolver) LookupSRV

func (r *Resolver) LookupSRV(
	ctx context.Context,
	service, proto, name string,
) (string, []*net.SRV, error)

func (*Resolver) LookupTXT

func (r *Resolver) LookupTXT(
	ctx context.Context,
	name string,
) ([]string, error)

type ResolverProvider

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

ResolverProvider adapts a gonnect.Resolver into a DNS Interface.

It supports standard IN-class A, AAAA, PTR, CNAME, TXT, MX, NS, and SRV queries. Unsupported opcodes, classes, or record types are answered with RCodeNotImplemented. Resolver lookup failures are mapped to NameError when the resolver reports not-found and ServerFailure otherwise. Successful resource records use the configured TTL.

func NewResolverProvider

func NewResolverProvider(
	resolver gonnect.Resolver,
	ttl time.Duration,
) *ResolverProvider

NewResolverProvider returns a DNS provider backed by resolver.

func (*ResolverProvider) Close

func (r *ResolverProvider) Close() error

func (*ResolverProvider) Requests

func (r *ResolverProvider) Requests() chan<- Request

type Resource

type Resource struct {
	Name  string
	Type  uint16
	Class uint16
	TTL   uint32
	Data  []byte
}

Resource identifies one DNS resource record. Data stores record-specific payload in DNS wire format without the owner name, type, class, or TTL.

type Response

type Response struct {
	Message *Message
	Err     error
}

Response is delivered on a request's response channel.

type RouteFunc

type RouteFunc func(*Message) string

RouteFunc selects the backend name for a DNS request.

Returning an empty string or a name without an attached backend rejects the request with ErrNoUpstream.

type Router

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

Router is a DNS Interface that routes requests to named backend interfaces.

Backends and the route function can be attached, detached, or replaced while the Router is serving requests. Mutations cancel in-flight requests that were routed through an older backend set or route function. Closing the Router cancels in-flight work owned by the Router but does not close attached backends.

func NewRouter

func NewRouter() *Router

NewRouter creates an empty DNS Router.

func (*Router) Attach

func (r *Router) Attach(name string, backend Interface) error

Attach installs backend under name. Passing nil is equivalent to Detach.

func (*Router) AttachRouter

func (r *Router) AttachRouter(route RouteFunc) error

AttachRouter installs or replaces the route function. Passing nil is equivalent to DetachRouter.

func (*Router) Close

func (r *Router) Close() error

func (*Router) Detach

func (r *Router) Detach(name string) error

Detach removes the backend named name.

func (*Router) DetachRouter

func (r *Router) DetachRouter() error

DetachRouter removes the route function.

func (*Router) Requests

func (r *Router) Requests() chan<- Request

func (*Router) SetRouter

func (r *Router) SetRouter(route RouteFunc) error

SetRouter installs or replaces the route function. Passing nil removes it.

type Server

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

Server is a simple UDP DNS server backed by a packet connection.

For every client packet it unpacks the DNS message, replaces the client's ID with a new internal ID before forwarding through the attached DNS Interface, then maps the response ID back to the original client ID. Attach and Detach can replace the upstream without closing the packet connection; detaching cancels requests currently waiting on the old upstream.

func NewServer

func NewServer(conn net.PacketConn, upstream Interface) *Server

NewServer starts serving DNS packets from conn.

func (*Server) Attach

func (s *Server) Attach(upstream Interface)

Attach replaces the upstream DNS interface and cancels requests using the previous upstream.

func (*Server) Close

func (s *Server) Close() error

func (*Server) Detach

func (s *Server) Detach()

Detach removes the upstream and cancels in-flight forwarded requests.

func (*Server) Requests

func (s *Server) Requests() chan<- Request

Jump to

Keyboard shortcuts

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