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