diff options
Diffstat (limited to 'source4/dns_server')
-rw-r--r-- | source4/dns_server/dns_query.c | 61 |
1 files changed, 56 insertions, 5 deletions
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index 0e63058228..40df3a1ff0 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -231,11 +231,11 @@ static WERROR handle_question(struct dns_server *dns, const struct dns_name_question *question, struct dns_res_rec **answers, uint16_t *ancount) { - struct dns_res_rec *ans; + struct dns_res_rec *ans = *answers; WERROR werror; unsigned int ri; struct dnsp_DnssrvRpcRecord *recs; - uint16_t rec_count, ai = 0; + uint16_t rec_count, ai = *ancount; struct ldb_dn *dn = NULL; werror = dns_name2dn(dns, mem_ctx, question->name, &dn); @@ -244,16 +244,67 @@ static WERROR handle_question(struct dns_server *dns, werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); W_ERROR_NOT_OK_RETURN(werror); - ans = talloc_zero_array(mem_ctx, struct dns_res_rec, rec_count); - W_ERROR_HAVE_NO_MEMORY(ans); + ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, rec_count + ai); + if (ans == NULL) { + return WERR_NOMEM; + } for (ri = 0; ri < rec_count; ri++) { + if ((recs[ri].wType == DNS_TYPE_CNAME) && + ((question->question_type == DNS_QTYPE_A) || + (question->question_type == DNS_QTYPE_AAAA))) { + struct dns_name_question *new_q = + talloc(mem_ctx, struct dns_name_question); + + if (new_q == NULL) { + return WERR_NOMEM; + } + + /* We reply with one more record, so grow the array */ + ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, + rec_count + 1); + if (ans == NULL) { + TALLOC_FREE(new_q); + return WERR_NOMEM; + } + + /* First put in the CNAME record */ + werror = create_response_rr(question, &recs[ri], &ans, &ai); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + + /* And then look up the name it points at.. */ + + /* First build up the new question */ + new_q->question_type = question->question_type; + new_q->question_class = question->question_class; + if (new_q->question_type == DNS_QTYPE_A) { + new_q->name = talloc_strdup(new_q, recs[ri].data.ipv4); + } else if (new_q->question_type == DNS_QTYPE_AAAA) { + new_q->name = talloc_strdup(new_q, recs[ri].data.ipv6); + } + if (new_q->name == NULL) { + TALLOC_FREE(new_q); + return WERR_NOMEM; + } + /* and then call the lookup again */ + werror = handle_question(dns, mem_ctx, new_q, &ans, &ai); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + + + continue; + } if ((question->question_type != DNS_QTYPE_ALL) && (recs[ri].wType != question->question_type)) { continue; } werror = create_response_rr(question, &recs[ri], &ans, &ai); - W_ERROR_NOT_OK_RETURN(werror); + if (!W_ERROR_IS_OK(werror)) { + return werror; + } } if (ai == 0) { |