nsecx.go 2.5 KB

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