Help us shape the future of Go! Take the 2026 Go Developer Survey

dnse

package module
v0.0.0-...-a5dbc9d Latest Latest
Warning

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

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 25 Imported by: 0

README

dnse

This is a DNS library that extends the excellent miekg/dns library with some higher-level functionality.

The library provides:

  • A generalised configuration of name servers.
  • Zone-Verifier; a batteries included DNS Zone testing framework.
  • Utility functions simplifing working with DNS zones and records.

_demo

Contains a demonstration environment leveraging dnse to configure and run a set of name servers to show the functionality of zone-verifier.

cmd

Contains some tools that are useful when working with DNS.

gen-tsig : generates a TSIG key

zone-verifier : verifies a zone

zonediff : compares two zones

zonemd-generate : generates a zonemd for a DNS zone

zonemd-validate : validates all zonemd records in a DNS zone

gen-tsig

gen-tsig creates a TSIG key with the specified algorithm and name output in the BIND-style format:

key "name" {
  algorithm <algorithm>;
  secret    "<base64(key)>";
}
zone-verifier

Zone-verifier verifies a DNS zone based on the the configured test batteries in the zone-verifier.yaml file.

For details see the zoneverifier usage file.

zonediff

zonediff reads two DNS zones and computes the differences between them.

For details see the zonediff usage file.

zonemd-generate

zonemd-generate reads a DNS zone from a file, or STDIN if ZONEFILE is "-" or not supplied, and generates a ZONEMD record for the zone.

For details see the zonemd-generate usage file.

zonemd-validate

Zonemd-validate validates all ZONEMD resource records in a DNS zone.

For details see zonemd-validate usage file.

dnsclient

Contains a client type to simplify DNS client operations.

dnsserver

Contains a server type that wraps multiple miekg/dns listeners in a single server with a single handler.

nameserver

A common interface to configure and run a third-party DNS server, e.g. Knot DNS, NSD.

zone

Contains types and functions for working with zone files and zone transfers.

zoneverifier

Contains the code for the zone-verifier tool.

🤝 Contributing

We welcome contributions! Please see our CONTRIBUTING file for details on our code of conduct and the process for submitting pull requests.

📜 License

This project is distributed under the terms of the MIT license.

About The Swedish Internet Foundation

The Swedish Internet Foundation is an independent, private foundation that works for the positive development of the internet. We are responsible for the Swedish top-level domain .se and the operation of the top-level domain .nu, and our vision is that everyone in Sweden wants to, dares to and is able to use the internet.

Find more information at https://internetstiftelsen.se/en/

Documentation

Overview

Package dnse extends the excellent miekg/dns library with some higher-level functionality. The library provides:

  • A generalised configuration of name servers
  • Zone-Verifier; a batteries included DNS Zone testing framework.
  • Utility functions simplyfing working with DNS zones and records.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrIsNotWildcard is an error for when something was expected to be a
	// wildcard but wasn’t.
	ErrIsNotWildcard = errors.New("is not wildcard")

	// ErrIsWildcard is an error for when something was a wildcard but it
	// shouldn’t.
	ErrIsWildcard = errors.New("is wildcard")

	// ErrTooFewLabels is an error for when a [Name] contained too few labels
	// for some purpose.
	ErrTooFewLabels = errors.New("too few labels")
)

Functions

func AsRRs

func AsRRs[T dns.RR](in iter.Seq[T]) iter.Seq[dns.RR]

AsRRs converts an iterator of a specific RR type to an iterator of github.com/miekg/dns.RR.

func AsType

func AsType[T dns.RR](in iter.Seq[dns.RR]) iter.Seq[T]

AsType filters an iterator of github.com/miekg/dns.RR to an iterator of a specific RR type.

func IsNotWildcard

func IsNotWildcard(value any) error

IsNotWildcard is a github.com/go-ozzo/ozzo-validation/v4.RuleFunc that returns ErrIsWildcard if an IsWildcarder is a wildcard.

func IsWildcard

func IsWildcard(value any) error

IsWildcard is a github.com/go-ozzo/ozzo-validation/v4.RuleFunc that returns ErrIsNotWildcard if an IsWildcarder is not a wildcard.

