nsecx.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package dns
  2. import (
  3. "crypto/sha1"
  4. "encoding/hex"
  5. "strings"
  6. )
  7. // HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
  8. func HashName(label string, ha uint8, iter uint16, salt string) string {
  9. if ha != SHA1 {
  10. return ""
  11. }
  12. wireSalt := make([]byte, hex.DecodedLen(len(salt)))
  13. n, err := packStringHex(salt, wireSalt, 0)
  14. if err != nil {
  15. return ""
  16. }
  17. wireSalt = wireSalt[:n]
  18. name := make([]byte, 255)
  19. off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
  20. if err != nil {
  21. return ""
  22. }
  23. name = name[:off]
  24. s := sha1.New()
  25. // k = 0
  26. s.Write(name)
  27. s.Write(wireSalt)
  28. nsec3 := s.Sum(nil)
  29. // k > 0
  30. for k := uint16(0); k < iter; k++ {
  31. s.Reset()
  32. s.Write(nsec3)
  33. s.Write(wireSalt)
  34. nsec3 = s.Sum(nsec3[:0])
  35. }
  36. return toBase32(nsec3)
  37. }
  38. // Cover returns true if a name is covered by the NSEC3 record.
  39. func (rr *NSEC3) Cover(name string) bool {
  40. nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
  41. owner := strings.ToUpper(rr.Hdr.Name)
  42. labelIndices := Split(owner)
  43. if len(labelIndices) < 2 {
  44. return false
  45. }
  46. ownerHash := owner[:labelIndices[1]-1]
  47. ownerZone := owner[labelIndices[1]:]
  48. if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
  49. return false
  50. }
  51. nextHash := rr.NextDomain
  52. // if empty interval found, try cover wildcard hashes so nameHash shouldn't match with ownerHash
  53. if ownerHash == nextHash && nameHash != ownerHash { // empty interval
  54. return true
  55. }
  56. if ownerHash > nextHash { // end of zone
  57. if nameHash > ownerHash { // covered since there is nothing after ownerHash
  58. return true
  59. }
  60. return nameHash < nextHash // if nameHash is before beginning of zone it is covered
  61. }
  62. if nameHash < ownerHash { // nameHash is before ownerHash, not covered
  63. return false
  64. }
  65. return nameHash < nextHash // if nameHash is before nextHash is it covered (between ownerHash and nextHash)
  66. }
  67. // Match returns true if a name matches the NSEC3 record
  68. func (rr *NSEC3) Match(name string) bool {
  69. nameHash := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
  70. owner := strings.ToUpper(rr.Hdr.Name)
  71. labelIndices := Split(owner)
  72. if len(labelIndices) < 2 {
  73. return false
  74. }
  75. ownerHash := owner[:labelIndices[1]-1]
  76. ownerZone := owner[labelIndices[1]:]
  77. if !IsSubDomain(ownerZone, strings.ToUpper(name)) { // name is outside owner zone
  78. return false
  79. }
  80. if ownerHash == nameHash {
  81. return true
  82. }
  83. return false
  84. }