or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bpf.mdcontext-ctxhttp.mdcontext.mddict.mddns-dnsmessage.mdhtml-atom.mdhtml-charset.mdhtml.mdhttp-httpguts.mdhttp-httpproxy.mdhttp2-h2c.mdhttp2-hpack.mdhttp2.mdicmp.mdidna.mdindex.mdipv4.mdipv6.mdnettest.mdnetutil.mdproxy.mdpublicsuffix.mdquic-qlog.mdquic.mdtrace.mdwebdav.mdwebsocket.mdxsrftoken.md
tile.json

dns-dnsmessage.mddocs/

DNS Message Parsing

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

import "golang.org/x/net/dns/dnsmessage"

Errors

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 Structure

// 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

// 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

// Question is a DNS query
type Question struct {
    Name  Name
    Type  Type
    Class Class
}

func (q *Question) GoString() string

Resource

// 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

// 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

Types and Classes

// 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 and RCode

// 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

Resource Types

A Resource

// AResource is an A Resource record
type AResource struct {
    A [4]byte
}

func (r *AResource) GoString() string

AAAA Resource

// AAAAResource is an AAAA Resource record
type AAAAResource struct {
    AAAA [16]byte
}

func (r *AAAAResource) GoString() string

CNAME Resource

// CNAMEResource is a CNAME Resource record
type CNAMEResource struct {
    CNAME Name
}

func (r *CNAMEResource) GoString() string

MX Resource

// MXResource is an MX Resource record
type MXResource struct {
    Pref uint16
    MX   Name
}

func (r *MXResource) GoString() string

NS Resource

// NSResource is an NS Resource record
type NSResource struct {
    NS Name
}

func (r *NSResource) GoString() string

PTR Resource

// PTRResource is a PTR Resource record
type PTRResource struct {
    PTR Name
}

func (r *PTRResource) GoString() string

SOA Resource

// 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

SRV Resource

// 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

TXT Resource

// TXTResource is a TXT Resource record
type TXTResource struct {
    TXT []string
}

func (r *TXTResource) GoString() string

SVCB Resource

// 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

HTTPS Resource

// HTTPSResource is an HTTPS Resource record (same format as SVCB)
type HTTPSResource struct {
    SVCBResource
}

func (r *HTTPSResource) GoString() string

OPT Resource

// 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

Unknown Resource

// UnknownResource is a catch-all container for unknown record types
type UnknownResource struct {
    Type Type
    Data []byte
}

func (r *UnknownResource) GoString() string

Builder

// 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)

Builder Section Methods

func (b *Builder) StartQuestions() error
func (b *Builder) StartAnswers() error
func (b *Builder) StartAuthorities() error
func (b *Builder) StartAdditionals() error

Builder Resource Methods

func (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

// Parser allows incrementally parsing a DNS message
type Parser struct {
    // Has unexported fields
}

func (p *Parser) Start(msg []byte) (Header, error)

Parser Question Methods

func (p *Parser) Question() (Question, error)
func (p *Parser) AllQuestions() ([]Question, error)
func (p *Parser) SkipQuestion() error
func (p *Parser) SkipAllQuestions() error

Parser Answer Methods

func (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() error

Parser Authority Methods

func (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() error

Parser Additional Methods

func (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() error

Parser Resource Methods

func (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.

Usage Examples

Building a DNS Query

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()
}

Parsing a DNS Response

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
}

Building a DNS Response with Multiple Records

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()
}