func RcodeFromError deprecated

func RcodeFromError(err error) (rcode int, tsigError uint16)

RcodeFromError returns an RCODE (and a TSIG error) for an error.

Deprecated: Use SetMsgError instead. This function was a bad idea; an RCODE must be set before TSIG signing, so it made little sense.

func SerialGreater

func SerialGreater(a, b uint32) bool

SerialGreater returns true if a > b as per RFC 1982 §3.2 (with SERIAL_BITS = 32).

func SerialLess

func SerialLess(a, b uint32) bool

SerialLess returns true if a < b as per RFC 1982 §3.2 (with SERIAL_BITS = 32).

func SerialToTime

func SerialToTime(now time.Time, serial uint32) time.Time

SerialToTime converts an unsigned 32-bit integer into a time.Time using the wrapping arithmetic described in RFC 1982, i.e. the resulting time won’t be more than 2³²∕2 seconds (~68 years) before or after the ‘now’ time.

func SetMsgError

func SetMsgError(msg *dns.Msg, err error)

SetMsgError takes a DNS message (a response) and an error and sets a matching RCODE based on the error.

If the error is nil then the message is unchanged.

If the errors is, or wraps (see errors), an RcodeError then it is used as the RCODE. Otherwise the RCODE is guessed based on known errors from github.com/miekg/dns, falling back to ServFail (2).

If the message uses EDNS(0) and the error is, or wraps, one or more ExtendedDNSError then they are (all!) added as Extended DNS Errors (RFC 8914). This does not affect the RCODE.

To set set an Extended DNS Error and a specific RCODE use something like:

err = errors.Join(
	dnse.RcodeError(dns.RcodeServerFailure),
	dnse.ExtendedDNSError{
		InfoCode:  dns.ExtendedErrorCodeOther,
		ExtraText: fmt.Errorf("[…]"),
	},
)

func TimeToSerial

func TimeToSerial(t time.Time) uint32

TimeToSerial converts a time.Time (UTC) to an unsigned 32-bit integer by simple overflow, i.e. both 1970-01-01T00:00:00Z and 2106-02-07T06:28:16Z convert to 0.

func ValidateURIName

func ValidateURIName(rules ...validation.Rule) validation.RuleWithContextFunc

ValidateURIName returns a github.com/go-ozzo/ozzo-validation/v4.RuleWithContextFunc for validating a the name of a URI with some github.com/go-ozzo/ozzo-validation/v4.Rule.

func ValidateURINameIs

func ValidateURINameIs(name Name) validation.RuleWithContextFunc

ValidateURINameIs returns a github.com/go-ozzo/ozzo-validation/v4.RuleWithContextFunc for validating a the name of a URI is a certain name.

func WriteZoneFile

func WriteZoneFile(
	ctx context.Context,
	rrs iter.Seq[dns.RR],
	w io.Writer,
) (n int, err error)

WriteZoneFile reads records from a channel and writes them to a writer.

Types

type Comparer

type Comparer[T any] interface {
	Compare(T) int
}

Comparer is a generic type that can compare itself to other values of the same type.

type Equaler

type Equaler[T any] interface {
	Equal(T) bool
}

Equaler is something that can be equality-compared to other values.

type ExtendedDNSError

type ExtendedDNSError struct {
	InfoCode  uint16
	ExtraText error
}

ExtendedDNSError is an Extended DNS Error (see RFC 8914) that implements the error interface.

EXTRA-TEXT is an (optional) error, which can be unwrapped (ExtendedDNSError.Unwrap).

See also: SetMsgError.

func (ExtendedDNSError) Error

func (err ExtendedDNSError) Error() string

Error returns the INFO-CODE (string and number if known, otherwise just number) and EXTRA-TEXT (unless unset).

func (ExtendedDNSError) ToOption

func (err ExtendedDNSError) ToOption() dns.EDNS0

ToOption converts this ExtendedDNSError into a github.com/miekg/dns.EDNS0.

func (ExtendedDNSError) Unwrap

func (err ExtendedDNSError) Unwrap() error

