2013-05-12 14:15:52 +00:00
|
|
|
// Copyright 2011 Miek Gieben. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-01-27 14:52:58 +00:00
|
|
|
package dns
|
|
|
|
|
2011-03-07 20:56:36 +00:00
|
|
|
import (
|
2011-12-09 20:45:57 +00:00
|
|
|
"crypto/sha1"
|
2011-03-07 21:47:20 +00:00
|
|
|
"hash"
|
2011-12-16 14:08:44 +00:00
|
|
|
"io"
|
2011-03-07 21:47:20 +00:00
|
|
|
"strings"
|
2011-03-07 20:56:36 +00:00
|
|
|
)
|
|
|
|
|
2012-01-22 10:33:51 +00:00
|
|
|
const (
|
|
|
|
_ = iota
|
2012-08-20 07:39:10 +00:00
|
|
|
_NSEC3_NXDOMAIN
|
|
|
|
_NSEC3_NODATA
|
2012-01-22 10:33:51 +00:00
|
|
|
)
|
|
|
|
|
2011-03-07 21:47:20 +00:00
|
|
|
type saltWireFmt struct {
|
2012-04-29 19:55:29 +00:00
|
|
|
Salt string `dns:"size-hex"`
|
2011-03-07 21:47:20 +00:00
|
|
|
}
|
2011-01-27 14:52:58 +00:00
|
|
|
|
2012-12-02 09:14:53 +00:00
|
|
|
// HashName hashes a string (label) according to RFC 5155. It returns the hashed string.
|
2012-01-22 09:52:06 +00:00
|
|
|
func HashName(label string, ha uint8, iter uint16, salt string) string {
|
2011-03-07 21:47:20 +00:00
|
|
|
saltwire := new(saltWireFmt)
|
|
|
|
saltwire.Salt = salt
|
|
|
|
wire := make([]byte, DefaultMsgSize)
|
2012-10-09 19:17:54 +00:00
|
|
|
n, err := PackStruct(saltwire, wire, 0)
|
|
|
|
if err != nil {
|
2011-03-07 21:47:20 +00:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
wire = wire[:n]
|
2011-03-09 13:27:41 +00:00
|
|
|
name := make([]byte, 255)
|
2012-10-09 19:17:54 +00:00
|
|
|
off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
|
|
|
|
if err != nil {
|
2011-03-07 21:47:20 +00:00
|
|
|
return ""
|
|
|
|
}
|
2011-03-09 13:27:41 +00:00
|
|
|
name = name[:off]
|
2011-03-07 21:47:20 +00:00
|
|
|
var s hash.Hash
|
|
|
|
switch ha {
|
2011-07-08 15:27:44 +00:00
|
|
|
case SHA1:
|
2011-03-07 21:47:20 +00:00
|
|
|
s = sha1.New()
|
2011-03-24 08:24:49 +00:00
|
|
|
default:
|
|
|
|
return ""
|
2011-03-07 21:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// k = 0
|
2011-03-09 13:27:41 +00:00
|
|
|
name = append(name, wire...)
|
2011-12-16 18:42:30 +00:00
|
|
|
io.WriteString(s, string(name))
|
2011-12-16 14:08:44 +00:00
|
|
|
nsec3 := s.Sum(nil)
|
2011-03-24 08:24:49 +00:00
|
|
|
// k > 0
|
2012-01-22 09:52:06 +00:00
|
|
|
for k := uint16(0); k < iter; k++ {
|
2011-03-24 08:24:49 +00:00
|
|
|
s.Reset()
|
|
|
|
nsec3 = append(nsec3, wire...)
|
2011-12-16 18:42:30 +00:00
|
|
|
io.WriteString(s, string(nsec3))
|
2011-12-16 14:12:01 +00:00
|
|
|
nsec3 = s.Sum(nil)
|
2011-03-24 08:24:49 +00:00
|
|
|
}
|
2011-03-07 21:47:20 +00:00
|
|
|
return unpackBase32(nsec3)
|
2011-03-07 20:56:36 +00:00
|
|
|
}
|
2011-03-09 17:54:55 +00:00
|
|
|
|
2012-06-06 13:27:35 +00:00
|
|
|
// Implement the HashNames method of Denialer
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC3) HashNames(domain string) {
|
2012-09-02 09:45:29 +00:00
|
|
|
rr.Header().Name = strings.ToLower(HashName(rr.Header().Name, rr.Hash, rr.Iterations, rr.Salt)) + "." + domain
|
|
|
|
rr.NextDomain = HashName(rr.NextDomain, rr.Hash, rr.Iterations, rr.Salt)
|
2012-01-22 09:52:06 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 13:27:35 +00:00
|
|
|
// Implement the Match method of Denialer
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC3) Match(domain string) bool {
|
2012-09-02 09:45:29 +00:00
|
|
|
return strings.ToUpper(SplitLabels(rr.Header().Name)[0]) == strings.ToUpper(HashName(domain, rr.Hash, rr.Iterations, rr.Salt))
|
2012-01-22 10:33:51 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 13:27:35 +00:00
|
|
|
// Implement the Match method of Denialer
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC) Match(domain string) bool {
|
2012-09-02 09:45:29 +00:00
|
|
|
return strings.ToUpper(rr.Header().Name) == strings.ToUpper(domain)
|
2012-06-06 13:27:35 +00:00
|
|
|
}
|
|
|
|
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC3) MatchType(rrtype uint16) bool {
|
2012-09-02 09:45:29 +00:00
|
|
|
for _, t := range rr.TypeBitMap {
|
2012-06-06 13:27:35 +00:00
|
|
|
if t == rrtype {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if t > rrtype {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC) MatchType(rrtype uint16) bool {
|
2012-09-02 09:45:29 +00:00
|
|
|
for _, t := range rr.TypeBitMap {
|
2012-06-06 13:27:35 +00:00
|
|
|
if t == rrtype {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if t > rrtype {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2012-06-06 05:36:45 +00:00
|
|
|
|
|
|
|
// Cover checks if domain is covered by the NSEC3 record. Domain must be given in plain text (i.e. not hashed)
|
|
|
|
// TODO(mg): this doesn't loop around
|
|
|
|
// TODO(mg): make a CoverHashed variant?
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC3) Cover(domain string) bool {
|
2012-09-02 09:45:29 +00:00
|
|
|
hashdom := strings.ToUpper(HashName(domain, rr.Hash, rr.Iterations, rr.Salt))
|
|
|
|
nextdom := strings.ToUpper(rr.NextDomain)
|
2012-09-10 18:51:19 +00:00
|
|
|
owner := strings.ToUpper(SplitLabels(rr.Header().Name)[0]) // The hashed part
|
2012-09-02 09:45:29 +00:00
|
|
|
apex := strings.ToUpper(HashName(strings.Join(SplitLabels(rr.Header().Name)[1:], "."), rr.Hash, rr.Iterations, rr.Salt)) + "." // The name of the zone
|
2012-01-22 15:12:10 +00:00
|
|
|
// if nextdomain equals the apex, it is considered The End. So in that case hashdom is always less then nextdomain
|
|
|
|
if hashdom > owner && nextdom == apex {
|
|
|
|
return true
|
|
|
|
}
|
2012-01-22 14:40:59 +00:00
|
|
|
|
|
|
|
if hashdom > owner && hashdom <= nextdom {
|
2012-01-22 15:12:10 +00:00
|
|
|
return true
|
|
|
|
}
|
2012-01-22 14:40:59 +00:00
|
|
|
|
2012-01-22 15:12:10 +00:00
|
|
|
return false
|
2011-03-09 17:54:55 +00:00
|
|
|
}
|
2011-09-15 18:13:21 +00:00
|
|
|
|
2012-03-08 20:16:51 +00:00
|
|
|
// Cover checks if domain is covered by the NSEC record. Domain must be given in plain text.
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *NSEC) Cover(domain string) bool {
|
2012-03-08 20:16:51 +00:00
|
|
|
return false
|
|
|
|
}
|