gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

edns.go (25893B)


      1 package dns
      2 
      3 import (
      4 	"encoding/binary"
      5 	"encoding/hex"
      6 	"errors"
      7 	"fmt"
      8 	"net"
      9 	"strconv"
     10 )
     11 
     12 // EDNS0 Option codes.
     13 const (
     14 	EDNS0LLQ          = 0x1     // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
     15 	EDNS0UL           = 0x2     // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
     16 	EDNS0NSID         = 0x3     // nsid (See RFC 5001)
     17 	EDNS0ESU          = 0x4     // ENUM Source-URI draft: https://datatracker.ietf.org/doc/html/draft-kaplan-enum-source-uri-00
     18 	EDNS0DAU          = 0x5     // DNSSEC Algorithm Understood
     19 	EDNS0DHU          = 0x6     // DS Hash Understood
     20 	EDNS0N3U          = 0x7     // NSEC3 Hash Understood
     21 	EDNS0SUBNET       = 0x8     // client-subnet (See RFC 7871)
     22 	EDNS0EXPIRE       = 0x9     // EDNS0 expire
     23 	EDNS0COOKIE       = 0xa     // EDNS0 Cookie
     24 	EDNS0TCPKEEPALIVE = 0xb     // EDNS0 tcp keep alive (See RFC 7828)
     25 	EDNS0PADDING      = 0xc     // EDNS0 padding (See RFC 7830)
     26 	EDNS0EDE          = 0xf     // EDNS0 extended DNS errors (See RFC 8914)
     27 	EDNS0LOCALSTART   = 0xFDE9  // Beginning of range reserved for local/experimental use (See RFC 6891)
     28 	EDNS0LOCALEND     = 0xFFFE  // End of range reserved for local/experimental use (See RFC 6891)
     29 	_DO               = 1 << 15 // DNSSEC OK
     30 )
     31 
     32 // makeDataOpt is used to unpack the EDNS0 option(s) from a message.
     33 func makeDataOpt(code uint16) EDNS0 {
     34 	// All the EDNS0.* constants above need to be in this switch.
     35 	switch code {
     36 	case EDNS0LLQ:
     37 		return new(EDNS0_LLQ)
     38 	case EDNS0UL:
     39 		return new(EDNS0_UL)
     40 	case EDNS0NSID:
     41 		return new(EDNS0_NSID)
     42 	case EDNS0DAU:
     43 		return new(EDNS0_DAU)
     44 	case EDNS0DHU:
     45 		return new(EDNS0_DHU)
     46 	case EDNS0N3U:
     47 		return new(EDNS0_N3U)
     48 	case EDNS0SUBNET:
     49 		return new(EDNS0_SUBNET)
     50 	case EDNS0EXPIRE:
     51 		return new(EDNS0_EXPIRE)
     52 	case EDNS0COOKIE:
     53 		return new(EDNS0_COOKIE)
     54 	case EDNS0TCPKEEPALIVE:
     55 		return new(EDNS0_TCP_KEEPALIVE)
     56 	case EDNS0PADDING:
     57 		return new(EDNS0_PADDING)
     58 	case EDNS0EDE:
     59 		return new(EDNS0_EDE)
     60 	case EDNS0ESU:
     61 		return &EDNS0_ESU{Code: EDNS0ESU}
     62 	default:
     63 		e := new(EDNS0_LOCAL)
     64 		e.Code = code
     65 		return e
     66 	}
     67 }
     68 
     69 // OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
     70 // See RFC 6891.
     71 type OPT struct {
     72 	Hdr    RR_Header
     73 	Option []EDNS0 `dns:"opt"`
     74 }
     75 
     76 func (rr *OPT) String() string {
     77 	s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
     78 	if rr.Do() {
     79 		s += "flags: do; "
     80 	} else {
     81 		s += "flags:; "
     82 	}
     83 	if rr.Hdr.Ttl&0x7FFF != 0 {
     84 		s += fmt.Sprintf("MBZ: 0x%04x, ", rr.Hdr.Ttl&0x7FFF)
     85 	}
     86 	s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
     87 
     88 	for _, o := range rr.Option {
     89 		switch o.(type) {
     90 		case *EDNS0_NSID:
     91 			s += "\n; NSID: " + o.String()
     92 			h, e := o.pack()
     93 			var r string
     94 			if e == nil {
     95 				for _, c := range h {
     96 					r += "(" + string(c) + ")"
     97 				}
     98 				s += "  " + r
     99 			}
    100 		case *EDNS0_SUBNET:
    101 			s += "\n; SUBNET: " + o.String()
    102 		case *EDNS0_COOKIE:
    103 			s += "\n; COOKIE: " + o.String()
    104 		case *EDNS0_EXPIRE:
    105 			s += "\n; EXPIRE: " + o.String()
    106 		case *EDNS0_TCP_KEEPALIVE:
    107 			s += "\n; KEEPALIVE: " + o.String()
    108 		case *EDNS0_UL:
    109 			s += "\n; UPDATE LEASE: " + o.String()
    110 		case *EDNS0_LLQ:
    111 			s += "\n; LONG LIVED QUERIES: " + o.String()
    112 		case *EDNS0_DAU:
    113 			s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
    114 		case *EDNS0_DHU:
    115 			s += "\n; DS HASH UNDERSTOOD: " + o.String()
    116 		case *EDNS0_N3U:
    117 			s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
    118 		case *EDNS0_LOCAL:
    119 			s += "\n; LOCAL OPT: " + o.String()
    120 		case *EDNS0_PADDING:
    121 			s += "\n; PADDING: " + o.String()
    122 		case *EDNS0_EDE:
    123 			s += "\n; EDE: " + o.String()
    124 		case *EDNS0_ESU:
    125 			s += "\n; ESU: " + o.String()
    126 		}
    127 	}
    128 	return s
    129 }
    130 
    131 func (rr *OPT) len(off int, compression map[string]struct{}) int {
    132 	l := rr.Hdr.len(off, compression)
    133 	for _, o := range rr.Option {
    134 		l += 4 // Account for 2-byte option code and 2-byte option length.
    135 		lo, _ := o.pack()
    136 		l += len(lo)
    137 	}
    138 	return l
    139 }
    140 
    141 func (*OPT) parse(c *zlexer, origin string) *ParseError {
    142 	return &ParseError{err: "OPT records do not have a presentation format"}
    143 }
    144 
    145 func (rr *OPT) isDuplicate(r2 RR) bool { return false }
    146 
    147 // return the old value -> delete SetVersion?
    148 
    149 // Version returns the EDNS version used. Only zero is defined.
    150 func (rr *OPT) Version() uint8 {
    151 	return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16)
    152 }
    153 
    154 // SetVersion sets the version of EDNS. This is usually zero.
    155 func (rr *OPT) SetVersion(v uint8) {
    156 	rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | uint32(v)<<16
    157 }
    158 
    159 // ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
    160 func (rr *OPT) ExtendedRcode() int {
    161 	return int(rr.Hdr.Ttl&0xFF000000>>24) << 4
    162 }
    163 
    164 // SetExtendedRcode sets the EDNS extended RCODE field.
    165 //
    166 // If the RCODE is not an extended RCODE, will reset the extended RCODE field to 0.
    167 func (rr *OPT) SetExtendedRcode(v uint16) {
    168 	rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v>>4)<<24
    169 }
    170 
    171 // UDPSize returns the UDP buffer size.
    172 func (rr *OPT) UDPSize() uint16 {
    173 	return rr.Hdr.Class
    174 }
    175 
    176 // SetUDPSize sets the UDP buffer size.
    177 func (rr *OPT) SetUDPSize(size uint16) {
    178 	rr.Hdr.Class = size
    179 }
    180 
    181 // Do returns the value of the DO (DNSSEC OK) bit.
    182 func (rr *OPT) Do() bool {
    183 	return rr.Hdr.Ttl&_DO == _DO
    184 }
    185 
    186 // SetDo sets the DO (DNSSEC OK) bit.
    187 // If we pass an argument, set the DO bit to that value.
    188 // It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored.
    189 func (rr *OPT) SetDo(do ...bool) {
    190 	if len(do) == 1 {
    191 		if do[0] {
    192 			rr.Hdr.Ttl |= _DO
    193 		} else {
    194 			rr.Hdr.Ttl &^= _DO
    195 		}
    196 	} else {
    197 		rr.Hdr.Ttl |= _DO
    198 	}
    199 }
    200 
    201 // Z returns the Z part of the OPT RR as a uint16 with only the 15 least significant bits used.
    202 func (rr *OPT) Z() uint16 {
    203 	return uint16(rr.Hdr.Ttl & 0x7FFF)
    204 }
    205 
    206 // SetZ sets the Z part of the OPT RR, note only the 15 least significant bits of z are used.
    207 func (rr *OPT) SetZ(z uint16) {
    208 	rr.Hdr.Ttl = rr.Hdr.Ttl&^0x7FFF | uint32(z&0x7FFF)
    209 }
    210 
    211 // EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
    212 type EDNS0 interface {
    213 	// Option returns the option code for the option.
    214 	Option() uint16
    215 	// pack returns the bytes of the option data.
    216 	pack() ([]byte, error)
    217 	// unpack sets the data as found in the buffer. Is also sets
    218 	// the length of the slice as the length of the option data.
    219 	unpack([]byte) error
    220 	// String returns the string representation of the option.
    221 	String() string
    222 	// copy returns a deep-copy of the option.
    223 	copy() EDNS0
    224 }
    225 
    226 // EDNS0_NSID option is used to retrieve a nameserver
    227 // identifier. When sending a request Nsid must be set to the empty string
    228 // The identifier is an opaque string encoded as hex.
    229 // Basic use pattern for creating an nsid option:
    230 //
    231 //	o := new(dns.OPT)
    232 //	o.Hdr.Name = "."
    233 //	o.Hdr.Rrtype = dns.TypeOPT
    234 //	e := new(dns.EDNS0_NSID)
    235 //	e.Code = dns.EDNS0NSID
    236 //	e.Nsid = "AA"
    237 //	o.Option = append(o.Option, e)
    238 type EDNS0_NSID struct {
    239 	Code uint16 // Always EDNS0NSID
    240 	Nsid string // This string needs to be hex encoded
    241 }
    242 
    243 func (e *EDNS0_NSID) pack() ([]byte, error) {
    244 	h, err := hex.DecodeString(e.Nsid)
    245 	if err != nil {
    246 		return nil, err
    247 	}
    248 	return h, nil
    249 }
    250 
    251 // Option implements the EDNS0 interface.
    252 func (e *EDNS0_NSID) Option() uint16        { return EDNS0NSID } // Option returns the option code.
    253 func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
    254 func (e *EDNS0_NSID) String() string        { return e.Nsid }
    255 func (e *EDNS0_NSID) copy() EDNS0           { return &EDNS0_NSID{e.Code, e.Nsid} }
    256 
    257 // EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
    258 // an idea of where the client lives. See RFC 7871. It can then give back a different
    259 // answer depending on the location or network topology.
    260 // Basic use pattern for creating an subnet option:
    261 //
    262 //	o := new(dns.OPT)
    263 //	o.Hdr.Name = "."
    264 //	o.Hdr.Rrtype = dns.TypeOPT
    265 //	e := new(dns.EDNS0_SUBNET)
    266 //	e.Code = dns.EDNS0SUBNET // by default this is filled in through unpacking OPT packets (unpackDataOpt)
    267 //	e.Family = 1	// 1 for IPv4 source address, 2 for IPv6
    268 //	e.SourceNetmask = 32	// 32 for IPV4, 128 for IPv6
    269 //	e.SourceScope = 0
    270 //	e.Address = net.ParseIP("127.0.0.1").To4()	// for IPv4
    271 //	// e.Address = net.ParseIP("2001:7b8:32a::2")	// for IPV6
    272 //	o.Option = append(o.Option, e)
    273 //
    274 // This code will parse all the available bits when unpacking (up to optlen).
    275 // When packing it will apply SourceNetmask. If you need more advanced logic,
    276 // patches welcome and good luck.
    277 type EDNS0_SUBNET struct {
    278 	Code          uint16 // Always EDNS0SUBNET
    279 	Family        uint16 // 1 for IP, 2 for IP6
    280 	SourceNetmask uint8
    281 	SourceScope   uint8
    282 	Address       net.IP
    283 }
    284 
    285 // Option implements the EDNS0 interface.
    286 func (e *EDNS0_SUBNET) Option() uint16 { return EDNS0SUBNET }
    287 
    288 func (e *EDNS0_SUBNET) pack() ([]byte, error) {
    289 	b := make([]byte, 4)
    290 	binary.BigEndian.PutUint16(b[0:], e.Family)
    291 	b[2] = e.SourceNetmask
    292 	b[3] = e.SourceScope
    293 	switch e.Family {
    294 	case 0:
    295 		// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
    296 		// We might don't need to complain either
    297 		if e.SourceNetmask != 0 {
    298 			return nil, errors.New("dns: bad address family")
    299 		}
    300 	case 1:
    301 		if e.SourceNetmask > net.IPv4len*8 {
    302 			return nil, errors.New("dns: bad netmask")
    303 		}
    304 		if len(e.Address.To4()) != net.IPv4len {
    305 			return nil, errors.New("dns: bad address")
    306 		}
    307 		ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
    308 		needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
    309 		b = append(b, ip[:needLength]...)
    310 	case 2:
    311 		if e.SourceNetmask > net.IPv6len*8 {
    312 			return nil, errors.New("dns: bad netmask")
    313 		}
    314 		if len(e.Address) != net.IPv6len {
    315 			return nil, errors.New("dns: bad address")
    316 		}
    317 		ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
    318 		needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
    319 		b = append(b, ip[:needLength]...)
    320 	default:
    321 		return nil, errors.New("dns: bad address family")
    322 	}
    323 	return b, nil
    324 }
    325 
    326 func (e *EDNS0_SUBNET) unpack(b []byte) error {
    327 	if len(b) < 4 {
    328 		return ErrBuf
    329 	}
    330 	e.Family = binary.BigEndian.Uint16(b)
    331 	e.SourceNetmask = b[2]
    332 	e.SourceScope = b[3]
    333 	switch e.Family {
    334 	case 0:
    335 		// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
    336 		// It's okay to accept such a packet
    337 		if e.SourceNetmask != 0 {
    338 			return errors.New("dns: bad address family")
    339 		}
    340 		e.Address = net.IPv4(0, 0, 0, 0)
    341 	case 1:
    342 		if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
    343 			return errors.New("dns: bad netmask")
    344 		}
    345 		addr := make(net.IP, net.IPv4len)
    346 		copy(addr, b[4:])
    347 		e.Address = addr.To16()
    348 	case 2:
    349 		if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
    350 			return errors.New("dns: bad netmask")
    351 		}
    352 		addr := make(net.IP, net.IPv6len)
    353 		copy(addr, b[4:])
    354 		e.Address = addr
    355 	default:
    356 		return errors.New("dns: bad address family")
    357 	}
    358 	return nil
    359 }
    360 
    361 func (e *EDNS0_SUBNET) String() (s string) {
    362 	if e.Address == nil {
    363 		s = "<nil>"
    364 	} else if e.Address.To4() != nil {
    365 		s = e.Address.String()
    366 	} else {
    367 		s = "[" + e.Address.String() + "]"
    368 	}
    369 	s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
    370 	return
    371 }
    372 
    373 func (e *EDNS0_SUBNET) copy() EDNS0 {
    374 	return &EDNS0_SUBNET{
    375 		e.Code,
    376 		e.Family,
    377 		e.SourceNetmask,
    378 		e.SourceScope,
    379 		e.Address,
    380 	}
    381 }
    382 
    383 // The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
    384 //
    385 //	o := new(dns.OPT)
    386 //	o.Hdr.Name = "."
    387 //	o.Hdr.Rrtype = dns.TypeOPT
    388 //	e := new(dns.EDNS0_COOKIE)
    389 //	e.Code = dns.EDNS0COOKIE
    390 //	e.Cookie = "24a5ac.."
    391 //	o.Option = append(o.Option, e)
    392 //
    393 // The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is
    394 // always 8 bytes. It may then optionally be followed by the server cookie. The server
    395 // cookie is of variable length, 8 to a maximum of 32 bytes. In other words:
    396 //
    397 //	cCookie := o.Cookie[:16]
    398 //	sCookie := o.Cookie[16:]
    399 //
    400 // There is no guarantee that the Cookie string has a specific length.
    401 type EDNS0_COOKIE struct {
    402 	Code   uint16 // Always EDNS0COOKIE
    403 	Cookie string // Hex-encoded cookie data
    404 }
    405 
    406 func (e *EDNS0_COOKIE) pack() ([]byte, error) {
    407 	h, err := hex.DecodeString(e.Cookie)
    408 	if err != nil {
    409 		return nil, err
    410 	}
    411 	return h, nil
    412 }
    413 
    414 // Option implements the EDNS0 interface.
    415 func (e *EDNS0_COOKIE) Option() uint16        { return EDNS0COOKIE }
    416 func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
    417 func (e *EDNS0_COOKIE) String() string        { return e.Cookie }
    418 func (e *EDNS0_COOKIE) copy() EDNS0           { return &EDNS0_COOKIE{e.Code, e.Cookie} }
    419 
    420 // The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
    421 // an expiration on an update RR. This is helpful for clients that cannot clean
    422 // up after themselves. This is a draft RFC and more information can be found at
    423 // https://tools.ietf.org/html/draft-sekar-dns-ul-02
    424 //
    425 //	o := new(dns.OPT)
    426 //	o.Hdr.Name = "."
    427 //	o.Hdr.Rrtype = dns.TypeOPT
    428 //	e := new(dns.EDNS0_UL)
    429 //	e.Code = dns.EDNS0UL
    430 //	e.Lease = 120 // in seconds
    431 //	o.Option = append(o.Option, e)
    432 type EDNS0_UL struct {
    433 	Code     uint16 // Always EDNS0UL
    434 	Lease    uint32
    435 	KeyLease uint32
    436 }
    437 
    438 // Option implements the EDNS0 interface.
    439 func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
    440 func (e *EDNS0_UL) String() string { return fmt.Sprintf("%d %d", e.Lease, e.KeyLease) }
    441 func (e *EDNS0_UL) copy() EDNS0    { return &EDNS0_UL{e.Code, e.Lease, e.KeyLease} }
    442 
    443 // Copied: http://golang.org/src/pkg/net/dnsmsg.go
    444 func (e *EDNS0_UL) pack() ([]byte, error) {
    445 	var b []byte
    446 	if e.KeyLease == 0 {
    447 		b = make([]byte, 4)
    448 	} else {
    449 		b = make([]byte, 8)
    450 		binary.BigEndian.PutUint32(b[4:], e.KeyLease)
    451 	}
    452 	binary.BigEndian.PutUint32(b, e.Lease)
    453 	return b, nil
    454 }
    455 
    456 func (e *EDNS0_UL) unpack(b []byte) error {
    457 	switch len(b) {
    458 	case 4:
    459 		e.KeyLease = 0
    460 	case 8:
    461 		e.KeyLease = binary.BigEndian.Uint32(b[4:])
    462 	default:
    463 		return ErrBuf
    464 	}
    465 	e.Lease = binary.BigEndian.Uint32(b)
    466 	return nil
    467 }
    468 
    469 // EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
    470 // Implemented for completeness, as the EDNS0 type code is assigned.
    471 type EDNS0_LLQ struct {
    472 	Code      uint16 // Always EDNS0LLQ
    473 	Version   uint16
    474 	Opcode    uint16
    475 	Error     uint16
    476 	Id        uint64
    477 	LeaseLife uint32
    478 }
    479 
    480 // Option implements the EDNS0 interface.
    481 func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
    482 
    483 func (e *EDNS0_LLQ) pack() ([]byte, error) {
    484 	b := make([]byte, 18)
    485 	binary.BigEndian.PutUint16(b[0:], e.Version)
    486 	binary.BigEndian.PutUint16(b[2:], e.Opcode)
    487 	binary.BigEndian.PutUint16(b[4:], e.Error)
    488 	binary.BigEndian.PutUint64(b[6:], e.Id)
    489 	binary.BigEndian.PutUint32(b[14:], e.LeaseLife)
    490 	return b, nil
    491 }
    492 
    493 func (e *EDNS0_LLQ) unpack(b []byte) error {
    494 	if len(b) < 18 {
    495 		return ErrBuf
    496 	}
    497 	e.Version = binary.BigEndian.Uint16(b[0:])
    498 	e.Opcode = binary.BigEndian.Uint16(b[2:])
    499 	e.Error = binary.BigEndian.Uint16(b[4:])
    500 	e.Id = binary.BigEndian.Uint64(b[6:])
    501 	e.LeaseLife = binary.BigEndian.Uint32(b[14:])
    502 	return nil
    503 }
    504 
    505 func (e *EDNS0_LLQ) String() string {
    506 	s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
    507 		" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(e.Id, 10) +
    508 		" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
    509 	return s
    510 }
    511 func (e *EDNS0_LLQ) copy() EDNS0 {
    512 	return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
    513 }
    514 
    515 // EDNS0_DAU implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
    516 type EDNS0_DAU struct {
    517 	Code    uint16 // Always EDNS0DAU
    518 	AlgCode []uint8
    519 }
    520 
    521 // Option implements the EDNS0 interface.
    522 func (e *EDNS0_DAU) Option() uint16        { return EDNS0DAU }
    523 func (e *EDNS0_DAU) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
    524 func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
    525 
    526 func (e *EDNS0_DAU) String() string {
    527 	s := ""
    528 	for _, alg := range e.AlgCode {
    529 		if a, ok := AlgorithmToString[alg]; ok {
    530 			s += " " + a
    531 		} else {
    532 			s += " " + strconv.Itoa(int(alg))
    533 		}
    534 	}
    535 	return s
    536 }
    537 func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
    538 
    539 // EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
    540 type EDNS0_DHU struct {
    541 	Code    uint16 // Always EDNS0DHU
    542 	AlgCode []uint8
    543 }
    544 
    545 // Option implements the EDNS0 interface.
    546 func (e *EDNS0_DHU) Option() uint16        { return EDNS0DHU }
    547 func (e *EDNS0_DHU) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
    548 func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
    549 
    550 func (e *EDNS0_DHU) String() string {
    551 	s := ""
    552 	for _, alg := range e.AlgCode {
    553 		if a, ok := HashToString[alg]; ok {
    554 			s += " " + a
    555 		} else {
    556 			s += " " + strconv.Itoa(int(alg))
    557 		}
    558 	}
    559 	return s
    560 }
    561 func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
    562 
    563 // EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
    564 type EDNS0_N3U struct {
    565 	Code    uint16 // Always EDNS0N3U
    566 	AlgCode []uint8
    567 }
    568 
    569 // Option implements the EDNS0 interface.
    570 func (e *EDNS0_N3U) Option() uint16        { return EDNS0N3U }
    571 func (e *EDNS0_N3U) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
    572 func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
    573 
    574 func (e *EDNS0_N3U) String() string {
    575 	// Re-use the hash map
    576 	s := ""
    577 	for _, alg := range e.AlgCode {
    578 		if a, ok := HashToString[alg]; ok {
    579 			s += " " + a
    580 		} else {
    581 			s += " " + strconv.Itoa(int(alg))
    582 		}
    583 	}
    584 	return s
    585 }
    586 func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
    587 
    588 // EDNS0_EXPIRE implements the EDNS0 option as described in RFC 7314.
    589 type EDNS0_EXPIRE struct {
    590 	Code   uint16 // Always EDNS0EXPIRE
    591 	Expire uint32
    592 	Empty  bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire.
    593 }
    594 
    595 // Option implements the EDNS0 interface.
    596 func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
    597 func (e *EDNS0_EXPIRE) copy() EDNS0    { return &EDNS0_EXPIRE{e.Code, e.Expire, e.Empty} }
    598 
    599 func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
    600 	if e.Empty {
    601 		return []byte{}, nil
    602 	}
    603 	b := make([]byte, 4)
    604 	binary.BigEndian.PutUint32(b, e.Expire)
    605 	return b, nil
    606 }
    607 
    608 func (e *EDNS0_EXPIRE) unpack(b []byte) error {
    609 	if len(b) == 0 {
    610 		// zero-length EXPIRE query, see RFC 7314 Section 2
    611 		e.Empty = true
    612 		return nil
    613 	}
    614 	if len(b) < 4 {
    615 		return ErrBuf
    616 	}
    617 	e.Expire = binary.BigEndian.Uint32(b)
    618 	e.Empty = false
    619 	return nil
    620 }
    621 
    622 func (e *EDNS0_EXPIRE) String() (s string) {
    623 	if e.Empty {
    624 		return ""
    625 	}
    626 	return strconv.FormatUint(uint64(e.Expire), 10)
    627 }
    628 
    629 // The EDNS0_LOCAL option is used for local/experimental purposes. The option
    630 // code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
    631 // (RFC6891), although any unassigned code can actually be used.  The content of
    632 // the option is made available in Data, unaltered.
    633 // Basic use pattern for creating a local option:
    634 //
    635 //	o := new(dns.OPT)
    636 //	o.Hdr.Name = "."
    637 //	o.Hdr.Rrtype = dns.TypeOPT
    638 //	e := new(dns.EDNS0_LOCAL)
    639 //	e.Code = dns.EDNS0LOCALSTART
    640 //	e.Data = []byte{72, 82, 74}
    641 //	o.Option = append(o.Option, e)
    642 type EDNS0_LOCAL struct {
    643 	Code uint16
    644 	Data []byte
    645 }
    646 
    647 // Option implements the EDNS0 interface.
    648 func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
    649 
    650 func (e *EDNS0_LOCAL) String() string {
    651 	return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
    652 }
    653 
    654 func (e *EDNS0_LOCAL) copy() EDNS0 {
    655 	return &EDNS0_LOCAL{e.Code, cloneSlice(e.Data)}
    656 }
    657 
    658 func (e *EDNS0_LOCAL) pack() ([]byte, error) {
    659 	return cloneSlice(e.Data), nil
    660 }
    661 
    662 func (e *EDNS0_LOCAL) unpack(b []byte) error {
    663 	e.Data = cloneSlice(b)
    664 	return nil
    665 }
    666 
    667 // EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
    668 // the TCP connection alive. See RFC 7828.
    669 type EDNS0_TCP_KEEPALIVE struct {
    670 	Code uint16 // Always EDNSTCPKEEPALIVE
    671 
    672 	// Timeout is an idle timeout value for the TCP connection, specified in
    673 	// units of 100 milliseconds, encoded in network byte order. If set to 0,
    674 	// pack will return a nil slice.
    675 	Timeout uint16
    676 
    677 	// Length is the option's length.
    678 	// Deprecated: this field is deprecated and is always equal to 0.
    679 	Length uint16
    680 }
    681 
    682 // Option implements the EDNS0 interface.
    683 func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
    684 
    685 func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
    686 	if e.Timeout > 0 {
    687 		b := make([]byte, 2)
    688 		binary.BigEndian.PutUint16(b, e.Timeout)
    689 		return b, nil
    690 	}
    691 	return nil, nil
    692 }
    693 
    694 func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
    695 	switch len(b) {
    696 	case 0:
    697 	case 2:
    698 		e.Timeout = binary.BigEndian.Uint16(b)
    699 	default:
    700 		return fmt.Errorf("dns: length mismatch, want 0/2 but got %d", len(b))
    701 	}
    702 	return nil
    703 }
    704 
    705 func (e *EDNS0_TCP_KEEPALIVE) String() string {
    706 	s := "use tcp keep-alive"
    707 	if e.Timeout == 0 {
    708 		s += ", timeout omitted"
    709 	} else {
    710 		s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
    711 	}
    712 	return s
    713 }
    714 
    715 func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Timeout, e.Length} }
    716 
    717 // EDNS0_PADDING option is used to add padding to a request/response. The default
    718 // value of padding SHOULD be 0x0 but other values MAY be used, for instance if
    719 // compression is applied before encryption which may break signatures.
    720 type EDNS0_PADDING struct {
    721 	Padding []byte
    722 }
    723 
    724 // Option implements the EDNS0 interface.
    725 func (e *EDNS0_PADDING) Option() uint16        { return EDNS0PADDING }
    726 func (e *EDNS0_PADDING) pack() ([]byte, error) { return cloneSlice(e.Padding), nil }
    727 func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = cloneSlice(b); return nil }
    728 func (e *EDNS0_PADDING) String() string        { return fmt.Sprintf("%0X", e.Padding) }
    729 func (e *EDNS0_PADDING) copy() EDNS0           { return &EDNS0_PADDING{cloneSlice(e.Padding)} }
    730 
    731 // Extended DNS Error Codes (RFC 8914).
    732 const (
    733 	ExtendedErrorCodeOther uint16 = iota
    734 	ExtendedErrorCodeUnsupportedDNSKEYAlgorithm
    735 	ExtendedErrorCodeUnsupportedDSDigestType
    736 	ExtendedErrorCodeStaleAnswer
    737 	ExtendedErrorCodeForgedAnswer
    738 	ExtendedErrorCodeDNSSECIndeterminate
    739 	ExtendedErrorCodeDNSBogus
    740 	ExtendedErrorCodeSignatureExpired
    741 	ExtendedErrorCodeSignatureNotYetValid
    742 	ExtendedErrorCodeDNSKEYMissing
    743 	ExtendedErrorCodeRRSIGsMissing
    744 	ExtendedErrorCodeNoZoneKeyBitSet
    745 	ExtendedErrorCodeNSECMissing
    746 	ExtendedErrorCodeCachedError
    747 	ExtendedErrorCodeNotReady
    748 	ExtendedErrorCodeBlocked
    749 	ExtendedErrorCodeCensored
    750 	ExtendedErrorCodeFiltered
    751 	ExtendedErrorCodeProhibited
    752 	ExtendedErrorCodeStaleNXDOMAINAnswer
    753 	ExtendedErrorCodeNotAuthoritative
    754 	ExtendedErrorCodeNotSupported
    755 	ExtendedErrorCodeNoReachableAuthority
    756 	ExtendedErrorCodeNetworkError
    757 	ExtendedErrorCodeInvalidData
    758 )
    759 
    760 // ExtendedErrorCodeToString maps extended error info codes to a human readable
    761 // description.
    762 var ExtendedErrorCodeToString = map[uint16]string{
    763 	ExtendedErrorCodeOther:                      "Other",
    764 	ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm",
    765 	ExtendedErrorCodeUnsupportedDSDigestType:    "Unsupported DS Digest Type",
    766 	ExtendedErrorCodeStaleAnswer:                "Stale Answer",
    767 	ExtendedErrorCodeForgedAnswer:               "Forged Answer",
    768 	ExtendedErrorCodeDNSSECIndeterminate:        "DNSSEC Indeterminate",
    769 	ExtendedErrorCodeDNSBogus:                   "DNSSEC Bogus",
    770 	ExtendedErrorCodeSignatureExpired:           "Signature Expired",
    771 	ExtendedErrorCodeSignatureNotYetValid:       "Signature Not Yet Valid",
    772 	ExtendedErrorCodeDNSKEYMissing:              "DNSKEY Missing",
    773 	ExtendedErrorCodeRRSIGsMissing:              "RRSIGs Missing",
    774 	ExtendedErrorCodeNoZoneKeyBitSet:            "No Zone Key Bit Set",
    775 	ExtendedErrorCodeNSECMissing:                "NSEC Missing",
    776 	ExtendedErrorCodeCachedError:                "Cached Error",
    777 	ExtendedErrorCodeNotReady:                   "Not Ready",
    778 	ExtendedErrorCodeBlocked:                    "Blocked",
    779 	ExtendedErrorCodeCensored:                   "Censored",
    780 	ExtendedErrorCodeFiltered:                   "Filtered",
    781 	ExtendedErrorCodeProhibited:                 "Prohibited",
    782 	ExtendedErrorCodeStaleNXDOMAINAnswer:        "Stale NXDOMAIN Answer",
    783 	ExtendedErrorCodeNotAuthoritative:           "Not Authoritative",
    784 	ExtendedErrorCodeNotSupported:               "Not Supported",
    785 	ExtendedErrorCodeNoReachableAuthority:       "No Reachable Authority",
    786 	ExtendedErrorCodeNetworkError:               "Network Error",
    787 	ExtendedErrorCodeInvalidData:                "Invalid Data",
    788 }
    789 
    790 // StringToExtendedErrorCode is a map from human readable descriptions to
    791 // extended error info codes.
    792 var StringToExtendedErrorCode = reverseInt16(ExtendedErrorCodeToString)
    793 
    794 // EDNS0_EDE option is used to return additional information about the cause of
    795 // DNS errors.
    796 type EDNS0_EDE struct {
    797 	InfoCode  uint16
    798 	ExtraText string
    799 }
    800 
    801 // Option implements the EDNS0 interface.
    802 func (e *EDNS0_EDE) Option() uint16 { return EDNS0EDE }
    803 func (e *EDNS0_EDE) copy() EDNS0    { return &EDNS0_EDE{e.InfoCode, e.ExtraText} }
    804 
    805 func (e *EDNS0_EDE) String() string {
    806 	info := strconv.FormatUint(uint64(e.InfoCode), 10)
    807 	if s, ok := ExtendedErrorCodeToString[e.InfoCode]; ok {
    808 		info += fmt.Sprintf(" (%s)", s)
    809 	}
    810 	return fmt.Sprintf("%s: (%s)", info, e.ExtraText)
    811 }
    812 
    813 func (e *EDNS0_EDE) pack() ([]byte, error) {
    814 	b := make([]byte, 2+len(e.ExtraText))
    815 	binary.BigEndian.PutUint16(b[0:], e.InfoCode)
    816 	copy(b[2:], e.ExtraText)
    817 	return b, nil
    818 }
    819 
    820 func (e *EDNS0_EDE) unpack(b []byte) error {
    821 	if len(b) < 2 {
    822 		return ErrBuf
    823 	}
    824 	e.InfoCode = binary.BigEndian.Uint16(b[0:])
    825 	e.ExtraText = string(b[2:])
    826 	return nil
    827 }
    828 
    829 // The EDNS0_ESU option for ENUM Source-URI Extension
    830 type EDNS0_ESU struct {
    831 	Code uint16
    832 	Uri  string
    833 }
    834 
    835 // Option implements the EDNS0 interface.
    836 func (e *EDNS0_ESU) Option() uint16        { return EDNS0ESU }
    837 func (e *EDNS0_ESU) String() string        { return e.Uri }
    838 func (e *EDNS0_ESU) copy() EDNS0           { return &EDNS0_ESU{e.Code, e.Uri} }
    839 func (e *EDNS0_ESU) pack() ([]byte, error) { return []byte(e.Uri), nil }
    840 func (e *EDNS0_ESU) unpack(b []byte) error {
    841 	e.Uri = string(b)
    842 	return nil
    843 }