419f67e9054dd5d80ab21fa366f4e44532f112e9
[metze/samba/wip.git] / source4 / dns_server / dns_query.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    DNS server handler for queries
5
6    Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/service_task.h"
24 #include "libcli/util/werror.h"
25 #include "librpc/ndr/libndr.h"
26 #include "librpc/gen_ndr/ndr_dns.h"
27 #include "librpc/gen_ndr/ndr_dnsp.h"
28 #include <ldb.h>
29 #include "param/param.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "dsdb/common/util.h"
32 #include "dns_server/dns_server.h"
33 #include "libcli/dns/libdns.h"
34 #include "lib/util/util_net.h"
35 #include "lib/util/tevent_werror.h"
36
37 static WERROR create_response_rr(const struct dns_name_question *question,
38                                  const struct dnsp_DnssrvRpcRecord *rec,
39                                  struct dns_res_rec **answers, uint16_t *ancount)
40 {
41         struct dns_res_rec *ans = *answers;
42         uint16_t ai = *ancount;
43         char *tmp;
44         uint32_t i;
45
46         ZERO_STRUCT(ans[ai]);
47
48         switch (rec->wType) {
49         case DNS_QTYPE_CNAME:
50                 ans[ai].rdata.cname_record = talloc_strdup(ans, rec->data.cname);
51                 if (ans[ai].rdata.cname_record == NULL) {
52                         return WERR_NOMEM;
53                 }
54                 break;
55         case DNS_QTYPE_A:
56                 ans[ai].rdata.ipv4_record = talloc_strdup(ans, rec->data.ipv4);
57                 if (ans[ai].rdata.ipv4_record == NULL) {
58                         return WERR_NOMEM;
59                 }
60                 break;
61         case DNS_QTYPE_AAAA:
62                 ans[ai].rdata.ipv6_record = rec->data.ipv6;
63                 break;
64         case DNS_TYPE_NS:
65                 ans[ai].rdata.ns_record = rec->data.ns;
66                 break;
67         case DNS_QTYPE_SRV:
68                 ans[ai].rdata.srv_record.priority = rec->data.srv.wPriority;
69                 ans[ai].rdata.srv_record.weight   = rec->data.srv.wWeight;
70                 ans[ai].rdata.srv_record.port     = rec->data.srv.wPort;
71                 ans[ai].rdata.srv_record.target   = talloc_strdup(
72                         ans, rec->data.srv.nameTarget);
73                 if (ans[ai].rdata.srv_record.target == NULL) {
74                         return WERR_NOMEM;
75                 }
76                 break;
77         case DNS_QTYPE_SOA:
78                 ans[ai].rdata.soa_record.mname   = talloc_strdup(
79                         ans, rec->data.soa.mname);
80                 if (ans[ai].rdata.soa_record.mname == NULL) {
81                         return WERR_NOMEM;
82                 }
83                 ans[ai].rdata.soa_record.rname   = talloc_strdup(
84                         ans, rec->data.soa.rname);
85                 if (ans[ai].rdata.soa_record.rname == NULL) {
86                         return WERR_NOMEM;
87                 }
88                 ans[ai].rdata.soa_record.serial  = rec->data.soa.serial;
89                 ans[ai].rdata.soa_record.refresh = rec->data.soa.refresh;
90                 ans[ai].rdata.soa_record.retry   = rec->data.soa.retry;
91                 ans[ai].rdata.soa_record.expire  = rec->data.soa.expire;
92                 ans[ai].rdata.soa_record.minimum = rec->data.soa.minimum;
93                 break;
94         case DNS_QTYPE_PTR:
95                 ans[ai].rdata.ptr_record = talloc_strdup(ans, rec->data.ptr);
96                 break;
97         case DNS_QTYPE_TXT:
98                 tmp = talloc_asprintf(ans, "\"%s\"", rec->data.txt.str[0]);
99                 if (tmp == NULL) {
100                         return WERR_NOMEM;
101                 }
102                 for (i=1; i<rec->data.txt.count; i++) {
103                         tmp = talloc_asprintf_append_buffer(
104                                 tmp, " \"%s\"", rec->data.txt.str[i]);
105                         if (tmp == NULL) {
106                                 return WERR_NOMEM;
107                         }
108                 }
109                 ans[ai].rdata.txt_record.txt = tmp;
110                 break;
111         default:
112                 DEBUG(0, ("Got unhandled type %u query.\n", rec->wType));
113                 return DNS_ERR(NOT_IMPLEMENTED);
114         }
115
116         ans[ai].name = talloc_strdup(ans, question->name);
117         if (ans[ai].name == NULL) {
118                 return WERR_NOMEM;
119         }
120         ans[ai].rr_type = rec->wType;
121         ans[ai].rr_class = DNS_QCLASS_IN;
122         ans[ai].ttl = rec->dwTtlSeconds;
123         ans[ai].length = UINT16_MAX;
124         ai++;
125
126         *answers = ans;
127         *ancount = ai;
128
129         return WERR_OK;
130 }
131
132 struct ask_forwarder_state {
133         struct tevent_context *ev;
134         uint16_t id;
135         struct dns_name_packet in_packet;
136 };
137
138 static void ask_forwarder_done(struct tevent_req *subreq);
139
140 static struct tevent_req *ask_forwarder_send(
141         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
142         const char *forwarder, struct dns_name_question *question)
143 {
144         struct tevent_req *req, *subreq;
145         struct ask_forwarder_state *state;
146         struct dns_name_packet out_packet = { 0, };
147         DATA_BLOB out_blob;
148         enum ndr_err_code ndr_err;
149
150         req = tevent_req_create(mem_ctx, &state, struct ask_forwarder_state);
151         if (req == NULL) {
152                 return NULL;
153         }
154         state->ev = ev;
155         generate_random_buffer((uint8_t *)&state->id, sizeof(state->id));
156
157         if (!is_ipaddress(forwarder)) {
158                 DEBUG(0, ("Invalid 'dns forwarder' setting '%s', needs to be "
159                           "an IP address\n", forwarder));
160                 tevent_req_werror(req, DNS_ERR(NAME_ERROR));
161                 return tevent_req_post(req, ev);
162         }
163
164         out_packet.id = state->id;
165         out_packet.operation |= DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED;
166         out_packet.qdcount = 1;
167         out_packet.questions = question;
168
169         ndr_err = ndr_push_struct_blob(
170                 &out_blob, state, &out_packet,
171                 (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
172         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
173                 tevent_req_werror(req, DNS_ERR(SERVER_FAILURE));
174                 return tevent_req_post(req, ev);
175         }
176         subreq = dns_udp_request_send(state, ev, forwarder, out_blob.data,
177                                       out_blob.length);
178         if (tevent_req_nomem(subreq, req)) {
179                 return tevent_req_post(req, ev);
180         }
181         tevent_req_set_callback(subreq, ask_forwarder_done, req);
182         return req;
183 }
184
185 static void ask_forwarder_done(struct tevent_req *subreq)
186 {
187         struct tevent_req *req = tevent_req_callback_data(
188                 subreq, struct tevent_req);
189         struct ask_forwarder_state *state = tevent_req_data(
190                 req, struct ask_forwarder_state);
191         DATA_BLOB in_blob;
192         enum ndr_err_code ndr_err;
193         WERROR ret;
194
195         ret = dns_udp_request_recv(subreq, state,
196                                    &in_blob.data, &in_blob.length);
197         TALLOC_FREE(subreq);
198         if (tevent_req_werror(req, ret)) {
199                 return;
200         }
201
202         ndr_err = ndr_pull_struct_blob(
203                 &in_blob, state, &state->in_packet,
204                 (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
205         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
206                 tevent_req_werror(req, DNS_ERR(SERVER_FAILURE));
207                 return;
208         }
209         if (state->in_packet.id != state->id) {
210                 tevent_req_werror(req, DNS_ERR(NAME_ERROR));
211                 return;
212         }
213         tevent_req_done(req);
214 }
215
216 static WERROR ask_forwarder_recv(
217         struct tevent_req *req, TALLOC_CTX *mem_ctx,
218         struct dns_res_rec **answers, uint16_t *ancount,
219         struct dns_res_rec **nsrecs, uint16_t *nscount,
220         struct dns_res_rec **additional, uint16_t *arcount)
221 {
222         struct ask_forwarder_state *state = tevent_req_data(
223                 req, struct ask_forwarder_state);
224         struct dns_name_packet *in_packet = &state->in_packet;
225         WERROR err;
226
227         if (tevent_req_is_werror(req, &err)) {
228                 return err;
229         }
230
231         *ancount = in_packet->ancount;
232         *answers = talloc_move(mem_ctx, &in_packet->answers);
233
234         *nscount = in_packet->nscount;
235         *nsrecs = talloc_move(mem_ctx, &in_packet->nsrecs);
236
237         *arcount = in_packet->arcount;
238         *additional = talloc_move(mem_ctx, &in_packet->additional);
239
240         return WERR_OK;
241 }
242
243 static WERROR handle_question(struct dns_server *dns,
244                               TALLOC_CTX *mem_ctx,
245                               const struct dns_name_question *question,
246                               struct dns_res_rec **answers, uint16_t *ancount)
247 {
248         struct dns_res_rec *ans;
249         WERROR werror;
250         unsigned int ri;
251         struct dnsp_DnssrvRpcRecord *recs;
252         uint16_t rec_count, ai = 0;
253         struct ldb_dn *dn = NULL;
254
255         werror = dns_name2dn(dns, mem_ctx, question->name, &dn);
256         W_ERROR_NOT_OK_RETURN(werror);
257
258         werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count);
259         W_ERROR_NOT_OK_RETURN(werror);
260
261         ans = talloc_zero_array(mem_ctx, struct dns_res_rec, rec_count);
262         W_ERROR_HAVE_NO_MEMORY(ans);
263
264         for (ri = 0; ri < rec_count; ri++) {
265                 if ((question->question_type != DNS_QTYPE_ALL) &&
266                     (recs[ri].wType != question->question_type)) {
267                         continue;
268                 }
269                 werror = create_response_rr(question, &recs[ri], &ans, &ai);
270                 W_ERROR_NOT_OK_RETURN(werror);
271         }
272
273         if (ai == 0) {
274                 return DNS_ERR(NAME_ERROR);
275         }
276
277         *ancount = ai;
278         *answers = ans;
279
280         return WERR_OK;
281
282 }
283
284 struct dns_server_process_query_state {
285         struct dns_res_rec *answers;
286         uint16_t ancount;
287         struct dns_res_rec *nsrecs;
288         uint16_t nscount;
289         struct dns_res_rec *additional;
290         uint16_t arcount;
291 };
292
293 static void dns_server_process_query_got_response(struct tevent_req *subreq);
294
295 struct tevent_req *dns_server_process_query_send(
296         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
297         struct dns_server *dns, struct dns_request_state *req_state,
298         const struct dns_name_packet *in)
299 {
300         struct tevent_req *req, *subreq;
301         struct dns_server_process_query_state *state;
302
303         req = tevent_req_create(mem_ctx, &state,
304                                 struct dns_server_process_query_state);
305         if (req == NULL) {
306                 return NULL;
307         }
308         if (in->qdcount != 1) {
309                 tevent_req_werror(req, DNS_ERR(FORMAT_ERROR));
310                 return tevent_req_post(req, ev);
311         }
312
313         /* Windows returns NOT_IMPLEMENTED on this as well */
314         if (in->questions[0].question_class == DNS_QCLASS_NONE) {
315                 tevent_req_werror(req, DNS_ERR(NOT_IMPLEMENTED));
316                 return tevent_req_post(req, ev);
317         }
318
319         if (dns_authorative_for_zone(dns, in->questions[0].name)) {
320                 WERROR err;
321
322                 req_state->flags |= DNS_FLAG_AUTHORITATIVE;
323                 err = handle_question(dns, state, &in->questions[0],
324                                       &state->answers, &state->ancount);
325                 if (tevent_req_werror(req, err)) {
326                         return tevent_req_post(req, ev);
327                 }
328                 tevent_req_done(req);
329                 return tevent_req_post(req, ev);
330         }
331
332         if ((req_state->flags & DNS_FLAG_RECURSION_DESIRED) &&
333             (req_state->flags & DNS_FLAG_RECURSION_AVAIL)) {
334                 DEBUG(2, ("Not authoritative for '%s', forwarding\n",
335                           in->questions[0].name));
336
337                 subreq = ask_forwarder_send(
338                         state, ev, lpcfg_dns_forwarder(dns->task->lp_ctx),
339                         &in->questions[0]);
340                 if (tevent_req_nomem(subreq, req)) {
341                         return tevent_req_post(req, ev);
342                 }
343                 tevent_req_set_callback(
344                         subreq, dns_server_process_query_got_response, req);
345                 return req;
346         }
347
348         tevent_req_werror(req, DNS_ERR(NAME_ERROR));
349         return tevent_req_post(req, ev);
350 }
351
352 static void dns_server_process_query_got_response(struct tevent_req *subreq)
353 {
354         struct tevent_req *req = tevent_req_callback_data(
355                 subreq, struct tevent_req);
356         struct dns_server_process_query_state *state = tevent_req_data(
357                 req, struct dns_server_process_query_state);
358         WERROR err;
359
360         err = ask_forwarder_recv(subreq, state,
361                                  &state->answers, &state->ancount,
362                                  &state->nsrecs, &state->nscount,
363                                  &state->additional, &state->arcount);
364         TALLOC_FREE(subreq);
365         if (tevent_req_werror(req, err)) {
366                 return;
367         }
368         tevent_req_done(req);
369 }
370
371 WERROR dns_server_process_query_recv(
372         struct tevent_req *req, TALLOC_CTX *mem_ctx,
373         struct dns_res_rec **answers,    uint16_t *ancount,
374         struct dns_res_rec **nsrecs,     uint16_t *nscount,
375         struct dns_res_rec **additional, uint16_t *arcount)
376 {
377         struct dns_server_process_query_state *state = tevent_req_data(
378                 req, struct dns_server_process_query_state);
379         WERROR err;
380
381         if (tevent_req_is_werror(req, &err)) {
382                 return err;
383         }
384         *answers = talloc_move(mem_ctx, &state->answers);
385         *ancount = state->ancount;
386         *nsrecs = talloc_move(mem_ctx, &state->nsrecs);
387         *nscount = state->nscount;
388         *additional = talloc_move(mem_ctx, &state->additional);
389         *arcount = state->arcount;
390         return WERR_OK;
391 }