1 package dns
2
3 import (
4 "bytes"
5 "fmt"
6 "net"
7 "strconv"
8 "strings"
9 "time"
10 )
11
12 type (
13
14 Type uint16
15
16 Class uint16
17
18 Name string
19 )
20
21
22
23
24 const (
25
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
65 TypeAPL uint16 = 42
66 TypeDS uint16 = 43
67 TypeSSHFP uint16 = 44
68 TypeIPSECKEY uint16 = 45
69 TypeRRSIG uint16 = 46
70 TypeNSEC uint16 = 47
71 TypeDNSKEY uint16 = 48
72 TypeDHCID uint16 = 49
73 TypeNSEC3 uint16 = 50
74 TypeNSEC3PARAM uint16 = 51
75 TypeTLSA uint16 = 52
76 TypeSMIMEA uint16 = 53
77 TypeHIP uint16 = 55
78 TypeNINFO uint16 = 56
79 TypeRKEY uint16 = 57
80 TypeTALINK uint16 = 58
81 TypeCDS uint16 = 59
82 TypeCDNSKEY uint16 = 60
83 TypeOPENPGPKEY uint16 = 61
84 TypeCSYNC uint16 = 62
85 TypeZONEMD uint16 = 63
86 TypeSVCB uint16 = 64
87 TypeHTTPS uint16 = 65
88 TypeSPF uint16 = 99
89 TypeUINFO uint16 = 100
90 TypeUID uint16 = 101
91 TypeGID uint16 = 102
92 TypeUNSPEC uint16 = 103
93 TypeNID uint16 = 104
94 TypeL32 uint16 = 105
95 TypeL64 uint16 = 106
96 TypeLP uint16 = 107
97 TypeEUI48 uint16 = 108
98 TypeEUI64 uint16 = 109
99 TypeURI uint16 = 256
100 TypeCAA uint16 = 257
101 TypeAVC uint16 = 258
102 TypeAMTRELAY uint16 = 260
103
104 TypeTKEY uint16 = 249
105 TypeTSIG uint16 = 250
106
107
108 TypeIXFR uint16 = 251
109 TypeAXFR uint16 = 252
110 TypeMAILB uint16 = 253
111 TypeMAILA uint16 = 254
112 TypeANY uint16 = 255
113
114 TypeTA uint16 = 32768
115 TypeDLV uint16 = 32769
116 TypeReserved uint16 = 65535
117
118
119 ClassINET = 1
120 ClassCSNET = 2
121 ClassCHAOS = 3
122 ClassHESIOD = 4
123 ClassNONE = 254
124 ClassANY = 255
125
126
127 RcodeSuccess = 0
128 RcodeFormatError = 1
129 RcodeServerFailure = 2
130 RcodeNameError = 3
131 RcodeNotImplemented = 4
132 RcodeRefused = 5
133 RcodeYXDomain = 6
134 RcodeYXRrset = 7
135 RcodeNXRrset = 8
136 RcodeNotAuth = 9
137 RcodeNotZone = 10
138 RcodeBadSig = 16
139 RcodeBadVers = 16
140 RcodeBadKey = 17
141 RcodeBadTime = 18
142 RcodeBadMode = 19
143 RcodeBadName = 20
144 RcodeBadAlg = 21
145 RcodeBadTrunc = 22
146 RcodeBadCookie = 23
147
148
149 OpcodeQuery = 0
150 OpcodeIQuery = 1
151 OpcodeStatus = 2
152 OpcodeNotify = 4
153 OpcodeUpdate = 5
154 )
155
156
157 const (
158 ZoneMDSchemeSimple = 1
159
160 ZoneMDHashAlgSHA384 = 1
161 ZoneMDHashAlgSHA512 = 2
162 )
163
164
165 const (
166 IPSECGatewayNone uint8 = iota
167 IPSECGatewayIPv4
168 IPSECGatewayIPv6
169 IPSECGatewayHost
170 )
171
172
173 const (
174 AMTRELAYNone = IPSECGatewayNone
175 AMTRELAYIPv4 = IPSECGatewayIPv4
176 AMTRELAYIPv6 = IPSECGatewayIPv6
177 AMTRELAYHost = IPSECGatewayHost
178 )
179
180
181 type Header struct {
182 Id uint16
183 Bits uint16
184 Qdcount, Ancount, Nscount, Arcount uint16
185 }
186
187 const (
188 headerSize = 12
189
190
191 _QR = 1 << 15
192 _AA = 1 << 10
193 _TC = 1 << 9
194 _RD = 1 << 8
195 _RA = 1 << 7
196 _Z = 1 << 6
197 _AD = 1 << 5
198 _CD = 1 << 4
199 )
200
201
202 const (
203 LOC_EQUATOR = 1 << 31
204 LOC_PRIMEMERIDIAN = 1 << 31
205 LOC_HOURS = 60 * 1000
206 LOC_DEGREES = 60 * LOC_HOURS
207 LOC_ALTITUDEBASE = 100000
208 )
209
210
211 const (
212 CertPKIX = 1 + iota
213 CertSPKI
214 CertPGP
215 CertIPIX
216 CertISPKI
217 CertIPGP
218 CertACPKIX
219 CertIACPKIX
220 CertURI = 253
221 CertOID = 254
222 )
223
224
225
226 var CertTypeToString = map[uint16]string{
227 CertPKIX: "PKIX",
228 CertSPKI: "SPKI",
229 CertPGP: "PGP",
230 CertIPIX: "IPIX",
231 CertISPKI: "ISPKI",
232 CertIPGP: "IPGP",
233 CertACPKIX: "ACPKIX",
234 CertIACPKIX: "IACPKIX",
235 CertURI: "URI",
236 CertOID: "OID",
237 }
238
239
240 const ipv4InIPv6Prefix = "::ffff:"
241
242
243
244
245
246
247
248
249 type Question struct {
250 Name string `dns:"cdomain-name"`
251 Qtype uint16
252 Qclass uint16
253 }
254
255 func (q *Question) len(off int, compression map[string]struct{}) int {
256 l := domainNameLen(q.Name, off, compression, true)
257 l += 2 + 2
258 return l
259 }
260
261 func (q *Question) String() (s string) {
262
263 s = ";" + sprintName(q.Name) + "\t"
264 s += Class(q.Qclass).String() + "\t"
265 s += " " + Type(q.Qtype).String()
266 return s
267 }
268
269
270
271 type ANY struct {
272 Hdr RR_Header
273
274 }
275
276 func (rr *ANY) String() string { return rr.Hdr.String() }
277
278 func (*ANY) parse(c *zlexer, origin string) *ParseError {
279 return &ParseError{err: "ANY records do not have a presentation format"}
280 }
281
282
283 type NULL struct {
284 Hdr RR_Header
285 Data string `dns:"any"`
286 }
287
288 func (rr *NULL) String() string {
289
290 return ";" + rr.Hdr.String() + rr.Data
291 }
292
293 func (*NULL) parse(c *zlexer, origin string) *ParseError {
294 return &ParseError{err: "NULL records do not have a presentation format"}
295 }
296
297
298 type CNAME struct {
299 Hdr RR_Header
300 Target string `dns:"cdomain-name"`
301 }
302
303 func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
304
305
306 type HINFO struct {
307 Hdr RR_Header
308 Cpu string
309 Os string
310 }
311
312 func (rr *HINFO) String() string {
313 return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
314 }
315
316
317 type MB struct {
318 Hdr RR_Header
319 Mb string `dns:"cdomain-name"`
320 }
321
322 func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
323
324
325 type MG struct {
326 Hdr RR_Header
327 Mg string `dns:"cdomain-name"`
328 }
329
330 func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
331
332
333 type MINFO struct {
334 Hdr RR_Header
335 Rmail string `dns:"cdomain-name"`
336 Email string `dns:"cdomain-name"`
337 }
338
339 func (rr *MINFO) String() string {
340 return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
341 }
342
343
344 type MR struct {
345 Hdr RR_Header
346 Mr string `dns:"cdomain-name"`
347 }
348
349 func (rr *MR) String() string {
350 return rr.Hdr.String() + sprintName(rr.Mr)
351 }
352
353
354 type MF struct {
355 Hdr RR_Header
356 Mf string `dns:"cdomain-name"`
357 }
358
359 func (rr *MF) String() string {
360 return rr.Hdr.String() + sprintName(rr.Mf)
361 }
362
363
364 type MD struct {
365 Hdr RR_Header
366 Md string `dns:"cdomain-name"`
367 }
368
369 func (rr *MD) String() string {
370 return rr.Hdr.String() + sprintName(rr.Md)
371 }
372
373
374 type MX struct {
375 Hdr RR_Header
376 Preference uint16
377 Mx string `dns:"cdomain-name"`
378 }
379
380 func (rr *MX) String() string {
381 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
382 }
383
384
385 type AFSDB struct {
386 Hdr RR_Header
387 Subtype uint16
388 Hostname string `dns:"domain-name"`
389 }
390
391 func (rr *AFSDB) String() string {
392 return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
393 }
394
395
396 type X25 struct {
397 Hdr RR_Header
398 PSDNAddress string
399 }
400
401 func (rr *X25) String() string {
402 return rr.Hdr.String() + rr.PSDNAddress
403 }
404
405
406 type RT struct {
407 Hdr RR_Header
408 Preference uint16
409 Host string `dns:"domain-name"`
410 }
411
412 func (rr *RT) String() string {
413 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
414 }
415
416
417 type NS struct {
418 Hdr RR_Header
419 Ns string `dns:"cdomain-name"`
420 }
421
422 func (rr *NS) String() string {
423 return rr.Hdr.String() + sprintName(rr.Ns)
424 }
425
426
427 type PTR struct {
428 Hdr RR_Header
429 Ptr string `dns:"cdomain-name"`
430 }
431
432 func (rr *PTR) String() string {
433 return rr.Hdr.String() + sprintName(rr.Ptr)
434 }
435
436
437 type RP struct {
438 Hdr RR_Header
439 Mbox string `dns:"domain-name"`
440 Txt string `dns:"domain-name"`
441 }
442
443 func (rr *RP) String() string {
444 return rr.Hdr.String() + sprintName(rr.Mbox) + " " + sprintName(rr.Txt)
445 }
446
447
448 type SOA struct {
449 Hdr RR_Header
450 Ns string `dns:"cdomain-name"`
451 Mbox string `dns:"cdomain-name"`
452 Serial uint32
453 Refresh uint32
454 Retry uint32
455 Expire uint32
456 Minttl uint32
457 }
458
459 func (rr *SOA) String() string {
460 return rr.Hdr.String() + sprintName(rr.Ns) + " " + sprintName(rr.Mbox) +
461 " " + strconv.FormatInt(int64(rr.Serial), 10) +
462 " " + strconv.FormatInt(int64(rr.Refresh), 10) +
463 " " + strconv.FormatInt(int64(rr.Retry), 10) +
464 " " + strconv.FormatInt(int64(rr.Expire), 10) +
465 " " + strconv.FormatInt(int64(rr.Minttl), 10)
466 }
467
468
469 type TXT struct {
470 Hdr RR_Header
471 Txt []string `dns:"txt"`
472 }
473
474 func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
475
476 func sprintName(s string) string {
477 var dst strings.Builder
478
479 for i := 0; i < len(s); {
480 if s[i] == '.' {
481 if dst.Len() != 0 {
482 dst.WriteByte('.')
483 }
484 i++
485 continue
486 }
487
488 b, n := nextByte(s, i)
489 if n == 0 {
490
491 if dst.Len() == 0 {
492 return s[:i]
493 }
494 break
495 }
496 if isDomainNameLabelSpecial(b) {
497 if dst.Len() == 0 {
498 dst.Grow(len(s) * 2)
499 dst.WriteString(s[:i])
500 }
501 dst.WriteByte('\\')
502 dst.WriteByte(b)
503 } else if b < ' ' || b > '~' {
504 if dst.Len() == 0 {
505 dst.Grow(len(s) * 2)
506 dst.WriteString(s[:i])
507 }
508 dst.WriteString(escapeByte(b))
509 } else {
510 if dst.Len() != 0 {
511 dst.WriteByte(b)
512 }
513 }
514 i += n
515 }
516 if dst.Len() == 0 {
517 return s
518 }
519 return dst.String()
520 }
521
522 func sprintTxtOctet(s string) string {
523 var dst strings.Builder
524 dst.Grow(2 + len(s))
525 dst.WriteByte('"')
526 for i := 0; i < len(s); {
527 if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
528 dst.WriteString(s[i : i+2])
529 i += 2
530 continue
531 }
532
533 b, n := nextByte(s, i)
534 if n == 0 {
535 i++
536 } else {
537 writeTXTStringByte(&dst, b)
538 }
539 i += n
540 }
541 dst.WriteByte('"')
542 return dst.String()
543 }
544
545 func sprintTxt(txt []string) string {
546 var out strings.Builder
547 for i, s := range txt {
548 out.Grow(3 + len(s))
549 if i > 0 {
550 out.WriteString(` "`)
551 } else {
552 out.WriteByte('"')
553 }
554 for j := 0; j < len(s); {
555 b, n := nextByte(s, j)
556 if n == 0 {
557 break
558 }
559 writeTXTStringByte(&out, b)
560 j += n
561 }
562 out.WriteByte('"')
563 }
564 return out.String()
565 }
566
567 func writeTXTStringByte(s *strings.Builder, b byte) {
568 switch {
569 case b == '"' || b == '\\':
570 s.WriteByte('\\')
571 s.WriteByte(b)
572 case b < ' ' || b > '~':
573 s.WriteString(escapeByte(b))
574 default:
575 s.WriteByte(b)
576 }
577 }
578
579 const (
580 escapedByteSmall = "" +
581 `\000\001\002\003\004\005\006\007\008\009` +
582 `\010\011\012\013\014\015\016\017\018\019` +
583 `\020\021\022\023\024\025\026\027\028\029` +
584 `\030\031`
585 escapedByteLarge = `\127\128\129` +
586 `\130\131\132\133\134\135\136\137\138\139` +
587 `\140\141\142\143\144\145\146\147\148\149` +
588 `\150\151\152\153\154\155\156\157\158\159` +
589 `\160\161\162\163\164\165\166\167\168\169` +
590 `\170\171\172\173\174\175\176\177\178\179` +
591 `\180\181\182\183\184\185\186\187\188\189` +
592 `\190\191\192\193\194\195\196\197\198\199` +
593 `\200\201\202\203\204\205\206\207\208\209` +
594 `\210\211\212\213\214\215\216\217\218\219` +
595 `\220\221\222\223\224\225\226\227\228\229` +
596 `\230\231\232\233\234\235\236\237\238\239` +
597 `\240\241\242\243\244\245\246\247\248\249` +
598 `\250\251\252\253\254\255`
599 )
600
601
602
603 func escapeByte(b byte) string {
604 if b < ' ' {
605 return escapedByteSmall[b*4 : b*4+4]
606 }
607
608 b -= '~' + 1
609
610 return escapedByteLarge[int(b)*4 : int(b)*4+4]
611 }
612
613
614
615
616 func isDomainNameLabelSpecial(b byte) bool {
617 switch b {
618 case '.', ' ', '\'', '@', ';', '(', ')', '"', '\\':
619 return true
620 }
621 return false
622 }
623
624 func nextByte(s string, offset int) (byte, int) {
625 if offset >= len(s) {
626 return 0, 0
627 }
628 if s[offset] != '\\' {
629
630 return s[offset], 1
631 }
632 switch len(s) - offset {
633 case 1:
634 return 0, 0
635 case 2, 3:
636 default:
637 if isDDD(s[offset+1:]) {
638 return dddToByte(s[offset+1:]), 4
639 }
640 }
641
642 return s[offset+1], 2
643 }
644
645
646 type SPF struct {
647 Hdr RR_Header
648 Txt []string `dns:"txt"`
649 }
650
651 func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
652
653
654 type AVC struct {
655 Hdr RR_Header
656 Txt []string `dns:"txt"`
657 }
658
659 func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
660
661
662 type SRV struct {
663 Hdr RR_Header
664 Priority uint16
665 Weight uint16
666 Port uint16
667 Target string `dns:"domain-name"`
668 }
669
670 func (rr *SRV) String() string {
671 return rr.Hdr.String() +
672 strconv.Itoa(int(rr.Priority)) + " " +
673 strconv.Itoa(int(rr.Weight)) + " " +
674 strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
675 }
676
677
678 type NAPTR struct {
679 Hdr RR_Header
680 Order uint16
681 Preference uint16
682 Flags string
683 Service string
684 Regexp string
685 Replacement string `dns:"domain-name"`
686 }
687
688 func (rr *NAPTR) String() string {
689 return rr.Hdr.String() +
690 strconv.Itoa(int(rr.Order)) + " " +
691 strconv.Itoa(int(rr.Preference)) + " " +
692 "\"" + rr.Flags + "\" " +
693 "\"" + rr.Service + "\" " +
694 "\"" + rr.Regexp + "\" " +
695 rr.Replacement
696 }
697
698
699 type CERT struct {
700 Hdr RR_Header
701 Type uint16
702 KeyTag uint16
703 Algorithm uint8
704 Certificate string `dns:"base64"`
705 }
706
707 func (rr *CERT) String() string {
708 var (
709 ok bool
710 certtype, algorithm string
711 )
712 if certtype, ok = CertTypeToString[rr.Type]; !ok {
713 certtype = strconv.Itoa(int(rr.Type))
714 }
715 if algorithm, ok = AlgorithmToString[rr.Algorithm]; !ok {
716 algorithm = strconv.Itoa(int(rr.Algorithm))
717 }
718 return rr.Hdr.String() + certtype +
719 " " + strconv.Itoa(int(rr.KeyTag)) +
720 " " + algorithm +
721 " " + rr.Certificate
722 }
723
724
725 type DNAME struct {
726 Hdr RR_Header
727 Target string `dns:"domain-name"`
728 }
729
730 func (rr *DNAME) String() string {
731 return rr.Hdr.String() + sprintName(rr.Target)
732 }
733
734
735 type A struct {
736 Hdr RR_Header
737 A net.IP `dns:"a"`
738 }
739
740 func (rr *A) String() string {
741 if rr.A == nil {
742 return rr.Hdr.String()
743 }
744 return rr.Hdr.String() + rr.A.String()
745 }
746
747
748 type AAAA struct {
749 Hdr RR_Header
750 AAAA net.IP `dns:"aaaa"`
751 }
752
753 func (rr *AAAA) String() string {
754 if rr.AAAA == nil {
755 return rr.Hdr.String()
756 }
757
758 if rr.AAAA.To4() != nil {
759 return rr.Hdr.String() + ipv4InIPv6Prefix + rr.AAAA.String()
760 }
761
762 return rr.Hdr.String() + rr.AAAA.String()
763 }
764
765
766 type PX struct {
767 Hdr RR_Header
768 Preference uint16
769 Map822 string `dns:"domain-name"`
770 Mapx400 string `dns:"domain-name"`
771 }
772
773 func (rr *PX) String() string {
774 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
775 }
776
777
778 type GPOS struct {
779 Hdr RR_Header
780 Longitude string
781 Latitude string
782 Altitude string
783 }
784
785 func (rr *GPOS) String() string {
786 return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
787 }
788
789
790 type LOC struct {
791 Hdr RR_Header
792 Version uint8
793 Size uint8
794 HorizPre uint8
795 VertPre uint8
796 Latitude uint32
797 Longitude uint32
798 Altitude uint32
799 }
800
801
802
803 func cmToM(x uint8) string {
804 m := x & 0xf0 >> 4
805 e := x & 0x0f
806
807 if e < 2 {
808 if e == 1 {
809 m *= 10
810 }
811
812 return fmt.Sprintf("0.%02d", m)
813 }
814
815 s := fmt.Sprintf("%d", m)
816 for e > 2 {
817 s += "0"
818 e--
819 }
820 return s
821 }
822
823 func (rr *LOC) String() string {
824 s := rr.Hdr.String()
825
826 lat := rr.Latitude
827 ns := "N"
828 if lat > LOC_EQUATOR {
829 lat = lat - LOC_EQUATOR
830 } else {
831 ns = "S"
832 lat = LOC_EQUATOR - lat
833 }
834 h := lat / LOC_DEGREES
835 lat = lat % LOC_DEGREES
836 m := lat / LOC_HOURS
837 lat = lat % LOC_HOURS
838 s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lat)/1000, ns)
839
840 lon := rr.Longitude
841 ew := "E"
842 if lon > LOC_PRIMEMERIDIAN {
843 lon = lon - LOC_PRIMEMERIDIAN
844 } else {
845 ew = "W"
846 lon = LOC_PRIMEMERIDIAN - lon
847 }
848 h = lon / LOC_DEGREES
849 lon = lon % LOC_DEGREES
850 m = lon / LOC_HOURS
851 lon = lon % LOC_HOURS
852 s += fmt.Sprintf("%02d %02d %0.3f %s ", h, m, float64(lon)/1000, ew)
853
854 var alt = float64(rr.Altitude) / 100
855 alt -= LOC_ALTITUDEBASE
856 if rr.Altitude%100 != 0 {
857 s += fmt.Sprintf("%.2fm ", alt)
858 } else {
859 s += fmt.Sprintf("%.0fm ", alt)
860 }
861
862 s += cmToM(rr.Size) + "m "
863 s += cmToM(rr.HorizPre) + "m "
864 s += cmToM(rr.VertPre) + "m"
865 return s
866 }
867
868
869 type SIG struct {
870 RRSIG
871 }
872
873
874 type RRSIG struct {
875 Hdr RR_Header
876 TypeCovered uint16
877 Algorithm uint8
878 Labels uint8
879 OrigTtl uint32
880 Expiration uint32
881 Inception uint32
882 KeyTag uint16
883 SignerName string `dns:"domain-name"`
884 Signature string `dns:"base64"`
885 }
886
887 func (rr *RRSIG) String() string {
888 s := rr.Hdr.String()
889 s += Type(rr.TypeCovered).String()
890 s += " " + strconv.Itoa(int(rr.Algorithm)) +
891 " " + strconv.Itoa(int(rr.Labels)) +
892 " " + strconv.FormatInt(int64(rr.OrigTtl), 10) +
893 " " + TimeToString(rr.Expiration) +
894 " " + TimeToString(rr.Inception) +
895 " " + strconv.Itoa(int(rr.KeyTag)) +
896 " " + sprintName(rr.SignerName) +
897 " " + rr.Signature
898 return s
899 }
900
901
902 type NSEC struct {
903 Hdr RR_Header
904 NextDomain string `dns:"domain-name"`
905 TypeBitMap []uint16 `dns:"nsec"`
906 }
907
908 func (rr *NSEC) String() string {
909 s := rr.Hdr.String() + sprintName(rr.NextDomain)
910 for _, t := range rr.TypeBitMap {
911 s += " " + Type(t).String()
912 }
913 return s
914 }
915
916 func (rr *NSEC) len(off int, compression map[string]struct{}) int {
917 l := rr.Hdr.len(off, compression)
918 l += domainNameLen(rr.NextDomain, off+l, compression, false)
919 l += typeBitMapLen(rr.TypeBitMap)
920 return l
921 }
922
923
924 type DLV struct{ DS }
925
926
927 type CDS struct{ DS }
928
929
930 type DS struct {
931 Hdr RR_Header
932 KeyTag uint16
933 Algorithm uint8
934 DigestType uint8
935 Digest string `dns:"hex"`
936 }
937
938 func (rr *DS) String() string {
939 return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
940 " " + strconv.Itoa(int(rr.Algorithm)) +
941 " " + strconv.Itoa(int(rr.DigestType)) +
942 " " + strings.ToUpper(rr.Digest)
943 }
944
945
946 type KX struct {
947 Hdr RR_Header
948 Preference uint16
949 Exchanger string `dns:"domain-name"`
950 }
951
952 func (rr *KX) String() string {
953 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
954 " " + sprintName(rr.Exchanger)
955 }
956
957
958 type TA struct {
959 Hdr RR_Header
960 KeyTag uint16
961 Algorithm uint8
962 DigestType uint8
963 Digest string `dns:"hex"`
964 }
965
966 func (rr *TA) String() string {
967 return rr.Hdr.String() + strconv.Itoa(int(rr.KeyTag)) +
968 " " + strconv.Itoa(int(rr.Algorithm)) +
969 " " + strconv.Itoa(int(rr.DigestType)) +
970 " " + strings.ToUpper(rr.Digest)
971 }
972
973
974 type TALINK struct {
975 Hdr RR_Header
976 PreviousName string `dns:"domain-name"`
977 NextName string `dns:"domain-name"`
978 }
979
980 func (rr *TALINK) String() string {
981 return rr.Hdr.String() +
982 sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
983 }
984
985
986 type SSHFP struct {
987 Hdr RR_Header
988 Algorithm uint8
989 Type uint8
990 FingerPrint string `dns:"hex"`
991 }
992
993 func (rr *SSHFP) String() string {
994 return rr.Hdr.String() + strconv.Itoa(int(rr.Algorithm)) +
995 " " + strconv.Itoa(int(rr.Type)) +
996 " " + strings.ToUpper(rr.FingerPrint)
997 }
998
999
1000 type KEY struct {
1001 DNSKEY
1002 }
1003
1004
1005 type CDNSKEY struct {
1006 DNSKEY
1007 }
1008
1009
1010 type DNSKEY struct {
1011 Hdr RR_Header
1012 Flags uint16
1013 Protocol uint8
1014 Algorithm uint8
1015 PublicKey string `dns:"base64"`
1016 }
1017
1018 func (rr *DNSKEY) String() string {
1019 return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
1020 " " + strconv.Itoa(int(rr.Protocol)) +
1021 " " + strconv.Itoa(int(rr.Algorithm)) +
1022 " " + rr.PublicKey
1023 }
1024
1025
1026 type IPSECKEY struct {
1027 Hdr RR_Header
1028 Precedence uint8
1029 GatewayType uint8
1030 Algorithm uint8
1031 GatewayAddr net.IP `dns:"-"`
1032 GatewayHost string `dns:"ipsechost"`
1033 PublicKey string `dns:"base64"`
1034 }
1035
1036 func (rr *IPSECKEY) String() string {
1037 var gateway string
1038 switch rr.GatewayType {
1039 case IPSECGatewayIPv4, IPSECGatewayIPv6:
1040 gateway = rr.GatewayAddr.String()
1041 case IPSECGatewayHost:
1042 gateway = rr.GatewayHost
1043 case IPSECGatewayNone:
1044 fallthrough
1045 default:
1046 gateway = "."
1047 }
1048
1049 return rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
1050 " " + strconv.Itoa(int(rr.GatewayType)) +
1051 " " + strconv.Itoa(int(rr.Algorithm)) +
1052 " " + gateway +
1053 " " + rr.PublicKey
1054 }
1055
1056
1057 type AMTRELAY struct {
1058 Hdr RR_Header
1059 Precedence uint8
1060 GatewayType uint8
1061 GatewayAddr net.IP `dns:"-"`
1062 GatewayHost string `dns:"amtrelayhost"`
1063 }
1064
1065 func (rr *AMTRELAY) String() string {
1066 var gateway string
1067 switch rr.GatewayType & 0x7f {
1068 case AMTRELAYIPv4, AMTRELAYIPv6:
1069 gateway = rr.GatewayAddr.String()
1070 case AMTRELAYHost:
1071 gateway = rr.GatewayHost
1072 case AMTRELAYNone:
1073 fallthrough
1074 default:
1075 gateway = "."
1076 }
1077 boolS := "0"
1078 if rr.GatewayType&0x80 == 0x80 {
1079 boolS = "1"
1080 }
1081
1082 return rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
1083 " " + boolS +
1084 " " + strconv.Itoa(int(rr.GatewayType&0x7f)) +
1085 " " + gateway
1086 }
1087
1088
1089 type RKEY struct {
1090 Hdr RR_Header
1091 Flags uint16
1092 Protocol uint8
1093 Algorithm uint8
1094 PublicKey string `dns:"base64"`
1095 }
1096
1097 func (rr *RKEY) String() string {
1098 return rr.Hdr.String() + strconv.Itoa(int(rr.Flags)) +
1099 " " + strconv.Itoa(int(rr.Protocol)) +
1100 " " + strconv.Itoa(int(rr.Algorithm)) +
1101 " " + rr.PublicKey
1102 }
1103
1104
1105 type NSAPPTR struct {
1106 Hdr RR_Header
1107 Ptr string `dns:"domain-name"`
1108 }
1109
1110 func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
1111
1112
1113 type NSEC3 struct {
1114 Hdr RR_Header
1115 Hash uint8
1116 Flags uint8
1117 Iterations uint16
1118 SaltLength uint8
1119 Salt string `dns:"size-hex:SaltLength"`
1120 HashLength uint8
1121 NextDomain string `dns:"size-base32:HashLength"`
1122 TypeBitMap []uint16 `dns:"nsec"`
1123 }
1124
1125 func (rr *NSEC3) String() string {
1126 s := rr.Hdr.String()
1127 s += strconv.Itoa(int(rr.Hash)) +
1128 " " + strconv.Itoa(int(rr.Flags)) +
1129 " " + strconv.Itoa(int(rr.Iterations)) +
1130 " " + saltToString(rr.Salt) +
1131 " " + rr.NextDomain
1132 for _, t := range rr.TypeBitMap {
1133 s += " " + Type(t).String()
1134 }
1135 return s
1136 }
1137
1138 func (rr *NSEC3) len(off int, compression map[string]struct{}) int {
1139 l := rr.Hdr.len(off, compression)
1140 l += 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
1141 l += typeBitMapLen(rr.TypeBitMap)
1142 return l
1143 }
1144
1145
1146 type NSEC3PARAM struct {
1147 Hdr RR_Header
1148 Hash uint8
1149 Flags uint8
1150 Iterations uint16
1151 SaltLength uint8
1152 Salt string `dns:"size-hex:SaltLength"`
1153 }
1154
1155 func (rr *NSEC3PARAM) String() string {
1156 s := rr.Hdr.String()
1157 s += strconv.Itoa(int(rr.Hash)) +
1158 " " + strconv.Itoa(int(rr.Flags)) +
1159 " " + strconv.Itoa(int(rr.Iterations)) +
1160 " " + saltToString(rr.Salt)
1161 return s
1162 }
1163
1164
1165 type TKEY struct {
1166 Hdr RR_Header
1167 Algorithm string `dns:"domain-name"`
1168 Inception uint32
1169 Expiration uint32
1170 Mode uint16
1171 Error uint16
1172 KeySize uint16
1173 Key string `dns:"size-hex:KeySize"`
1174 OtherLen uint16
1175 OtherData string `dns:"size-hex:OtherLen"`
1176 }
1177
1178
1179 func (rr *TKEY) String() string {
1180 s := ";" + rr.Hdr.String() +
1181 " " + rr.Algorithm +
1182 " " + TimeToString(rr.Inception) +
1183 " " + TimeToString(rr.Expiration) +
1184 " " + strconv.Itoa(int(rr.Mode)) +
1185 " " + strconv.Itoa(int(rr.Error)) +
1186 " " + strconv.Itoa(int(rr.KeySize)) +
1187 " " + rr.Key +
1188 " " + strconv.Itoa(int(rr.OtherLen)) +
1189 " " + rr.OtherData
1190 return s
1191 }
1192
1193
1194 type RFC3597 struct {
1195 Hdr RR_Header
1196 Rdata string `dns:"hex"`
1197 }
1198
1199 func (rr *RFC3597) String() string {
1200
1201 s := rfc3597Header(rr.Hdr)
1202
1203 s += "\\# " + strconv.Itoa(len(rr.Rdata)/2) + " " + rr.Rdata
1204 return s
1205 }
1206
1207 func rfc3597Header(h RR_Header) string {
1208 var s string
1209
1210 s += sprintName(h.Name) + "\t"
1211 s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
1212 s += "CLASS" + strconv.Itoa(int(h.Class)) + "\t"
1213 s += "TYPE" + strconv.Itoa(int(h.Rrtype)) + "\t"
1214 return s
1215 }
1216
1217
1218 type URI struct {
1219 Hdr RR_Header
1220 Priority uint16
1221 Weight uint16
1222 Target string `dns:"octet"`
1223 }
1224
1225
1226 func (rr *URI) String() string {
1227 return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
1228 " " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
1229 }
1230
1231
1232 type DHCID struct {
1233 Hdr RR_Header
1234 Digest string `dns:"base64"`
1235 }
1236
1237 func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
1238
1239
1240 type TLSA struct {
1241 Hdr RR_Header
1242 Usage uint8
1243 Selector uint8
1244 MatchingType uint8
1245 Certificate string `dns:"hex"`
1246 }
1247
1248 func (rr *TLSA) String() string {
1249 return rr.Hdr.String() +
1250 strconv.Itoa(int(rr.Usage)) +
1251 " " + strconv.Itoa(int(rr.Selector)) +
1252 " " + strconv.Itoa(int(rr.MatchingType)) +
1253 " " + rr.Certificate
1254 }
1255
1256
1257 type SMIMEA struct {
1258 Hdr RR_Header
1259 Usage uint8
1260 Selector uint8
1261 MatchingType uint8
1262 Certificate string `dns:"hex"`
1263 }
1264
1265 func (rr *SMIMEA) String() string {
1266 s := rr.Hdr.String() +
1267 strconv.Itoa(int(rr.Usage)) +
1268 " " + strconv.Itoa(int(rr.Selector)) +
1269 " " + strconv.Itoa(int(rr.MatchingType))
1270
1271
1272
1273
1274 sx := splitN(rr.Certificate, 1024)
1275 s += " " + strings.Join(sx, " ")
1276 return s
1277 }
1278
1279
1280 type HIP struct {
1281 Hdr RR_Header
1282 HitLength uint8
1283 PublicKeyAlgorithm uint8
1284 PublicKeyLength uint16
1285 Hit string `dns:"size-hex:HitLength"`
1286 PublicKey string `dns:"size-base64:PublicKeyLength"`
1287 RendezvousServers []string `dns:"domain-name"`
1288 }
1289
1290 func (rr *HIP) String() string {
1291 s := rr.Hdr.String() +
1292 strconv.Itoa(int(rr.PublicKeyAlgorithm)) +
1293 " " + rr.Hit +
1294 " " + rr.PublicKey
1295 for _, d := range rr.RendezvousServers {
1296 s += " " + sprintName(d)
1297 }
1298 return s
1299 }
1300
1301
1302 type NINFO struct {
1303 Hdr RR_Header
1304 ZSData []string `dns:"txt"`
1305 }
1306
1307 func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
1308
1309
1310 type NID struct {
1311 Hdr RR_Header
1312 Preference uint16
1313 NodeID uint64
1314 }
1315
1316 func (rr *NID) String() string {
1317 s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1318 node := fmt.Sprintf("%0.16x", rr.NodeID)
1319 s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1320 return s
1321 }
1322
1323
1324 type L32 struct {
1325 Hdr RR_Header
1326 Preference uint16
1327 Locator32 net.IP `dns:"a"`
1328 }
1329
1330 func (rr *L32) String() string {
1331 if rr.Locator32 == nil {
1332 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1333 }
1334 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
1335 " " + rr.Locator32.String()
1336 }
1337
1338
1339 type L64 struct {
1340 Hdr RR_Header
1341 Preference uint16
1342 Locator64 uint64
1343 }
1344
1345 func (rr *L64) String() string {
1346 s := rr.Hdr.String() + strconv.Itoa(int(rr.Preference))
1347 node := fmt.Sprintf("%0.16X", rr.Locator64)
1348 s += " " + node[0:4] + ":" + node[4:8] + ":" + node[8:12] + ":" + node[12:16]
1349 return s
1350 }
1351
1352
1353 type LP struct {
1354 Hdr RR_Header
1355 Preference uint16
1356 Fqdn string `dns:"domain-name"`
1357 }
1358
1359 func (rr *LP) String() string {
1360 return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
1361 }
1362
1363
1364 type EUI48 struct {
1365 Hdr RR_Header
1366 Address uint64 `dns:"uint48"`
1367 }
1368
1369 func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
1370
1371
1372 type EUI64 struct {
1373 Hdr RR_Header
1374 Address uint64
1375 }
1376
1377 func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
1378
1379
1380 type CAA struct {
1381 Hdr RR_Header
1382 Flag uint8
1383 Tag string
1384 Value string `dns:"octet"`
1385 }
1386
1387
1388 func (rr *CAA) String() string {
1389 return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
1390 }
1391
1392
1393 type UID struct {
1394 Hdr RR_Header
1395 Uid uint32
1396 }
1397
1398 func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
1399
1400
1401 type GID struct {
1402 Hdr RR_Header
1403 Gid uint32
1404 }
1405
1406 func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
1407
1408
1409 type UINFO struct {
1410 Hdr RR_Header
1411 Uinfo string
1412 }
1413
1414 func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
1415
1416
1417 type EID struct {
1418 Hdr RR_Header
1419 Endpoint string `dns:"hex"`
1420 }
1421
1422 func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
1423
1424
1425 type NIMLOC struct {
1426 Hdr RR_Header
1427 Locator string `dns:"hex"`
1428 }
1429
1430 func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
1431
1432
1433 type OPENPGPKEY struct {
1434 Hdr RR_Header
1435 PublicKey string `dns:"base64"`
1436 }
1437
1438 func (rr *OPENPGPKEY) String() string { return rr.Hdr.String() + rr.PublicKey }
1439
1440
1441 type CSYNC struct {
1442 Hdr RR_Header
1443 Serial uint32
1444 Flags uint16
1445 TypeBitMap []uint16 `dns:"nsec"`
1446 }
1447
1448 func (rr *CSYNC) String() string {
1449 s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Serial), 10) + " " + strconv.Itoa(int(rr.Flags))
1450
1451 for _, t := range rr.TypeBitMap {
1452 s += " " + Type(t).String()
1453 }
1454 return s
1455 }
1456
1457 func (rr *CSYNC) len(off int, compression map[string]struct{}) int {
1458 l := rr.Hdr.len(off, compression)
1459 l += 4 + 2
1460 l += typeBitMapLen(rr.TypeBitMap)
1461 return l
1462 }
1463
1464
1465 type ZONEMD struct {
1466 Hdr RR_Header
1467 Serial uint32
1468 Scheme uint8
1469 Hash uint8
1470 Digest string `dns:"hex"`
1471 }
1472
1473 func (rr *ZONEMD) String() string {
1474 return rr.Hdr.String() +
1475 strconv.Itoa(int(rr.Serial)) +
1476 " " + strconv.Itoa(int(rr.Scheme)) +
1477 " " + strconv.Itoa(int(rr.Hash)) +
1478 " " + rr.Digest
1479 }
1480
1481
1482 type APL struct {
1483 Hdr RR_Header
1484 Prefixes []APLPrefix `dns:"apl"`
1485 }
1486
1487
1488 type APLPrefix struct {
1489 Negation bool
1490 Network net.IPNet
1491 }
1492
1493
1494 func (rr *APL) String() string {
1495 var sb strings.Builder
1496 sb.WriteString(rr.Hdr.String())
1497 for i, p := range rr.Prefixes {
1498 if i > 0 {
1499 sb.WriteByte(' ')
1500 }
1501 sb.WriteString(p.str())
1502 }
1503 return sb.String()
1504 }
1505
1506
1507 func (a *APLPrefix) str() string {
1508 var sb strings.Builder
1509 if a.Negation {
1510 sb.WriteByte('!')
1511 }
1512
1513 switch len(a.Network.IP) {
1514 case net.IPv4len:
1515 sb.WriteByte('1')
1516 case net.IPv6len:
1517 sb.WriteByte('2')
1518 }
1519
1520 sb.WriteByte(':')
1521
1522 switch len(a.Network.IP) {
1523 case net.IPv4len:
1524 sb.WriteString(a.Network.IP.String())
1525 case net.IPv6len:
1526
1527 if v4 := a.Network.IP.To4(); v4 != nil {
1528 sb.WriteString(ipv4InIPv6Prefix)
1529 }
1530 sb.WriteString(a.Network.IP.String())
1531 }
1532
1533 sb.WriteByte('/')
1534
1535 prefix, _ := a.Network.Mask.Size()
1536 sb.WriteString(strconv.Itoa(prefix))
1537
1538 return sb.String()
1539 }
1540
1541
1542 func (a *APLPrefix) equals(b *APLPrefix) bool {
1543 return a.Negation == b.Negation &&
1544 a.Network.IP.Equal(b.Network.IP) &&
1545 bytes.Equal(a.Network.Mask, b.Network.Mask)
1546 }
1547
1548
1549 func (a *APLPrefix) copy() APLPrefix {
1550 return APLPrefix{
1551 Negation: a.Negation,
1552 Network: copyNet(a.Network),
1553 }
1554 }
1555
1556
1557 func (a *APLPrefix) len() int {
1558
1559 prefix, _ := a.Network.Mask.Size()
1560 return 4 + (prefix+7)/8
1561 }
1562
1563
1564
1565
1566 func TimeToString(t uint32) string {
1567 mod := (int64(t)-time.Now().Unix())/year68 - 1
1568 if mod < 0 {
1569 mod = 0
1570 }
1571 ti := time.Unix(int64(t)-mod*year68, 0).UTC()
1572 return ti.Format("20060102150405")
1573 }
1574
1575
1576
1577
1578 func StringToTime(s string) (uint32, error) {
1579 t, err := time.Parse("20060102150405", s)
1580 if err != nil {
1581 return 0, err
1582 }
1583 mod := t.Unix()/year68 - 1
1584 if mod < 0 {
1585 mod = 0
1586 }
1587 return uint32(t.Unix() - mod*year68), nil
1588 }
1589
1590
1591 func saltToString(s string) string {
1592 if s == "" {
1593 return "-"
1594 }
1595 return strings.ToUpper(s)
1596 }
1597
1598 func euiToString(eui uint64, bits int) (hex string) {
1599 switch bits {
1600 case 64:
1601 hex = fmt.Sprintf("%16.16x", eui)
1602 hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1603 "-" + hex[8:10] + "-" + hex[10:12] + "-" + hex[12:14] + "-" + hex[14:16]
1604 case 48:
1605 hex = fmt.Sprintf("%12.12x", eui)
1606 hex = hex[0:2] + "-" + hex[2:4] + "-" + hex[4:6] + "-" + hex[6:8] +
1607 "-" + hex[8:10] + "-" + hex[10:12]
1608 }
1609 return
1610 }
1611
1612
1613 func cloneSlice[E any, S ~[]E](s S) S {
1614 if s == nil {
1615 return nil
1616 }
1617 return append(S(nil), s...)
1618 }
1619
1620
1621 func copyNet(n net.IPNet) net.IPNet {
1622 return net.IPNet{
1623 IP: cloneSlice(n.IP),
1624 Mask: cloneSlice(n.Mask),
1625 }
1626 }
1627
1628
1629
1630 func splitN(s string, n int) []string {
1631 if len(s) < n {
1632 return []string{s}
1633 }
1634 sx := []string{}
1635 p, i := 0, n
1636 for {
1637 if i <= len(s) {
1638 sx = append(sx, s[p:i])
1639 } else {
1640 sx = append(sx, s[p:])
1641 break
1642
1643 }
1644 p, i = p+n, i+n
1645 }
1646
1647 return sx
1648 }
1649
View as plain text