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