Line data Source code
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 :
48 1449 : 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 0 : struct tevent_req *req, *subreq;
55 0 : struct dns_udp_request_state *state;
56 0 : struct tsocket_address *local_addr, *server_addr;
57 0 : struct tdgram_context *dgram;
58 0 : int ret;
59 :
60 1449 : req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
61 1449 : if (req == NULL) {
62 0 : return NULL;
63 : }
64 :
65 1449 : state->ev = ev;
66 :
67 : /* Use connected UDP sockets */
68 1449 : ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
69 : &local_addr);
70 1449 : if (ret != 0) {
71 0 : tevent_req_error(req, errno);
72 0 : return tevent_req_post(req, ev);
73 : }
74 :
75 1449 : ret = tsocket_address_inet_from_hostport_strings(
76 : state, "ip", server_addr_string, DNS_SERVICE_PORT, &server_addr);
77 1449 : if (ret != 0) {
78 0 : tevent_req_error(req, errno);
79 0 : return tevent_req_post(req, ev);
80 : }
81 :
82 1449 : ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
83 1449 : if (ret != 0) {
84 0 : tevent_req_error(req, errno);
85 0 : return tevent_req_post(req, ev);
86 : }
87 :
88 1449 : state->dgram = dgram;
89 1449 : state->query_len = query_len;
90 :
91 1449 : dump_data(10, query, query_len);
92 :
93 1449 : subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
94 1449 : if (tevent_req_nomem(subreq, req)) {
95 0 : return tevent_req_post(req, ev);
96 : }
97 :
98 1449 : if (!tevent_req_set_endtime(req, ev,
99 : timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
100 0 : return tevent_req_post(req, ev);
101 : }
102 :
103 1449 : tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
104 1449 : return req;
105 : }
106 :
107 1449 : static void dns_udp_request_get_reply(struct tevent_req *subreq)
108 : {
109 1449 : struct tevent_req *req = tevent_req_callback_data(subreq,
110 : struct tevent_req);
111 1449 : struct dns_udp_request_state *state = tevent_req_data(req,
112 : struct dns_udp_request_state);
113 0 : ssize_t len;
114 1449 : int err = 0;
115 :
116 1449 : len = tdgram_sendto_recv(subreq, &err);
117 1449 : TALLOC_FREE(subreq);
118 :
119 1449 : if (len == -1 && err != 0) {
120 10 : tevent_req_error(req, err);
121 10 : return;
122 : }
123 :
124 1439 : if (len != state->query_len) {
125 0 : tevent_req_error(req, EIO);
126 0 : return;
127 : }
128 :
129 1439 : subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
130 1439 : if (tevent_req_nomem(subreq, req)) {
131 0 : return;
132 : }
133 :
134 1439 : tevent_req_set_callback(subreq, dns_udp_request_done, req);
135 : }
136 :
137 1429 : static void dns_udp_request_done(struct tevent_req *subreq)
138 : {
139 1429 : struct tevent_req *req = tevent_req_callback_data(subreq,
140 : struct tevent_req);
141 1429 : struct dns_udp_request_state *state = tevent_req_data(req,
142 : struct dns_udp_request_state);
143 :
144 0 : ssize_t len;
145 1429 : int err = 0;
146 :
147 1429 : len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
148 1429 : TALLOC_FREE(subreq);
149 :
150 1429 : if (len == -1 && err != 0) {
151 0 : tevent_req_error(req, err);
152 0 : return;
153 : }
154 :
155 1429 : state->reply_len = len;
156 1429 : dump_data(10, state->reply, state->reply_len);
157 1429 : tevent_req_done(req);
158 : }
159 :
160 1449 : 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 1449 : struct dns_udp_request_state *state = tevent_req_data(req,
166 : struct dns_udp_request_state);
167 0 : int err;
168 :
169 1449 : if (tevent_req_is_unix_error(req, &err)) {
170 20 : tevent_req_received(req);
171 20 : return err;
172 : }
173 :
174 1429 : *reply = talloc_move(mem_ctx, &state->reply);
175 1429 : *reply_len = state->reply_len;
176 1429 : tevent_req_received(req);
177 :
178 1429 : 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 :
203 0 : 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 0 : struct tevent_req *req, *subreq;
210 0 : struct dns_tcp_request_state *state;
211 0 : struct tsocket_address *local, *remote;
212 0 : int ret;
213 :
214 0 : req = tevent_req_create(mem_ctx, &state,
215 : struct dns_tcp_request_state);
216 0 : if (req == NULL) {
217 0 : return NULL;
218 : }
219 0 : state->ev = ev;
220 0 : state->query = query;
221 0 : state->query_len = query_len;
222 :
223 0 : if (query_len > UINT16_MAX) {
224 0 : tevent_req_error(req, EMSGSIZE);
225 0 : return tevent_req_post(req, ev);
226 : }
227 :
228 0 : ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
229 0 : if (ret != 0) {
230 0 : tevent_req_error(req, errno);
231 0 : return tevent_req_post(req, ev);
232 : }
233 :
234 0 : ret = tsocket_address_inet_from_hostport_strings(
235 : state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
236 0 : if (ret != 0) {
237 0 : tevent_req_error(req, errno);
238 0 : return tevent_req_post(req, ev);
239 : }
240 :
241 0 : subreq = tstream_inet_tcp_connect_send(state, state->ev,
242 : local, remote);
243 0 : if (tevent_req_nomem(subreq, req)) {
244 0 : return tevent_req_post(req, ev);
245 : }
246 0 : tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
247 :
248 0 : return req;
249 : }
250 :
251 0 : static void dns_tcp_request_connected(struct tevent_req *subreq)
252 : {
253 0 : struct tevent_req *req = tevent_req_callback_data(
254 : subreq, struct tevent_req);
255 0 : struct dns_tcp_request_state *state = tevent_req_data(
256 : req, struct dns_tcp_request_state);
257 0 : int ret, err;
258 :
259 0 : ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
260 : &state->stream, NULL);
261 0 : TALLOC_FREE(subreq);
262 0 : if (ret == -1) {
263 0 : tevent_req_error(req, err);
264 0 : return;
265 : }
266 :
267 0 : RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
268 0 : state->iov[0] = (struct iovec) {
269 0 : .iov_base = state->dns_msglen_hdr,
270 : .iov_len = sizeof(state->dns_msglen_hdr)
271 : };
272 0 : state->iov[1] = (struct iovec) {
273 0 : .iov_base = discard_const_p(void, state->query),
274 0 : .iov_len = state->query_len
275 : };
276 :
277 0 : subreq = tstream_writev_send(state, state->ev, state->stream,
278 0 : state->iov, ARRAY_SIZE(state->iov));
279 0 : if (tevent_req_nomem(subreq, req)) {
280 0 : return;
281 : }
282 0 : tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
283 : }
284 :
285 0 : static void dns_tcp_request_sent(struct tevent_req *subreq)
286 : {
287 0 : struct tevent_req *req = tevent_req_callback_data(
288 : subreq, struct tevent_req);
289 0 : struct dns_tcp_request_state *state = tevent_req_data(
290 : req, struct dns_tcp_request_state);
291 0 : int ret, err;
292 :
293 0 : ret = tstream_writev_recv(subreq, &err);
294 0 : TALLOC_FREE(subreq);
295 0 : if (ret == -1) {
296 0 : tevent_req_error(req, err);
297 0 : return;
298 : }
299 :
300 0 : subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
301 : dns_tcp_request_next_vector, state);
302 0 : if (tevent_req_nomem(subreq, req)) {
303 0 : return;
304 : }
305 0 : tevent_req_set_callback(subreq, dns_tcp_request_received, req);
306 : }
307 :
308 0 : 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 0 : struct dns_tcp_request_state *state = talloc_get_type_abort(
315 : private_data, struct dns_tcp_request_state);
316 0 : struct iovec *vector;
317 0 : uint16_t msglen;
318 :
319 0 : if (state->nread == 0) {
320 0 : vector = talloc_array(mem_ctx, struct iovec, 1);
321 0 : if (vector == NULL) {
322 0 : return -1;
323 : }
324 0 : vector[0] = (struct iovec) {
325 0 : .iov_base = state->dns_msglen_hdr,
326 : .iov_len = sizeof(state->dns_msglen_hdr)
327 : };
328 0 : state->nread = sizeof(state->dns_msglen_hdr);
329 :
330 0 : *_vector = vector;
331 0 : *_count = 1;
332 0 : return 0;
333 : }
334 :
335 0 : if (state->nread == sizeof(state->dns_msglen_hdr)) {
336 0 : msglen = RSVAL(state->dns_msglen_hdr, 0);
337 :
338 0 : state->reply = talloc_array(state, uint8_t, msglen);
339 0 : if (state->reply == NULL) {
340 0 : return -1;
341 : }
342 :
343 0 : vector = talloc_array(mem_ctx, struct iovec, 1);
344 0 : if (vector == NULL) {
345 0 : return -1;
346 : }
347 0 : vector[0] = (struct iovec) {
348 0 : .iov_base = state->reply,
349 : .iov_len = msglen
350 : };
351 0 : state->nread += msglen;
352 :
353 0 : *_vector = vector;
354 0 : *_count = 1;
355 0 : return 0;
356 : }
357 :
358 0 : *_vector = NULL;
359 0 : *_count = 0;
360 0 : return 0;
361 : }
362 :
363 0 : static void dns_tcp_request_received(struct tevent_req *subreq)
364 : {
365 0 : struct tevent_req *req = tevent_req_callback_data(
366 : subreq, struct tevent_req);
367 0 : int ret, err;
368 :
369 0 : ret = tstream_readv_pdu_recv(subreq, &err);
370 0 : TALLOC_FREE(subreq);
371 0 : if (ret == -1) {
372 0 : tevent_req_error(req, err);
373 0 : return;
374 : }
375 :
376 0 : tevent_req_done(req);
377 : }
378 :
379 0 : 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 0 : struct dns_tcp_request_state *state = tevent_req_data(
385 : req, struct dns_tcp_request_state);
386 0 : int err;
387 :
388 0 : if (tevent_req_is_unix_error(req, &err)) {
389 0 : tevent_req_received(req);
390 0 : return err;
391 : }
392 :
393 0 : *reply_len = talloc_array_length(state->reply);
394 0 : *reply = talloc_move(mem_ctx, &state->reply);
395 0 : tevent_req_received(req);
396 :
397 0 : 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 :
414 1449 : 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 0 : struct tevent_req *req, *subreq;
422 0 : struct dns_cli_request_state *state;
423 0 : struct dns_name_question question;
424 0 : struct dns_name_packet out_packet;
425 0 : enum ndr_err_code ndr_err;
426 :
427 1449 : req = tevent_req_create(mem_ctx, &state,
428 : struct dns_cli_request_state);
429 1449 : if (req == NULL) {
430 0 : return NULL;
431 : }
432 1449 : state->ev = ev;
433 1449 : state->nameserver = nameserver;
434 :
435 1449 : DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
436 : name, (int)qclass, (int)qtype);
437 :
438 1449 : generate_random_buffer((uint8_t *)&state->req_id,
439 : sizeof(state->req_id));
440 :
441 1449 : question = (struct dns_name_question) {
442 : .name = discard_const_p(char, name),
443 : .question_type = qtype, .question_class = qclass
444 : };
445 :
446 1449 : out_packet = (struct dns_name_packet) {
447 1449 : .id = state->req_id,
448 : .operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
449 : .qdcount = 1,
450 : .questions = &question
451 : };
452 :
453 1449 : ndr_err = ndr_push_struct_blob(
454 1449 : &state->query, state, &out_packet,
455 : (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
456 1449 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
457 0 : tevent_req_error(req, ndr_map_error2errno(ndr_err));
458 0 : return tevent_req_post(req, ev);
459 : }
460 :
461 1449 : subreq = dns_udp_request_send(state, state->ev, state->nameserver,
462 1449 : state->query.data, state->query.length);
463 1449 : if (tevent_req_nomem(subreq, req)) {
464 0 : return tevent_req_post(req, ev);
465 : }
466 1449 : tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
467 1449 : return req;
468 : }
469 :
470 1449 : static void dns_cli_request_udp_done(struct tevent_req *subreq)
471 : {
472 1449 : struct tevent_req *req = tevent_req_callback_data(
473 : subreq, struct tevent_req);
474 1449 : struct dns_cli_request_state *state = tevent_req_data(
475 : req, struct dns_cli_request_state);
476 0 : DATA_BLOB reply;
477 0 : enum ndr_err_code ndr_err;
478 0 : uint16_t reply_id, operation;
479 0 : int ret;
480 :
481 1449 : ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
482 1449 : TALLOC_FREE(subreq);
483 1449 : if (tevent_req_error(req, ret)) {
484 20 : return;
485 : }
486 :
487 1429 : if (reply.length < 4) {
488 0 : DBG_DEBUG("Short DNS packet: length=%zu\n", reply.length);
489 0 : tevent_req_error(req, EINVAL);
490 0 : return;
491 : }
492 :
493 1429 : reply_id = PULL_BE_U16(reply.data, 0);
494 1429 : if (reply_id != state->req_id) {
495 0 : DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
496 : state->reply->id, state->req_id);
497 0 : tevent_req_error(req, ENOMSG);
498 0 : return;
499 : }
500 :
501 1429 : operation = PULL_BE_U16(reply.data, 2);
502 1429 : if ((operation & DNS_FLAG_TRUNCATION) != 0) {
503 0 : DBG_DEBUG("Reply was truncated, retrying TCP\n");
504 0 : subreq = dns_tcp_request_send(
505 : state,
506 : state->ev,
507 : state->nameserver,
508 0 : state->query.data,
509 : state->query.length);
510 0 : if (tevent_req_nomem(subreq, req)) {
511 0 : return;
512 : }
513 0 : tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
514 0 : return;
515 : }
516 :
517 1429 : state->reply = talloc(state, struct dns_name_packet);
518 1429 : if (tevent_req_nomem(state->reply, req)) {
519 0 : return;
520 : }
521 :
522 1429 : ndr_err = ndr_pull_struct_blob(
523 1429 : &reply, state->reply, state->reply,
524 : (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
525 1429 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
526 0 : tevent_req_error(req, ndr_map_error2errno(ndr_err));
527 0 : return;
528 : }
529 1429 : TALLOC_FREE(reply.data);
530 :
531 1429 : tevent_req_done(req);
532 : }
533 :
534 0 : static void dns_cli_request_tcp_done(struct tevent_req *subreq)
535 : {
536 0 : struct tevent_req *req = tevent_req_callback_data(
537 : subreq, struct tevent_req);
538 0 : struct dns_cli_request_state *state = tevent_req_data(
539 : req, struct dns_cli_request_state);
540 0 : DATA_BLOB reply;
541 0 : enum ndr_err_code ndr_err;
542 0 : int ret;
543 :
544 0 : ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
545 0 : TALLOC_FREE(subreq);
546 0 : if (tevent_req_error(req, ret)) {
547 0 : return;
548 : }
549 :
550 0 : state->reply = talloc(state, struct dns_name_packet);
551 0 : if (tevent_req_nomem(state->reply, req)) {
552 0 : return;
553 : }
554 :
555 0 : ndr_err = ndr_pull_struct_blob(
556 0 : &reply, state->reply, state->reply,
557 : (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
558 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
559 0 : tevent_req_error(req, ndr_map_error2errno(ndr_err));
560 0 : return;
561 : }
562 0 : TALLOC_FREE(reply.data);
563 :
564 0 : if (state->reply->id != state->req_id) {
565 0 : DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
566 : state->reply->id, state->req_id);
567 0 : tevent_req_error(req, ENOMSG);
568 0 : return;
569 : }
570 :
571 0 : DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
572 : " recs\n", (int)state->reply->operation,
573 : state->reply->qdcount, state->reply->ancount,
574 : state->reply->nscount, state->reply->nscount);
575 :
576 0 : tevent_req_done(req);
577 : }
578 :
579 1449 : int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
580 : struct dns_name_packet **reply)
581 : {
582 1449 : struct dns_cli_request_state *state = tevent_req_data(
583 : req, struct dns_cli_request_state);
584 0 : int err;
585 :
586 1449 : if (tevent_req_is_unix_error(req, &err)) {
587 20 : return err;
588 : }
589 1429 : *reply = talloc_move(mem_ctx, &state->reply);
590 1429 : return 0;
591 : }
|