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