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