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