+20 September 2007: Wouter
+ - fixup and test for NSEC wildcard with empty nonterminals.
+ - makedist.sh fixup for svn info.
+ - acl features request in plan.
+
19 September 2007: Wouter
- comments about non-packed usage.
- plan for overload support in 0.6.
if phase 1, start servicing, phase is 0 again. Make robust against delays.
readme: max about 1 second worth of incoming queries, 10k perhaps,
or 1/number of seconds it takes start up of 10k.
+* features from Jakob's graph.
+ * acl for allowed recursion (RD=1), then drop or refused query.
+ * static answers for queries, option
+ * blacklist (return fixed nxdomain), option
+ * after checking acl, static, blacklist, do iter forwards, recurse.
*** Local zones feature.
* Build in local zone features. First the total stop for1912.
# Check if SVNROOT is specified.
if [ -z "$SVNROOT" ]; then
if test -f .svn/entries; then
- eval `grep 'url=' .svn/entries | head -1`
+ eval `svn info | grep 'URL:' | sed -e 's/URL: /url=/' | head -1`
SVNROOT="$url"
fi
if test -z "$SVNROOT"; then
--- /dev/null
+; config options
+; The island of trust is at example.com
+server:
+ trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+ val-override-date: "20070916134226"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with nodata, wildcards and ENT
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+ ADDRESS 193.0.14.129
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET. IN A 193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION AUTHORITY
+com. IN NS a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net. IN A 192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+ ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. 86394 IN SOA NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400
+example.com. 86394 IN RRSIG SOA 3 2 86394 20070926135752 20070829135752 2854 example.com. MCwCFFHjDbVjiPywHcXm669wMUJ7dlcoAhRfuauTUoExMSx96lTVYbBHOXtQEw== ;{id = 2854}
+
+; note that b.example.com. is an empty nonterminal
+*.example.com. 3600 IN NSEC *.b.example.com. A MX RRSIG NSEC
+*.example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. MCwCFE9CopvxP6w/1HqnqxNluh1Qbgk0AhRgKrdjk/YoEm4tcYflNX6McDMCgQ== ;{id = 2854}
+
+SECTION ADDITIONAL
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+b.example.com. IN DS
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. 86394 IN SOA NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400
+SECTION ADDITIONAL
+ENTRY_END
+
+SCENARIO_END
#include "util/data/msgreply.h"
#include "util/data/dname.h"
+/** get ttl of rrset */
+static uint32_t
+rrset_get_ttl(struct ub_packed_rrset_key* k)
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
+ return d->ttl;
+}
+
int
nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
{
qinfo->qclass);
enum sec_status sec;
size_t i;
+ uint8_t* wc = NULL, *ce = NULL;
+ int valid_nsec = 0;
/* If we have a NSEC at the same name, it must prove one
* of two things
"did not verify.");
return sec_status_bogus;
}
- if(nsec_proves_nodata(rep->rrsets[i], qinfo)) {
+ if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"proved no DS.");
- return sec_status_secure;
+ *proof_ttl = rrset_get_ttl(rep->rrsets[i]);
+ valid_nsec = 1;
+ }
+ if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) {
+ ce = nsec_closest_encloser(qinfo->qname,
+ rep->rrsets[i]);
}
}
+ if(wc && !ce)
+ valid_nsec = 0;
+ else if(wc && ce) {
+ /* ce and wc must match */
+ if(query_dname_compare(wc, ce) != 0)
+ valid_nsec = 0;
+ }
+ if(valid_nsec) {
+ return sec_status_secure;
+ }
/* NSEC proof did not conlusively point to DS or no DS */
return sec_status_unchecked;
}
int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo)
+ struct query_info* qinfo, uint8_t** wc)
{
+ log_assert(wc);
if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) {
uint8_t* nm;
size_t ln;
+
+ /* empty-non-terminal checking.
+ * Done before wildcard, because this is an exact match,
+ * and would prevent a wildcard from matching. */
+
+ /* If the nsec is proving that qname is an ENT, the nsec owner
+ * will be less than qname, and the next name will be a child
+ * domain of the qname. */
+ if(!nsec_get_next(nsec, &nm, &ln))
+ return 0; /* bad nsec */
+ if(dname_strict_subdomain_c(nm, qinfo->qname) &&
+ dname_canonical_compare(nsec->rk.dname,
+ qinfo->qname) < 0) {
+ return 1; /* proves ENT */
+ }
+
/* wildcard checking. */
/* If this is a wildcard NSEC, make sure that a) it was
dname_remove_label(&ce, &ce_len);
/* The qname must be a strict subdomain of the
- * closest encloser, for the wildcard to apply */
+ * closest encloser, for the wildcard to apply
+ */
if(dname_strict_subdomain_c(qinfo->qname, ce)) {
/* here we have a matching NSEC for the qname,
* perform matching NSEC checks */
if(nsec_has_type(nsec, qinfo->qtype)) {
return 0;
}
+ *wc = ce;
return 1;
}
}
- /* empty-non-terminal checking. */
-
- /* If the nsec is proving that qname is an ENT, the nsec owner
- * will be less than qname, and the next name will be a child
- * domain of the qname. */
- if(!nsec_get_next(nsec, &nm, &ln))
- return 0; /* bad nsec */
- if(dname_strict_subdomain_c(nm, qinfo->qname) &&
- dname_canonical_compare(nsec->rk.dname,
- qinfo->qname) < 0) {
- return 1; /* proves ENT */
- }
- /* Otherwise, this NSEC does not prove ENT, so it does not
- * prove NODATA. */
+ /* Otherwise, this NSEC does not prove ENT and is not a
+ * wildcard, so it does not prove NODATA. */
return 0;
}
*
* @param nsec: the nsec record to check against.
* @param qinfo: the query info.
+ * @param wc: if the nodata is proven for a wildcard match, the wildcard
+ * closest encloser is returned, else NULL (wc is unchanged).
+ * This closest encloser must then match the nameerror given for the
+ * nextcloser of qname.
* @return true if NSEC proves this.
*/
int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
- struct query_info* qinfo);
+ struct query_info* qinfo, uint8_t** wc);
/**
* Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
* NODATA.
* This needs to handle the ENT NODATA case. */
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(nsec_proves_nodata(s, qchase)) {
+ if(nsec_proves_nodata(s, qchase, &wc)) {
has_valid_nsec = 1;
- /* set wc only if wildcard applicable, which
- * is a *.name, and qname sub of .name */
- if(dname_is_wild(s->rk.dname) &&
- dname_strict_subdomain_c(
- qchase->qname, s->rk.dname+2))
- wc = s->rk.dname;
+ /* sets wc-encloser if wildcard applicable */
}
if(val_nsec_proves_name_error(s, qchase->qname)) {
ce = nsec_closest_encloser(qchase->qname, s);
if(wc && !ce)
has_valid_nsec = 0;
else if(wc && ce) {
- log_assert(dname_is_wild(wc));
- /* first label wc is \001*, so remove and compare to ce */
- if(query_dname_compare(wc+2, ce) != 0) {
+ if(query_dname_compare(wc, ce) != 0) {
has_valid_nsec = 0;
}
}
* NODATA. This needs to handle the ENT NODATA case.
* Also try to prove NAMEERROR, and absence of a wildcard */
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
- if(nsec_proves_nodata(s, qchase)) {
+ if(nsec_proves_nodata(s, qchase, &wc)) {
nodata_valid_nsec = 1;
- /* set wc only if wildcard applicable, which
- * is a *.name, and qname sub of .name */
- if(dname_is_wild(s->rk.dname) &&
- dname_strict_subdomain_c(
- qchase->qname, s->rk.dname+2))
- wc = s->rk.dname;
+ /* set wc encloser if wildcard applicable */
}
if(val_nsec_proves_name_error(s, qchase->qname)) {
ce = nsec_closest_encloser(qchase->qname, s);
if(wc && !ce)
nodata_valid_nsec = 0;
else if(wc && ce) {
- log_assert(dname_is_wild(wc));
- /* first label wc is \001*, so remove and compare to ce */
- if(query_dname_compare(wc+2, ce) != 0) {
+ if(query_dname_compare(wc, ce) != 0) {
nodata_valid_nsec = 0;
}
}