summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2015-01-31 23:34:18 +0000
committerBrad Smith <brad@cvs.openbsd.org>2015-01-31 23:34:18 +0000
commit6a4c5de37a6d91559fa82861d373bd7dea7b10de (patch)
tree99df46087c5e14ba05278e0403c2c48ae64ff104
parent552c3b320d499314fba7a83f825b96a2235c8f4b (diff)
Merge in a commit from upstream..
- Fix 0x20 capsforid fallback to omit gratuitous NS and additional section changes. ok sthen@
-rw-r--r--usr.sbin/unbound/iterator/iter_utils.c36
-rw-r--r--usr.sbin/unbound/iterator/iter_utils.h9
-rw-r--r--usr.sbin/unbound/iterator/iterator.c3
3 files changed, 48 insertions, 0 deletions
diff --git a/usr.sbin/unbound/iterator/iter_utils.c b/usr.sbin/unbound/iterator/iter_utils.c
index 9d0aa698f99..10ae12f75c6 100644
--- a/usr.sbin/unbound/iterator/iter_utils.c
+++ b/usr.sbin/unbound/iterator/iter_utils.c
@@ -715,6 +715,42 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region)
}
void
+caps_strip_reply(struct reply_info* rep)
+{
+ size_t i;
+ if(!rep) return;
+ /* see if message is a referral, in which case the additional and
+ * NS record cannot be removed */
+ /* referrals have the AA flag unset (strict check, not elsewhere in
+ * unbound, but for 0x20 this is very convenient). */
+ if(!(rep->flags&BIT_AA))
+ return;
+ /* remove the additional section from the reply */
+ if(rep->ar_numrrsets != 0) {
+ verbose(VERB_ALGO, "caps fallback: removing additional section");
+ rep->rrset_count -= rep->ar_numrrsets;
+ rep->ar_numrrsets = 0;
+ }
+ /* is there an NS set in the authority section to remove? */
+ /* the failure case (Cisco firewalls) only has one rrset in authsec */
+ for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS) {
+ /* remove NS rrset and break from loop (loop limits
+ * have changed) */
+ /* move last rrset into this position (there is no
+ * additional section any more) */
+ verbose(VERB_ALGO, "caps fallback: removing NS rrset");
+ if(i < rep->rrset_count-1)
+ rep->rrsets[i]=rep->rrsets[rep->rrset_count-1];
+ rep->rrset_count --;
+ rep->ns_numrrsets --;
+ break;
+ }
+ }
+}
+
+void
iter_store_parentside_rrset(struct module_env* env,
struct ub_packed_rrset_key* rrset)
{
diff --git a/usr.sbin/unbound/iterator/iter_utils.h b/usr.sbin/unbound/iterator/iter_utils.h
index d7c2b68afa2..9373487e002 100644
--- a/usr.sbin/unbound/iterator/iter_utils.h
+++ b/usr.sbin/unbound/iterator/iter_utils.h
@@ -223,6 +223,15 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
int reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region);
/**
+ * Remove unused bits from the reply if possible.
+ * So that caps-for-id (0x20) fallback is more likely to be successful.
+ * This removes like, the additional section, and NS record in the authority
+ * section if those records are gratuitous (not for a referral).
+ * @param rep: the reply to strip stuff out of.
+ */
+void caps_strip_reply(struct reply_info* rep);
+
+/**
* Store parent-side rrset in seperate rrset cache entries for later
* last-resort * lookups in case the child-side versions of this information
* fails.
diff --git a/usr.sbin/unbound/iterator/iterator.c b/usr.sbin/unbound/iterator/iterator.c
index 6e05c99a0e9..21ef397f1c9 100644
--- a/usr.sbin/unbound/iterator/iterator.c
+++ b/usr.sbin/unbound/iterator/iterator.c
@@ -2878,6 +2878,9 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
iq->response->rep);
if(event == module_event_capsfail || iq->caps_fallback) {
+ /* for fallback we care about main answer, not additionals */
+ /* removing that makes comparison more likely to succeed */
+ caps_strip_reply(iq->response->rep);
if(!iq->caps_fallback) {
/* start fallback */
iq->caps_fallback = 1;