Unwrap returns the wrapped error.

type IsWildcarder

type IsWildcarder interface {
	IsWildcard() bool
}

IsWildcarder is something that can be a wildcard.

type Label

type Label []byte

Label is a DNS label, i.e. part of a domain name. You can construct one from a string or byte slice, e.g:

label := dnse.Label("example")

Which is nice and simple, but there’s no guarantee that it is valid, or that any of its methods will work as intended. To get a valid label use ParseLabel or Label.ValidateWithContext.

func LabelFromUnicode

func LabelFromUnicode(str string) (Label, error)

LabelFromUnicode creates a Label from an IDN string. It will also validate the Label, see Label.ValidateWithContext.

func ParseLabel

func ParseLabel(str string) (Label, error)

ParseLabel parses a Label from a string. It validates (Label.ValidateWithContext), but does not to any IDN conversion, for that use LabelFromUnicode.

func (Label) AsName

func (l Label) AsName() Name

AsName returns a single-label Name.

func (Label) Compare

func (l Label) Compare(other Label) int

Compare compares this label (𝑎) to another label (𝑏) according to RFC 4034 §6.1, and returns

  • -1 if 𝑎 < 𝑏,
  • 0 if 𝑎 = 𝑏 and
  • 1 if 𝑎 > 𝑏.

func (Label) Equal

func (l Label) Equal(other Label) bool

Equal returns true if this Label is canonically the same as another Label.

func (Label) IsWildcard

func (l Label) IsWildcard() bool

IsWildcard returns true if this Label is a wildcard label, i.e. ‘*’.

func (Label) Len

func (l Label) Len() int

Len returns the number of octets in the Label.

func (Label) LogValue

func (l Label) LogValue() slog.Value

LogValue returns a log/slog.Value for logging this Label.

func (Label) MarshalText

func (l Label) MarshalText() (text []byte, err error)

MarshalText implements encoding.TextMarshaler. It simply returns the Label as-is, and cannot fail.

func (Label) Normal

func (l Label) Normal() Label

Normal returns a normalised version of the Label, i.e. all lower case.

func (Label) Octets

func (l Label) Octets() iter.Seq[byte]

Octets returns an iter.Seq of the octets (bytes) in the Label.

func (*Label) Set

func (l *Label) Set(str string) error

Set implements flag.Value. It validates, see Label.ValidateWithContext.

func (Label) String

func (l Label) String() string

String returns this Label as a string, as-is.

func (Label) ToUnicode

func (l Label) ToUnicode() (str string, err error)

ToUnicode returns an IDN string of this Label.

func (*Label) UnmarshalText

func (l *Label) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler. It validates, see Label.ValidateWithContext.

func (Label) Validate

func (l Label) Validate() error

Validate calls Label.ValidateWithContext.

func (Label) ValidateWithContext

func (l Label) ValidateWithContext(ctx context.Context) error

ValidateWithContext returns an error if the Label has less than 1 or more than 63 octets.

(The root label is never stored as a Label and is thus never validated.)

type LabelOrName

type LabelOrName interface {
	Name | Label
}

LabelOrName is a Label or Name.

type Lener

type Lener interface {
	Len() int
}

Lener is something that has a length.

type Name

type Name []byte

Name is a DNS domain name, represented as a list of octets with full stop-separated labels to the left of the root (empty) label.

You can create a Name from a byte slice or string, e.g:

name := dnse.Name("example.test")

Which is convenient, but doesn‘t guarantee that the Name is valid or that its methods will behave as expected. To get a valid Name use ParseName or Name.ValidateWithContext.

Notably, using a string or byte slice with a trailing full stop will result in an invalid Name, since it will think it has an (extra) empty label at the end.

func MustParseName

func MustParseName(str string) Name

MustParseName calls ParseName and panics on error.

func NameFromUnicode

func NameFromUnicode(str string) (Name, error)

NameFromUnicode parses a Name from an IDN string.

func ParseName

func ParseName(str string) (Name, error)

ParseName parses a Name from a string. It also validates the Name, see Name.ValidateWithContext. It correctly handles a trailing full stop, but does not do IDN parsing, for that use NameFromUnicode.

