--- unbound-1.5.10.orig/Makefile.in 2017-11-09 22:58:08.476154201 +0100 +++ unbound-1.5.10/Makefile.in 2017-11-09 23:03:40.370372541 +0100 @@ -112,7 +112,7 @@ validator/autotrust.c validator/val_anchor.c validator/validator.c \ validator/val_kcache.c validator/val_kentry.c validator/val_neg.c \ validator/val_nsec3.c validator/val_nsec.c validator/val_secalgo.c \ -validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c cachedb/cachedb.c $(CHECKLOCK_SRC) \ +validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c cachedb/cachedb.c rewrite/rewrite.c $(CHECKLOCK_SRC) \ $(DNSTAP_SRC) COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \ @@ -123,7 +123,7 @@ random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \ slabhash.lo timehist.lo tube.lo winsock_event.lo autotrust.lo val_anchor.lo \ validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \ -val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo \ +val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo rewrite.lo \ $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \ outside_network.lo @@ -723,7 +723,7 @@ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h \ $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/dns64/dns64.h \ $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/validator/validator.h \ - $(srcdir)/validator/val_utils.h $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h + $(srcdir)/validator/val_utils.h $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h $(srcdir)/rewrite/rewrite.h outbound_list.lo outbound_list.o: $(srcdir)/services/outbound_list.c config.h \ $(srcdir)/services/outbound_list.h $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/netevent.h @@ -768,7 +768,7 @@ $(srcdir)/validator/val_neg.h $(srcdir)/validator/autotrust.h $(srcdir)/libunbound/libworker.h \ $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound.h \ $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h \ - $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h + $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h $(srcdir)/rewrite/rewrite.h locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ @@ -910,6 +910,12 @@ $(srcdir)/util/rbtree.h $(srcdir)/validator/val_secalgo.h $(srcdir)/iterator/iter_utils.h \ $(srcdir)/iterator/iter_resptype.h $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h \ $(srcdir)/sldns/sbuffer.h +rewrite.lo rewrite.o: $(srcdir)/rewrite/rewrite.c config.h $(srcdir)/rewrite/rewrite.h $(srcdir)/util/module.h \ + $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/msgreply.h \ + $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \ + $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/str2wire.h $(srcdir)/services/cache/dns.h $(srcdir)/util/config_file.h \ + $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \ + $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h $(srcdir)/util/regional.h $(srcdir)/util/data/dname.h checklocks.lo checklocks.o: $(srcdir)/testcode/checklocks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/testcode/checklocks.h unitanchor.lo unitanchor.o: $(srcdir)/testcode/unitanchor.c config.h $(srcdir)/util/log.h $(srcdir)/util/data/dname.h \ --- unbound-1.5.10.orig/services/modstack.c 2017-11-09 22:58:08.479154167 +0100 +++ unbound-1.5.10/services/modstack.c 2017-11-09 23:04:36.188736720 +0100 @@ -53,6 +53,7 @@ #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif +#include "rewrite/rewrite.h" /** count number of modules (words) in the string */ static int @@ -129,6 +130,7 @@ #endif "validator", "iterator", + "rewrite", NULL}; return names; } @@ -150,6 +152,7 @@ #endif &val_get_funcblock, &iter_get_funcblock, + &rewrite_get_funcblock, NULL}; return fb; } --- unbound-1.5.10.orig/util/config_file.c 2017-11-09 22:58:08.471154258 +0100 +++ unbound-1.5.10/util/config_file.c 2017-11-09 23:05:30.060123126 +0100 @@ -247,6 +247,7 @@ cfg->ratelimit_below_domain = NULL; cfg->ratelimit_factor = 10; cfg->qname_minimisation = 0; + cfg->rewrite_domain = NULL; return cfg; error_exit: config_delete(cfg); @@ -797,6 +798,7 @@ else O_LS3(opt, "local-zone-override", local_zone_overrides) else O_LS3(opt, "access-control-tag-action", acl_tag_actions) else O_LS3(opt, "access-control-tag-data", acl_tag_datas) + else O_LS2(opt, "rewrite-domain", rewrite_domain) /* not here: * outgoing-permit, outgoing-avoid - have list of ports * local-zone - zones and nodefault variables @@ -1063,6 +1065,7 @@ free(cfg->dnstap_version); config_deldblstrlist(cfg->ratelimit_for_domain); config_deldblstrlist(cfg->ratelimit_below_domain); + config_deldblstrlist(cfg->rewrite_domain); free(cfg); } --- unbound-1.5.10.orig/util/config_file.h 2017-11-09 22:58:08.472154246 +0100 +++ unbound-1.5.10/util/config_file.h 2017-11-09 23:05:49.042906923 +0100 @@ -396,6 +396,8 @@ int ratelimit_factor; /** minimise outgoing QNAME and hide original QTYPE if possible */ int qname_minimisation; + /** from/to-pairs of domains to rewrite */ + struct config_str2list* rewrite_domain; }; /** from cfg username, after daemonise setup performed */ --- unbound-1.5.10.orig/util/configlexer.lex 2017-11-09 22:58:08.474154223 +0100 +++ unbound-1.5.10/util/configlexer.lex 2017-11-09 23:06:18.304573662 +0100 @@ -380,6 +380,7 @@ ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) } +rewrite-domain{COLON} { YDVAR(2, VAR_REWRITE_DOMAIN) } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } /* Quoted strings. Strip leading and ending quotes */ --- unbound-1.5.10.orig/util/configparser.y 2017-11-09 22:58:08.473154235 +0100 +++ unbound-1.5.10/util/configparser.y 2017-11-09 23:08:16.210230970 +0100 @@ -128,6 +128,7 @@ %token VAR_QNAME_MINIMISATION VAR_IP_FREEBIND VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG %token VAR_ACCESS_CONTROL_TAG VAR_LOCAL_ZONE_OVERRIDE %token VAR_ACCESS_CONTROL_TAG_ACTION VAR_ACCESS_CONTROL_TAG_DATA +%token VAR_REWRITE_DOMAIN %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -199,7 +200,7 @@ server_ip_freebind | server_define_tag | server_local_zone_tag | server_disable_dnssec_lame_check | server_access_control_tag | server_local_zone_override | server_access_control_tag_action | - server_access_control_tag_data + server_access_control_tag_data | server_rewrite_domain ; stubstart: VAR_STUB_ZONE { @@ -1497,6 +1498,15 @@ free($2); } ; +server_rewrite_domain: VAR_REWRITE_DOMAIN STRING_ARG STRING_ARG + { + OUTYY(("P(server_rewrite_domain:%s %s)\n", $2, $3)); + if(!cfg_str2list_insert(&cfg_parser->cfg-> + rewrite_domain, $2, $3)) + fatal_exit("out of memory adding " + "rewrite-domain"); + } + ; stub_name: VAR_NAME STRING_ARG { OUTYY(("P(name:%s)\n", $2)); --- unbound-1.5.10.orig/util/fptr_wlist.c 2017-11-09 22:58:08.474154223 +0100 +++ unbound-1.5.10/util/fptr_wlist.c 2017-11-09 23:09:33.746348119 +0100 @@ -81,6 +81,7 @@ #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif +#include "rewrite/rewrite.h" int fptr_whitelist_comm_point(comm_point_callback_t *fptr) @@ -321,6 +322,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_init) return 1; #endif + else if(fptr == &rewrite_init) return 1; return 0; } @@ -336,6 +338,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_deinit) return 1; #endif + else if(fptr == &rewrite_deinit) return 1; return 0; } @@ -352,6 +355,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_operate) return 1; #endif + else if(fptr == &rewrite_operate) return 1; return 0; } @@ -368,6 +372,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_inform_super) return 1; #endif + else if(fptr == &rewrite_inform_super) return 1; return 0; } @@ -384,6 +389,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_clear) return 1; #endif + else if(fptr == &rewrite_clear) return 1; return 0; } @@ -399,6 +405,7 @@ #ifdef USE_CACHEDB else if(fptr == &cachedb_get_mem) return 1; #endif + else if(fptr == &rewrite_get_mem) return 1; return 0; } --- /dev/null 1970-01-01 01:00:00.000000000 +0100 +++ unbound-1.5.10/rewrite/rewrite.c 2017-11-09 23:10:03.903004770 +0100 @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2015, Manuel Mausz. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of Viagénie nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "rewrite/rewrite.h" +#include "sldns/str2wire.h" +#include "services/cache/dns.h" +#include "util/config_file.h" +#include "util/fptr_wlist.h" +#include "util/regional.h" +#include "util/data/dname.h" + +/** + * This structure contains module configuration information. One instance of + * this structure exists per instance of the module. Normally there is only one + * instance of the module. + */ +struct rewrite_domain { + uint8_t* dname; + size_t dname_len; + int labs; +}; + +struct rewrite_env { + struct rewrite_domain from; + struct rewrite_domain to; + struct rewrite_env *next; +}; + +enum rewrite_qstate { + REWRITE_IS_SUBQUERY = 1, +}; + +/** + * This function applies the configuration found in the parsed configuration + * file \a cfg to this instance of the rewrite module + * + * \param rewrite_env Module-specific global parameters. + * \param cfg Parsed configuration file. + */ +static int +rewrite_apply_cfg(struct rewrite_env** rewrite_env, struct config_file* cfg) +{ + struct rewrite_env** current = rewrite_env; + struct config_str2list* p; + *current = NULL; + for(p = cfg->rewrite_domain; p; p = p->next) { + struct rewrite_env* entry = + (struct rewrite_env*)calloc(1, sizeof(struct rewrite_env)); + if (!(entry->from.dname = sldns_str2wire_dname(p->str, &entry->from.dname_len))) { + log_err("rewrite-domain: cannot parse source field: %s", p->str); + return 0; + } + entry->from.labs = dname_count_labels(entry->from.dname); + if (!(entry->to.dname = sldns_str2wire_dname(p->str2, &entry->to.dname_len))) { + log_err("rewrite-domain: cannot parse target field: %s", p->str2); + return 0; + } + entry->to.labs = dname_count_labels(entry->to.dname); + if (dname_subdomain_c(entry->to.dname, entry->from.dname)) { + log_err("rewrite-domain: target %s cannot be a sub-domain of source %s", + p->str, p->str2); + return 0; + } + *current = entry; + current = &entry->next; + verbose(VERB_ALGO, "rewrite: added %s => %s", p->str, p->str2); + } + return 1; +} + +/** + * Initializes this instance of the rewrite module. + * + * \param env Global state of all module instances. + * \param id This instance's ID number. + */ +int +rewrite_init(struct module_env* env, int id) +{ + struct rewrite_env* rewrite_env; + if (!rewrite_apply_cfg(&rewrite_env, env->cfg)) { + log_err("rewrite: could not apply configuration settings."); + return 0; + } + env->modinfo[id] = (void*)rewrite_env; + return 1; +} + +/** + * Deinitializes this instance of the rewrite module. + * + * \param env Global state of all module instances. + * \param id This instance's ID number. + */ +void +rewrite_deinit(struct module_env* env, int id) +{ + if (!env) + return; + + struct rewrite_env* cur = (struct rewrite_env*)env->modinfo[id]; + struct rewrite_env* next; + while(cur) { + next = cur->next; + free(cur->from.dname); + free(cur->to.dname); + free(cur); + cur = next; + } + + env->modinfo[id] = NULL; +} + +static int +dname_is_subdomain(uint8_t* dname, size_t dname_len, + struct rewrite_domain* dom) +{ + return (dname_len > dom->dname_len + && dname_strict_subdomain(dname, dname_count_labels(dname), + dom->dname, dom->labs)); +} + + +static struct rewrite_domain +rewrite_dname(uint8_t* dname, size_t dname_len, struct rewrite_domain* from, + struct rewrite_domain* to, struct regional *region) +{ + struct rewrite_domain new = { NULL, 0 }; + size_t sub_len = dname_len - from->dname_len; + new.dname_len = sub_len + to->dname_len; + + if (!(new.dname = regional_alloc(region, new.dname_len))) + return new; + memcpy(new.dname, dname, sub_len); + memcpy(new.dname + sub_len, to->dname, to->dname_len); + + char buf[LDNS_MAX_DOMAINLEN+1]; + dname_str((uint8_t*)new.dname, buf); + verbose(VERB_ALGO, "rewrite: name rewritten to %s", buf); + + return new; +} + +/** + * Handles the "pass" event for a query. This event is received when a new query + * is received by this module. The query may have been generated internally by + * another module, in which case we don't want to do any special processing + * (this is an interesting discussion topic), or it may be brand new, e.g. + * received over a socket, in which case we do want to do rewrite processing. + * + * \param qstate A structure representing the state of the query that has just + * received the "pass" event. + * \param id This module's instance ID. + * + * \return The new state of the query. + */ +static enum module_ext_state +handle_event_pass(struct module_qstate* qstate, int id) +{ + if (qstate->minfo[id]) { + /* we're either inside our sub-query ... */ + if ((uintptr_t)qstate->minfo[id] == REWRITE_IS_SUBQUERY) + return module_wait_module; + /* ... or called again after the sub-query has finished */ + else + return module_finished; + } + + struct rewrite_env* rewrite_env; + for(rewrite_env = (struct rewrite_env*)qstate->env->modinfo[id]; + rewrite_env; rewrite_env = rewrite_env->next) { + if (dname_is_subdomain(qstate->qinfo.qname, qstate->qinfo.qname_len, + &rewrite_env->from)) { + struct rewrite_domain new = rewrite_dname( + qstate->qinfo.qname, qstate->qinfo.qname_len, + &rewrite_env->from, &rewrite_env->to, + qstate->region); + if (!new.dname) + return module_error; + + qstate->minfo[id] = (void*)rewrite_env; + + /* start our sub query */ + struct module_qstate* subq = NULL; + struct query_info qinfo = qstate->qinfo; + qinfo.qname = new.dname; + qinfo.qname_len = new.dname_len; + fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); + if (!(*qstate->env->attach_sub)(qstate, &qinfo, + qstate->query_flags, 0, 0, &subq)) + return module_error; + if (subq) { + subq->curmod = id; + subq->ext_state[id] = module_state_initial; + subq->minfo[id] = (void*)REWRITE_IS_SUBQUERY; + } + return module_wait_subquery; + } + } + + /* otherwise, pass request to next module. */ + return module_wait_module; +} + +/** + * This is the module's main() function. It gets called each time a query + * receives an event which we may need to handle. We respond by updating the + * state of the query. + * + * \param qstate Structure containing the state of the query. + * \param event Event that has just been received. + * \param id This module's instance ID. + * \param outbound State of a DNS query on an authoritative server. We never do + * our own queries ourselves (other modules do it for us), so + * this is unused. + */ +void +rewrite_operate(struct module_qstate* qstate, enum module_ev event, int id, + struct outbound_entry* outbound) +{ + (void)outbound; + switch(event) { + case module_event_new: + case module_event_pass: + qstate->ext_state[id] = handle_event_pass(qstate, id); + break; + case module_event_moddone: + default: + qstate->ext_state[id] = module_finished; + break; + } +} + +/** allocate (special) rrset keys, return 0 on error */ +static int +repinfo_alloc_rrset_keys(struct reply_info* rep, struct regional* region) +{ + size_t i; + for(i = 0; i < rep->rrset_count; i++) { + rep->rrsets[i] = (struct ub_packed_rrset_key*)regional_alloc_zero( + region, sizeof(struct ub_packed_rrset_key)); + if (!rep->rrsets[i]) + return 0; + rep->rrsets[i]->entry.key = rep->rrsets[i]; + rep->rrsets[i]->entry.data = NULL; + } + return 1; +} + +/** copy rrsets from replyinfo to dest replyinfo */ +static int +repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, + struct regional* region, struct rewrite_env* rewrite_env) +{ + size_t i, s; + struct packed_rrset_data* fd, *dd; + struct ub_packed_rrset_key* fk, *dk; + + for(i = 0; i < dest->rrset_count; i++) { + fk = from->rrsets[i]; + dk = dest->rrsets[i]; + fd = (struct packed_rrset_data*)fk->entry.data; + dk->rk = fk->rk; + dk->id = fk->id; + + if (dname_is_subdomain(fk->rk.dname, fk->rk.dname_len, + &rewrite_env->to)) { + struct rewrite_domain new = rewrite_dname(fk->rk.dname, + fk->rk.dname_len, &rewrite_env->to, + &rewrite_env->from, region); + if (!new.dname) + return 0; + dk->rk.dname = new.dname; + dk->rk.dname_len = new.dname_len; + dk->entry.hash = rrset_key_hash(&dk->rk); + } + else { + dk->entry.hash = fk->entry.hash; + dk->rk.dname = (uint8_t*)regional_alloc_init(region, + fk->rk.dname, fk->rk.dname_len); + if(!dk->rk.dname) + return 0; + } + s = packed_rrset_sizeof(fd); + dd = (struct packed_rrset_data*)regional_alloc_init(region, + fd, s); + if (!dd) + return 0; + packed_rrset_ptr_fixup(dd); + dk->entry.data = (void*)dd; + } + + return 1; +} + +static int +rewrite_copy_rrsets(struct module_qstate* from, int id, + struct module_qstate* dest) +{ + struct rewrite_env* rewrite_env = (struct rewrite_env*)dest->minfo[id]; + + /* build the actual reply */ + struct reply_info* frep = from->return_msg->rep; + struct reply_info* drep = construct_reply_info_base(dest->region, + frep->flags, frep->qdcount, frep->ttl, + frep->prefetch_ttl, frep->an_numrrsets, + frep->ns_numrrsets, frep->ar_numrrsets, + frep->rrset_count, frep->security); + if (!drep) + return 0; + + /* allocate ub_key structures special or not */ + if (!repinfo_alloc_rrset_keys(drep, dest->region)) + return 0; + + /* copy rrsets from replyinfo to dest and replace dname */ + if (!repinfo_copy_rrsets(drep, frep, dest->region, rewrite_env)) + return 0; + + if (!dest->return_msg) { + dest->return_msg = (struct dns_msg*)regional_alloc( + dest->region, sizeof(struct dns_msg)); + if (!dest->return_msg) + return 0; + dest->return_msg->qinfo = dest->qinfo; + } + dest->return_msg->rep = drep; + return 1; +} + + +/** + * This function is called when a sub-query finishes to inform the parent query. + * + * We issue two kinds of sub-queries: PTR and A. + * + * \param qstate State of the sub-query. + * \param id This module's instance ID. + * \param super State of the super-query. + */ +void +rewrite_inform_super(struct module_qstate* qstate, int id, + struct module_qstate* super) +{ + log_query_info(VERB_ALGO, "rewrite: inform_super, sub is", + &qstate->qinfo); + log_query_info(VERB_ALGO, "super is", &super->qinfo); + + /* sub-query has finished */ + qstate->minfo[id] = NULL; + + /* if there is no successful answer, we're done */ + if (qstate->return_rcode != LDNS_RCODE_NOERROR + || !qstate->return_msg + || !qstate->return_msg->rep) + return; + + /* copy and rewrite rrsets */ + if (!rewrite_copy_rrsets(qstate, id, super)) + log_err("rewrite: cannot copy rrsets from subquery"); + + /* store the generated response in cache */ + if (!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep, + 0, 0, 0, NULL, super->query_flags)) + log_err("out of memory"); + +} + +/** + * Clear module-specific data from query state. Since we do not allocate memory, + * it's just a matter of setting a pointer to NULL. + * + * \param qstate Query state. + * \param id This module's instance ID. + */ +void +rewrite_clear(struct module_qstate* qstate, int id) +{ + qstate->minfo[id] = NULL; +} + +/** + * Returns the amount of global memory that this module uses, not including + * per-query data. + * + * \param env Module environment. + * \param id This module's instance ID. + */ +size_t +rewrite_get_mem(struct module_env* env, int id) +{ + size_t mem = 0; + struct rewrite_env* cur; + for(cur = (struct rewrite_env*)env->modinfo[id]; cur; cur = cur->next) { + mem += sizeof(*cur); + mem += cur->from.dname_len * sizeof(*cur->from.dname); + mem += cur->to.dname_len * sizeof(*cur->to.dname); + } + return mem; +} + +/** + * The rewrite function block. + */ +static struct module_func_block rewrite_block = { + "rewrite", + &rewrite_init, &rewrite_deinit, &rewrite_operate, &rewrite_inform_super, + &rewrite_clear, &rewrite_get_mem +}; + +struct module_func_block * +rewrite_get_funcblock() +{ + return &rewrite_block; +} --- /dev/null 1970-01-01 01:00:00.000000000 +0100 +++ unbound-1.5.10/rewrite/rewrite.h 2017-11-09 23:10:03.903004770 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Manuel Mausz. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef REWRITE_REWRITE_H +#define REWRITE_REWRITE_H +#include "util/module.h" + +/** + * Get the rewrite function block. + * @return: function block with function pointers to rewrite methods. + */ +struct module_func_block *rewrite_get_funcblock(void); + +/** rewrite init */ +int rewrite_init(struct module_env* env, int id); + +/** rewrite deinit */ +void rewrite_deinit(struct module_env* env, int id); + +/** rewrite operate on a query */ +void rewrite_operate(struct module_qstate* qstate, enum module_ev event, int id, + struct outbound_entry* outbound); + +void rewrite_inform_super(struct module_qstate* qstate, int id, + struct module_qstate* super); + +/** rewrite cleanup query state */ +void rewrite_clear(struct module_qstate* qstate, int id); + +/** rewrite alloc size routine */ +size_t rewrite_get_mem(struct module_env* env, int id); + +#endif