mockdns

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Mar 26, 2026 License: MIT Imports: 12 Imported by: 9

README

go-mockdns

Reference

Boilerplate for testing of code involving DNS lookups, including unholy hacks to redirect net.Lookup* calls.

Example

Trivial mock resolver, for cases where tested code supports custom resolvers:

r := mockdns.Resolver{
    Zones: map[string]mockdns.Zone{
        "example.org.": {
            A: []string{"1.2.3.4"},
        },
    },
}

addrs, err := r.LookupHost(context.Background(), "example.org")
fmt.Println(addrs, err)

// Output:
// [1.2.3.4] <nil>

Unholy hack for cases where it doesn't:

srv, _ := mockdns.NewServer(map[string]mockdns.Zone{
    "example.org.": {
        A: []string{"1.2.3.4"},
    },
}, false)
defer srv.Close()

srv.PatchNet(net.DefaultResolver)
defer mockdns.UnpatchNet(net.DefaultResolver)

addrs, err := net.LookupHost("example.org")
fmt.Println(addrs, err)

// Output:
// [1.2.3.4] <nil>

Note, if you need to replace net.Dial calls and tested code supports custom net.Dial, patch the resolver object inside it instead of net.DefaultResolver. If tested code supports Dialer-like objects - use Resolver itself, it implements Dial and DialContext methods.

Documentation

Index

Examples

Constants

View Source
const (
	RRTypeA     = dns.TypeA
	RRTypeAAAA  = dns.TypeAAAA
	RRTypeCNAME = dns.TypeCNAME
	RRTypeMX    = dns.TypeMX
	RRTypeNS    = dns.TypeNS
	RRTypePTR   = dns.TypePTR
	RRTypeSRV   = dns.TypeSRV
	RRTypeTXT   = dns.TypeTXT
)

These constants are re-exported from github.com/miekg/dns for convenience, so that users of this package don't need to import github.com/miekg/dns just for these.

Variables

This section is empty.

Functions

func UnpatchNet

func UnpatchNet(r *net.Resolver)

Types

type Logger

type Logger interface {
	Printf(f string, args ...interface{})
}

type Resolver

type Resolver struct {
	Zones map[string]Zone

	// Don't follow CNAME in Zones for Lookup*.
	SkipCNAME bool
}

Resolver is the struct that implements interface same as net.Resolver and so can be used as a drop-in replacement for it if tested code supports it.

Example
package main

import (
	"context"
	"fmt"

	"github.com/foxcpp/go-mockdns"
)

func main() {
	// Use for code that supports custom resolver implementations.
	r := mockdns.Resolver{
		Zones: map[string]mockdns.Zone{
			"example.org.": {
				A: []string{"1.2.3.4"},
			},
		},
	}

	addrs, err := r.LookupHost(context.Background(), "example.org")
	fmt.Println(addrs, err)

}
Output:
[1.2.3.4] <nil>

func (*Resolver) Dial

func (r *Resolver) Dial(network, addr string) (net.Conn, error)

Dial implements the function similar to net.Dial that uses Resolver zones to find the the IP address to use. It is very simple and does not fully replicate the net.Dial behavior. Notably it does not implement Fast Fallback and always prefers IPv6 over IPv4.

func (*Resolver) DialContext

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

func (*Resolver) LookupAddr

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

func (*Resolver) LookupCNAME

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

func (*Resolver) LookupHost

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

func (*Resolver) LookupIP added in v1.1.0

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 added in v1.1.0

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) (port int, err error)

func (*Resolver) LookupSRV

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

func (*Resolver) LookupTXT

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

type Server

type Server struct {
	Log           Logger
	Authoritative bool
	// contains filtered or unexported fields
}

Server is the wrapper that binds Resolver to the DNS server implementation from github.com/miekg/dns. This allows it to be used as a replacement resolver for testing code that doesn't support DNS callbacks. See PatchNet.

func NewServer

func NewServer(zones map[string]Zone, authoritative bool) (*Server, error)

func NewServerWithLogger

func NewServerWithLogger(zones map[string]Zone, l Logger, authoritative bool) (*Server, error)

func (*Server) AppendRR added in v1.3.0

func (s *Server) AppendRR(name string, rrType uint16, rrData string) error

AppendRR appends a resource record to the zone for the given name. If the zone does not exist, it is created. For RR types that only support a single value (CNAME), the existing value is replaced. The function is thread-safe.

func (*Server) Close

func (s *Server) Close() error

func (*Server) LocalAddr

func (s *Server) LocalAddr() net.Addr

LocalAddr returns the local endpoint used by the server. It will always be *net.UDPAddr, however it is also usable for TCP connections.

func (*Server) NewResolver added in v1.3.0

func (s *Server) NewResolver() *net.Resolver

NewResolver returns a new net.Resolver instance patched to connect to this Server.

func (*Server) PatchNet

func (s *Server) PatchNet(r *net.Resolver)

PatchNet configures net.Resolver instance to use this Server object.

Use UnpatchNet to revert changes.

Example
package main

import (
	"fmt"
	"net"

	"github.com/foxcpp/go-mockdns"
)

func main() {
	// Use for code that directly calls net.Lookup*.
	srv, _ := mockdns.NewServer(map[string]mockdns.Zone{
		"example.org.": {
			A: []string{"1.2.3.4"},
		},
	}, false)
	defer srv.Close()

	srv.PatchNet(net.DefaultResolver)
	// Important if net.DefaultResolver is modified.
	defer mockdns.UnpatchNet(net.DefaultResolver)

	addrs, err := net.LookupHost("example.org")
	fmt.Println(addrs, err)

}
Output:
[1.2.3.4] <nil>

func (*Server) RemoveRR added in v1.3.0

func (s *Server) RemoveRR(name string, rrType uint16)

RemoveRR removes all records of the given type from the zone for the given name. If the zone becomes empty, it is removed. The function is thread-safe.

func (*Server) Reset added in v1.3.0

func (s *Server) Reset()

Reset removes all zones from the server. The function is thread-safe.

func (*Server) Resolver deprecated

func (s *Server) Resolver() *Resolver

Deprecated: use NewResolver() instead.

func (*Server) ServeDNS

func (s *Server) ServeDNS(w dns.ResponseWriter, m *dns.Msg)

ServeDNS implements miekg/dns.Handler. It responds with values from underlying Resolver object.

type Zone

type Zone struct {
	// Return the specified error on any lookup using this zone.
	// For Server, non-nil value results in SERVFAIL response.
	Err error

	// When used with Server, set the Authenticated Data (AD) flag
	// in the responses.
	AD bool

	A     []string
	AAAA  []string
	TXT   []string
	PTR   []string
	CNAME string
	MX    []net.MX
	NS    []net.NS
	SRV   []net.SRV

	// Misc includes other associated zone records, they can be returned only
	// when used with Server.
	Misc map[dns.Type][]dns.RR
}

Jump to

Keyboard shortcuts

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