tessl install tessl/golang-github-com-miekg--dns@1.1.1Complete DNS library for Go with full protocol control, DNSSEC support, and both client and server programming capabilities
EDNS0 (Extension Mechanisms for DNS) provides additional features and larger message sizes beyond original DNS limits (RFC 6891).
Pseudo-RR that carries EDNS0 options in the additional section.
type OPT struct {
Hdr RR_Header
Option []EDNS0 // EDNS0 options
}
// Version returns EDNS version (usually 0)
func (rr *OPT) Version() uint8
// SetVersion sets EDNS version
func (rr *OPT) SetVersion(v uint8)
// ExtendedRcode returns extended RCODE (upper 8 bits)
func (rr *OPT) ExtendedRcode() int
// SetExtendedRcode sets extended RCODE
func (rr *OPT) SetExtendedRcode(v uint16)
// UDPSize returns UDP payload size
func (rr *OPT) UDPSize() uint16
// SetUDPSize sets UDP payload size
func (rr *OPT) SetUDPSize(size uint16)
// Do returns DNSSEC OK bit
func (rr *OPT) Do() bool
// SetDo sets DNSSEC OK bit
func (rr *OPT) SetDo(do ...bool)
// Co returns Compact Answers OK bit
func (rr *OPT) Co() bool
// SetCo sets Compact Answers OK bit
func (rr *OPT) SetCo(co ...bool)
// Z returns Z field (14 least significant bits)
func (rr *OPT) Z() uint16
// SetZ sets Z field
func (rr *OPT) SetZ(z uint16)Base interface for all EDNS0 options.
type EDNS0 interface {
Option() uint16 // Option code
String() string // String representation
pack() ([]byte, error) // Pack to wire format
unpack([]byte) error // Unpack from wire format
copy() EDNS0 // Deep copy
}const (
EDNS0LLQ = 0x1 // Long Lived Queries
EDNS0UL = 0x2 // Update Lease
EDNS0NSID = 0x3 // Name Server Identifier (RFC 5001)
EDNS0ESU = 0x4 // ENUM Source-URI
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
EDNS0DHU = 0x6 // DS Hash Understood
EDNS0N3U = 0x7 // NSEC3 Hash Understood
EDNS0SUBNET = 0x8 // Client Subnet (RFC 7871)
EDNS0EXPIRE = 0x9 // EDNS Expire
EDNS0COOKIE = 0xa // DNS Cookie (RFC 7873)
EDNS0TCPKEEPALIVE = 0xb // TCP Keepalive (RFC 7828)
EDNS0PADDING = 0xc // Padding (RFC 7830)
EDNS0EDE = 0xf // Extended DNS Errors (RFC 8914)
EDNS0LOCALSTART = 0xFDE9 // Local/experimental range start
EDNS0LOCALEND = 0xFFFE // Local/experimental range end
}type EDNS0_NSID struct {
Code uint16 // EDNS0NSID
Nsid string // Hex encoded server identifier
}
func (e *EDNS0_NSID) Option() uint16
func (e *EDNS0_NSID) String() stringtype EDNS0_SUBNET struct {
Code uint16 // EDNS0SUBNET
Family uint16 // 1 for IPv4, 2 for IPv6
SourceNetmask uint8 // Client netmask
SourceScope uint8 // Scope netmask
Address net.IP // Client address
}
func (e *EDNS0_SUBNET) Option() uint16
func (e *EDNS0_SUBNET) String() stringtype EDNS0_COOKIE struct {
Code uint16 // EDNS0COOKIE
Cookie string // Hex encoded cookie
}
func (e *EDNS0_COOKIE) Option() uint16
func (e *EDNS0_COOKIE) String() stringtype EDNS0_EXPIRE struct {
Code uint16 // EDNS0EXPIRE
Expire uint32 // Expire time in seconds
}
func (e *EDNS0_EXPIRE) Option() uint16
func (e *EDNS0_EXPIRE) String() stringtype EDNS0_TCP_KEEPALIVE struct {
Code uint16 // EDNS0TCPKEEPALIVE
Length uint16 // Option length
Timeout uint16 // Keepalive timeout (100ms units)
}
func (e *EDNS0_TCP_KEEPALIVE) Option() uint16
func (e *EDNS0_TCP_KEEPALIVE) String() stringtype EDNS0_PADDING struct {
Code uint16 // EDNS0PADDING
Padding []byte // Padding bytes
}
func (e *EDNS0_PADDING) Option() uint16
func (e *EDNS0_PADDING) String() stringtype EDNS0_EDE struct {
Code uint16 // EDNS0EDE
InfoCode uint16 // Extended error code
ExtraText string // Human-readable error text
}
func (e *EDNS0_EDE) Option() uint16
func (e *EDNS0_EDE) String() stringtype EDNS0_DAU struct {
Code uint16 // EDNS0DAU
AlgCode []uint8 // Supported DNSSEC algorithms
}
func (e *EDNS0_DAU) Option() uint16
func (e *EDNS0_DAU) String() stringtype EDNS0_DHU struct {
Code uint16 // EDNS0DHU
AlgCode []uint8 // Supported DS hash algorithms
}
func (e *EDNS0_DHU) Option() uint16
func (e *EDNS0_DHU) String() stringtype EDNS0_N3U struct {
Code uint16 // EDNS0N3U
AlgCode []uint8 // Supported NSEC3 hash algorithms
}
func (e *EDNS0_N3U) Option() uint16
func (e *EDNS0_N3U) String() stringtype EDNS0_LLQ struct {
Code uint16 // EDNS0LLQ
Version uint16 // LLQ version
Opcode uint16 // LLQ opcode
Error uint16 // LLQ error code
Id uint64 // LLQ identifier
LeaseLife uint32 // Lease lifetime
}
func (e *EDNS0_LLQ) Option() uint16
func (e *EDNS0_LLQ) String() stringtype EDNS0_UL struct {
Code uint16 // EDNS0UL
Lease uint32 // Lease time in seconds
}
func (e *EDNS0_UL) Option() uint16
func (e *EDNS0_UL) String() stringtype EDNS0_ESU struct {
Code uint16 // EDNS0ESU
Uri string // Source URI
}
func (e *EDNS0_ESU) Option() uint16
func (e *EDNS0_ESU) String() stringtype EDNS0_LOCAL struct {
Code uint16 // Option code (EDNS0LOCALSTART-EDNS0LOCALEND)
Data []byte // Option data
}
func (e *EDNS0_LOCAL) Option() uint16
func (e *EDNS0_LOCAL) String() stringm := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
// Add EDNS0 with 4096 byte UDP size
m.SetEdns0(4096, false)
// Send query
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
// Enable DNSSEC (DO bit)
m.SetEdns0(4096, true)
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil {
log.Fatal(err)
}
// Check for DNSSEC records
for _, rr := range r.Answer {
if rrsig, ok := rr.(*dns.RRSIG); ok {
fmt.Printf("Found RRSIG: %v\n", rrsig)
}
}m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
// Add EDNS0 OPT record
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Add client subnet option
ecs := new(dns.EDNS0_SUBNET)
ecs.Code = dns.EDNS0SUBNET
ecs.Family = 1 // IPv4
ecs.SourceNetmask = 24
ecs.SourceScope = 0
ecs.Address = net.ParseIP("203.0.113.0").To4()
opt.Option = append(opt.Option, ecs)
m.Extra = append(m.Extra, opt)
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
// Create OPT record
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Add NSID option (empty to request server's NSID)
nsid := new(dns.EDNS0_NSID)
nsid.Code = dns.EDNS0NSID
nsid.Nsid = "" // Empty = request
opt.Option = append(opt.Option, nsid)
m.Extra = append(m.Extra, opt)
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil {
log.Fatal(err)
}
// Extract NSID from response
if opt := r.IsEdns0(); opt != nil {
for _, o := range opt.Option {
if nsid, ok := o.(*dns.EDNS0_NSID); ok {
fmt.Printf("Server NSID: %s\n", nsid.Nsid)
}
}
}m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Add cookie option
cookie := new(dns.EDNS0_COOKIE)
cookie.Code = dns.EDNS0COOKIE
cookie.Cookie = generateClientCookie() // 8-byte client cookie
opt.Option = append(opt.Option, cookie)
m.Extra = append(m.Extra, opt)
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil {
log.Fatal(err)
}
// Extract server cookie for subsequent requests
if opt := r.IsEdns0(); opt != nil {
for _, o := range opt.Option {
if cookie, ok := o.(*dns.EDNS0_COOKIE); ok {
// Save cookie for next request
fmt.Printf("Server cookie: %s\n", cookie.Cookie)
}
}
}m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Add TCP keepalive option
keepalive := new(dns.EDNS0_TCP_KEEPALIVE)
keepalive.Code = dns.EDNS0TCPKEEPALIVE
keepalive.Timeout = 300 // 30 seconds (in 100ms units)
opt.Option = append(opt.Option, keepalive)
m.Extra = append(m.Extra, opt)
c := &dns.Client{Net: "tcp"}
r, _, err := c.Exchange(m, "8.8.8.8:53")m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Add padding to reach specific message size
padding := new(dns.EDNS0_PADDING)
padding.Code = dns.EDNS0PADDING
padding.Padding = make([]byte, 128) // 128 bytes of padding
opt.Option = append(opt.Option, padding)
m.Extra = append(m.Extra, opt)
c := new(dns.Client)
r, _, err := c.Exchange(m, "1.1.1.1:53")// Server returning extended error
dns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeServerFailure)
// Add EDE option to explain error
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
ede := new(dns.EDNS0_EDE)
ede.Code = dns.EDNS0EDE
ede.InfoCode = 1 // Unsupported DNSKEY Algorithm
ede.ExtraText = "Algorithm 255 not supported"
opt.Option = append(opt.Option, ede)
m.Extra = append(m.Extra, opt)
w.WriteMsg(m)
})
// Client receiving extended error
if opt := response.IsEdns0(); opt != nil {
for _, o := range opt.Option {
if ede, ok := o.(*dns.EDNS0_EDE); ok {
fmt.Printf("Extended Error %d: %s\n", ede.InfoCode, ede.ExtraText)
}
}
}m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeDNSKEY)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
opt.SetDo(true)
// Signal supported DNSSEC algorithms
dau := new(dns.EDNS0_DAU)
dau.Code = dns.EDNS0DAU
dau.AlgCode = []uint8{
dns.RSASHA256,
dns.RSASHA512,
dns.ECDSAP256SHA256,
dns.ECDSAP384SHA384,
dns.ED25519,
}
// Signal supported DS hash algorithms
dhu := new(dns.EDNS0_DHU)
dhu.Code = dns.EDNS0DHU
dhu.AlgCode = []uint8{
dns.SHA256,
dns.SHA384,
}
// Signal supported NSEC3 hash algorithms
n3u := new(dns.EDNS0_N3U)
n3u.Code = dns.EDNS0N3U
n3u.AlgCode = []uint8{dns.SHA1}
opt.Option = append(opt.Option, dau, dhu, n3u)
m.Extra = append(m.Extra, opt)// Use local/experimental option code
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
// Custom option in local range
local := new(dns.EDNS0_LOCAL)
local.Code = 0xFFF0 // In EDNS0LOCALSTART-EDNS0LOCALEND range
local.Data = []byte("custom data")
opt.Option = append(opt.Option, local)
m.Extra = append(m.Extra, opt)m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
m.SetEdns0(4096, false)
c := new(dns.Client)
r, _, err := c.Exchange(m, "8.8.8.8:53")
if err != nil {
log.Fatal(err)
}
// Check if server supports EDNS0
if opt := r.IsEdns0(); opt != nil {
fmt.Printf("Server supports EDNS0\n")
fmt.Printf("UDP size: %d\n", opt.UDPSize())
fmt.Printf("Version: %d\n", opt.Version())
fmt.Printf("DO bit: %v\n", opt.Do())
} else {
fmt.Println("Server does not support EDNS0")
}m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
opt := new(dns.OPT)
opt.Hdr.Name = "."
opt.Hdr.Rrtype = dns.TypeOPT
opt.SetUDPSize(4096)
opt.SetDo(true)
// Add multiple options
nsid := &dns.EDNS0_NSID{Code: dns.EDNS0NSID}
ecs := &dns.EDNS0_SUBNET{
Code: dns.EDNS0SUBNET,
Family: 1,
SourceNetmask: 24,
Address: net.ParseIP("203.0.113.0").To4(),
}
cookie := &dns.EDNS0_COOKIE{
Code: dns.EDNS0COOKIE,
Cookie: "0123456789abcdef",
}
opt.Option = append(opt.Option, nsid, ecs, cookie)
m.Extra = append(m.Extra, opt)Common InfoCode values for EDNS0_EDE:
const (
ExtendedErrorCodeOther = 0
ExtendedErrorCodeUnsupportedDNSKEYAlg = 1
ExtendedErrorCodeUnsupportedDSDigest = 2
ExtendedErrorCodeStaleAnswer = 3
ExtendedErrorCodeForgedAnswer = 4
ExtendedErrorCodeDNSSECIndeterminate = 5
ExtendedErrorCodeDNSSECBogus = 6
ExtendedErrorCodeSignatureExpired = 7
ExtendedErrorCodeSignatureNotYetValid = 8
ExtendedErrorCodeDNSKEYMissing = 9
ExtendedErrorCodeRRSIGsMissing = 10
ExtendedErrorCodeNoZoneKeyBitSet = 11
ExtendedErrorCodeNSECMissing = 12
ExtendedErrorCodeCachedError = 13
ExtendedErrorCodeNotReady = 14
ExtendedErrorCodeBlocked = 15
ExtendedErrorCodeCensored = 16
ExtendedErrorCodeFiltered = 17
ExtendedErrorCodeProhibited = 18
ExtendedErrorCodeStaleNXDOMAINAnswer = 19
ExtendedErrorCodeNotAuthoritative = 20
ExtendedErrorCodeNotSupported = 21
ExtendedErrorCodeNoReachableAuthority = 22
ExtendedErrorCodeNetworkError = 23
ExtendedErrorCodeInvalidData = 24
)