// newNSEC3CEandWildcard returns the NSEC3 for the closest encloser // and the NSEC3 that denies that wildcard at that level. func newNSEC3CEandWildcard(apex, ce string, ttl uint32) (*dns.NSEC3, *dns.NSEC3) { n1 := new(dns.NSEC3) n1.Hdr.Class = dns.ClassINET n1.Hdr.Rrtype = dns.TypeNSEC3 n1.Hdr.Ttl = ttl n1.Hash = dns.SHA1 n1.Flags = 0 n1.Iterations = 0 n1.Salt = "" n1.TypeBitMap = []uint16{dns.TypeA, dns.TypeNS, dns.TypeSOA, dns.TypeAAAA, dns.TypeRRSIG, dns.TypeDNSKEY} prev := dns.HashName(ce, dns.SHA1, n1.Iterations, n1.Salt) n1.Hdr.Name = strings.ToLower(prev) + "." + apex buf := packBase32(prev) byteArith(buf, true) // one next n1.NextDomain = unpackBase32(buf) n2 := new(dns.NSEC3) n2.Hdr.Class = dns.ClassINET n2.Hdr.Rrtype = dns.TypeNSEC3 n2.Hdr.Ttl = ttl n2.Hash = dns.SHA1 n2.Flags = 0 n2.Iterations = 0 n2.Salt = "" prev = dns.HashName("*."+ce, dns.SHA1, n2.Iterations, n2.Salt) buf = packBase32(prev) byteArith(buf, false) // one before n2.Hdr.Name = strings.ToLower(unpackBase32(buf)) + "." + apex byteArith(buf, true) // one next byteArith(buf, true) // and another one n2.NextDomain = unpackBase32(buf) return n1, n2 }
// NewNSEC3 returns the NSEC3 record needed to denial the types func (s *server) NewNSEC3NoData(qname string) *dns.NSEC3 { n := new(dns.NSEC3) n.Hdr.Class = dns.ClassINET n.Hdr.Rrtype = dns.TypeNSEC3 n.Hdr.Ttl = s.config.MinTtl n.Hash = dns.SHA1 n.Flags = 0 n.Salt = "" n.TypeBitMap = []uint16{} n.Hdr.Name = dns.HashName(qname, dns.SHA1, 0, "") buf := packBase32(n.Hdr.Name) byteArith(buf, true) // one next n.NextDomain = unpackBase32(buf) n.Hdr.Name += "." + s.config.Domain return n }
// newNSEC3NoData returns the NSEC3 record needed to denial the types func (s *server) newNSEC3NoData(qname string) *dns.NSEC3 { n := new(dns.NSEC3) n.Hdr.Class = dns.ClassINET n.Hdr.Rrtype = dns.TypeNSEC3 n.Hdr.Ttl = s.config.MinTtl n.Hash = dns.SHA1 n.HashLength = sha1.Size n.Flags = 0 n.Salt = "" n.TypeBitMap = []uint16{dns.TypeA, dns.TypeAAAA, dns.TypeSRV, dns.TypeRRSIG} n.Hdr.Name = dns.HashName(qname, dns.SHA1, 0, "") buf := packBase32(n.Hdr.Name) byteArith(buf, true) // one next n.NextDomain = unpackBase32(buf) n.Hdr.Name += appendDomain("", s.config.Domain) return n }
// NewNSEC3 returns the NSEC3 record needed to denial qname. func (s *server) NewNSEC3NameError(qname string) *dns.NSEC3 { n := new(dns.NSEC3) n.Hdr.Class = dns.ClassINET n.Hdr.Rrtype = dns.TypeNSEC3 n.Hdr.Ttl = s.config.MinTtl n.Hash = dns.SHA1 n.Flags = 0 n.Salt = "" n.TypeBitMap = []uint16{} covername := dns.HashName(qname, dns.SHA1, 0, "") buf := packBase32(covername) byteArith(buf, false) // one before n.Hdr.Name = strings.ToLower(unpackBase32(buf)) + "." + s.config.Domain byteArith(buf, true) // one next byteArith(buf, true) // and another one n.NextDomain = unpackBase32(buf) return n }
// NSEC3 Helper func denial3(nsec3 []dns.RR, in *dns.Msg) { qname := in.Question[0].Name qtype := in.Question[0].Qtype switch in.Rcode { case dns.RcodeSuccess: // qname should match nsec3, type should not be in bitmap match := nsec3[0].(*dns.NSEC3).Match(qname) if !match { fmt.Printf(";- Denial, owner name does not match qname\n") fmt.Printf(";- Denial, failed authenticated denial of existence proof for no data\n") return } for _, t := range nsec3[0].(*dns.NSEC3).TypeBitMap { if t == qtype { fmt.Printf(";- Denial, found type, %d, in bitmap\n", qtype) fmt.Printf(";- Denial, failed authenticated denial of existence proof for no data\n") return } if t > qtype { // ordered list, bail out, because not found break } } // Some success data printed here fmt.Printf(";+ Denial, matching record, %s, (%s) found and type %s denied\n", qname, strings.ToLower(dns.HashName(qname, nsec3[0].(*dns.NSEC3).Hash, nsec3[0].(*dns.NSEC3).Iterations, nsec3[0].(*dns.NSEC3).Salt)), dns.TypeToString[qtype]) fmt.Printf(";+ Denial, secure authenticated denial of existence proof for no data\n") return case dns.RcodeNameError: // NXDOMAIN Proof indx := dns.Split(qname) ce := "" // Closest Encloser nc := "" // Next Closer wc := "" // Source of Synthesis (wildcard) ClosestEncloser: for i := 0; i < len(indx); i++ { for j := 0; j < len(nsec3); j++ { if nsec3[j].(*dns.NSEC3).Match(qname[indx[i]:]) { ce = qname[indx[i]:] wc = "*." + ce if i == 0 { nc = qname } else { nc = qname[indx[i-1]:] } break ClosestEncloser } } } if ce == "" { fmt.Printf(";- Denial, closest encloser not found\n") return } fmt.Printf(";+ Denial, closest encloser, %s (%s)\n", ce, strings.ToLower(dns.HashName(ce, nsec3[0].(*dns.NSEC3).Hash, nsec3[0].(*dns.NSEC3).Iterations, nsec3[0].(*dns.NSEC3).Salt))) covered := 0 // Both nc and wc must be covered for i := 0; i < len(nsec3); i++ { if nsec3[i].(*dns.NSEC3).Cover(nc) { fmt.Printf(";+ Denial, next closer %s (%s), covered by %s -> %s\n", nc, nsec3[i].Header().Name, nsec3[i].(*dns.NSEC3).NextDomain, strings.ToLower(dns.HashName(ce, nsec3[0].(*dns.NSEC3).Hash, nsec3[0].(*dns.NSEC3).Iterations, nsec3[0].(*dns.NSEC3).Salt))) covered++ } if nsec3[i].(*dns.NSEC3).Cover(wc) { fmt.Printf(";+ Denial, source of synthesis %s (%s), covered by %s -> %s\n", wc, nsec3[i].Header().Name, nsec3[i].(*dns.NSEC3).NextDomain, strings.ToLower(dns.HashName(ce, nsec3[0].(*dns.NSEC3).Hash, nsec3[0].(*dns.NSEC3).Iterations, nsec3[0].(*dns.NSEC3).Salt))) covered++ } } if covered != 2 { fmt.Printf(";- Denial, too many, %d, covering records\n", covered) fmt.Printf(";- Denial, failed authenticated denial of existence proof for name error\n") return } fmt.Printf(";+ Denial, secure authenticated denial of existence proof for name error\n") return } }