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