func (Name) AsLevel

func (n Name) AsLevel(level int) (Name, error)

AsLevel trims off the left-most labels of this Name to get a new name with the required number of (right-most) labels. If more labels are requested than this Name has, ErrTooFewLabels is returned.

func (Name) Compare

func (n Name) Compare(other Name) int

Compare compares this name (𝑎) to another name (𝑏) according to RFC 4034 §6.1 by comparing labels right-to-left, and when they are equal using Label.Compare, and returns

  • -1 if 𝑎 < 𝑏,
  • 0 if 𝑎 = 𝑏 and
  • 1 if 𝑎 > 𝑏.

func (Name) Equal

func (n Name) Equal(other Name) bool

Equal returns true if this Name is canonically equal to another Name.

func (Name) FQDN

func (n Name) FQDN() string

FQDN returns a fully qualified domain name string of this Name.

func (Name) IsRoot

func (n Name) IsRoot() bool

IsRoot returns true if this is the root (empty) Name.

func (Name) IsSub

func (n Name) IsSub(super Name) bool

IsSub returns true if this Name is a sub-domain of another Name.

See also:

func (Name) IsSuper

func (n Name) IsSuper(sub Name) bool

IsSuper returns true if this Name is a super-domain of another Name.

See also:

func (Name) IsWildcard

func (n Name) IsWildcard() bool

IsWildcard returns true if this is a wildcard Name.

func (Name) Labels

func (n Name) Labels() iter.Seq[Label]

Labels returns an iter.Seq that iterates individual Label in this Name, left-to-right (bottom-to-top).

See also: Name.LabelsReverse.

func (Name) LabelsReverse

func (n Name) LabelsReverse() iter.Seq[Label]

LabelsReverse is like Name.Labels, but iterates right-to-left (top-to-bottom).

func (Name) Len

func (n Name) Len() int

Len returns the number of octets in this Name.

func (Name) Level

func (n Name) Level() (level int)

Level returns the number of labels in this Name.

func (Name) LogValue

func (n Name) LogValue() slog.Value

LogValue returns a log/slog.Value for logging this Name.

func (Name) MarshalText

func (n Name) MarshalText() (text []byte, err error)

MarshalText implements encoding.TextMarshaler. It returns the Name as-is, and cannot fail.

func (Name) Normal

func (n Name) Normal() Name

Normal returns a new Name that is the canonical version of this Name, i.e. all lower case.

func (Name) Octets

func (n Name) Octets() iter.Seq[byte]

Octets returns an iter.Seq of the octets (bytes) in the Name.

func (*Name) Set

func (n *Name) Set(str string) error

Set implements flag.Value. It validates, see Name.ValidateWithContext.

func (Name) String

func (n Name) String() string

String returns this Name as a string, as-is.

func (Name) Sub

func (n Name) Sub(l Label) Name

Sub returns a sub-name of this Name with the supplied Label.

See also:

func (Name) Super

func (n Name) Super() Name

Super returns the super-domain of this name, i.e. the left-most label removed. If this name is root then it returns root.

See also:

func (Name) TLD

func (n Name) TLD() (Label, error)

TLD returns the last Label in this Name, or ErrTooFewLabels if this Name is empty.

See also: Name.IsRoot.

func (Name) ToUnicode

func (n Name) ToUnicode() (str string, err error)

ToUnicode returns an IDN string of this Name.

func (*Name) UnmarshalText

func (n *Name) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler. It validates, see Name.ValidateWithContext.

func (Name) Validate

func (n Name) Validate() error

Validate calls Name.ValidateWithContext.

func (Name) ValidateWithContext

func (n Name) ValidateWithContext(ctx context.Context) error

ValidateWithContext returns an error if any of the labels in this name is invalid.

See also: Label.ValidateWithContext.

type NameMap

type NameMap[V any] struct {
	// contains filtered or unexported fields
}

NameMap is a map with Name keys. It exist because 1) Go doesn’t allow byte slice (and thus Name) map keys and 2) to normalise the key format.

func NewNameMap

