xref: /openbsd-src/usr.sbin/unbound/testcode/streamtcp.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /*
2  * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp.
3  *
4  * Copyright (c) 2008, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This program performs multiple DNS queries on a TCP stream.
40  */
41 
42 #include "config.h"
43 #ifdef HAVE_GETOPT_H
44 #include <getopt.h>
45 #endif
46 #include <signal.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include "util/locks.h"
50 #include "util/log.h"
51 #include "util/net_help.h"
52 #include "util/proxy_protocol.h"
53 #include "util/data/msgencode.h"
54 #include "util/data/msgparse.h"
55 #include "util/data/msgreply.h"
56 #include "util/data/dname.h"
57 #include "sldns/sbuffer.h"
58 #include "sldns/str2wire.h"
59 #include "sldns/wire2str.h"
60 #include <openssl/ssl.h>
61 #include <openssl/rand.h>
62 #include <openssl/err.h>
63 
64 #ifndef PF_INET6
65 /** define in case streamtcp is compiled on legacy systems */
66 #define PF_INET6 10
67 #endif
68 
69 /** usage information for streamtcp */
70 static void usage(char* argv[])
71 {
72 	printf("usage: %s [options] name type class ...\n", argv[0]);
73 	printf("	sends the name-type-class queries over TCP.\n");
74 	printf("-f server	what ipaddr@portnr to send the queries to\n");
75 	printf("-p client	what ipaddr@portnr to include in PROXYv2\n");
76 	printf("-u 		use UDP. No retries are attempted.\n");
77 	printf("-n 		do not wait for an answer.\n");
78 	printf("-a 		print answers as they arrive.\n");
79 	printf("-d secs		delay after connection before sending query\n");
80 	printf("-s		use ssl\n");
81 	printf("-h 		this help text\n");
82 	exit(1);
83 }
84 
85 /** open TCP socket to svr */
86 static int
87 open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
88 	socklen_t* addrlen)
89 {
90 	int fd = -1;
91 	/* svr can be ip@port */
92 	memset(addr, 0, sizeof(*addr));
93 	if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) {
94 		printf("fatal: bad server specs '%s'\n", svr);
95 		exit(1);
96 	}
97 	fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET,
98 		udp?SOCK_DGRAM:SOCK_STREAM, 0);
99 	if(fd == -1) {
100 #ifndef USE_WINSOCK
101 		perror("socket() error");
102 #else
103 		printf("socket: %s\n", wsa_strerror(WSAGetLastError()));
104 #endif
105 		exit(1);
106 	}
107 	if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) {
108 #ifndef USE_WINSOCK
109 		perror("connect() error");
110 #else
111 		printf("connect: %s\n", wsa_strerror(WSAGetLastError()));
112 #endif
113 		exit(1);
114 	}
115 	return fd;
116 }
117 
118 /** write a query over the TCP fd */
119 static void
120 write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
121 	sldns_buffer* proxy_buf, int pp2_parsed,
122 	const char* strname, const char* strtype, const char* strclass)
123 {
124 	struct query_info qinfo;
125 	size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
126 	/* qname */
127 	qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
128 	if(!qinfo.qname) {
129 		printf("cannot parse query name: '%s'\n", strname);
130 		exit(1);
131 	}
132 
133 	/* qtype and qclass */
134 	qinfo.qtype = sldns_get_rr_type_by_name(strtype);
135 	qinfo.qclass = sldns_get_rr_class_by_name(strclass);
136 
137 	/* clear local alias */
138 	qinfo.local_alias = NULL;
139 
140 	/* make query */
141 	qinfo_query_encode(buf, &qinfo);
142 	sldns_buffer_write_u16_at(buf, 0, id);
143 	sldns_buffer_write_u16_at(buf, 2, BIT_RD);
144 
145 	if(1) {
146 		/* add EDNS DO */
147 		struct edns_data edns;
148 		memset(&edns, 0, sizeof(edns));
149 		edns.edns_present = 1;
150 		edns.bits = EDNS_DO;
151 		edns.udp_size = 4096;
152 		if(sldns_buffer_capacity(buf) >=
153 			sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
154 			attach_edns_record(buf, &edns);
155 	}
156 
157 	/* we need to send the PROXYv2 information in every UDP message */
158 	if(udp && pp2_parsed) {
159 		/* append the proxy_buf with the buf's content
160 		 * and use that for sending */
161 		if(sldns_buffer_capacity(proxy_buf) <
162 			sldns_buffer_limit(proxy_buf) +
163 			sldns_buffer_limit(buf)) {
164 			printf("buffer too small for packet + proxy");
165 			exit(1);
166 		}
167 		sldns_buffer_clear(proxy_buf);
168 		sldns_buffer_skip(proxy_buf, proxy_buf_limit);
169 		sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
170 			sldns_buffer_limit(buf));
171 		sldns_buffer_flip(proxy_buf);
172 		buf = proxy_buf;
173 	}
174 
175 	/* send it */
176 	if(!udp) {
177 		uint16_t len = (uint16_t)sldns_buffer_limit(buf);
178 		len = htons(len);
179 		if(ssl) {
180 			if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
181 				log_crypto_err("cannot SSL_write");
182 				exit(1);
183 			}
184 		} else {
185 			if(send(fd, (void*)&len, sizeof(len), 0) <
186 				(ssize_t)sizeof(len)){
187 #ifndef USE_WINSOCK
188 				perror("send() len failed");
189 #else
190 				printf("send len: %s\n",
191 					wsa_strerror(WSAGetLastError()));
192 #endif
193 				exit(1);
194 			}
195 		}
196 	}
197 	if(ssl) {
198 		if(SSL_write(ssl, (void*)sldns_buffer_begin(buf),
199 			(int)sldns_buffer_limit(buf)) <= 0) {
200 			log_crypto_err("cannot SSL_write");
201 			exit(1);
202 		}
203 	} else {
204 		if(send(fd, (void*)sldns_buffer_begin(buf),
205 			sldns_buffer_limit(buf), 0) <
206 			(ssize_t)sldns_buffer_limit(buf)) {
207 #ifndef USE_WINSOCK
208 			perror("send() data failed");
209 #else
210 			printf("send data: %s\n",
211 				wsa_strerror(WSAGetLastError()));
212 #endif
213 			exit(1);
214 		}
215 	}
216 
217 	/* reset the proxy_buf for next packet */
218 	sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
219 	free(qinfo.qname);
220 }
221 
222 /** receive DNS datagram over TCP and print it */
223 static void
224 recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
225 {
226 	size_t i;
227 	char* pktstr;
228 	uint16_t len;
229 	if(!udp) {
230 		if(ssl) {
231 			int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
232 			if(sr == 0) {
233 				printf("ssl: stream closed\n");
234 				exit(1);
235 			}
236 			if(sr < 0) {
237 				log_crypto_err("could not SSL_read");
238 				exit(1);
239 			}
240 		} else {
241 			ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
242 			if(r == 0) {
243 				printf("recv: stream closed\n");
244 				exit(1);
245 			}
246 			if(r < (ssize_t)sizeof(len)) {
247 #ifndef USE_WINSOCK
248 				perror("read() len failed");
249 #else
250 				printf("read len: %s\n",
251 					wsa_strerror(WSAGetLastError()));
252 #endif
253 				exit(1);
254 			}
255 		}
256 		len = ntohs(len);
257 		sldns_buffer_clear(buf);
258 		sldns_buffer_set_limit(buf, len);
259 		if(ssl) {
260 			int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
261 				(int)len);
262 			if(r <= 0) {
263 				log_crypto_err("could not SSL_read");
264 				exit(1);
265 			}
266 			if(r != (int)len)
267 				fatal_exit("ssl_read %d of %d", r, len);
268 		} else {
269 			if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
270 				(ssize_t)len) {
271 #ifndef USE_WINSOCK
272 				perror("read() data failed");
273 #else
274 				printf("read data: %s\n",
275 					wsa_strerror(WSAGetLastError()));
276 #endif
277 				exit(1);
278 			}
279 		}
280 	} else {
281 		ssize_t l;
282 		sldns_buffer_clear(buf);
283 		if((l=recv(fd, (void*)sldns_buffer_begin(buf),
284 			sldns_buffer_capacity(buf), 0)) < 0) {
285 #ifndef USE_WINSOCK
286 			perror("read() data failed");
287 #else
288 			printf("read data: %s\n",
289 				wsa_strerror(WSAGetLastError()));
290 #endif
291 			exit(1);
292 		}
293 		sldns_buffer_set_limit(buf, (size_t)l);
294 		len = (size_t)l;
295 	}
296 	printf("\nnext received packet\n");
297 	printf("data[%d] ", (int)sldns_buffer_limit(buf));
298 	for(i=0; i<sldns_buffer_limit(buf); i++) {
299 		const char* hex = "0123456789ABCDEF";
300 		printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4],
301                         hex[sldns_buffer_read_u8_at(buf, i)&0x0f]);
302 	}
303 	printf("\n");
304 
305 	pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
306 	printf("%s", pktstr);
307 	free(pktstr);
308 }
309 
310 /** see if we can receive any results */
311 static void
312 print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
313 	int* num_answers, int wait_all)
314 {
315 	/* see if the fd can read, if so, print one answer, repeat */
316 	int ret;
317 	struct timeval tv, *waittv;
318 	fd_set rfd;
319 	while(*num_answers > 0) {
320 		memset(&rfd, 0, sizeof(rfd));
321 		memset(&tv, 0, sizeof(tv));
322 		FD_ZERO(&rfd);
323 		FD_SET(fd, &rfd);
324 		if(wait_all) waittv = NULL;
325 		else waittv = &tv;
326 		ret = select(fd+1, &rfd, NULL, NULL, waittv);
327 		if(ret < 0) {
328 			if(errno == EINTR || errno == EAGAIN) continue;
329 			perror("select() failed");
330 			exit(1);
331 		}
332 		if(ret == 0) {
333 			if(wait_all) continue;
334 			return;
335 		}
336 		(*num_answers) -= 1;
337 		recv_one(fd, udp, ssl, buf);
338 	}
339 }
340 
341 static int get_random(void)
342 {
343 	int r;
344 	if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
345 		return r;
346 	}
347 	return (int)arc4random();
348 }
349 
350 /* parse the pp2_client and populate the proxy_buffer
351  * It doesn't populate the destination parts. */
352 static int parse_pp2_client(const char* pp2_client, int udp,
353 	sldns_buffer* proxy_buf)
354 {
355 	struct sockaddr_storage pp2_addr;
356 	socklen_t pp2_addrlen = 0;
357 	memset(&pp2_addr, 0, sizeof(pp2_addr));
358 	if(*pp2_client == 0) return 0;
359 	if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
360 		printf("fatal: bad proxy client specs '%s'\n", pp2_client);
361 		exit(1);
362 	}
363 	sldns_buffer_clear(proxy_buf);
364 	pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
365 	sldns_buffer_flip(proxy_buf);
366 	return 1;
367 }
368 
369 /** send the TCP queries and print answers */
370 static void
371 send_em(const char* svr, const char* pp2_client, int udp, int usessl,
372 	int noanswer, int onarrival, int delay, int num, char** qs)
373 {
374 	sldns_buffer* buf = sldns_buffer_new(65553);
375 	sldns_buffer* proxy_buf = sldns_buffer_new(65553);
376 	struct sockaddr_storage svr_addr;
377 	socklen_t svr_addrlen;
378 	int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
379 	int i, wait_results = 0, pp2_parsed;
380 	SSL_CTX* ctx = NULL;
381 	SSL* ssl = NULL;
382 	if(!buf) fatal_exit("out of memory");
383 	pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
384 	if(usessl) {
385 		ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
386 		if(!ctx) fatal_exit("cannot create ssl ctx");
387 		ssl = outgoing_ssl_fd(ctx, fd);
388 		if(!ssl) fatal_exit("cannot create ssl");
389 		while(1) {
390 			int r;
391 			ERR_clear_error();
392 			if( (r=SSL_do_handshake(ssl)) == 1)
393 				break;
394 			r = SSL_get_error(ssl, r);
395 			if(r != SSL_ERROR_WANT_READ &&
396 				r != SSL_ERROR_WANT_WRITE) {
397 				log_crypto_err("could not ssl_handshake");
398 				exit(1);
399 			}
400 		}
401 		if(1) {
402 			X509* x = SSL_get_peer_certificate(ssl);
403 			if(!x) printf("SSL: no peer certificate\n");
404 			else {
405 				X509_print_fp(stdout, x);
406 				X509_free(x);
407 			}
408 		}
409 	}
410 	/* Send the PROXYv2 information once per stream */
411 	if(!udp && pp2_parsed) {
412 		if(ssl) {
413 			if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
414 				(int)sldns_buffer_limit(proxy_buf)) <= 0) {
415 				log_crypto_err("cannot SSL_write");
416 				exit(1);
417 			}
418 		} else {
419 			if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
420 				sldns_buffer_limit(proxy_buf), 0) <
421 				(ssize_t)sldns_buffer_limit(proxy_buf)) {
422 #ifndef USE_WINSOCK
423 				perror("send() data failed");
424 #else
425 				printf("send data: %s\n",
426 					wsa_strerror(WSAGetLastError()));
427 #endif
428 				exit(1);
429 			}
430 		}
431 	}
432 	for(i=0; i<num; i+=3) {
433 		if (delay != 0) {
434 #ifdef HAVE_SLEEP
435 			sleep((unsigned)delay);
436 #else
437 			Sleep(delay*1000);
438 #endif
439 		}
440 		printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
441 		write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
442 			pp2_parsed,
443 			qs[i], qs[i+1], qs[i+2]);
444 		/* print at least one result */
445 		if(onarrival) {
446 			wait_results += 1; /* one more answer to fetch */
447 			print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
448 		} else if(!noanswer) {
449 			recv_one(fd, udp, ssl, buf);
450 		}
451 	}
452 	if(onarrival)
453 		print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
454 
455 	if(usessl) {
456 		SSL_shutdown(ssl);
457 		SSL_free(ssl);
458 		SSL_CTX_free(ctx);
459 	}
460 	sock_close(fd);
461 	sldns_buffer_free(buf);
462 	sldns_buffer_free(proxy_buf);
463 	printf("orderly exit\n");
464 }
465 
466 #ifdef SIGPIPE
467 /** SIGPIPE handler */
468 static RETSIGTYPE sigh(int sig)
469 {
470 	char str[] = "Got unhandled signal   \n";
471 	if(sig == SIGPIPE) {
472 		char* strpipe = "got SIGPIPE, remote connection gone\n";
473 		/* simple cast to void will not silence Wunused-result */
474 		(void)!write(STDOUT_FILENO, strpipe, strlen(strpipe));
475 		exit(1);
476 	}
477 	str[21] = '0' + (sig/10)%10;
478 	str[22] = '0' + sig%10;
479 	/* simple cast to void will not silence Wunused-result */
480 	(void)!write(STDOUT_FILENO, str, strlen(str));
481 	exit(1);
482 }
483 #endif /* SIGPIPE */
484 
485 /** getopt global, in case header files fail to declare it. */
486 extern int optind;
487 /** getopt global, in case header files fail to declare it. */
488 extern char* optarg;
489 
490 /** main program for streamtcp */
491 int main(int argc, char** argv)
492 {
493 	int c;
494 	const char* svr = "127.0.0.1";
495 	const char* pp2_client = "";
496 	int udp = 0;
497 	int noanswer = 0;
498 	int onarrival = 0;
499 	int usessl = 0;
500 	int delay = 0;
501 
502 #ifdef USE_WINSOCK
503 	WSADATA wsa_data;
504 	if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
505 		printf("WSAStartup failed\n");
506 		return 1;
507 	}
508 #endif
509 
510 	/* lock debug start (if any) */
511 	checklock_start();
512 	log_init(0, 0, 0);
513 
514 #ifdef SIGPIPE
515 	if(signal(SIGPIPE, &sigh) == SIG_ERR) {
516 		perror("could not install signal handler");
517 		return 1;
518 	}
519 #endif
520 
521 	/* command line options */
522 	if(argc == 1) {
523 		usage(argv);
524 	}
525 	while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
526 		switch(c) {
527 			case 'f':
528 				svr = optarg;
529 				break;
530 			case 'p':
531 				pp2_client = optarg;
532 				break;
533 			case 'a':
534 				onarrival = 1;
535 				break;
536 			case 'n':
537 				noanswer = 1;
538 				break;
539 			case 'u':
540 				udp = 1;
541 				break;
542 			case 's':
543 				usessl = 1;
544 				break;
545 			case 'd':
546 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
547 					printf("error parsing delay, "
548 					    "number expected: %s\n", optarg);
549 					return 1;
550 				}
551 				delay = atoi(optarg);
552 				break;
553 			case 'h':
554 			case '?':
555 			default:
556 				usage(argv);
557 		}
558 	}
559 	argc -= optind;
560 	argv += optind;
561 
562 	if(argc % 3 != 0) {
563 		printf("queries must be multiples of name,type,class\n");
564 		return 1;
565 	}
566 	if(usessl) {
567 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
568 		ERR_load_SSL_strings();
569 #endif
570 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
571 #  ifndef S_SPLINT_S
572 		OpenSSL_add_all_algorithms();
573 #  endif
574 #else
575 		OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
576 			| OPENSSL_INIT_ADD_ALL_DIGESTS
577 			| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
578 #endif
579 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
580 		(void)SSL_library_init();
581 #else
582 		(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
583 #endif
584 	}
585 	send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
586 	checklock_stop();
587 #ifdef USE_WINSOCK
588 	WSACleanup();
589 #endif
590 	return 0;
591 }
592