From 630e1ab06a81f3467149ae6d7973a26e45ecf2ae Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Wed, 18 Apr 2012 02:18:19 -0700 Subject: [PATCH] Hack to work around DNS not returning a coresponding A(AAA) record for CNAMEs when A(AAA) record is asked for --- source4/dns_server/dns_query.c | 54 +++++++++++++++++++++++++++++++++++++++- 1 files changed, 53 insertions(+), 1 deletions(-) diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c index b3984a4..90bef41 100644 --- a/source4/dns_server/dns_query.c +++ b/source4/dns_server/dns_query.c @@ -186,6 +186,7 @@ static WERROR handle_question(struct dns_server *dns, struct dnsp_DnssrvRpcRecord *recs; uint16_t rec_count, ai = 0; struct ldb_dn *dn = NULL; + unsigned int ans_size; werror = dns_name2dn(dns, mem_ctx, question->name, &dn); W_ERROR_NOT_OK_RETURN(werror); @@ -193,15 +194,66 @@ 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); + ans_size = rec_count; + ans = talloc_zero_array(mem_ctx, struct dns_res_rec, ans_size); W_ERROR_HAVE_NO_MEMORY(ans); for (ri = 0; ri < rec_count; ri++) { + bool need_cname_recursion = false; + + /* + * As per kai through RFC. rfc1034 + * If we ask for A(AAA) and the actual record is CNAME + * we return the CNAME + the A or AAAA record. + */ + if (recs[ri].wType == DNS_QTYPE_CNAME && + (question->question_type == DNS_QTYPE_A || question->question_type == DNS_QTYPE_AAAA)) { + need_cname_recursion = true; + } + if ((question->question_type != DNS_QTYPE_ALL) && + !need_cname_recursion && (recs[ri].wType != question->question_type)) { continue; } + werror = create_response_rr(question, &recs[ri], &ans, &ai); + + if (need_cname_recursion) { + /* This is not very elegant and we should be able to call ourselves for + * a recursive call, but it's working. + */ + struct dnsp_DnssrvRpcRecord *recs2; + uint16_t rec_count2; + unsigned int ri2; + struct ldb_dn *dn2 = NULL; + struct dns_name_question pseudoq; + + memset(&pseudoq, 0, sizeof(struct dns_name_question)); + pseudoq.name = recs[ri].data.cname; + werror = dns_name2dn(dns, mem_ctx, pseudoq.name, &dn2); + + if (W_ERROR_EQUAL(werror, WERR_DNS_ERROR_RCODE_NAME_ERROR)) + continue; + W_ERROR_NOT_OK_RETURN(werror); + + werror = dns_lookup_records(dns, mem_ctx, dn2, &recs2, &rec_count2); + W_ERROR_NOT_OK_RETURN(werror); + + if (rec_count2 > 0) { + ans_size += rec_count2; + ans = talloc_realloc(mem_ctx, ans, struct dns_res_rec, ans_size); + W_ERROR_HAVE_NO_MEMORY(ans); + + for (ri2 = 0; ri2 < rec_count2; ri2++) { + if (recs2[ri2].wType != ((enum dns_record_type)question->question_type)) { + continue; + } + werror = create_response_rr(&pseudoq, &recs2[ri2], &ans, &ai); + } + } + } + W_ERROR_NOT_OK_RETURN(werror); } -- 1.7.5.4