func NewNameMap[V any](values map[string]V) NameMap[V]

NewNameMap creates a new NameMap from a map with string keys. The resulting map may have fewer values if different string keys result in the same Name key.

func (NameMap[V]) All

func (m NameMap[V]) All() iter.Seq2[Name, V]

All returns a key-value iterator.

func (NameMap[V]) Keys

func (m NameMap[V]) Keys() iter.Seq[Name]

Keys returns a key iterator.

func (NameMap[V]) Len

func (m NameMap[V]) Len() int

Len returns the number of values.

func (NameMap[V]) Load

func (m NameMap[V]) Load(n Name) (v V, ok bool)

Load returns a value for a key and true if it exists, false otherwise.

func (NameMap[V]) Map

func (m NameMap[V]) Map() map[string]V

Map returns a copy of the underlying map, with string keys.

func (*NameMap[V]) Store

func (m *NameMap[V]) Store(n Name, v V)

Store stores a value for a key.

func (NameMap[V]) ValidateWithContext

func (m NameMap[V]) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates m, treating an unset m as valid. Keys are Name and validated as such. Values are only validated if V implements validation.ValidateableWithContext.

func (NameMap[V]) Values

func (m NameMap[V]) Values() iter.Seq[V]

Values returns a value iterator.

type Normaler

type Normaler[T any] interface {
	Normal() T
}

Normaler is something that can return a normalised version of itself.

type RcodeError

type RcodeError int

RcodeError is an RCODE that can be used as an error.

func (RcodeError) Error

func (err RcodeError) Error() string

type ToUnicoder

type ToUnicoder interface {
	ToUnicode() (string, error)
}

ToUnicoder is something that can return a Unicode string of itself.

type URI

type URI struct {
	Key   string
	Host  string
	Port  uint16
	Name  Name
	Class dns.Class
	Type  dns.Type
	Query map[string][]string
}

URI is a DNS URI as per RFC 4501 (with an added TSIG key field).

func MustParseURI

func MustParseURI(str string) URI

MustParseURI returns a DNS URI or panics.

func ParseURI

func ParseURI(str string) (*URI, error)

ParseURI parses a DNS URI from a string.

func (*URI) Lookup

func (u *URI) Lookup(
	ctx context.Context,
	resolver *net.Resolver,
) (addrPorts []netip.AddrPort, err error)

Lookup resolves the host of the URI and returns a slice of net/netip.AddrPort, one for each resolved address and each with the same port as the URI.

func (*URI) MarshalBinary

func (u *URI) MarshalBinary() (data []byte, err error)

MarshalBinary converts the DNS URI into a byte slice.

func (*URI) MarshalText

func (u *URI) MarshalText() (text []byte, err error)

MarshalText converts the DNS URI into a byte slice.

func (*URI) Set

func (u *URI) Set(str string) error

Set sets the DNS URI by parsing a string.

func (*URI) String

func (u *URI) String() string

String returns the DNS URI as a string.

func (*URI) URL

func (u *URI) URL() *url.URL

URL converts the DNS URI to a url.URL.

func (*URI) UnmarshalBinary

func (u *URI) UnmarshalBinary(data []byte) error

UnmarshalBinary sets the DNS URI by parsing a byte slice.

func (*URI) UnmarshalText

func (u *URI) UnmarshalText(text []byte) error

UnmarshalText sets the DNS URI by parsing a byte slice.

func (URI) ValidateWithContext

func (u URI) ValidateWithContext(ctx context.Context) error

ValidateWithContext validates the DNS URI.

Directories

