Package dnsmessage provides a mostly RFC 1035 compliant implementation of DNS message packing and unpacking.
The package also supports messages with Extension Mechanisms for DNS (EDNS(0)) as defined in RFC 6891.
This implementation is designed to minimize heap allocations and avoid unnecessary packing and unpacking as much as possible.
import "golang.org/x/net/dns/dnsmessage"var (
// ErrNotStarted indicates that the prerequisite information isn't available yet
ErrNotStarted = errors.New("parsing/packing of this type isn't available yet")
// ErrSectionDone indicates that all records in the section have been parsed or finished
ErrSectionDone = errors.New("parsing/packing of this section has completed")
)// Message is a representation of a DNS message
type Message struct {
Header
Questions []Question
Answers []Resource
Authorities []Resource
Additionals []Resource
}
func (m *Message) Pack() ([]byte, error)
func (m *Message) AppendPack(b []byte) ([]byte, error)
func (m *Message) Unpack(msg []byte) error
func (m *Message) GoString() string// Header is a representation of a DNS message header
type Header struct {
ID uint16
Response bool
OpCode OpCode
Authoritative bool
Truncated bool
RecursionDesired bool
RecursionAvailable bool
AuthenticData bool
CheckingDisabled bool
RCode RCode
}
func (m *Header) GoString() string// Question is a DNS query
type Question struct {
Name Name
Type Type
Class Class
}
func (q *Question) GoString() string// Resource is a DNS resource record
type Resource struct {
Header ResourceHeader
Body ResourceBody
}
func (r *Resource) GoString() string
// ResourceHeader is the header of a DNS resource record
type ResourceHeader struct {
Name Name // Domain name for which this resource record pertains
Type Type // Type of DNS resource record (set automatically during packing)
Class Class // Class of network to which this DNS resource record pertains
TTL uint32 // Time to live (seconds)
Length uint16 // Length of data after the header (set automatically during packing)
}
func (h *ResourceHeader) GoString() string
func (h *ResourceHeader) DNSSECAllowed() bool
func (h *ResourceHeader) ExtendedRCode(rcode RCode) RCode
func (h *ResourceHeader) SetEDNS0(udpPayloadLen int, extRCode RCode, dnssecOK bool) error
// ResourceBody is a DNS resource record minus the header
type ResourceBody interface {
GoString() string
// Has unexported methods
}// Name is a non-encoded and non-escaped domain name
type Name struct {
Data [255]byte
Length uint8
}
func NewName(name string) (Name, error)
func MustNewName(name string) Name
func (n *Name) GoString() string
func (n Name) String() string// Type is the type of a DNS Resource Record
type Type uint16
const (
// ResourceHeader.Type and Question.Type
TypeA Type = 1
TypeNS Type = 2
TypeCNAME Type = 5
TypeSOA Type = 6
TypePTR Type = 12
TypeMX Type = 15
TypeTXT Type = 16
TypeAAAA Type = 28
TypeSRV Type = 33
TypeOPT Type = 41
TypeSVCB Type = 64
TypeHTTPS Type = 65
// Question.Type only
TypeWKS Type = 11
TypeHINFO Type = 13
TypeMINFO Type = 14
TypeAXFR Type = 252
TypeALL Type = 255
)
func (t Type) GoString() string
func (t Type) String() string
// Class is a type of network
type Class uint16
const (
// ResourceHeader.Class and Question.Class
ClassINET Class = 1
ClassCSNET Class = 2
ClassCHAOS Class = 3
ClassHESIOD Class = 4
// Question.Class only
ClassANY Class = 255
)
func (c Class) GoString() string
func (c Class) String() string// OpCode is a DNS operation code
type OpCode uint16
func (o OpCode) GoString() string
// RCode is a DNS response status code
type RCode uint16
const (
RCodeSuccess RCode = 0 // NoError
RCodeFormatError RCode = 1 // FormErr
RCodeServerFailure RCode = 2 // ServFail
RCodeNameError RCode = 3 // NXDomain
RCodeNotImplemented RCode = 4 // NotImp
RCodeRefused RCode = 5 // Refused
)
func (r RCode) GoString() string
func (r RCode) String() string// AResource is an A Resource record
type AResource struct {
A [4]byte
}
func (r *AResource) GoString() string// AAAAResource is an AAAA Resource record
type AAAAResource struct {
AAAA [16]byte
}
func (r *AAAAResource) GoString() string// CNAMEResource is a CNAME Resource record
type CNAMEResource struct {
CNAME Name
}
func (r *CNAMEResource) GoString() string// MXResource is an MX Resource record
type MXResource struct {
Pref uint16
MX Name
}
func (r *MXResource) GoString() string// NSResource is an NS Resource record
type NSResource struct {
NS Name
}
func (r *NSResource) GoString() string// PTRResource is a PTR Resource record
type PTRResource struct {
PTR Name
}
func (r *PTRResource) GoString() string// SOAResource is an SOA Resource record
type SOAResource struct {
NS Name
MBox Name
Serial uint32
Refresh uint32
Retry uint32
Expire uint32
MinTTL uint32 // Default TTL and TTL of negative responses (RFC 2308 Section 4)
}
func (r *SOAResource) GoString() string// SRVResource is an SRV Resource record
type SRVResource struct {
Priority uint16
Weight uint16
Port uint16
Target Name // Not compressed as per RFC 2782
}
func (r *SRVResource) GoString() string// TXTResource is a TXT Resource record
type TXTResource struct {
TXT []string
}
func (r *TXTResource) GoString() string// SVCBResource is an SVCB Resource record
type SVCBResource struct {
Priority uint16
Target Name
Params []SVCParam // Must be in strict increasing order by Key
}
func (r *SVCBResource) GoString() string
func (r *SVCBResource) GetParam(key SVCParamKey) (value []byte, ok bool)
func (r *SVCBResource) SetParam(key SVCParamKey, value []byte)
func (r *SVCBResource) DeleteParam(key SVCParamKey) bool
// SVCParam is a service parameter
type SVCParam struct {
Key SVCParamKey
Value []byte
}
func (p SVCParam) GoString() string
// SVCParamKey is a key for a service parameter
type SVCParamKey uint16
const (
SVCParamMandatory SVCParamKey = 0
SVCParamALPN SVCParamKey = 1
SVCParamNoDefaultALPN SVCParamKey = 2
SVCParamPort SVCParamKey = 3
SVCParamIPv4Hint SVCParamKey = 4
SVCParamECH SVCParamKey = 5
SVCParamIPv6Hint SVCParamKey = 6
SVCParamDOHPath SVCParamKey = 7
SVCParamOHTTP SVCParamKey = 8
SVCParamTLSSupportedGroups SVCParamKey = 9
)
func (k SVCParamKey) GoString() string
func (k SVCParamKey) String() string// HTTPSResource is an HTTPS Resource record (same format as SVCB)
type HTTPSResource struct {
SVCBResource
}
func (r *HTTPSResource) GoString() string// OPTResource is an OPT pseudo Resource record (EDNS(0) extension)
type OPTResource struct {
Options []Option
}
func (r *OPTResource) GoString() string
// Option represents a DNS message option within OPTResource
type Option struct {
Code uint16 // option code
Data []byte
}
func (o *Option) GoString() string// UnknownResource is a catch-all container for unknown record types
type UnknownResource struct {
Type Type
Data []byte
}
func (r *UnknownResource) GoString() string// Builder allows incrementally packing a DNS message
type Builder struct {
// Has unexported fields
}
func NewBuilder(buf []byte, h Header) Builder
func (b *Builder) EnableCompression()
func (b *Builder) Finish() ([]byte, error)func (b *Builder) StartQuestions() error
func (b *Builder) StartAnswers() error
func (b *Builder) StartAuthorities() error
func (b *Builder) StartAdditionals() errorfunc (b *Builder) Question(q Question) error
func (b *Builder) AResource(h ResourceHeader, r AResource) error
func (b *Builder) AAAAResource(h ResourceHeader, r AAAAResource) error
func (b *Builder) CNAMEResource(h ResourceHeader, r CNAMEResource) error
func (b *Builder) MXResource(h ResourceHeader, r MXResource) error
func (b *Builder) NSResource(h ResourceHeader, r NSResource) error
func (b *Builder) PTRResource(h ResourceHeader, r PTRResource) error
func (b *Builder) SOAResource(h ResourceHeader, r SOAResource) error
func (b *Builder) SRVResource(h ResourceHeader, r SRVResource) error
func (b *Builder) TXTResource(h ResourceHeader, r TXTResource) error
func (b *Builder) SVCBResource(h ResourceHeader, r SVCBResource) error
func (b *Builder) HTTPSResource(h ResourceHeader, r HTTPSResource) error
func (b *Builder) OPTResource(h ResourceHeader, r OPTResource) error
func (b *Builder) UnknownResource(h ResourceHeader, r UnknownResource) error// Parser allows incrementally parsing a DNS message
type Parser struct {
// Has unexported fields
}
func (p *Parser) Start(msg []byte) (Header, error)func (p *Parser) Question() (Question, error)
func (p *Parser) AllQuestions() ([]Question, error)
func (p *Parser) SkipQuestion() error
func (p *Parser) SkipAllQuestions() errorfunc (p *Parser) Answer() (Resource, error)
func (p *Parser) AnswerHeader() (ResourceHeader, error)
func (p *Parser) AllAnswers() ([]Resource, error)
func (p *Parser) SkipAnswer() error
func (p *Parser) SkipAllAnswers() errorfunc (p *Parser) Authority() (Resource, error)
func (p *Parser) AuthorityHeader() (ResourceHeader, error)
func (p *Parser) AllAuthorities() ([]Resource, error)
func (p *Parser) SkipAuthority() error
func (p *Parser) SkipAllAuthorities() errorfunc (p *Parser) Additional() (Resource, error)
func (p *Parser) AdditionalHeader() (ResourceHeader, error)
func (p *Parser) AllAdditionals() ([]Resource, error)
func (p *Parser) SkipAdditional() error
func (p *Parser) SkipAllAdditionals() errorfunc (p *Parser) AResource() (AResource, error)
func (p *Parser) AAAAResource() (AAAAResource, error)
func (p *Parser) CNAMEResource() (CNAMEResource, error)
func (p *Parser) MXResource() (MXResource, error)
func (p *Parser) NSResource() (NSResource, error)
func (p *Parser) PTRResource() (PTRResource, error)
func (p *Parser) SOAResource() (SOAResource, error)
func (p *Parser) SRVResource() (SRVResource, error)
func (p *Parser) TXTResource() (TXTResource, error)
func (p *Parser) SVCBResource() (SVCBResource, error)
func (p *Parser) HTTPSResource() (HTTPSResource, error)
func (p *Parser) OPTResource() (OPTResource, error)
func (p *Parser) UnknownResource() (UnknownResource, error)Note: One of the XXXHeader methods must have been called before calling resource-specific parsing methods.
import "golang.org/x/net/dns/dnsmessage"
func buildDNSQuery(domain string) ([]byte, error) {
// Create message header
header := dnsmessage.Header{
ID: 1234,
Response: false,
OpCode: 0,
RecursionDesired: true,
}
// Create builder
buf := make([]byte, 2, 514)
b := dnsmessage.NewBuilder(buf, header)
b.EnableCompression()
// Start questions section
if err := b.StartQuestions(); err != nil {
return nil, err
}
// Add question
name, err := dnsmessage.NewName(domain)
if err != nil {
return nil, err
}
question := dnsmessage.Question{
Name: name,
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
}
if err := b.Question(question); err != nil {
return nil, err
}
// Finish building
return b.Finish()
}func parseDNSResponse(msg []byte) error {
var parser dnsmessage.Parser
// Parse header
header, err := parser.Start(msg)
if err != nil {
return err
}
fmt.Printf("Response ID: %d, RCode: %s\n", header.ID, header.RCode)
// Skip questions
if err := parser.SkipAllQuestions(); err != nil {
return err
}
// Parse answers
for {
ansHeader, err := parser.AnswerHeader()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
return err
}
switch ansHeader.Type {
case dnsmessage.TypeA:
a, err := parser.AResource()
if err != nil {
return err
}
fmt.Printf("A: %v\n", net.IP(a.A[:]))
case dnsmessage.TypeAAAA:
aaaa, err := parser.AAAAResource()
if err != nil {
return err
}
fmt.Printf("AAAA: %v\n", net.IP(aaaa.AAAA[:]))
case dnsmessage.TypeCNAME:
cname, err := parser.CNAMEResource()
if err != nil {
return err
}
fmt.Printf("CNAME: %s\n", cname.CNAME.String())
default:
if err := parser.SkipAnswer(); err != nil {
return err
}
}
}
return nil
}func buildDNSResponse() ([]byte, error) {
header := dnsmessage.Header{
ID: 1234,
Response: true,
Authoritative: true,
RecursionAvailable: true,
RCode: dnsmessage.RCodeSuccess,
}
buf := make([]byte, 2, 514)
b := dnsmessage.NewBuilder(buf, header)
b.EnableCompression()
// Add answer records
if err := b.StartAnswers(); err != nil {
return nil, err
}
name := dnsmessage.MustNewName("example.com.")
// Add A record
aHeader := dnsmessage.ResourceHeader{
Name: name,
Class: dnsmessage.ClassINET,
TTL: 300,
}
aResource := dnsmessage.AResource{
A: [4]byte{192, 0, 2, 1},
}
if err := b.AResource(aHeader, aResource); err != nil {
return nil, err
}
return b.Finish()
}