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