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