2011-01-28 01:52:58 +11:00
package dns
2011-03-08 07:56:36 +11:00
import (
2011-12-10 07:45:57 +11:00
"crypto/sha1"
2011-03-08 08:47:20 +11:00
"hash"
2011-12-17 01:08:44 +11:00
"io"
2011-03-08 08:47:20 +11:00
"strings"
2011-03-08 07:56:36 +11:00
)
2012-01-22 21:33:51 +11:00
const (
_ = iota
NSEC3_NXDOMAIN
NSEC3_NODATA
)
2011-03-08 08:47:20 +11:00
type saltWireFmt struct {
2012-04-30 05:55:29 +10:00
Salt string ` dns:"size-hex" `
2011-03-08 08:47:20 +11:00
}
2011-01-28 01:52:58 +11:00
2012-01-17 08:08:02 +11:00
// HashName hashes a string (label) according to RFC5155. It returns the hashed string.
2012-01-22 20:52:06 +11:00
func HashName ( label string , ha uint8 , iter uint16 , salt string ) string {
2011-03-08 08:47:20 +11:00
saltwire := new ( saltWireFmt )
saltwire . Salt = salt
wire := make ( [ ] byte , DefaultMsgSize )
2012-01-12 06:33:38 +11:00
n , ok := packStruct ( saltwire , wire , 0 )
2011-03-08 08:47:20 +11:00
if ! ok {
return ""
}
wire = wire [ : n ]
2011-03-10 00:27:41 +11:00
name := make ( [ ] byte , 255 )
2012-01-12 02:16:09 +11:00
off , ok1 := PackDomainName ( strings . ToLower ( label ) , name , 0 , nil , false )
2011-03-08 08:47:20 +11:00
if ! ok1 {
return ""
}
2011-03-10 00:27:41 +11:00
name = name [ : off ]
2011-03-08 08:47:20 +11:00
var s hash . Hash
switch ha {
2011-07-09 01:27:44 +10:00
case SHA1 :
2011-03-08 08:47:20 +11:00
s = sha1 . New ( )
2011-03-24 19:24:49 +11:00
default :
return ""
2011-03-08 08:47:20 +11:00
}
// k = 0
2011-03-10 00:27:41 +11:00
name = append ( name , wire ... )
2011-12-17 05:42:30 +11:00
io . WriteString ( s , string ( name ) )
2011-12-17 01:08:44 +11:00
nsec3 := s . Sum ( nil )
2011-03-24 19:24:49 +11:00
// k > 0
2012-01-22 20:52:06 +11:00
for k := uint16 ( 0 ) ; k < iter ; k ++ {
2011-03-24 19:24:49 +11:00
s . Reset ( )
nsec3 = append ( nsec3 , wire ... )
2011-12-17 05:42:30 +11:00
io . WriteString ( s , string ( nsec3 ) )
2011-12-17 01:12:01 +11:00
nsec3 = s . Sum ( nil )
2011-03-24 19:24:49 +11:00
}
2011-03-08 08:47:20 +11:00
return unpackBase32 ( nsec3 )
2011-03-08 07:56:36 +11:00
}
2011-03-10 04:54:55 +11:00
2012-01-14 20:52:37 +11:00
// HashNames hashes the ownername and the next owner name in an NSEC3 record according to RFC 5155.
// It uses the paramaters as set in the NSEC3 record. The string zone is appended to the hashed
// ownername.
func ( nsec3 * RR_NSEC3 ) HashNames ( zone string ) {
2012-01-22 20:52:06 +11:00
nsec3 . Header ( ) . Name = strings . ToLower ( HashName ( nsec3 . Header ( ) . Name , nsec3 . Hash , nsec3 . Iterations , nsec3 . Salt ) ) + "." + zone
nsec3 . NextDomain = HashName ( nsec3 . NextDomain , nsec3 . Hash , nsec3 . Iterations , nsec3 . Salt )
}
2012-03-09 07:16:51 +11:00
// Match checks if domain matches the first (hashed) owner name of the NSEC3 record. Domain must be given
2012-01-22 21:33:51 +11:00
// in plain text.
2012-01-22 20:52:06 +11:00
func ( nsec3 * RR_NSEC3 ) Match ( domain string ) bool {
2012-01-22 21:33:51 +11:00
return strings . ToUpper ( SplitLabels ( nsec3 . Header ( ) . Name ) [ 0 ] ) == strings . ToUpper ( HashName ( domain , nsec3 . Hash , nsec3 . Iterations , nsec3 . Salt ) )
}
2012-03-09 07:16:51 +11:00
// Cover checks if domain is covered by the NSEC3 record. Domain must be given in plain text.
2012-01-22 21:33:51 +11:00
func ( nsec3 * RR_NSEC3 ) Cover ( domain string ) bool {
hashdom := strings . ToUpper ( HashName ( domain , nsec3 . Hash , nsec3 . Iterations , nsec3 . Salt ) )
nextdom := strings . ToUpper ( nsec3 . NextDomain )
2012-01-23 02:12:10 +11:00
owner := strings . ToUpper ( SplitLabels ( nsec3 . Header ( ) . Name ) [ 0 ] ) // The hashed part
apex := strings . ToUpper ( HashName ( strings . Join ( SplitLabels ( nsec3 . Header ( ) . Name ) [ 1 : ] , "." ) , nsec3 . Hash , nsec3 . Iterations , nsec3 . Salt ) ) + "." // The name of the zone
// 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-23 01:40:59 +11:00
if hashdom > owner && hashdom <= nextdom {
2012-01-23 02:12:10 +11:00
return true
}
2012-01-23 01:40:59 +11:00
2012-01-23 02:12:10 +11:00
return false
2011-03-10 04:54:55 +11:00
}
2011-09-16 04:13:21 +10:00
2012-03-09 07:16:51 +11:00
// Cover checks if domain is covered by the NSEC record. Domain must be given in plain text.
func ( nsec * RR_NSEC ) Cover ( domain string ) bool {
return false
}
2012-01-18 05:16:58 +11:00
// NsecVerify verifies an denial of existence response with NSECs
2011-09-16 04:13:21 +10:00
// NsecVerify returns nil when the NSECs in the message contain
2012-01-18 04:48:40 +11:00
// the correct proof. This function does not validates the NSECs.
2011-11-03 09:06:54 +11:00
func ( m * Msg ) NsecVerify ( q Question ) error {
2011-09-16 04:13:21 +10:00
2011-11-03 09:06:54 +11:00
return nil
2011-09-16 04:13:21 +10:00
}
2012-01-18 05:16:58 +11:00
// Nsec3Verify verifies an denial of existence response with NSEC3s.
// This function does not validate the NSEC3s.
2012-01-22 21:33:51 +11:00
func ( m * Msg ) Nsec3Verify ( q Question ) ( int , error ) {
2012-01-20 05:48:09 +11:00
var (
nsec3 [ ] * RR_NSEC3
ncdenied = false // next closer denied
sodenied = false // source of synthesis denied
2012-01-22 21:33:51 +11:00
ce = "" // closest encloser
nc = "" // next closer
so = "" // source of synthesis
2012-01-20 05:48:09 +11:00
)
2012-01-18 05:16:58 +11:00
if len ( m . Answer ) > 0 && len ( m . Ns ) > 0 {
// Wildcard expansion
// Closest encloser inferred from SIG in authority and qname
2012-01-20 05:48:09 +11:00
// println("EXPANDED WILDCARD PROOF or DNAME CNAME")
// println("NODATA")
2012-01-18 05:16:58 +11:00
// I need to check the type bitmap
// wildcard bit not set?
// MM: No need to check the wildcard bit here:
// This response has only 1 NSEC4 and it does not match
// the closest encloser (it covers next closer).
}
if len ( m . Answer ) == 0 && len ( m . Ns ) > 0 {
2012-01-22 21:33:51 +11:00
// Maybe an NXDOMAIN or NODATA, we only know when we check
2012-01-20 05:48:09 +11:00
for _ , n := range m . Ns {
if n . Header ( ) . Rrtype == TypeNSEC3 {
nsec3 = append ( nsec3 , n . ( * RR_NSEC3 ) )
2012-01-18 05:16:58 +11:00
}
}
2012-01-20 05:48:09 +11:00
if len ( nsec3 ) == 0 {
2012-01-22 21:33:51 +11:00
return 0 , ErrDenialNsec3
2012-01-20 05:48:09 +11:00
}
2012-01-18 05:16:58 +11:00
2012-01-20 05:48:09 +11:00
lastchopped := ""
labels := SplitLabels ( q . Name )
2012-01-18 05:16:58 +11:00
2012-01-20 05:48:09 +11:00
// Find the closest encloser and create the next closer
for _ , nsec := range nsec3 {
candidate := ""
for i := len ( labels ) - 1 ; i >= 0 ; i -- {
candidate = labels [ i ] + "." + candidate
2012-01-22 20:52:06 +11:00
if nsec . Match ( candidate ) {
2012-01-20 05:48:09 +11:00
ce = candidate
2012-01-18 05:16:58 +11:00
}
2012-01-20 05:48:09 +11:00
lastchopped = labels [ i ]
2012-01-18 05:16:58 +11:00
}
}
2012-01-20 05:48:09 +11:00
if ce == "" { // what about root label?
2012-01-22 21:33:51 +11:00
return 0 , ErrDenialCe
2012-01-20 05:48:09 +11:00
}
nc = lastchopped + "." + ce
so = "*." + ce
// Check if the next closer is covered and thus denied
for _ , nsec := range nsec3 {
2012-01-22 21:33:51 +11:00
if nsec . Cover ( nc ) {
2012-01-20 05:48:09 +11:00
ncdenied = true
2012-01-20 22:24:20 +11:00
break
2012-01-18 05:16:58 +11:00
}
2012-01-20 05:48:09 +11:00
}
if ! ncdenied {
2012-01-23 02:12:10 +11:00
if m . MsgHdr . Rcode == RcodeNameError {
// For NXDOMAIN this is a problem
return 0 , ErrDenialNc // add next closer name here
}
2012-01-22 21:33:51 +11:00
goto NoData
2012-01-18 05:16:58 +11:00
}
2011-09-16 04:13:21 +10:00
2012-02-25 07:26:01 +11:00
// Check if the source of synthesis is covered and thus also denied
2012-01-20 05:48:09 +11:00
for _ , nsec := range nsec3 {
2012-01-22 21:33:51 +11:00
if nsec . Cover ( so ) {
2012-01-20 05:48:09 +11:00
sodenied = true
2012-01-20 22:24:20 +11:00
break
2012-01-18 05:16:58 +11:00
}
}
2012-01-20 05:48:09 +11:00
if ! sodenied {
2012-01-22 21:33:51 +11:00
return 0 , ErrDenialSo
2012-01-20 05:48:09 +11:00
}
2012-02-26 05:12:02 +11:00
// The message headers claims something different!
if m . MsgHdr . Rcode != RcodeNameError {
return 0 , ErrDenialHdr
}
2012-01-22 21:33:51 +11:00
return NSEC3_NXDOMAIN , nil
2012-01-18 05:16:58 +11:00
}
2012-01-22 21:33:51 +11:00
return 0 , nil
NoData :
2012-02-25 09:43:34 +11:00
// For NODATA we need to to check if the matching nsec3 has to correct type bit map
// And we need to check that the wildcard does NOT exist
for _ , nsec := range nsec3 {
if nsec . Cover ( so ) {
sodenied = true
break
}
}
if sodenied {
// Whoa, the closest encloser is denied, but there does exist
// a wildcard a that level. That's not good
return 0 , ErrDenialWc
}
2012-01-22 21:33:51 +11:00
// The closest encloser MUST be the query name
for _ , nsec := range nsec3 {
if nsec . Match ( nc ) {
// This nsec3 must NOT have the type bitmap set of the qtype. If it does have it, return an error
for _ , t := range nsec . TypeBitMap {
if t == q . Qtype {
return 0 , ErrDenialBit
}
}
}
}
2012-02-26 05:12:02 +11:00
if m . MsgHdr . Rcode == RcodeNameError {
return 0 , ErrDenialHdr
}
2012-01-22 21:33:51 +11:00
return NSEC3_NODATA , nil
2011-09-16 04:13:21 +10:00
}