1 /*
2 Unix SMB/CIFS implementation.
3
4 Small async DNS library for Samba with socketwrapper support
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 "replace.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/dns/libdns.h"
27 #include "lib/util/tevent_unix.h"
28 #include "lib/util/samba_util.h"
29 #include "lib/util/debug.h"
30 #include "libcli/util/error.h"
31 #include "librpc/ndr/libndr.h"
32 #include "librpc/gen_ndr/ndr_dns.h"
33
34 struct dns_udp_request_state {
35 struct tevent_context *ev;
36 struct tdgram_context *dgram;
37 size_t query_len;
38 uint8_t *reply;
39 size_t reply_len;
40 };
41
42 #define DNS_REQUEST_TIMEOUT 10
43
44 /* Declare callback functions used below. */
45 static void dns_udp_request_get_reply(struct tevent_req *subreq);
46 static void dns_udp_request_done(struct tevent_req *subreq);
47
dns_udp_request_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const char * server_addr_string,const uint8_t * query,size_t query_len)48 static struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
49 struct tevent_context *ev,
50 const char *server_addr_string,
51 const uint8_t *query,
52 size_t query_len)
53 {
54 struct tevent_req *req, *subreq;
55 struct dns_udp_request_state *state;
56 struct tsocket_address *local_addr, *server_addr;
57 struct tdgram_context *dgram;
58 int ret;
59
60 req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
61 if (req == NULL) {
62 return NULL;
63 }
64
65 state->ev = ev;
66
67 /* Use connected UDP sockets */
68 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
69 &local_addr);
70 if (ret != 0) {
71 tevent_req_error(req, errno);
72 return tevent_req_post(req, ev);
73 }
74
75 ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
76 DNS_SERVICE_PORT, &server_addr);
77 if (ret != 0) {
78 tevent_req_error(req, errno);
79 return tevent_req_post(req, ev);
80 }
81
82 ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
83 if (ret != 0) {
84 tevent_req_error(req, errno);
85 return tevent_req_post(req, ev);
86 }
87
88 state->dgram = dgram;
89 state->query_len = query_len;
90
91 dump_data(10, query, query_len);
92
93 subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
94 if (tevent_req_nomem(subreq, req)) {
95 return tevent_req_post(req, ev);
96 }
97
98 if (!tevent_req_set_endtime(req, ev,
99 timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
100 return tevent_req_post(req, ev);
101 }
102
103 tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
104 return req;
105 }
106
dns_udp_request_get_reply(struct tevent_req * subreq)107 static void dns_udp_request_get_reply(struct tevent_req *subreq)
108 {
109 struct tevent_req *req = tevent_req_callback_data(subreq,
110 struct tevent_req);
111 struct dns_udp_request_state *state = tevent_req_data(req,
112 struct dns_udp_request_state);
113 ssize_t len;
114 int err = 0;
115
116 len = tdgram_sendto_recv(subreq, &err);
117 TALLOC_FREE(subreq);
118
119 if (len == -1 && err != 0) {
120 tevent_req_error(req, err);
121 return;
122 }
123
124 if (len != state->query_len) {
125 tevent_req_error(req, EIO);
126 return;
127 }
128
129 subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
130 if (tevent_req_nomem(subreq, req)) {
131 return;
132 }
133
134 tevent_req_set_callback(subreq, dns_udp_request_done, req);
135 }
136
dns_udp_request_done(struct tevent_req * subreq)137 static void dns_udp_request_done(struct tevent_req *subreq)
138 {
139 struct tevent_req *req = tevent_req_callback_data(subreq,
140 struct tevent_req);
141 struct dns_udp_request_state *state = tevent_req_data(req,
142 struct dns_udp_request_state);
143
144 ssize_t len;
145 int err = 0;
146
147 len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
148 TALLOC_FREE(subreq);
149
150 if (len == -1 && err != 0) {
151 tevent_req_error(req, err);
152 return;
153 }
154
155 state->reply_len = len;
156 dump_data(10, state->reply, state->reply_len);
157 tevent_req_done(req);
158 }
159
dns_udp_request_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,uint8_t ** reply,size_t * reply_len)160 static int dns_udp_request_recv(struct tevent_req *req,
161 TALLOC_CTX *mem_ctx,
162 uint8_t **reply,
163 size_t *reply_len)
164 {
165 struct dns_udp_request_state *state = tevent_req_data(req,
166 struct dns_udp_request_state);
167 int err;
168
169 if (tevent_req_is_unix_error(req, &err)) {
170 tevent_req_received(req);
171 return err;
172 }
173
174 *reply = talloc_move(mem_ctx, &state->reply);
175 *reply_len = state->reply_len;
176 tevent_req_received(req);
177
178 return 0;
179 }
180
181 struct dns_tcp_request_state {
182 struct tevent_context *ev;
183 struct tstream_context *stream;
184 const uint8_t *query;
185 size_t query_len;
186
187 uint8_t dns_msglen_hdr[2];
188 struct iovec iov[2];
189
190 size_t nread;
191 uint8_t *reply;
192 };
193
194 static void dns_tcp_request_connected(struct tevent_req *subreq);
195 static void dns_tcp_request_sent(struct tevent_req *subreq);
196 static int dns_tcp_request_next_vector(struct tstream_context *stream,
197 void *private_data,
198 TALLOC_CTX *mem_ctx,
199 struct iovec **_vector,
200 size_t *_count);
201 static void dns_tcp_request_received(struct tevent_req *subreq);
202
dns_tcp_request_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const char * server_addr_string,const uint8_t * query,size_t query_len)203 static struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
204 struct tevent_context *ev,
205 const char *server_addr_string,
206 const uint8_t *query,
207 size_t query_len)
208 {
209 struct tevent_req *req, *subreq;
210 struct dns_tcp_request_state *state;
211 struct tsocket_address *local, *remote;
212 int ret;
213
214 req = tevent_req_create(mem_ctx, &state,
215 struct dns_tcp_request_state);
216 if (req == NULL) {
217 return NULL;
218 }
219 state->ev = ev;
220 state->query = query;
221 state->query_len = query_len;
222
223 if (query_len > UINT16_MAX) {
224 tevent_req_error(req, EMSGSIZE);
225 return tevent_req_post(req, ev);
226 }
227
228 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
229 if (ret != 0) {
230 tevent_req_error(req, errno);
231 return tevent_req_post(req, ev);
232 }
233
234 ret = tsocket_address_inet_from_strings(
235 state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
236 if (ret != 0) {
237 tevent_req_error(req, errno);
238 return tevent_req_post(req, ev);
239 }
240
241 subreq = tstream_inet_tcp_connect_send(state, state->ev,
242 local, remote);
243 if (tevent_req_nomem(subreq, req)) {
244 return tevent_req_post(req, ev);
245 }
246 tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
247
248 return req;
249 }
250
dns_tcp_request_connected(struct tevent_req * subreq)251 static void dns_tcp_request_connected(struct tevent_req *subreq)
252 {
253 struct tevent_req *req = tevent_req_callback_data(
254 subreq, struct tevent_req);
255 struct dns_tcp_request_state *state = tevent_req_data(
256 req, struct dns_tcp_request_state);
257 int ret, err;
258
259 ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
260 &state->stream, NULL);
261 TALLOC_FREE(subreq);
262 if (ret == -1) {
263 tevent_req_error(req, err);
264 return;
265 }
266
267 RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
268 state->iov[0] = (struct iovec) {
269 .iov_base = state->dns_msglen_hdr,
270 .iov_len = sizeof(state->dns_msglen_hdr)
271 };
272 state->iov[1] = (struct iovec) {
273 .iov_base = discard_const_p(void, state->query),
274 .iov_len = state->query_len
275 };
276
277 subreq = tstream_writev_send(state, state->ev, state->stream,
278 state->iov, ARRAY_SIZE(state->iov));
279 if (tevent_req_nomem(subreq, req)) {
280 return;
281 }
282 tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
283 }
284
dns_tcp_request_sent(struct tevent_req * subreq)285 static void dns_tcp_request_sent(struct tevent_req *subreq)
286 {
287 struct tevent_req *req = tevent_req_callback_data(
288 subreq, struct tevent_req);
289 struct dns_tcp_request_state *state = tevent_req_data(
290 req, struct dns_tcp_request_state);
291 int ret, err;
292
293 ret = tstream_writev_recv(subreq, &err);
294 TALLOC_FREE(subreq);
295 if (ret == -1) {
296 tevent_req_error(req, err);
297 return;
298 }
299
300 subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
301 dns_tcp_request_next_vector, state);
302 if (tevent_req_nomem(subreq, req)) {
303 return;
304 }
305 tevent_req_set_callback(subreq, dns_tcp_request_received, req);
306 }
307
dns_tcp_request_next_vector(struct tstream_context * stream,void * private_data,TALLOC_CTX * mem_ctx,struct iovec ** _vector,size_t * _count)308 static int dns_tcp_request_next_vector(struct tstream_context *stream,
309 void *private_data,
310 TALLOC_CTX *mem_ctx,
311 struct iovec **_vector,
312 size_t *_count)
313 {
314 struct dns_tcp_request_state *state = talloc_get_type_abort(
315 private_data, struct dns_tcp_request_state);
316 struct iovec *vector;
317 uint16_t msglen;
318
319 if (state->nread == 0) {
320 vector = talloc_array(mem_ctx, struct iovec, 1);
321 if (vector == NULL) {
322 return -1;
323 }
324 vector[0] = (struct iovec) {
325 .iov_base = state->dns_msglen_hdr,
326 .iov_len = sizeof(state->dns_msglen_hdr)
327 };
328 state->nread = sizeof(state->dns_msglen_hdr);
329
330 *_vector = vector;
331 *_count = 1;
332 return 0;
333 }
334
335 if (state->nread == sizeof(state->dns_msglen_hdr)) {
336 msglen = RSVAL(state->dns_msglen_hdr, 0);
337
338 state->reply = talloc_array(state, uint8_t, msglen);
339 if (state->reply == NULL) {
340 return -1;
341 }
342
343 vector = talloc_array(mem_ctx, struct iovec, 1);
344 if (vector == NULL) {
345 return -1;
346 }
347 vector[0] = (struct iovec) {
348 .iov_base = state->reply,
349 .iov_len = msglen
350 };
351 state->nread += msglen;
352
353 *_vector = vector;
354 *_count = 1;
355 return 0;
356 }
357
358 *_vector = NULL;
359 *_count = 0;
360 return 0;
361 }
362
dns_tcp_request_received(struct tevent_req * subreq)363 static void dns_tcp_request_received(struct tevent_req *subreq)
364 {
365 struct tevent_req *req = tevent_req_callback_data(
366 subreq, struct tevent_req);
367 int ret, err;
368
369 ret = tstream_readv_pdu_recv(subreq, &err);
370 TALLOC_FREE(subreq);
371 if (ret == -1) {
372 tevent_req_error(req, err);
373 return;
374 }
375
376 tevent_req_done(req);
377 }
378
dns_tcp_request_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,uint8_t ** reply,size_t * reply_len)379 static int dns_tcp_request_recv(struct tevent_req *req,
380 TALLOC_CTX *mem_ctx,
381 uint8_t **reply,
382 size_t *reply_len)
383 {
384 struct dns_tcp_request_state *state = tevent_req_data(
385 req, struct dns_tcp_request_state);
386 int err;
387
388 if (tevent_req_is_unix_error(req, &err)) {
389 tevent_req_received(req);
390 return err;
391 }
392
393 *reply_len = talloc_array_length(state->reply);
394 *reply = talloc_move(mem_ctx, &state->reply);
395 tevent_req_received(req);
396
397 return 0;
398 }
399
400 struct dns_cli_request_state {
401 struct tevent_context *ev;
402 const char *nameserver;
403
404 uint16_t req_id;
405
406 DATA_BLOB query;
407
408 struct dns_name_packet *reply;
409 };
410
411 static void dns_cli_request_udp_done(struct tevent_req *subreq);
412 static void dns_cli_request_tcp_done(struct tevent_req *subreq);
413
dns_cli_request_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,const char * nameserver,const char * name,enum dns_qclass qclass,enum dns_qtype qtype)414 struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
415 struct tevent_context *ev,
416 const char *nameserver,
417 const char *name,
418 enum dns_qclass qclass,
419 enum dns_qtype qtype)
420 {
421 struct tevent_req *req, *subreq;
422 struct dns_cli_request_state *state;
423 struct dns_name_question question;
424 struct dns_name_packet out_packet;
425 enum ndr_err_code ndr_err;
426
427 req = tevent_req_create(mem_ctx, &state,
428 struct dns_cli_request_state);
429 if (req == NULL) {
430 return NULL;
431 }
432 state->ev = ev;
433 state->nameserver = nameserver;
434
435 DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
436 name, (int)qclass, (int)qtype);
437
438 generate_random_buffer((uint8_t *)&state->req_id,
439 sizeof(state->req_id));
440
441 question = (struct dns_name_question) {
442 .name = discard_const_p(char, name),
443 .question_type = qtype, .question_class = qclass
444 };
445
446 out_packet = (struct dns_name_packet) {
447 .id = state->req_id,
448 .operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
449 .qdcount = 1,
450 .questions = &question
451 };
452
453 ndr_err = ndr_push_struct_blob(
454 &state->query, state, &out_packet,
455 (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
456 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
457 tevent_req_error(req, ndr_map_error2errno(ndr_err));
458 return tevent_req_post(req, ev);
459 }
460
461 subreq = dns_udp_request_send(state, state->ev, state->nameserver,
462 state->query.data, state->query.length);
463 if (tevent_req_nomem(subreq, req)) {
464 return tevent_req_post(req, ev);
465 }
466 tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
467 return req;
468 }
469
dns_cli_request_udp_done(struct tevent_req * subreq)470 static void dns_cli_request_udp_done(struct tevent_req *subreq)
471 {
472 struct tevent_req *req = tevent_req_callback_data(
473 subreq, struct tevent_req);
474 struct dns_cli_request_state *state = tevent_req_data(
475 req, struct dns_cli_request_state);
476 DATA_BLOB reply;
477 enum ndr_err_code ndr_err;
478 int ret;
479
480 ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
481 TALLOC_FREE(subreq);
482 if (tevent_req_error(req, ret)) {
483 return;
484 }
485
486 state->reply = talloc(state, struct dns_name_packet);
487 if (tevent_req_nomem(state->reply, req)) {
488 return;
489 }
490
491 ndr_err = ndr_pull_struct_blob(
492 &reply, state->reply, state->reply,
493 (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
494 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
495 tevent_req_error(req, ndr_map_error2errno(ndr_err));
496 return;
497 }
498 TALLOC_FREE(reply.data);
499
500 if (state->reply->id != state->req_id) {
501 DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
502 state->reply->id, state->req_id);
503 tevent_req_error(req, ENOMSG);
504 return;
505 }
506
507 if ((state->reply->operation & DNS_FLAG_TRUNCATION) == 0) {
508 DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
509 " recs\n", (int)state->reply->operation,
510 state->reply->qdcount, state->reply->ancount,
511 state->reply->nscount, state->reply->nscount);
512 tevent_req_done(req);
513 return;
514 }
515
516 DBG_DEBUG("Reply was truncated, retrying TCP\n");
517
518 TALLOC_FREE(state->reply);
519
520 subreq = dns_tcp_request_send(state, state->ev, state->nameserver,
521 state->query.data, state->query.length);
522 if (tevent_req_nomem(subreq, req)) {
523 return;
524 }
525 tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
526 }
527
dns_cli_request_tcp_done(struct tevent_req * subreq)528 static void dns_cli_request_tcp_done(struct tevent_req *subreq)
529 {
530 struct tevent_req *req = tevent_req_callback_data(
531 subreq, struct tevent_req);
532 struct dns_cli_request_state *state = tevent_req_data(
533 req, struct dns_cli_request_state);
534 DATA_BLOB reply;
535 enum ndr_err_code ndr_err;
536 int ret;
537
538 ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
539 TALLOC_FREE(subreq);
540 if (tevent_req_error(req, ret)) {
541 return;
542 }
543
544 state->reply = talloc(state, struct dns_name_packet);
545 if (tevent_req_nomem(state->reply, req)) {
546 return;
547 }
548
549 ndr_err = ndr_pull_struct_blob(
550 &reply, state->reply, state->reply,
551 (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
552 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
553 tevent_req_error(req, ndr_map_error2errno(ndr_err));
554 return;
555 }
556 TALLOC_FREE(reply.data);
557
558 if (state->reply->id != state->req_id) {
559 DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
560 state->reply->id, state->req_id);
561 tevent_req_error(req, ENOMSG);
562 return;
563 }
564
565 DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
566 " recs\n", (int)state->reply->operation,
567 state->reply->qdcount, state->reply->ancount,
568 state->reply->nscount, state->reply->nscount);
569
570 tevent_req_done(req);
571 }
572
dns_cli_request_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct dns_name_packet ** reply)573 int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
574 struct dns_name_packet **reply)
575 {
576 struct dns_cli_request_state *state = tevent_req_data(
577 req, struct dns_cli_request_state);
578 int err;
579
580 if (tevent_req_is_unix_error(req, &err)) {
581 return err;
582 }
583 *reply = talloc_move(mem_ctx, &state->reply);
584 return 0;
585 }
586