1package dns
2
3import (
4	"fmt"
5	"net"
6	"strconv"
7	"strings"
8	"time"
9)
10
11type (
12	// Type is a DNS type.
13	Type uint16
14	// Class is a DNS class.
15	Class uint16
16	// Name is a DNS domain name.
17	Name string
18)
19
20// Packet formats
21
22// Wire constants and supported types.
23const (
24	// valid RR_Header.Rrtype and Question.qtype
25
26	TypeNone       uint16 = 0
27	TypeA          uint16 = 1
28	TypeNS         uint16 = 2
29	TypeMD         uint16 = 3
30	TypeMF         uint16 = 4
31	TypeCNAME      uint16 = 5
32	TypeSOA        uint16 = 6
33	TypeMB         uint16 = 7
34	TypeMG         uint16 = 8
35	TypeMR         uint16 = 9
36	TypeNULL       uint16 = 10
37	TypePTR        uint16 = 12
38	TypeHINFO      uint16 = 13
39	TypeMINFO      uint16 = 14
40	TypeMX         uint16 = 15
41	TypeTXT        uint16 = 16
42	TypeRP         uint16 = 17
43	TypeAFSDB      uint16 = 18
44	TypeX25        uint16 = 19
45	TypeISDN       uint16 = 20
46	TypeRT         uint16 = 21
47	TypeNSAPPTR    uint16 = 23
48	TypeSIG        uint16 = 24
49	TypeKEY        uint16 = 25
50	TypePX         uint16 = 26
51	TypeGPOS       uint16 = 27
52	TypeAAAA       uint16 = 28
53	TypeLOC        uint16 = 29
54	TypeNXT        uint16 = 30
55	TypeEID        uint16 = 31
56	TypeNIMLOC     uint16 = 32
57	TypeSRV        uint16 = 33
58	TypeATMA       uint16 = 34
59	TypeNAPTR      uint16 = 35
60	TypeKX         uint16 = 36
61	TypeCERT       uint16 = 37
62	TypeDNAME      uint16 = 39
63	TypeOPT        uint16 = 41 // EDNS
64	TypeDS         uint16 = 43
65	TypeSSHFP      uint16 = 44
66	TypeRRSIG      uint16 = 46
67	TypeNSEC       uint16 = 47
68	TypeDNSKEY     uint16 = 48
69	TypeDHCID      uint16 = 49
70	TypeNSEC3      uint16 = 50
71	TypeNSEC3PARAM uint16 = 51
72	TypeTLSA       uint16 = 52
73	TypeSMIMEA     uint16 = 53
74	TypeHIP        uint16 = 55
75	TypeNINFO      uint16 = 56
76	TypeRKEY       uint16 = 57
77	TypeTALINK     uint16 = 58
78	TypeCDS        uint16 = 59
79	TypeCDNSKEY    uint16 = 60
80	TypeOPENPGPKEY uint16 = 61
81	TypeCSYNC      uint16 = 62
82	TypeSPF        uint16 = 99
83	TypeUINFO      uint16 = 100
84	TypeUID        uint16 = 101
85	TypeGID        uint16 = 102
86	TypeUNSPEC     uint16 = 103
87	TypeNID        uint16 = 104
88	TypeL32        uint16 = 105
89	TypeL64        uint16 = 106
90	TypeLP         uint16 = 107
91	TypeEUI48      uint16 = 108
92	TypeEUI64      uint16 = 109
93	TypeURI        uint16 = 256
94	TypeCAA        uint16 = 257
95	TypeAVC        uint16 = 258
96
97	TypeTKEY uint16 = 249
98	TypeTSIG uint16 = 250
99
100	// valid Question.Qtype only
101	TypeIXFR  uint16 = 251
102	TypeAXFR  uint16 = 252
103	TypeMAILB uint16 = 253
104	TypeMAILA uint16 = 254
105	TypeANY   uint16 = 255
106
107	TypeTA       uint16 = 32768
108	TypeDLV      uint16 = 32769
109	TypeReserved uint16 = 65535
110
111	// valid Question.Qclass
112	ClassINET   = 1
113	ClassCSNET  = 2
114	ClassCHAOS  = 3
115	ClassHESIOD = 4
116	ClassNONE   = 254
117	ClassANY    = 255
118
119	// Message Response Codes, see https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
120	RcodeSuccess        = 0  // NoError   - No Error                          [DNS]
121	RcodeFormatError    = 1  // FormErr   - Format Error                      [DNS]
122	RcodeServerFailure  = 2  // ServFail  - Server Failure                    [DNS]
123	RcodeNameError      = 3  // NXDomain  - Non-Existent Domain               [DNS]
124	RcodeNotImplemented = 4  // NotImp    - Not Implemented                   [DNS]
125	RcodeRefused        = 5  // Refused   - Query Refused                     [DNS]
126	RcodeYXDomain       = 6  // YXDomain  - Name Exists when it should not    [DNS Update]
127	RcodeYXRrset        = 7  // YXRRSet   - RR Set Exists when it should not  [DNS Update]
128	RcodeNXRrset        = 8  // NXRRSet   - RR Set that should exist does not [DNS Update]
129	RcodeNotAuth        = 9  // NotAuth   - Server Not Authoritative for zone [DNS Update]
130	RcodeNotZone        = 10 // NotZone   - Name not contained in zone        [DNS Update/TSIG]
131	RcodeBadSig         = 16 // BADSIG    - TSIG Signature Failure            [TSIG]
132	RcodeBadVers        = 16 // BADVERS   - Bad OPT Version                   [EDNS0]
133	RcodeBadKey         = 17 // BADKEY    - Key not recognized                [TSIG]
134	RcodeBadTime        = 18 // BADTIME   - Signature out of time window      [TSIG]
135	RcodeBadMode        = 19 // BADMODE   - Bad TKEY Mode                     [TKEY]
136	RcodeBadName        = 20 // BADNAME   - Duplicate key name                [TKEY]
137	RcodeBadAlg         = 21 // BADALG    - Algorithm not supported           [TKEY]
138	RcodeBadTrunc       = 22 // BADTRUNC  - Bad Truncation                    [TSIG]
139	RcodeBadCookie      = 23 // BADCOOKIE - Bad/missing Server Cookie         [DNS Cookies]
140
141	// Message Opcodes. There is no 3.
142	OpcodeQuery  = 0
143	OpcodeIQuery = 1
144	OpcodeStatus = 2
145	OpcodeNotify = 4
146	OpcodeUpdate = 5
147)
148
149// Header is the wire format for the DNS packet header.
150type Header struct {
151	Id                                 uint16
152	Bits                               uint16
153	Qdcount, Ancount, Nscount, Arcount uint16
154}
155
156const (
157	headerSize = 12
158
159	// Header.Bits
160	_QR = 1 << 15 // query/response (response=1)
161	_AA = 1 << 10 // authoritative
162	_TC = 1 << 9  // truncated
163	_RD = 1 << 8  // recursion desired
164	_RA = 1 << 7  // recursion available
165	_Z  = 1 << 6  // Z
166	_AD = 1 << 5  // authticated data
167	_CD = 1 << 4  // checking disabled
168)
169
170// Various constants used in the LOC RR, See RFC 1887.
171const (
172	LOC_EQUATOR       = 1 << 31 // RFC 1876, Section 2.
173	LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
174	LOC_HOURS         = 60 * 1000
175	LOC_DEGREES       = 60 * LOC_HOURS
176	LOC_ALTITUDEBASE  = 100000
177)
178
179// Different Certificate Types, see RFC 4398, Section 2.1
180const (
181	CertPKIX = 1 + iota
182	CertSPKI
183	CertPGP
184	CertIPIX
185	CertISPKI
186	CertIPGP
187	CertACPKIX
188	CertIACPKIX
189	CertURI = 253
190	CertOID = 254
191)
192
193// CertTypeToString converts the Cert Type to its string representation.
194// See RFC 4398 and RFC 6944.
195var CertTypeToString = map[uint16]string{
196	CertPKIX:    "PKIX",
197	CertSPKI:    "SPKI",
198	CertPGP:     "PGP",
199	CertIPIX:    "IPIX",
200	CertISPKI:   "ISPKI",
201	CertIPGP:    "IPGP",
202	CertACPKIX:  "ACPKIX",
203	CertIACPKIX: "IACPKIX",
204	CertURI:     "URI",
205	CertOID:     "OID",
206}
207
208// StringToCertType is the reverseof CertTypeToString.
209var StringToCertType = reverseInt16(CertTypeToString)
210
211//go:generate go run types_generate.go
212
213// Question holds a DNS question. There can be multiple questions in the
214// question section of a message. Usually there is just one.
215type Question struct {
216	Name   string `dns:"cdomain-name"` // "cdomain-name" specifies encoding (and may be compressed)
217	Qtype  uint16
218	Qclass uint16
219}
220
221func (q *Question) len() int {
222	return len(q.Name) + 1 + 2 + 2
223}
224
225func (q *Question) String() (s string) {
226	// prefix with ; (as in dig)
227	s = ";" + sprintName(q.Name) + "\t"
228	s += Class(q.Qclass).String() + "\t"
229	s += " " + Type(q.Qtype).String()
230	return s
231}
232
233// ANY is a wildcard record. See RFC 1035, Section 3.2.3. ANY
234// is named "*" there.
235type ANY struct {
236	Hdr RR_Header
237	// Does not have any rdata
238}
239
240func (rr *ANY) String() string { return rr.Hdr.String() }
241
242// CNAME RR. See RFC 1034.
243type CNAME struct {
244	Hdr    RR_Header
245	Target string `dns:"cdomain-name"`
246}
247
248func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
249
250// HINFO RR. See RFC 1034.
251type HINFO struct {
252	Hdr RR_Header
253	Cpu string
254	Os  string
255}
256
257func (rr *HINFO) String() string {
258	return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
259}
260
261// MB RR. See RFC 1035.
262type MB struct {
263	Hdr RR_Header
264	Mb  string `dns:"cdomain-name"`
265}
266
267func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
268
269// MG RR. See RFC 1035.
270type MG struct {
271	Hdr RR_Header
272	Mg  string `dns:"cdomain-name"`
273}
274
275func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
276
277// MINFO RR. See RFC 1035.
278type MINFO struct {
279	Hdr   RR_Header
280	Rmail string `dns:"cdomain-name"`
281	Email string `dns:"cdomain-name"`
282}
283
284func (rr *MINFO) String() string {
285	return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
286}
287
288// MR RR. See RFC 1035.
289type MR struct {
290	Hdr RR_Header
291	Mr  string `dns:"cdomain-name"`
292}
293
294func (rr *MR) String() string {
295	return rr.Hdr.String() + sprintName(rr.Mr)
296}
297
298// MF RR. See RFC 1035.
299type MF struct {
300	Hdr RR_Header
301	Mf  string `dns:"cdomain-name"`
302}
303
304func (rr *MF) String() string {
305	return rr.Hdr.String() + sprintName(rr.Mf)
306}
307
308// MD RR. See RFC 1035.
309type MD struct {
310	Hdr RR_Header
311	Md  string `dns:"cdomain-name"`
312}
313
314func (rr *MD) String() string {
315	return rr.Hdr.String() + sprintName(rr.Md)
316}
317
318// MX RR. See RFC 1035.
319type MX struct {
320	Hdr        RR_Header
321	Preference uint16
322	Mx         string `dns:"cdomain-name"`
323}
324
325func (rr *MX) String() string {
326	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
327}
328
329// AFSDB RR. See RFC 1183.
330type AFSDB struct {
331	Hdr      RR_Header
332	Subtype  uint16
333	Hostname string `dns:"domain-name"`
334}
335
336func (rr *AFSDB) String() string {
337	return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
338}
339
340// X25 RR. See RFC 1183, Section 3.1.
341type X25 struct {
342	Hdr         RR_Header
343	PSDNAddress string
344}
345
346func (rr *X25) String() string {
347	return rr.Hdr.String() + rr.PSDNAddress
348}
349
350// RT RR. See RFC 1183, Section 3.3.
351type RT struct {
352	Hdr        RR_Header
353	Preference uint16
354	Host       string `dns:"cdomain-name"`
355}
356
357func (rr *RT) String() string {
358	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
359}
360
361// NS RR. See RFC 1035.
362type NS struct {
363	Hdr RR_Header
364	Ns  string `dns:"cdomain-name"`
365}
366
367func (rr *NS) String() string {
368	return rr.Hdr.String() + sprintName(rr.Ns)
369}
370
371// PTR RR. See RFC 1035.
372type PTR struct {
373	Hdr RR_Header
374	Ptr string `dns:"cdomain-name"`
375}
376
377func (rr *PTR) String() string {
378	return rr.Hdr.String() + sprintName(rr.Ptr)
379}
380
381// RP RR. See RFC 1138, Section 2.2.
382type RP struct {
383	Hdr  RR_Header
384	Mbox string `dns:"domain-name"`
385	Txt  string `dns:"domain-name"`
386}
387
388func (rr *RP) String() string {
389	return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
390}
391
392// SOA RR. See RFC 1035.
393type SOA struct {
394	Hdr     RR_Header
395	Ns      string `dns:"cdomain-name"`
396	Mbox    string `dns:"cdomain-name"`
397	Serial  uint32
398	Refresh uint32
399	Retry   uint32
400	Expire  uint32
401	Minttl  uint32
402}
403
404func (rr *SOA) String() string {
405	return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
406		" " + strconv.FormatInt(int64(rr.Serial), 10) +
407		" " + strconv.FormatInt(int64(rr.Refresh), 10) +
408		" " + strconv.FormatInt(int64(rr.Retry), 10) +
409		" " + strconv.FormatInt(int64(rr.Expire), 10) +
410		" " + strconv.FormatInt(int64(rr.Minttl), 10)
411}
412
413// TXT RR. See RFC 1035.
414type TXT struct {
415	Hdr RR_Header
416	Txt []string `dns:"txt"`
417}
418
419func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
420
421func sprintName(s string) string {
422	var dst strings.Builder
423	dst.Grow(len(s))
424	for i := 0; i < len(s); {
425		if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
426			dst.WriteString(s[i : i+2])
427			i += 2
428			continue
429		}
430
431		b, n := nextByte(s, i)
432		switch {
433		case n == 0:
434			i++ // dangling back slash
435		case b == '.':
436			dst.WriteByte('.')
437		default:
438			writeDomainNameByte(&dst, b)
439		}
440		i += n
441	}
442	return dst.String()
443}
444
445func sprintTxtOctet(s string) string {
446	var dst strings.Builder
447	dst.Grow(2 + len(s))
448	dst.WriteByte('"')
449	for i := 0; i < len(s); {
450		if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
451			dst.WriteString(s[i : i+2])
452			i += 2
453			continue
454		}
455
456		b, n := nextByte(s, i)
457		switch {
458		case n == 0:
459			i++ // dangling back slash
460		case b == '.':
461			dst.WriteByte('.')
462		case b < ' ' || b > '~':
463			writeEscapedByte(&dst, b)
464		default:
465			dst.WriteByte(b)
466		}
467		i += n
468	}
469	dst.WriteByte('"')
470	return dst.String()
471}
472
473func sprintTxt(txt []string) string {
474	var out strings.Builder
475	for i, s := range txt {
476		out.Grow(3 + len(s))
477		if i > 0 {
478			out.WriteString(` "`)
479		} else {
480			out.WriteByte('"')
481		}
482		for j := 0; j < len(s); {
483			b, n := nextByte(s, j)
484			if n == 0 {
485				break
486			}
487			writeTXTStringByte(&out, b)
488			j += n
489		}
490		out.WriteByte('"')
491	}
492	return out.String()
493}
494
495func writeDomainNameByte(s *strings.Builder, b byte) {
496	switch b {
497	case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
498		s.WriteByte('\\')
499		s.WriteByte(b)
500	default:
501		writeTXTStringByte(s, b)
502	}
503}
504
505func writeTXTStringByte(s *strings.Builder, b byte) {
506	switch {
507	case b == '"' || b == '\\':
508		s.WriteByte('\\')
509		s.WriteByte(b)
510	case b < ' ' || b > '~':
511		writeEscapedByte(s, b)
512	default:
513		s.WriteByte(b)
514	}
515}
516
517func writeEscapedByte(s *strings.Builder, b byte) {
518	var buf [3]byte
519	bufs := strconv.AppendInt(buf[:0], int64(b), 10)
520	s.WriteByte('\\')
521	for i := len(bufs); i < 3; i++ {
522		s.WriteByte('0')
523	}
524	s.Write(bufs)
525}
526
527func nextByte(s string, offset int) (byte, int) {
528	if offset >= len(s) {
529		return 0, 0
530	}
531	if s[offset] != '\\' {
532		// not an escape sequence
533		return s[offset], 1
534	}
535	switch len(s) - offset {
536	case 1: // dangling escape
537		return 0, 0
538	case 2, 3: // too short to be \ddd
539	default: // maybe \ddd
540		if isDigit(s[offset+1]) && isDigit(s[offset+2]) && isDigit(s[offset+3]) {
541			return dddStringToByte(s[offset+1:]), 4
542		}
543	}
544	// not \ddd, just an RFC 1035 "quoted" character
545	return s[offset+1], 2
546}
547
548// SPF RR. See RFC 4408, Section 3.1.1.
549type SPF struct {
550	Hdr RR_Header
551	Txt []string `dns:"txt"`
552}
553
554func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
555
556// AVC RR. See https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template.
557type AVC struct {
558	Hdr RR_Header
559	Txt []string `dns:"txt"`
560}
561
562func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
563
564// SRV RR. See RFC 2782.
565type SRV struct {
566	Hdr      RR_Header
567	Priority uint16
568	Weight   uint16
569	Port     uint16
570	Target   string `dns:"domain-name"`
571}
572
573func (rr *SRV) String() string {
574	return rr.Hdr.String() +
575		strconv.Itoa(int(rr.Priority)) + " " +
576		strconv.Itoa(int(rr.Weight)) + " " +
577		strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
578}
579
580// NAPTR RR. See RFC 2915.
581type NAPTR struct {
582	Hdr         RR_Header
583	Order       uint16
584	Preference  uint16
585	Flags       string
586	Service     string
587	Regexp      string
588	Replacement string `dns:"domain-name"`
589}
590
591func (rr *NAPTR) String() string {
592	return rr.Hdr.String() +
593		strconv.Itoa(int(rr.Order)) + " " +
594		strconv.Itoa(int(rr.Preference)) + " " +
595		"\"" + rr.Flags + "\" " +
596		"\"" + rr.Service + "\" " +
597		"\"" + rr.Regexp + "\" " +
598		rr.Replacement
599}
600
601// CERT RR. See RFC 4398.
602type CERT struct {
603	Hdr         RR_Header
604	Type        uint16
605	KeyTag      uint16
606	Algorithm   uint8
607	Certificate string `dns:"base64"`
608}
609
610func (rr *CERT) String() string {
611	var (
612		ok                  bool
613		certtype, algorithm string
614	)
615	if certtype, ok = CertTypeToString[rr.Type]; !ok {
616		certtype = strconv.Itoa(int(rr.Type))
617	}
618	if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok {
619		algorithm = strconv.Itoa(int(rr.Algorithm))
620	}
621	return rr.Hdr.String() + certtype +
622		" " + strconv.Itoa(int(rr.KeyTag)) +
623		" " + algorithm +
624		" " + rr.Certificate
625}
626
627// DNAME RR. See RFC 2672.
628type DNAME struct {
629	Hdr    RR_Header
630	Target string `dns:"domain-name"`
631}
632
633func (rr *DNAME) String() string {
634	return rr.Hdr.String() + sprintName(rr.Target)
635}
636
637// A RR. See RFC 1035.
638type A struct {
639	Hdr RR_Header
640	A   net.IP `dns:"a"`
641}
642
643func (rr *A) String() string {
644	if rr.A == nil {
645		return rr.Hdr.String()
646	}
647	return rr.Hdr.String() + rr.A.String()
648}
649
650// AAAA RR. See RFC 3596.
651type AAAA struct {
652	Hdr  RR_Header
653	AAAA net.IP `dns:"aaaa"`
654}
655
656func (rr *AAAA) String() string {
657	if rr.AAAA == nil {
658		return rr.Hdr.String()
659	}
660	return rr.Hdr.String() + rr.AAAA.String()
661}
662
663// PX RR. See RFC 2163.
664type PX struct {
665	Hdr        RR_Header
666	Preference uint16
667	Map822     string `dns:"domain-name"`
668	Mapx400    string `dns:"domain-name"`
669}
670
671func (rr *PX) String() string {
672	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
673}
674
675// GPOS RR. See RFC 1712.
676type GPOS struct {
677	Hdr       RR_Header
678	Longitude string
679	Latitude  string
680	Altitude  string
681}
682
683func (rr *GPOS) String() string {
684	return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
685}
686
687// LOC RR. See RFC RFC 1876.
688type LOC struct {
689	Hdr       RR_Header
690	Version   uint8
691	Size      uint8
692	HorizPre  uint8
693	VertPre   uint8
694	Latitude  uint32
695	Longitude uint32
696	Altitude  uint32
697}
698
699// cmToM takes a cm value expressed in RFC1876 SIZE mantissa/exponent
700// format and returns a string in m (two decimals for the cm)
701func cmToM(m, e uint8) string {
702	if e < 2 {
703		if e == 1 {
704			m *= 10
705		}
706
707		return fmt.Sprintf("0.%02d", m)
708	}
709
710	s := fmt.Sprintf("%d", m)
711	for e > 2 {
712		s += "0"
713		e--
714	}
715	return s
716}
717
718func (rr *LOC) String() string {
719	s := rr.Hdr.String()
720
721	lat := rr.Latitude
722	ns := "N"
723	if lat > LOC_EQUATOR {
724		lat = lat - LOC_EQUATOR
725	} else {
726		ns = "S"
727		lat = LOC_EQUATOR - lat
728	}
729	h := lat / LOC_DEGREES
730	lat = lat % LOC_DEGREES
731	m := lat / LOC_HOURS
732	lat = lat % LOC_HOURS
733	s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lat)/1000, ns)
734
735	lon := rr.Longitude
736	ew := "E"
737	if lon > LOC_PRIMEMERIDIAN {
738		lon = lon - LOC_PRIMEMERIDIAN
739	} else {
740		ew = "W"
741		lon = LOC_PRIMEMERIDIAN - lon
742	}
743	h = lon / LOC_DEGREES
744	lon = lon % LOC_DEGREES
745	m = lon / LOC_HOURS
746	lon = lon % LOC_HOURS
747	s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lon)/1000, ew)
748
749	var alt = float64(rr.Altitude) / 100
750	alt -= LOC_ALTITUDEBASE
751	if rr.Altitude%100 != 0 {
752		s += fmt.Sprintf("%.2fm ", alt)
753	} else {
754		s += fmt.Sprintf("%.0fm ", alt)
755	}
756
757	s += cmToM(rr.Size&0xf0>>4, rr.Size&0x0f) + "m "
758	s += cmToM(rr.HorizPre&0xf0>>4, rr.HorizPre&0x0f) + "m "
759	s += cmToM(rr.VertPre&0xf0>>4, rr.VertPre&0x0f) + "m"
760
761	return s
762}
763
764// SIG RR. See RFC 2535. The SIG RR is identical to RRSIG and nowadays only used for SIG(0), See RFC 2931.
765type SIG struct {
766	RRSIG
767}
768
769// RRSIG RR. See RFC 4034 and RFC 3755.
770type RRSIG struct {
771	Hdr         RR_Header
772	TypeCovered uint16
773	Algorithm   uint8
774	Labels      uint8
775	OrigTtl     uint32
776	Expiration  uint32
777	Inception   uint32
778	KeyTag      uint16
779	SignerName  string `dns:"domain-name"`
780	Signature   string `dns:"base64"`
781}
782
783func (rr *RRSIG) String() string {
784	s := rr.Hdr.String()
785	s += Type(rr.TypeCovered).String()
786	s += " " + strconv.Itoa(int(rr.Algorithm)) +
787		" " + strconv.Itoa(int(rr.Labels)) +
788		" " + strconv.FormatInt(int64(rr.OrigTtl), 10) +
789		" " + TimeToString(rr.Expiration) +
790		" " + TimeToString(rr.Inception) +
791		" " + strconv.Itoa(int(rr.KeyTag)) +
792		" " + sprintName(rr.SignerName) +
793		" " + rr.Signature
794	return s
795}
796
797// NSEC RR. See RFC 4034 and RFC 3755.
798type NSEC struct {
799	Hdr        RR_Header
800	NextDomain string   `dns:"domain-name"`
801	TypeBitMap []uint16 `dns:"nsec"`
802}
803
804func (rr *NSEC) String() string {
805	s := rr.Hdr.String() + sprintName(rr.NextDomain)
806	for i := 0; i < len(rr.TypeBitMap); i++ {
807		s += " " + Type(rr.TypeBitMap[i]).String()
808	}
809	return s
810}
811
812func (rr *NSEC) len() int {
813	l := rr.Hdr.len() + len(rr.NextDomain) + 1
814	lastwindow := uint32(2 ^ 32 + 1)
815	for _, t := range rr.TypeBitMap {
816		window := t / 256
817		if uint32(window) != lastwindow {
818			l += 1 + 32
819		}
820		lastwindow = uint32(window)
821	}
822	return l
823}
824
825// DLV RR. See RFC 4431.
826type DLV struct{ DS }
827
828// CDS RR. See RFC 7344.
829type CDS struct{ DS }
830
831// DS RR. See RFC 4034 and RFC 3658.
832type DS struct {
833	Hdr        RR_Header
834	KeyTag     uint16
835	Algorithm  uint8
836	DigestType uint8
837	Digest     string `dns:"hex"`
838}
839
840func (rr *DS) String() string {
841	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
842		" " + strconv.Itoa(int(rr.Algorithm)) +
843		" " + strconv.Itoa(int(rr.DigestType)) +
844		" " + strings.ToUpper(rr.Digest)
845}
846
847// KX RR. See RFC 2230.
848type KX struct {
849	Hdr        RR_Header
850	Preference uint16
851	Exchanger  string `dns:"domain-name"`
852}
853
854func (rr *KX) String() string {
855	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
856		" " + sprintName(rr.Exchanger)
857}
858
859// TA RR. See http://www.watson.org/~weiler/INI1999-19.pdf.
860type TA struct {
861	Hdr        RR_Header
862	KeyTag     uint16
863	Algorithm  uint8
864	DigestType uint8
865	Digest     string `dns:"hex"`
866}
867
868func (rr *TA) String() string {
869	return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
870		" " + strconv.Itoa(int(rr.Algorithm)) +
871		" " + strconv.Itoa(int(rr.DigestType)) +
872		" " + strings.ToUpper(rr.Digest)
873}
874
875// TALINK RR. See https://www.iana.org/assignments/dns-parameters/TALINK/talink-completed-template.
876type TALINK struct {
877	Hdr          RR_Header
878	PreviousName string `dns:"domain-name"`
879	NextName     string `dns:"domain-name"`
880}
881
882func (rr *TALINK) String() string {
883	return rr.Hdr.String() +
884		sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
885}
886
887// SSHFP RR. See RFC RFC 4255.
888type SSHFP struct {
889	Hdr         RR_Header
890	Algorithm   uint8
891	Type        uint8
892	FingerPrint string `dns:"hex"`
893}
894
895func (rr *SSHFP) String() string {
896	return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
897		" " + strconv.Itoa(int(rr.Type)) +
898		" " + strings.ToUpper(rr.FingerPrint)
899}
900
901// KEY RR. See RFC RFC 2535.
902type KEY struct {
903	DNSKEY
904}
905
906// CDNSKEY RR. See RFC 7344.
907type CDNSKEY struct {
908	DNSKEY
909}
910
911// DNSKEY RR. See RFC 4034 and RFC 3755.
912type DNSKEY struct {
913	Hdr       RR_Header
914	Flags     uint16
915	Protocol  uint8
916	Algorithm uint8
917	PublicKey string `dns:"base64"`
918}
919
920func (rr *DNSKEY) String() string {
921	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
922		" " + strconv.Itoa(int(rr.Protocol)) +
923		" " + strconv.Itoa(int(rr.Algorithm)) +
924		" " + rr.PublicKey
925}
926
927// RKEY RR. See https://www.iana.org/assignments/dns-parameters/RKEY/rkey-completed-template.
928type RKEY struct {
929	Hdr       RR_Header
930	Flags     uint16
931	Protocol  uint8
932	Algorithm uint8
933	PublicKey string `dns:"base64"`
934}
935
936func (rr *RKEY) String() string {
937	return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
938		" " + strconv.Itoa(int(rr.Protocol)) +
939		" " + strconv.Itoa(int(rr.Algorithm)) +
940		" " + rr.PublicKey
941}
942
943// NSAPPTR RR. See RFC 1348.
944type NSAPPTR struct {
945	Hdr RR_Header
946	Ptr string `dns:"domain-name"`
947}
948
949func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
950
951// NSEC3 RR. See RFC 5155.
952type NSEC3 struct {
953	Hdr        RR_Header
954	Hash       uint8
955	Flags      uint8
956	Iterations uint16
957	SaltLength uint8
958	Salt       string `dns:"size-hex:SaltLength"`
959	HashLength uint8
960	NextDomain string   `dns:"size-base32:HashLength"`
961	TypeBitMap []uint16 `dns:"nsec"`
962}
963
964func (rr *NSEC3) String() string {
965	s := rr.Hdr.String()
966	s += strconv.Itoa(int(rr.Hash)) +
967		" " + strconv.Itoa(int(rr.Flags)) +
968		" " + strconv.Itoa(int(rr.Iterations)) +
969		" " + saltToString(rr.Salt) +
970		" " + rr.NextDomain
971	for i := 0; i < len(rr.TypeBitMap); i++ {
972		s += " " + Type(rr.TypeBitMap[i]).String()
973	}
974	return s
975}
976
977func (rr *NSEC3) len() int {
978	l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
979	lastwindow := uint32(2 ^ 32 + 1)
980	for _, t := range rr.TypeBitMap {
981		window := t / 256
982		if uint32(window) != lastwindow {
983			l += 1 + 32
984		}
985		lastwindow = uint32(window)
986	}
987	return l
988}
989
990// NSEC3PARAM RR. See RFC 5155.
991type NSEC3PARAM struct {
992	Hdr        RR_Header
993	Hash       uint8
994	Flags      uint8
995	Iterations uint16
996	SaltLength uint8
997	Salt       string `dns:"size-hex:SaltLength"`
998}
999
1000func (rr *NSEC3PARAM) String() string {
1001	s := rr.Hdr.String()
1002	s += strconv.Itoa(int(rr.Hash)) +
1003		" " + strconv.Itoa(int(rr.Flags)) +
1004		" " + strconv.Itoa(int(rr.Iterations)) +
1005		" " + saltToString(rr.Salt)
1006	return s
1007}
1008
1009// TKEY RR. See RFC 2930.
1010type TKEY struct {
1011	Hdr        RR_Header
1012	Algorithm  string `dns:"domain-name"`
1013	Inception  uint32
1014	Expiration uint32
1015	Mode       uint16
1016	Error      uint16
1017	KeySize    uint16
1018	Key        string `dns:"size-hex:KeySize"`
1019	OtherLen   uint16
1020	OtherData  string `dns:"size-hex:OtherLen"`
1021}
1022
1023// TKEY has no official presentation format, but this will suffice.
1024func (rr *TKEY) String() string {
1025	s := "\n;; TKEY PSEUDOSECTION:\n"
1026	s += rr.Hdr.String() + " " + rr.Algorithm + " " +
1027		strconv.Itoa(int(rr.KeySize)) + " " + rr.Key + " " +
1028		strconv.Itoa(int(rr.OtherLen)) + " " + rr.OtherData
1029	return s
1030}
1031
1032// RFC3597 represents an unknown/generic RR. See RFC 3597.
1033type RFC3597 struct {
1034	Hdr   RR_Header
1035	Rdata string `dns:"hex"`
1036}
1037
1038func (rr *RFC3597) String() string {
1039	// Let's call it a hack
1040	s := rfc3597Header(rr.Hdr)
1041
1042	s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata
1043	return s
1044}
1045
1046func rfc3597Header(h RR_Header) string {
1047	var s string
1048
1049	s += sprintName(h.Name) + "\t"
1050	s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
1051	s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t"
1052	s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t"
1053	return s
1054}
1055
1056// URI RR. See RFC 7553.
1057type URI struct {
1058	Hdr      RR_Header
1059	Priority uint16
1060	Weight   uint16
1061	Target   string `dns:"octet"`
1062}
1063
1064func (rr *URI) String() string {
1065	return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
1066		" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
1067}
1068
1069// DHCID RR. See RFC 4701.
1070type DHCID struct {
1071	Hdr    RR_Header
1072	Digest string `dns:"base64"`
1073}
1074
1075func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
1076
1077// TLSA RR. See RFC 6698.
1078type TLSA struct {
1079	Hdr          RR_Header
1080	Usage        uint8
1081	Selector     uint8
1082	MatchingType uint8
1083	Certificate  string `dns:"hex"`
1084}
1085
1086func (rr *TLSA) String() string {
1087	return rr.Hdr.String() +
1088		strconv.Itoa(int(rr.Usage)) +
1089		" " + strconv.Itoa(int(rr.Selector)) +
1090		" " + strconv.Itoa(int(rr.MatchingType)) +
1091		" " + rr.Certificate
1092}
1093
1094// SMIMEA RR. See RFC 8162.
1095type SMIMEA struct {
1096	Hdr          RR_Header
1097	Usage        uint8
1098	Selector     uint8
1099	MatchingType uint8
1100	Certificate  string `dns:"hex"`
1101}
1102
1103func (rr *SMIMEA) String() string {
1104	s := rr.Hdr.String() +
1105		strconv.Itoa(int(rr.Usage)) +
1106		" " + strconv.Itoa(int(rr.Selector)) +
1107		" " + strconv.Itoa(int(rr.MatchingType))
1108
1109	// Every Nth char needs a space on this output. If we output
1110	// this as one giant line, we can't read it can in because in some cases
1111	// the cert length overflows scan.maxTok (2048).
1112	sx := splitN(rr.Certificate, 1024) // conservative value here
1113	s += " " + strings.Join(sx, " ")
1114	return s
1115}
1116
1117// HIP RR. See RFC 8005.
1118type HIP struct {
1119	Hdr                RR_Header
1120	HitLength          uint8
1121	PublicKeyAlgorithm uint8
1122	PublicKeyLength    uint16
1123	Hit                string   `dns:"size-hex:HitLength"`
1124	PublicKey          string   `dns:"size-base64:PublicKeyLength"`
1125	RendezvousServers  []string `dns:"domain-name"`
1126}
1127
1128func (rr *HIP) String() string {
1129	s := rr.Hdr.String() +
1130		strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
1131		" " + rr.Hit +
1132		" " + rr.PublicKey
1133	for _, d := range rr.RendezvousServers {
1134		s += " " + sprintName(d)
1135	}
1136	return s
1137}
1138
1139// NINFO RR. See https://www.iana.org/assignments/dns-parameters/NINFO/ninfo-completed-template.
1140type NINFO struct {
1141	Hdr    RR_Header
1142	ZSData []string `dns:"txt"`
1143}
1144
1145func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
1146
1147// NID RR. See RFC RFC 6742.
1148type NID struct {
1149	Hdr        RR_Header
1150	Preference uint16
1151	NodeID     uint64
1152}
1153
1154func (rr *NID) String() string {
1155	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1156	node := fmt.Sprintf("%0.16x", rr.NodeID)
1157	s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1158	return s
1159}
1160
1161// L32 RR, See RFC 6742.
1162type L32 struct {
1163	Hdr        RR_Header
1164	Preference uint16
1165	Locator32  net.IP `dns:"a"`
1166}
1167
1168func (rr *L32) String() string {
1169	if rr.Locator32 == nil {
1170		return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1171	}
1172	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
1173		" " + rr.Locator32.String()
1174}
1175
1176// L64 RR, See RFC 6742.
1177type L64 struct {
1178	Hdr        RR_Header
1179	Preference uint16
1180	Locator64  uint64
1181}
1182
1183func (rr *L64) String() string {
1184	s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1185	node := fmt.Sprintf("%0.16X", rr.Locator64)
1186	s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1187	return s
1188}
1189
1190// LP RR. See RFC 6742.
1191type LP struct {
1192	Hdr        RR_Header
1193	Preference uint16
1194	Fqdn       string `dns:"domain-name"`
1195}
1196
1197func (rr *LP) String() string {
1198	return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
1199}
1200
1201// EUI48 RR. See RFC 7043.
1202type EUI48 struct {
1203	Hdr     RR_Header
1204	Address uint64 `dns:"uint48"`
1205}
1206
1207func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
1208
1209// EUI64 RR. See RFC 7043.
1210type EUI64 struct {
1211	Hdr     RR_Header
1212	Address uint64
1213}
1214
1215func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
1216
1217// CAA RR. See RFC 6844.
1218type CAA struct {
1219	Hdr   RR_Header
1220	Flag  uint8
1221	Tag   string
1222	Value string `dns:"octet"`
1223}
1224
1225func (rr *CAA) String() string {
1226	return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
1227}
1228
1229// UID RR. Deprecated, IANA-Reserved.
1230type UID struct {
1231	Hdr RR_Header
1232	Uid uint32
1233}
1234
1235func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
1236
1237// GID RR. Deprecated, IANA-Reserved.
1238type GID struct {
1239	Hdr RR_Header
1240	Gid uint32
1241}
1242
1243func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
1244
1245// UINFO RR. Deprecated, IANA-Reserved.
1246type UINFO struct {
1247	Hdr   RR_Header
1248	Uinfo string
1249}
1250
1251func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
1252
1253// EID RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
1254type EID struct {
1255	Hdr      RR_Header
1256	Endpoint string `dns:"hex"`
1257}
1258
1259func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
1260
1261// NIMLOC RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
1262type NIMLOC struct {
1263	Hdr     RR_Header
1264	Locator string `dns:"hex"`
1265}
1266
1267func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
1268
1269// OPENPGPKEY RR. See RFC 7929.
1270type OPENPGPKEY struct {
1271	Hdr       RR_Header
1272	PublicKey string `dns:"base64"`
1273}
1274
1275func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
1276
1277// CSYNC RR. See RFC 7477.
1278type CSYNC struct {
1279	Hdr        RR_Header
1280	Serial     uint32
1281	Flags      uint16
1282	TypeBitMap []uint16 `dns:"nsec"`
1283}
1284
1285func (rr *CSYNC) String() string {
1286	s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Serial), 10) + " " + strconv.Itoa(int(rr.Flags))
1287
1288	for i := 0; i < len(rr.TypeBitMap); i++ {
1289		s += " " + Type(rr.TypeBitMap[i]).String()
1290	}
1291	return s
1292}
1293
1294func (rr *CSYNC) len() int {
1295	l := rr.Hdr.len() + 4 + 2
1296	lastwindow := uint32(2 ^ 32 + 1)
1297	for _, t := range rr.TypeBitMap {
1298		window := t / 256
1299		if uint32(window) != lastwindow {
1300			l += 1 + 32
1301		}
1302		lastwindow = uint32(window)
1303	}
1304	return l
1305}
1306
1307// TimeToString translates the RRSIG's incep. and expir. times to the
1308// string representation used when printing the record.
1309// It takes serial arithmetic (RFC 1982) into account.
1310func TimeToString(t uint32) string {
1311	mod := (int64(t)-time.Now().Unix())/year68 - 1
1312	if mod < 0 {
1313		mod = 0
1314	}
1315	ti := time.Unix(int64(t)-mod*year68, 0).UTC()
1316	return ti.Format("20060102150405")
1317}
1318
1319// StringToTime translates the RRSIG's incep. and expir. times from
1320// string values like "20110403154150" to an 32 bit integer.
1321// It takes serial arithmetic (RFC 1982) into account.
1322func StringToTime(s string) (uint32, error) {
1323	t, err := time.Parse("20060102150405", s)
1324	if err != nil {
1325		return 0, err
1326	}
1327	mod := t.Unix()/year68 - 1
1328	if mod < 0 {
1329		mod = 0
1330	}
1331	return uint32(t.Unix() - mod*year68), nil
1332}
1333
1334// saltToString converts a NSECX salt to uppercase and returns "-" when it is empty.
1335func saltToString(s string) string {
1336	if len(s) == 0 {
1337		return "-"
1338	}
1339	return strings.ToUpper(s)
1340}
1341
1342func euiToString(eui uint64, bits int) (hex string) {
1343	switch bits {
1344	case 64:
1345		hex = fmt.Sprintf("%16.16x", eui)
1346		hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1347			"-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
1348	case 48:
1349		hex = fmt.Sprintf("%12.12x", eui)
1350		hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1351			"-" + hex[8:10] + "-" + hex[10:12]
1352	}
1353	return
1354}
1355
1356// copyIP returns a copy of ip.
1357func copyIP(ip net.IP) net.IP {
1358	p := make(net.IP, len(ip))
1359	copy(p, ip)
1360	return p
1361}
1362
1363// SplitN splits a string into N sized string chunks.
1364// This might become an exported function once.
1365func splitN(s string, n int) []string {
1366	if len(s) < n {
1367		return []string{s}
1368	}
1369	sx := []string{}
1370	p, i := 0, n
1371	for {
1372		if i <= len(s) {
1373			sx = append(sx, s[p:i])
1374		} else {
1375			sx = append(sx, s[p:])
1376			break
1377
1378		}
1379		p, i = p+n, i+n
1380	}
1381
1382	return sx
1383}
1384