diff options
Diffstat (limited to 'services/localzone.c')
-rw-r--r-- | services/localzone.c | 128 |
1 files changed, 88 insertions, 40 deletions
diff --git a/services/localzone.c b/services/localzone.c index 0f608170c850..902a29f21d48 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1146,8 +1146,9 @@ void local_zones_print(struct local_zones* zones) /** encode answer consisting of 1 rrset */ static int local_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - struct ub_packed_rrset_key* rrset, int ansec, int rcode) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, + int rcode) { struct reply_info rep; uint16_t udpsize; @@ -1165,23 +1166,22 @@ local_encode(struct query_info* qinfo, struct module_env* env, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, temp) - || !reply_info_answer_encode(qinfo, &rep, - *(uint16_t*)sldns_buffer_begin(buf), - sldns_buffer_read_u16_at(buf, 2), - buf, 0, 0, temp, udpsize, edns, - (int)(edns->bits&EDNS_DO), 0)) + if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, + repinfo, temp) || !reply_info_answer_encode(qinfo, &rep, + *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), + buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) { error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); + } return 1; } /** encode local error answer */ static void local_error_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - int rcode, int r) + struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, + struct regional* temp, int rcode, int r) { edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; @@ -1189,7 +1189,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, edns->bits &= EDNS_DO; if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, - rcode, edns, temp)) + rcode, edns, repinfo, temp)) edns->opt_list = NULL; error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); @@ -1310,7 +1310,8 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list, /** answer local data match */ static int local_data_answer(struct local_zone* z, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, int labs, struct local_data** ldp, enum localzone_type lz_type, int tag, struct config_strlist** tag_datas, size_t tag_datas_size, char** tagname, int num_tags) @@ -1339,7 +1340,7 @@ local_data_answer(struct local_zone* z, struct module_env* env, * chain. */ if(qinfo->local_alias) return 1; - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1, LDNS_RCODE_NOERROR); } } @@ -1374,29 +1375,60 @@ local_data_answer(struct local_zone* z, struct module_env* env, struct ub_packed_rrset_key r = *lr->rrset; r.rk.dname = qinfo->qname; r.rk.dname_len = qinfo->qname_len; - return local_encode(qinfo, env, edns, buf, temp, &r, 1, + return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1, LDNS_RCODE_NOERROR); } - return local_encode(qinfo, env, edns, buf, temp, lr->rrset, 1, + return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1, LDNS_RCODE_NOERROR); } +/** + * See if the local zone does not cover the name, eg. the name is not + * in the zone and the zone is transparent */ +static int +local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo, + int labs) +{ + struct local_data key; + struct local_data* ld = NULL; + struct local_rrset* lr = NULL; + if(z->type == local_zone_always_transparent) + return 1; + if(z->type != local_zone_transparent + && z->type != local_zone_typetransparent + && z->type != local_zone_inform) + return 0; + key.node.key = &key; + key.name = qinfo->qname; + key.namelen = qinfo->qname_len; + key.namelabs = labs; + ld = (struct local_data*)rbtree_search(&z->data, &key.node); + if(z->type == local_zone_transparent || z->type == local_zone_inform) + return (ld == NULL); + if(ld) + lr = local_data_find_type(ld, qinfo->qtype, 1); + /* local_zone_typetransparent */ + return (lr == NULL); +} + /** - * answer in case where no exact match is found - * @param z: zone for query - * @param env: module environment - * @param qinfo: query - * @param edns: edns from query + * Answer in case where no exact match is found. + * @param z: zone for query. + * @param env: module environment. + * @param qinfo: query. + * @param edns: edns from query. + * @param repinfo: source address for checks. may be NULL. * @param buf: buffer for answer. - * @param temp: temp region for encoding + * @param temp: temp region for encoding. * @param ld: local data, if NULL, no such name exists in localdata. - * @param lz_type: type of the local zone + * @param lz_type: type of the local zone. * @return 1 if a reply is to be sent, 0 if not. */ static int lz_zone_answer(struct local_zone* z, struct module_env* env, - struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, - struct regional* temp, struct local_data* ld, enum localzone_type lz_type) + struct query_info* qinfo, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, + struct local_data* ld, enum localzone_type lz_type) { if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { /** no reply at all, signal caller by clearing buffer. */ @@ -1405,7 +1437,7 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, return 1; } else if(lz_type == local_zone_refuse || lz_type == local_zone_always_refuse) { - local_error_encode(qinfo, env, edns, buf, temp, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA)); return 1; } else if(lz_type == local_zone_static || @@ -1421,9 +1453,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, int rcode = (ld || lz_type == local_zone_redirect)? LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; if(z->soa) - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa, 0, rcode); - local_error_encode(qinfo, env, edns, buf, temp, rcode, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA)); return 1; } else if(lz_type == local_zone_typetransparent @@ -1438,9 +1470,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, if(ld && ld->rrsets) { int rcode = LDNS_RCODE_NOERROR; if(z->soa) - return local_encode(qinfo, env, edns, buf, temp, + return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa, 0, rcode); - local_error_encode(qinfo, env, edns, buf, temp, rcode, + local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA)); return 1; } @@ -1459,7 +1491,7 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo, uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); dname_str(z->name, zname); addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip, + snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip, (unsigned)port); log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); } @@ -1543,10 +1575,6 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, (z = local_zones_lookup(view->local_zones, qinfo->qname, qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype))) { - if(z->type != local_zone_noview) - verbose(VERB_ALGO, - "using localzone from view: %s", - view->name); lock_rw_rdlock(&z->lock); lzt = z->type; } @@ -1554,10 +1582,24 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, lock_rw_unlock(&z->lock); z = NULL; } + if(z && (lzt == local_zone_transparent || + lzt == local_zone_typetransparent || + lzt == local_zone_inform || + lzt == local_zone_always_transparent) && + local_zone_does_not_cover(z, qinfo, labs)) { + lock_rw_unlock(&z->lock); + z = NULL; + } if(view->local_zones && !z && !view->isfirst){ lock_rw_unlock(&view->lock); return 0; } + if(z && verbosity >= VERB_ALGO) { + char zname[255+1]; + dname_str(z->name, zname); + verbose(VERB_ALGO, "using localzone %s %s from view %s", + zname, local_zone_type2str(lzt), view->name); + } lock_rw_unlock(&view->lock); } if(!z) { @@ -1570,27 +1612,33 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, return 0; } lock_rw_rdlock(&z->lock); - lzt = lz_type(taglist, taglen, z->taglist, z->taglen, tagactions, tagactionssize, z->type, repinfo, z->override_tree, &tag, tagname, num_tags); lock_rw_unlock(&zones->lock); + if(z && verbosity >= VERB_ALGO) { + char zname[255+1]; + dname_str(z->name, zname); + verbose(VERB_ALGO, "using localzone %s %s", zname, + local_zone_type2str(lzt)); + } } - if((lzt == local_zone_inform || lzt == local_zone_inform_deny) - && repinfo) + if((env->cfg->log_local_actions || + lzt == local_zone_inform || lzt == local_zone_inform_deny) + && repinfo) lz_inform_print(z, qinfo, repinfo); if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent && lzt != local_zone_always_nxdomain - && local_data_answer(z, env, qinfo, edns, buf, temp, labs, &ld, lzt, - tag, tag_datas, tag_datas_size, tagname, num_tags)) { + && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs, + &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) { lock_rw_unlock(&z->lock); /* We should tell the caller that encode is deferred if we found * a local alias. */ return !qinfo->local_alias; } - r = lz_zone_answer(z, env, qinfo, edns, buf, temp, ld, lzt); + r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt); lock_rw_unlock(&z->lock); return r && !qinfo->local_alias; /* see above */ } |