diff options
author | Riccardo Spagni <ric@spagni.net> | 2014-12-04 23:10:49 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2014-12-04 23:10:49 +0200 |
commit | 831933425b3406310e70476dc56e822f7ae3c549 (patch) | |
tree | bd05c1b54f8cff8ef0bc1f769a22232172ec2a96 /external/unbound/contrib | |
parent | increased version number for tagged release (diff) | |
download | monero-831933425b3406310e70476dc56e822f7ae3c549.tar.xz |
update unbound from upstream
Diffstat (limited to 'external/unbound/contrib')
-rw-r--r-- | external/unbound/contrib/README | 4 | ||||
-rw-r--r-- | external/unbound/contrib/aaaa-filter-iterator.patch | 394 |
2 files changed, 398 insertions, 0 deletions
diff --git a/external/unbound/contrib/README b/external/unbound/contrib/README index efbffbd0c..49dee02e5 100644 --- a/external/unbound/contrib/README +++ b/external/unbound/contrib/README @@ -25,4 +25,8 @@ distribution but may be helpful. * unbound_cache.cmd: windows script to save and load the cache. * warmup.sh: shell script to warm up DNS cache by your own MRU domains. * warmup.cmd: windows script to warm up DNS cache by your own MRU domains. +* aaaa-filter-iterator.patch: adds config option aaaa-filter: yes that + works like the BIND feature (removes AAAA records unless AAAA-only domain). + Useful for certain 'broken IPv6 default route' scenarios. + Patch from Stephane Lapie for ASAHI Net. diff --git a/external/unbound/contrib/aaaa-filter-iterator.patch b/external/unbound/contrib/aaaa-filter-iterator.patch new file mode 100644 index 000000000..8e03d7c99 --- /dev/null +++ b/external/unbound/contrib/aaaa-filter-iterator.patch @@ -0,0 +1,394 @@ +--- unbound-1.4.17.orig/doc/unbound.conf.5.in ++++ unbound-1.4.17/doc/unbound.conf.5.in +@@ -519,6 +519,13 @@ authority servers and checks if the repl + Disabled by default. + This feature is an experimental implementation of draft dns\-0x20. + .TP ++.B aaaa\-filter: \fI<yes or no> ++Activate behavior similar to BIND's AAAA-filter. ++This forces the dropping of all AAAA records, unless in the case of ++explicit AAAA queries, when no A records have been confirmed. ++This also causes an additional A query to be sent for each AAAA query. ++This breaks DNSSEC! ++.TP + .B private\-address: \fI<IP address or subnet> + Give IPv4 of IPv6 addresses or classless subnets. These are addresses + on your private network, and are not allowed to be returned for public +--- unbound-1.4.17.orig/util/config_file.c ++++ unbound-1.4.17/util/config_file.c +@@ -160,6 +160,7 @@ config_create(void) + cfg->harden_below_nxdomain = 0; + cfg->harden_referral_path = 0; + cfg->use_caps_bits_for_id = 0; ++ cfg->aaaa_filter = 0; /* ASN: default is disabled */ + cfg->private_address = NULL; + cfg->private_domain = NULL; + cfg->unwanted_threshold = 0; +--- unbound-1.4.17.orig/iterator/iter_scrub.c ++++ unbound-1.4.17/iterator/iter_scrub.c +@@ -580,6 +580,32 @@ static int sanitize_nsec_is_overreach(st + } + + /** ++ * ASN: Lookup A records from rrset cache. ++ * @param qinfo: the question originally asked. ++ * @param env: module environment with config and cache. ++ * @param ie: iterator environment with private address data. ++ * @return 0 if no A record found, 1 if A record found. ++ */ ++static int ++asn_lookup_a_record_from_cache(struct query_info* qinfo, ++ struct module_env* env, struct iter_env* ie) ++{ ++ struct ub_packed_rrset_key* akey; ++ ++ /* get cached A records for queried name */ ++ akey = rrset_cache_lookup(env->rrset_cache, qinfo->qname, ++ qinfo->qname_len, LDNS_RR_TYPE_A, qinfo->qclass, ++ 0, *env->now, 0); ++ if(akey) { /* we had some. */ ++ log_rrset_key(VERB_ALGO, "ASN-AAAA-filter: found A record", ++ akey); ++ lock_rw_unlock(&akey->entry.lock); ++ return 1; ++ } ++ return 0; ++} ++ ++/** + * Given a response event, remove suspect RRsets from the response. + * "Suspect" rrsets are potentially poison. Note that this routine expects + * the response to be in a "normalized" state -- that is, all "irrelevant" +@@ -598,6 +625,7 @@ scrub_sanitize(ldns_buffer* pkt, struct + struct query_info* qinfo, uint8_t* zonename, struct module_env* env, + struct iter_env* ie) + { ++ int found_a_record = 0; /* ASN: do we have a A record? */ + int del_addi = 0; /* if additional-holding rrsets are deleted, we + do not trust the normalized additional-A-AAAA any more */ + struct rrset_parse* rrset, *prev; +@@ -633,6 +661,13 @@ scrub_sanitize(ldns_buffer* pkt, struct + rrset = rrset->rrset_all_next; + } + ++ /* ASN: Locate any A record we can find */ ++ if((ie->aaaa_filter) && (qinfo->qtype == LDNS_RR_TYPE_AAAA)) { ++ found_a_record = asn_lookup_a_record_from_cache(qinfo, ++ env, ie); ++ } ++ /* ASN: End of added code */ ++ + /* At this point, we brutally remove ALL rrsets that aren't + * children of the originating zone. The idea here is that, + * as far as we know, the server that we contacted is ONLY +@@ -644,6 +679,24 @@ scrub_sanitize(ldns_buffer* pkt, struct + rrset = msg->rrset_first; + while(rrset) { + ++ /* ASN: For AAAA records only... */ ++ if((ie->aaaa_filter) && (rrset->type == LDNS_RR_TYPE_AAAA)) { ++ /* ASN: If this is not a AAAA query, then remove AAAA ++ * records, no questions asked. If this IS a AAAA query ++ * then remove AAAA records if we have an A record. ++ * Otherwise, leave things be. */ ++ if((qinfo->qtype != LDNS_RR_TYPE_AAAA) || ++ (found_a_record)) { ++ remove_rrset("ASN-AAAA-filter: removing AAAA " ++ "for record", pkt, msg, prev, &rrset); ++ continue; ++ } ++ log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: " ++ "keep AAAA for", zonename, ++ LDNS_RR_TYPE_AAAA, qinfo->qclass); ++ } ++ /* ASN: End of added code */ ++ + /* remove private addresses */ + if( (rrset->type == LDNS_RR_TYPE_A || + rrset->type == LDNS_RR_TYPE_AAAA) && +--- unbound-1.4.17.orig/iterator/iterator.c ++++ unbound-1.4.17/iterator/iterator.c +@@ -1579,6 +1579,53 @@ processDSNSFind(struct module_qstate* qs + + return 0; + } ++ ++/** ++ * ASN: This event state was added as an intermediary step between ++ * QUERYTARGETS_STATE and the next step, in order to cast a subquery for the ++ * purpose of caching A records for the queried name. ++ * ++ * @param qstate: query state. ++ * @param iq: iterator query state. ++ * @param ie: iterator shared global environment. ++ * @param id: module id. ++ * @return true if the event requires more request processing immediately, ++ * false if not. This state only returns true when it is generating ++ * a SERVFAIL response because the query has hit a dead end. ++ */ ++static int ++asn_processQueryAAAA(struct module_qstate* qstate, struct iter_qstate* iq, ++ struct iter_env* ie, int id) ++{ ++ struct module_qstate* subq = NULL; ++ ++ log_assert(iq->fetch_a_for_aaaa == 0); ++ ++ /* flag the query properly in order to not loop */ ++ iq->fetch_a_for_aaaa = 1; ++ ++ /* re-throw same query, but with a different type */ ++ if(!generate_sub_request(iq->qchase.qname, ++ iq->qchase.qname_len, LDNS_RR_TYPE_A, ++ iq->qchase.qclass, qstate, id, iq, ++ INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { ++ log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: failed " ++ "preloading of A record for", ++ iq->qchase.qname, LDNS_RR_TYPE_A, ++ iq->qchase.qclass); ++ return error_response(qstate, id, LDNS_RCODE_SERVFAIL); ++ } ++ log_nametypeclass(VERB_ALGO, "ASN-AAAA-filter: " ++ "preloading records in cache for", ++ iq->qchase.qname, LDNS_RR_TYPE_A, ++ iq->qchase.qclass); ++ ++ /* set this query as waiting */ ++ qstate->ext_state[id] = module_wait_subquery; ++ /* at this point break loop */ ++ return 0; ++} ++/* ASN: End of added code */ + + /** + * This is the request event state where the request will be sent to one of +@@ -1626,6 +1673,13 @@ processQueryTargets(struct module_qstate + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + ++ /* ASN: If we have a AAAA query, then also query for A records */ ++ if((ie->aaaa_filter) && (iq->qchase.qtype == LDNS_RR_TYPE_AAAA) && ++ (iq->fetch_a_for_aaaa == 0)) { ++ return next_state(iq, ASN_FETCH_A_FOR_AAAA_STATE); ++ } ++ /* ASN: End of added code */ ++ + /* Make sure we have a delegation point, otherwise priming failed + * or another failure occurred */ + if(!iq->dp) { +@@ -2568,6 +2622,62 @@ processFinished(struct module_qstate* qs + return 0; + } + ++/** ++ * ASN: Do final processing on responses to A queries originated from AAAA ++ * queries. Events reach this state after the iterative resolution algorithm ++ * terminates. ++ * This is required down the road to decide whether to scrub AAAA records ++ * from the results or not. ++ * ++ * @param qstate: query state. ++ * @param id: module id. ++ * @param forq: super query state. ++ */ ++static void ++asn_processAAAAResponse(struct module_qstate* qstate, int id, ++ struct module_qstate* super) ++{ ++ struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; ++ struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id]; ++ struct ub_packed_rrset_key* rrset; ++ struct delegpt_ns* dpns = NULL; ++ int error = (qstate->return_rcode != LDNS_RCODE_NOERROR); ++ ++ log_assert(super_iq->fetch_a_for_aaaa > 0); ++ ++ /* let super go to evaluation of targets after this */ ++ super_iq->state = QUERYTARGETS_STATE; ++ ++ log_query_info(VERB_ALGO, "ASN-AAAA-filter: processAAAAResponse", ++ &qstate->qinfo); ++ log_query_info(VERB_ALGO, "ASN-AAAA-filter: processAAAAResponse super", ++ &super->qinfo); ++ ++ if(super_iq->dp) ++ dpns = delegpt_find_ns(super_iq->dp, ++ qstate->qinfo.qname, qstate->qinfo.qname_len); ++ if (!dpns) { ++ /* not interested */ ++ verbose(VERB_ALGO, "ASN-AAAA-filter: subq: %s, but parent not " ++ "interested%s", (error ? "error, but" : "success"), ++ (super_iq->dp ? "anymore" : " (was reset)")); ++ log_query_info(VERB_ALGO, "ASN-AAAA-filter: superq", &super->qinfo); ++ if(super_iq->dp && error) ++ delegpt_log(VERB_ALGO, super_iq->dp); ++ return; ++ } else if (error) { ++ verbose(VERB_ALGO, "ASN-AAAA-filter: mark as failed, " ++ "and go to target query."); ++ /* see if the failure did get (parent-lame) info */ ++ if(!cache_fill_missing(super->env, ++ super_iq->qchase.qclass, super->region, ++ super_iq->dp)) ++ log_err("ASN-AAAA-filter: out of memory adding missing"); ++ dpns->resolved = 1; /* mark as failed */ ++ } ++} ++/* ASN: End of added code */ ++ + /* + * Return priming query results to interestes super querystates. + * +@@ -2587,6 +2697,9 @@ iter_inform_super(struct module_qstate* + else if(super->qinfo.qtype == LDNS_RR_TYPE_DS && ((struct iter_qstate*) + super->minfo[id])->state == DSNS_FIND_STATE) + processDSNSResponse(qstate, id, super); ++ else if (super->qinfo.qtype == LDNS_RR_TYPE_AAAA && ((struct iter_qstate*) ++ super->minfo[id])->state == ASN_FETCH_A_FOR_AAAA_STATE) ++ asn_processAAAAResponse(qstate, id, super); + else if(qstate->return_rcode != LDNS_RCODE_NOERROR) + error_supers(qstate, id, super); + else if(qstate->is_priming) +@@ -2624,6 +2737,9 @@ iter_handle(struct module_qstate* qstate + case INIT_REQUEST_3_STATE: + cont = processInitRequest3(qstate, iq, id); + break; ++ case ASN_FETCH_A_FOR_AAAA_STATE: ++ cont = asn_processQueryAAAA(qstate, iq, ie, id); ++ break; + case QUERYTARGETS_STATE: + cont = processQueryTargets(qstate, iq, ie, id); + break; +@@ -2863,6 +2979,8 @@ iter_state_to_string(enum iter_state sta + return "INIT REQUEST STATE (stage 2)"; + case INIT_REQUEST_3_STATE: + return "INIT REQUEST STATE (stage 3)"; ++ case ASN_FETCH_A_FOR_AAAA_STATE: ++ return "ASN_FETCH_A_FOR_AAAA_STATE"; + case QUERYTARGETS_STATE : + return "QUERY TARGETS STATE"; + case PRIME_RESP_STATE : +@@ -2887,6 +3005,7 @@ iter_state_is_responsestate(enum iter_st + case INIT_REQUEST_STATE : + case INIT_REQUEST_2_STATE : + case INIT_REQUEST_3_STATE : ++ case ASN_FETCH_A_FOR_AAAA_STATE : + case QUERYTARGETS_STATE : + case COLLECT_CLASS_STATE : + return 0; +--- unbound-1.4.17.orig/iterator/iter_utils.c ++++ unbound-1.4.17/iterator/iter_utils.c +@@ -128,6 +128,7 @@ iter_apply_cfg(struct iter_env* iter_env + } + iter_env->supports_ipv6 = cfg->do_ip6; + iter_env->supports_ipv4 = cfg->do_ip4; ++ iter_env->aaaa_filter = cfg->aaaa_filter; + return 1; + } + +--- unbound-1.4.17.orig/iterator/iterator.h ++++ unbound-1.4.17/iterator/iterator.h +@@ -110,6 +110,9 @@ struct iter_env { + * array of max_dependency_depth+1 size. + */ + int* target_fetch_policy; ++ ++ /** ASN: AAAA-filter flag */ ++ int aaaa_filter; + }; + + /** +@@ -135,6 +138,14 @@ enum iter_state { + INIT_REQUEST_3_STATE, + + /** ++ * This state is responsible for intercepting AAAA queries, ++ * and launch a A subquery on the same target, to populate the ++ * cache with A records, so the AAAA filter scrubbing logic can ++ * work. ++ */ ++ ASN_FETCH_A_FOR_AAAA_STATE, ++ ++ /** + * Each time a delegation point changes for a given query or a + * query times out and/or wakes up, this state is (re)visited. + * This state is reponsible for iterating through a list of +@@ -309,6 +320,13 @@ struct iter_qstate { + */ + int refetch_glue; + ++ /** ++ * ASN: This is a flag that, if true, means that this query is ++ * for fetching A records to populate cache and determine if we must ++ * return AAAA records or not. ++ */ ++ int fetch_a_for_aaaa; ++ + /** list of pending queries to authoritative servers. */ + struct outbound_list outlist; + }; +--- unbound-1.4.17.orig/util/config_file.h ++++ unbound-1.4.17/util/config_file.h +@@ -169,6 +169,8 @@ struct config_file { + int harden_referral_path; + /** use 0x20 bits in query as random ID bits */ + int use_caps_bits_for_id; ++ /** ASN: enable AAAA filter? */ ++ int aaaa_filter; + /** strip away these private addrs from answers, no DNS Rebinding */ + struct config_strlist* private_address; + /** allow domain (and subdomains) to use private address space */ +--- unbound-1.4.17.orig/util/configlexer.lex ++++ unbound-1.4.17/util/configlexer.lex +@@ -177,6 +177,7 @@ harden-below-nxdomain{COLON} { YDVAR(1, + harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) } + use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) } + unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) } ++aaaa-filter{COLON} { YDVAR(1, VAR_AAAA_FILTER) } + private-address{COLON} { YDVAR(1, VAR_PRIVATE_ADDRESS) } + private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) } + prefetch-key{COLON} { YDVAR(1, VAR_PREFETCH_KEY) } +--- unbound-1.4.17.orig/util/configparser.y ++++ unbound-1.4.17/util/configparser.y +@@ -92,6 +92,7 @@ extern struct config_parser_state* cfg_p + %token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT + %token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR + %token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS ++%token VAR_AAAA_FILTER + %token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE + %token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE + %token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE +@@ -151,6 +152,7 @@ content_server: server_num_threads | ser + server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size | + server_harden_referral_path | server_private_address | + server_private_domain | server_extended_statistics | ++ server_aaaa_filter | + server_local_data_ptr | server_jostle_timeout | + server_unwanted_reply_threshold | server_log_time_ascii | + server_domain_insecure | server_val_sig_skew_min | +@@ -802,6 +803,15 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR + free($2); + } + ; ++server_aaaa_filter: VAR_AAAA_FILTER STRING_ARG ++ { ++ OUTYY(("P(server_aaaa_filter:%s)\n", $2)); ++ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) ++ yyerror("expected yes or no."); ++ else cfg_parser->cfg->aaaa_filter = (strcmp($2, "yes")==0); ++ free($2); ++ } ++ ; + server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG + { + OUTYY(("P(server_private_address:%s)\n", $2)); +--- unbound-1.4.17.orig/pythonmod/interface.i ++++ unbound-1.4.17/pythonmod/interface.i +@@ -626,6 +626,7 @@ struct config_file { + int harden_dnssec_stripped; + int harden_referral_path; + int use_caps_bits_for_id; ++ int aaaa_filter; /* ASN */ + struct config_strlist* private_address; + struct config_strlist* private_domain; + size_t unwanted_threshold; |