xref: /openbsd-src/usr.sbin/unbound/testcode/streamtcp.c (revision 1ad61ae0a79a724d2d3ec69e69c8e1d1ff6b53a0)
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 	if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
136 		printf("cannot parse query type: '%s'\n", strtype);
137 		exit(1);
138 	}
139 	qinfo.qclass = sldns_get_rr_class_by_name(strclass);
140 	if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
141 		printf("cannot parse query class: '%s'\n", strclass);
142 		exit(1);
143 	}
144 
145 	/* clear local alias */
146 	qinfo.local_alias = NULL;
147 
148 	/* make query */
149 	qinfo_query_encode(buf, &qinfo);
150 	sldns_buffer_write_u16_at(buf, 0, id);
151 	sldns_buffer_write_u16_at(buf, 2, BIT_RD);
152 
153 	if(1) {
154 		/* add EDNS DO */
155 		struct edns_data edns;
156 		memset(&edns, 0, sizeof(edns));
157 		edns.edns_present = 1;
158 		edns.bits = EDNS_DO;
159 		edns.udp_size = 4096;
160 		if(sldns_buffer_capacity(buf) >=
161 			sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
162 			attach_edns_record(buf, &edns);
163 	}
164 
165 	/* we need to send the PROXYv2 information in every UDP message */
166 	if(udp && pp2_parsed) {
167 		/* append the proxy_buf with the buf's content
168 		 * and use that for sending */
169 		if(sldns_buffer_capacity(proxy_buf) <
170 			sldns_buffer_limit(proxy_buf) +
171 			sldns_buffer_limit(buf)) {
172 			printf("buffer too small for packet + proxy");
173 			exit(1);
174 		}
175 		sldns_buffer_clear(proxy_buf);
176 		sldns_buffer_skip(proxy_buf, proxy_buf_limit);
177 		sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
178 			sldns_buffer_limit(buf));
179 		sldns_buffer_flip(proxy_buf);
180 		buf = proxy_buf;
181 	}
182 
183 	/* send it */
184 	if(!udp) {
185 		uint16_t len = (uint16_t)sldns_buffer_limit(buf);
186 		len = htons(len);
187 		if(ssl) {
188 			if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
189 				log_crypto_err("cannot SSL_write");
190 				exit(1);
191 			}
192 		} else {
193 			if(send(fd, (void*)&len, sizeof(len), 0) <
194 				(ssize_t)sizeof(len)){
195 #ifndef USE_WINSOCK
196 				perror("send() len failed");
197 #else
198 				printf("send len: %s\n",
199 					wsa_strerror(WSAGetLastError()));
200 #endif
201 				exit(1);
202 			}
203 		}
204 	}
205 	if(ssl) {
206 		if(SSL_write(ssl, (void*)sldns_buffer_begin(buf),
207 			(int)sldns_buffer_limit(buf)) <= 0) {
208 			log_crypto_err("cannot SSL_write");
209 			exit(1);
210 		}
211 	} else {
212 		if(send(fd, (void*)sldns_buffer_begin(buf),
213 			sldns_buffer_limit(buf), 0) <
214 			(ssize_t)sldns_buffer_limit(buf)) {
215 #ifndef USE_WINSOCK
216 			perror("send() data failed");
217 #else
218 			printf("send data: %s\n",
219 				wsa_strerror(WSAGetLastError()));
220 #endif
221 			exit(1);
222 		}
223 	}
224 
225 	/* reset the proxy_buf for next packet */
226 	sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
227 	free(qinfo.qname);
228 }
229 
230 /** receive DNS datagram over TCP and print it */
231 static void
232 recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
233 {
234 	size_t i;
235 	char* pktstr;
236 	uint16_t len;
237 	if(!udp) {
238 		if(ssl) {
239 			int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
240 			if(sr == 0) {
241 				printf("ssl: stream closed\n");
242 				exit(1);
243 			}
244 			if(sr < 0) {
245 				log_crypto_err("could not SSL_read");
246 				exit(1);
247 			}
248 		} else {
249 			ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
250 			if(r == 0) {
251 				printf("recv: stream closed\n");
252 				exit(1);
253 			}
254 			if(r < (ssize_t)sizeof(len)) {
255 #ifndef USE_WINSOCK
256 				perror("read() len failed");
257 #else
258 				printf("read len: %s\n",
259 					wsa_strerror(WSAGetLastError()));
260 #endif
261 				exit(1);
262 			}
263 		}
264 		len = ntohs(len);
265 		sldns_buffer_clear(buf);
266 		sldns_buffer_set_limit(buf, len);
267 		if(ssl) {
268 			int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
269 				(int)len);
270 			if(r <= 0) {
271 				log_crypto_err("could not SSL_read");
272 				exit(1);
273 			}
274 			if(r != (int)len)
275 				fatal_exit("ssl_read %d of %d", r, len);
276 		} else {
277 			if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
278 				(ssize_t)len) {
279 #ifndef USE_WINSOCK
280 				perror("read() data failed");
281 #else
282 				printf("read data: %s\n",
283 					wsa_strerror(WSAGetLastError()));
284 #endif
285 				exit(1);
286 			}
287 		}
288 	} else {
289 		ssize_t l;
290 		sldns_buffer_clear(buf);
291 		if((l=recv(fd, (void*)sldns_buffer_begin(buf),
292 			sldns_buffer_capacity(buf), 0)) < 0) {
293 #ifndef USE_WINSOCK
294 			perror("read() data failed");
295 #else
296 			printf("read data: %s\n",
297 				wsa_strerror(WSAGetLastError()));
298 #endif
299 			exit(1);
300 		}
301 		sldns_buffer_set_limit(buf, (size_t)l);
302 		len = (size_t)l;
303 	}
304 	printf("\nnext received packet\n");
305 	printf("data[%d] ", (int)sldns_buffer_limit(buf));
306 	for(i=0; i<sldns_buffer_limit(buf); i++) {
307 		const char* hex = "0123456789ABCDEF";
308 		printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4],
309                         hex[sldns_buffer_read_u8_at(buf, i)&0x0f]);
310 	}
311 	printf("\n");
312 
313 	pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
314 	printf("%s", pktstr);
315 	free(pktstr);
316 }
317 
318 /** see if we can receive any results */
319 static void
320 print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
321 	int* num_answers, int wait_all)
322 {
323 	/* see if the fd can read, if so, print one answer, repeat */
324 	int ret;
325 	struct timeval tv, *waittv;
326 	fd_set rfd;
327 	while(*num_answers > 0) {
328 		memset(&rfd, 0, sizeof(rfd));
329 		memset(&tv, 0, sizeof(tv));
330 		FD_ZERO(&rfd);
331 		FD_SET(fd, &rfd);
332 		if(wait_all) waittv = NULL;
333 		else waittv = &tv;
334 		ret = select(fd+1, &rfd, NULL, NULL, waittv);
335 		if(ret < 0) {
336 			if(errno == EINTR || errno == EAGAIN) continue;
337 			perror("select() failed");
338 			exit(1);
339 		}
340 		if(ret == 0) {
341 			if(wait_all) continue;
342 			return;
343 		}
344 		(*num_answers) -= 1;
345 		recv_one(fd, udp, ssl, buf);
346 	}
347 }
348 
349 static int get_random(void)
350 {
351 	int r;
352 	if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
353 		return r;
354 	}
355 	return (int)arc4random();
356 }
357 
358 /* parse the pp2_client and populate the proxy_buffer
359  * It doesn't populate the destination parts. */
360 static int parse_pp2_client(const char* pp2_client, int udp,
361 	sldns_buffer* proxy_buf)
362 {
363 	struct sockaddr_storage pp2_addr;
364 	socklen_t pp2_addrlen = 0;
365 	memset(&pp2_addr, 0, sizeof(pp2_addr));
366 	if(*pp2_client == 0) return 0;
367 	if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
368 		printf("fatal: bad proxy client specs '%s'\n", pp2_client);
369 		exit(1);
370 	}
371 	sldns_buffer_clear(proxy_buf);
372 	pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
373 	sldns_buffer_flip(proxy_buf);
374 	return 1;
375 }
376 
377 /** send the TCP queries and print answers */
378 static void
379 send_em(const char* svr, const char* pp2_client, int udp, int usessl,
380 	int noanswer, int onarrival, int delay, int num, char** qs)
381 {
382 	struct sockaddr_storage svr_addr;
383 	socklen_t svr_addrlen;
384 	int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
385 	int i, wait_results = 0, pp2_parsed;
386 	SSL_CTX* ctx = NULL;
387 	SSL* ssl = NULL;
388 	sldns_buffer* buf = sldns_buffer_new(65553);
389 	sldns_buffer* proxy_buf = sldns_buffer_new(65553);
390 	if(!buf || !proxy_buf) {
391 		sldns_buffer_free(buf);
392 		sldns_buffer_free(proxy_buf);
393 		fatal_exit("out of memory");
394 	}
395 	pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
396 	if(usessl) {
397 		ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
398 		if(!ctx) fatal_exit("cannot create ssl ctx");
399 		ssl = outgoing_ssl_fd(ctx, fd);
400 		if(!ssl) fatal_exit("cannot create ssl");
401 		while(1) {
402 			int r;
403 			ERR_clear_error();
404 			if( (r=SSL_do_handshake(ssl)) == 1)
405 				break;
406 			r = SSL_get_error(ssl, r);
407 			if(r != SSL_ERROR_WANT_READ &&
408 				r != SSL_ERROR_WANT_WRITE) {
409 				log_crypto_err("could not ssl_handshake");
410 				exit(1);
411 			}
412 		}
413 		if(1) {
414 			X509* x = SSL_get_peer_certificate(ssl);
415 			if(!x) printf("SSL: no peer certificate\n");
416 			else {
417 				X509_print_fp(stdout, x);
418 				X509_free(x);
419 			}
420 		}
421 	}
422 	/* Send the PROXYv2 information once per stream */
423 	if(!udp && pp2_parsed) {
424 		if(ssl) {
425 			if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
426 				(int)sldns_buffer_limit(proxy_buf)) <= 0) {
427 				log_crypto_err("cannot SSL_write");
428 				exit(1);
429 			}
430 		} else {
431 			if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
432 				sldns_buffer_limit(proxy_buf), 0) <
433 				(ssize_t)sldns_buffer_limit(proxy_buf)) {
434 #ifndef USE_WINSOCK
435 				perror("send() data failed");
436 #else
437 				printf("send data: %s\n",
438 					wsa_strerror(WSAGetLastError()));
439 #endif
440 				exit(1);
441 			}
442 		}
443 	}
444 	for(i=0; i<num; i+=3) {
445 		if (delay != 0) {
446 #ifdef HAVE_SLEEP
447 			sleep((unsigned)delay);
448 #else
449 			Sleep(delay*1000);
450 #endif
451 		}
452 		printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
453 		write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
454 			pp2_parsed,
455 			qs[i], qs[i+1], qs[i+2]);
456 		/* print at least one result */
457 		if(onarrival) {
458 			wait_results += 1; /* one more answer to fetch */
459 			print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
460 		} else if(!noanswer) {
461 			recv_one(fd, udp, ssl, buf);
462 		}
463 	}
464 	if(onarrival)
465 		print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
466 
467 	if(usessl) {
468 		SSL_shutdown(ssl);
469 		SSL_free(ssl);
470 		SSL_CTX_free(ctx);
471 	}
472 	sock_close(fd);
473 	sldns_buffer_free(buf);
474 	sldns_buffer_free(proxy_buf);
475 	printf("orderly exit\n");
476 }
477 
478 #ifdef SIGPIPE
479 /** SIGPIPE handler */
480 static RETSIGTYPE sigh(int sig)
481 {
482 	char str[] = "Got unhandled signal   \n";
483 	if(sig == SIGPIPE) {
484 		char* strpipe = "got SIGPIPE, remote connection gone\n";
485 		/* simple cast to void will not silence Wunused-result */
486 		(void)!write(STDOUT_FILENO, strpipe, strlen(strpipe));
487 		exit(1);
488 	}
489 	str[21] = '0' + (sig/10)%10;
490 	str[22] = '0' + sig%10;
491 	/* simple cast to void will not silence Wunused-result */
492 	(void)!write(STDOUT_FILENO, str, strlen(str));
493 	exit(1);
494 }
495 #endif /* SIGPIPE */
496 
497 /** getopt global, in case header files fail to declare it. */
498 extern int optind;
499 /** getopt global, in case header files fail to declare it. */
500 extern char* optarg;
501 
502 /** main program for streamtcp */
503 int main(int argc, char** argv)
504 {
505 	int c;
506 	const char* svr = "127.0.0.1";
507 	const char* pp2_client = "";
508 	int udp = 0;
509 	int noanswer = 0;
510 	int onarrival = 0;
511 	int usessl = 0;
512 	int delay = 0;
513 
514 #ifdef USE_WINSOCK
515 	WSADATA wsa_data;
516 	if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
517 		printf("WSAStartup failed\n");
518 		return 1;
519 	}
520 #endif
521 
522 	/* lock debug start (if any) */
523 	checklock_start();
524 	log_init(0, 0, 0);
525 
526 #ifdef SIGPIPE
527 	if(signal(SIGPIPE, &sigh) == SIG_ERR) {
528 		perror("could not install signal handler");
529 		return 1;
530 	}
531 #endif
532 
533 	/* command line options */
534 	if(argc == 1) {
535 		usage(argv);
536 	}
537 	while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
538 		switch(c) {
539 			case 'f':
540 				svr = optarg;
541 				break;
542 			case 'p':
543 				pp2_client = optarg;
544 				break;
545 			case 'a':
546 				onarrival = 1;
547 				break;
548 			case 'n':
549 				noanswer = 1;
550 				break;
551 			case 'u':
552 				udp = 1;
553 				break;
554 			case 's':
555 				usessl = 1;
556 				break;
557 			case 'd':
558 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
559 					printf("error parsing delay, "
560 					    "number expected: %s\n", optarg);
561 					return 1;
562 				}
563 				delay = atoi(optarg);
564 				break;
565 			case 'h':
566 			case '?':
567 			default:
568 				usage(argv);
569 		}
570 	}
571 	argc -= optind;
572 	argv += optind;
573 
574 	if(argc % 3 != 0) {
575 		printf("queries must be multiples of name,type,class\n");
576 		return 1;
577 	}
578 	if(usessl) {
579 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
580 		ERR_load_SSL_strings();
581 #endif
582 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
583 #  ifndef S_SPLINT_S
584 		OpenSSL_add_all_algorithms();
585 #  endif
586 #else
587 		OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
588 			| OPENSSL_INIT_ADD_ALL_DIGESTS
589 			| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
590 #endif
591 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
592 		(void)SSL_library_init();
593 #else
594 		(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
595 #endif
596 	}
597 	send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
598 	checklock_stop();
599 #ifdef USE_WINSOCK
600 	WSACleanup();
601 #endif
602 	return 0;
603 }
604