diff -ubr unbound-1.4.21/validator/val_neg.c unbound/validator/val_neg.c
--- unbound-1.4.21/validator/val_neg.c	2013-08-20 21:23:42.000000000 +0900
+++ unbound/validator/val_neg.c	2014-02-07 18:04:08.000000000 +0900
@@ -916,6 +916,107 @@
 	}
 }
 
+struct packed_rrset_data* val_neg_lookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
+        uint16_t qtype, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now)
+{
+	/* lookup closest zone */
+	struct val_neg_zone* zone;
+	struct val_neg_data* data;
+	int labs;
+	struct ub_packed_rrset_key* nsec;
+	struct packed_rrset_data* d;
+	uint32_t flags;
+	uint8_t* wc;
+	struct query_info qinfo;
+	if(!neg) return NULL;
+
+	log_nametypeclass(VERB_ALGO, "negcache lookup", qname, 
+		qtype, qclass);
+	
+	labs = dname_count_labels(qname);
+	lock_basic_lock(&neg->lock);
+	zone = neg_closest_zone_parent(neg, qname, len, labs, qclass);
+	while(zone && !zone->in_use)
+		zone = zone->parent;
+	if(!zone) {
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+	log_nametypeclass(VERB_ALGO, "negcache zone", zone->name, 0, 
+		zone->dclass);
+
+	/* DLV is defined to use NSEC only */
+	if(zone->nsec3_hash) {
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+
+	/* lookup closest data record */
+	(void)neg_closest_data(zone, qname, len, labs, &data);
+	while(data && !data->in_use)
+		data = data->parent;
+	if(!data) {
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+	log_nametypeclass(VERB_ALGO, "negcache rr", data->name, 
+		LDNS_RR_TYPE_NSEC, zone->dclass);
+
+	/* lookup rrset in rrset cache */
+	flags = 0;
+	if(query_dname_compare(data->name, zone->name) == 0)
+		flags = PACKED_RRSET_NSEC_AT_APEX;
+	nsec = rrset_cache_lookup(rrset_cache, data->name, data->len,
+		LDNS_RR_TYPE_NSEC, zone->dclass, flags, now, 0);
+
+	/* check if secure and TTL ok */
+	if(!nsec) {
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+	d = (struct packed_rrset_data*)nsec->entry.data;
+	if(!d || now > d->ttl) {
+		lock_rw_unlock(&nsec->entry.lock);
+		/* delete data record if expired */
+		neg_delete_data(neg, data);
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+	if(d->security != sec_status_secure) {
+		lock_rw_unlock(&nsec->entry.lock);
+		neg_delete_data(neg, data);
+		lock_basic_unlock(&neg->lock);
+		return NULL;
+	}
+	verbose(VERB_ALGO, "negcache got secure rrset");
+
+	/* check NSEC security */
+	/* check if NSEC proves no DLV type exists */
+	/* check if NSEC proves NXDOMAIN for qname */
+	qinfo.qname = qname;
+	qinfo.qtype = qtype;
+	qinfo.qclass = qclass;
+	if(!nsec_proves_nodata(nsec, &qinfo, &wc) &&
+		!val_nsec_proves_name_error(nsec, qname)) {
+		/* the NSEC is not a denial for the DLV */
+		lock_rw_unlock(&nsec->entry.lock);
+		lock_basic_unlock(&neg->lock);
+		verbose(VERB_ALGO, "negcache not proven");
+		return NULL;
+	}
+	/* so the NSEC was a NODATA proof, or NXDOMAIN proof. */
+
+	/* no need to check for wildcard NSEC; no wildcards in DLV repos */
+	/* no need to lookup SOA record for client; no response message */
+
+	lock_rw_unlock(&nsec->entry.lock);
+	/* if OK touch the LRU for neg_data element */
+	neg_lru_touch(neg, data);
+	lock_basic_unlock(&neg->lock);
+	verbose(VERB_ALGO, "negcache denial proven");
+	return nsec;
+}
+
 int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
         uint16_t qclass, struct rrset_cache* rrset_cache, time_t now)
 {
diff -ubr unbound-1.4.21/validator/val_neg.h unbound/validator/val_neg.h
--- unbound-1.4.21/validator/val_neg.h	2013-08-20 21:23:42.000000000 +0900
+++ unbound/validator/val_neg.h	2014-02-07 18:04:30.000000000 +0900
@@ -230,6 +230,8 @@
  */
 int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
 	uint16_t qclass, struct rrset_cache* rrset_cache, time_t now);
+struct packed_rrset_data* val_neg_lookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
+	uint16_t qtype, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now);
 
 /**
  * For the given query, try to get a reply out of the negative cache.
diff -ubr unbound-1.4.21/validator/validator.c unbound/validator/validator.c
--- unbound-1.4.21/validator/validator.c	2013-08-20 21:23:42.000000000 +0900
+++ unbound/validator/validator.c	2014-02-07 18:19:15.000000000 +0900
@@ -822,6 +822,9 @@
 	/* Otherwise, we consider the message secure. */
 	verbose(VERB_ALGO, "successfully validated NAME ERROR response.");
 	chase_reply->security = sec_status_secure;
+
+	/* store NSECs into negative cache */
+	val_neg_addreply(ve->neg_cache, chase_reply);
 }
 
 /** 
@@ -2164,6 +2167,8 @@
 {
 	struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
 	struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
+	struct packed_rrset_data* nsec;
+
 	verbose(VERB_QUERY, "validator[module %d] operate: extstate:%s "
 		"event:%s", id, strextstate(qstate->ext_state[id]), 
 		strmodulevent(event));
@@ -2175,6 +2180,20 @@
 	(void)outbound;
 	if(event == module_event_new || 
 		(event == module_event_pass && vq == NULL)) {
+
+		nsec = val_neg_lookup(ve->neg_cache, qstate->qinfo.qname,
+			qstate->qinfo.qname_len, qstate->qinfo.qtype,
+			qstate->qinfo.qclass,
+			qstate->env->rrset_cache, *qstate->env->now);
+
+		/* Aggressive NSEC caching */
+		if (nsec != NULL) {
+			qstate->return_rcode = LDNS_RCODE_NXDOMAIN;
+			qstate->return_msg = NULL;
+			qstate->ext_state[id] = module_finished;
+			return;
+		}
+
 		/* pass request to next module, to get it */
 		verbose(VERB_ALGO, "validator: pass to next module");
 		qstate->ext_state[id] = module_wait_module;