Path Synopsis
cmd
Package cmd hosts shared helpers for dnse CLI binaries: it wires up logging flag parsing, handles signals, prints usage, and offers Fatal/GetZone utilities so individual commands stay thin.
Package cmd hosts shared helpers for dnse CLI binaries: it wires up logging flag parsing, handles signals, prints usage, and offers Fatal/GetZone utilities so individual commands stay thin.
gen-tsig command
Package main creates a TSIG key with the specified algorithm and name.
Package main creates a TSIG key with the specified algorithm and name.
zone-verifier command
Package main executes zoneverifier and runs the configured tests.
Package main executes zoneverifier and runs the configured tests.
zonediff command
Package main compares two zone files for differences.
Package main compares two zone files for differences.
zonemd-generate command
Package main reads a DNS zone from a file, or STDIN if ZONEFILE is "-" or not supplied, and generates a ZONEMD record for the zone.
Package main reads a DNS zone from a file, or STDIN if ZONEFILE is "-" or not supplied, and generates a ZONEMD record for the zone.
zonemd-validate command
Package main validates all ZONEMD resource records in the given zone.
Package main validates all ZONEMD resource records in the given zone.
Package dnsclient contains general DNS-related functionality.
Package dnsclient contains general DNS-related functionality.
Package dnsserver wraps miekg/dns.Server to run an in-process authoritative server with configurable listeners, TSIG support, flexible handler return types, and built-in logging/telemetry hooks.
Package dnsserver wraps miekg/dns.Server to run an in-process authoritative server with configurable listeners, TSIG support, flexible handler return types, and built-in logging/telemetry hooks.
Package dnstelemetry provides metric names and attribute builders so instrumented clients and servers can emit consistent telemetry.
Package dnstelemetry provides metric names and attribute builders so instrumented clients and servers can emit consistent telemetry.
Package dnstest bundles test utilities for DNS code: It can spin up a configurable in-process authoritative server, set up TSIG/SoftHSM fixtures, generate names/records/ports, and provide helpers for requiring external commands or splitting RRsets.
Package dnstest bundles test utilities for DNS code: It can spin up a configurable in-process authoritative server, set up TSIG/SoftHSM fixtures, generate names/records/ports, and provide helpers for requiring external commands or splitting RRsets.
Package errors defines the shared error and exit-code vocabulary for dnse-based CLIs.
Package errors defines the shared error and exit-code vocabulary for dnse-based CLIs.
log
Package nameserver defines the common interface and support types for running DNS servers behind dnse—wrapping third‑party daemons like Knot/NSD so they can be configured, reloaded, and managed uniformly from Go code.
Package nameserver defines the common interface and support types for running DNS servers behind dnse—wrapping third‑party daemons like Knot/NSD so they can be configured, reloaded, and managed uniformly from Go code.
knot
Package knot configures and runs an [Knot DNS] nameserver that implements gitlab.com/internetstiftelsen-oss/dnse/nameserver.Nameserver.
Package knot configures and runs an [Knot DNS] nameserver that implements gitlab.com/internetstiftelsen-oss/dnse/nameserver.Nameserver.
nsd
Package nsd configures and runs an NSD nameserver that implements gitlab.com/internetstiftelsen-oss/dnse/nameserver.Nameserver.
Package nsd configures and runs an NSD nameserver that implements gitlab.com/internetstiftelsen-oss/dnse/nameserver.Nameserver.
Package record wraps github.com/miekg/dns.RR with helpers for canonicalising names, parsing text records, and working with rrsets in Go-friendly types.
Package record wraps github.com/miekg/dns.RR with helpers for canonicalising names, parsing text records, and working with rrsets in Go-friendly types.
Package tsig manages TSIG keys: It models key metadata, enforces validation, and provides key-set helpers for both clients and servers.
Package tsig manages TSIG keys: It models key metadata, enforces validation, and provides key-set helpers for both clients and servers.
Package zone models an in‑memory DNS zone that can be populated from files, streams, or AXFR sources, sorted, diffed, validated (incl.
Package zone models an in‑memory DNS zone that can be populated from files, streams, or AXFR sources, sorted, diffed, validated (incl.
diff
Package diff computes structured differences between two sorted record collections, keeping per-type statistics and printable summaries.
Package diff computes structured differences between two sorted record collections, keeping per-type statistics and printable summaries.
Package zonemd implements RFC 8976 primitives: parsing scheme/algorithm IDs, hashing records, validating digests, and handling “unknown” policy knobs.
Package zonemd implements RFC 8976 primitives: parsing scheme/algorithm IDs, hashing records, validating digests, and handling “unknown” policy knobs.
doc

Jump to

Keyboard shortcuts

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