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