mirror of
https://github.com/samba-team/samba.git
synced 2025-07-23 20:59:10 +03:00
s4 dns: Correctly handle A questions for CNAMEs
When an A/AAAA lookup is made for a name that actually is a CNAME record, we need to return the CNAME record, and then do the A/AAAA lookup for the name the CNAME points at. This still fails for CNAMEs pointing at records for domains we need to ask our forwarders for. Autobuild-User: Kai Blin <kai@samba.org> Autobuild-Date: Wed Jun 6 15:23:55 CEST 2012 on sn-devel-104
This commit is contained in:
@ -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) {
|
||||
|
@ -469,6 +469,82 @@ class TestDNSUpdates(DNSTest):
|
||||
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXDOMAIN)
|
||||
|
||||
|
||||
class TestComplexQueries(DNSTest):
|
||||
def setUp(self):
|
||||
super(TestComplexQueries, self).setUp()
|
||||
p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
|
||||
updates = []
|
||||
|
||||
name = self.get_dns_domain()
|
||||
|
||||
u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
|
||||
updates.append(u)
|
||||
self.finish_name_packet(p, updates)
|
||||
|
||||
updates = []
|
||||
r = dns.res_rec()
|
||||
r.name = "cname_test.%s" % self.get_dns_domain()
|
||||
r.rr_type = dns.DNS_QTYPE_CNAME
|
||||
r.rr_class = dns.DNS_QCLASS_IN
|
||||
r.ttl = 900
|
||||
r.length = 0xffff
|
||||
r.rdata = "%s.%s" % (os.getenv('DC_SERVER'), self.get_dns_domain())
|
||||
updates.append(r)
|
||||
p.nscount = len(updates)
|
||||
p.nsrecs = updates
|
||||
|
||||
response = self.dns_transaction_udp(p)
|
||||
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestComplexQueries, self).tearDown()
|
||||
p = self.make_name_packet(dns.DNS_OPCODE_UPDATE)
|
||||
updates = []
|
||||
|
||||
name = self.get_dns_domain()
|
||||
|
||||
u = self.make_name_question(name, dns.DNS_QTYPE_SOA, dns.DNS_QCLASS_IN)
|
||||
updates.append(u)
|
||||
self.finish_name_packet(p, updates)
|
||||
|
||||
updates = []
|
||||
r = dns.res_rec()
|
||||
r.name = "cname_test.%s" % self.get_dns_domain()
|
||||
r.rr_type = dns.DNS_QTYPE_CNAME
|
||||
r.rr_class = dns.DNS_QCLASS_NONE
|
||||
r.ttl = 0
|
||||
r.length = 0xffff
|
||||
r.rdata = "%s.%s" % (os.getenv('DC_SERVER'), self.get_dns_domain())
|
||||
updates.append(r)
|
||||
p.nscount = len(updates)
|
||||
p.nsrecs = updates
|
||||
|
||||
response = self.dns_transaction_udp(p)
|
||||
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
|
||||
|
||||
def test_one_a_query(self):
|
||||
"create a query packet containing one query record"
|
||||
p = self.make_name_packet(dns.DNS_OPCODE_QUERY)
|
||||
questions = []
|
||||
|
||||
name = "cname_test.%s" % self.get_dns_domain()
|
||||
q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN)
|
||||
print "asking for ", q.name
|
||||
questions.append(q)
|
||||
|
||||
self.finish_name_packet(p, questions)
|
||||
response = self.dns_transaction_udp(p)
|
||||
self.assert_dns_rcode_equals(response, dns.DNS_RCODE_OK)
|
||||
self.assert_dns_opcode_equals(response, dns.DNS_OPCODE_QUERY)
|
||||
self.assertEquals(response.ancount, 2)
|
||||
self.assertEquals(response.answers[0].rr_type, dns.DNS_QTYPE_CNAME)
|
||||
self.assertEquals(response.answers[0].rdata, "%s.%s" %
|
||||
(os.getenv('DC_SERVER'), self.get_dns_domain()))
|
||||
self.assertEquals(response.answers[1].rr_type, dns.DNS_QTYPE_A)
|
||||
self.assertEquals(response.answers[1].rdata,
|
||||
os.getenv('DC_SERVER_IP'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import unittest
|
||||
unittest.main()
|
||||
|
Reference in New Issue
Block a user