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/data/msgencode.h"
53 #include "util/data/msgparse.h"
54 #include "util/data/msgreply.h"
55 #include "util/data/dname.h"
56 #include "sldns/sbuffer.h"
57 #include "sldns/str2wire.h"
58 #include "sldns/wire2str.h"
59 #include <openssl/ssl.h>
60 #include <openssl/rand.h>
61 #include <openssl/err.h>
62 
63 #ifndef PF_INET6
64 /** define in case streamtcp is compiled on legacy systems */
65 #define PF_INET6 10
66 #endif
67 
68 /** usage information for streamtcp */
69 static void usage(char* argv[])
70 {
71 	printf("usage: %s [options] name type class ...\n", argv[0]);
72 	printf("	sends the name-type-class queries over TCP.\n");
73 	printf("-f server	what ipaddr@portnr to send the queries to\n");
74 	printf("-u 		use UDP. No retries are attempted.\n");
75 	printf("-n 		do not wait for an answer.\n");
76 	printf("-a 		print answers as they arrive.\n");
77 	printf("-d secs		delay after connection before sending query\n");
78 	printf("-s		use ssl\n");
79 	printf("-h 		this help text\n");
80 	exit(1);
81 }
82 
83 /** open TCP socket to svr */
84 static int
85 open_svr(const char* svr, int udp)
86 {
87 	struct sockaddr_storage addr;
88 	socklen_t addrlen;
89 	int fd = -1;
90 	/* svr can be ip@port */
91 	memset(&addr, 0, sizeof(addr));
92 	if(!extstrtoaddr(svr, &addr, &addrlen)) {
93 		printf("fatal: bad server specs '%s'\n", svr);
94 		exit(1);
95 	}
96 	fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
97 		udp?SOCK_DGRAM:SOCK_STREAM, 0);
98 	if(fd == -1) {
99 #ifndef USE_WINSOCK
100 		perror("socket() error");
101 #else
102 		printf("socket: %s\n", wsa_strerror(WSAGetLastError()));
103 #endif
104 		exit(1);
105 	}
106 	if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
107 #ifndef USE_WINSOCK
108 		perror("connect() error");
109 #else
110 		printf("connect: %s\n", wsa_strerror(WSAGetLastError()));
111 #endif
112 		exit(1);
113 	}
114 	return fd;
115 }
116 
117 /** write a query over the TCP fd */
118 static void
119 write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
120 	const char* strname, const char* strtype, const char* strclass)
121 {
122 	struct query_info qinfo;
123 	uint16_t len;
124 	/* qname */
125 	qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
126 	if(!qinfo.qname) {
127 		printf("cannot parse query name: '%s'\n", strname);
128 		exit(1);
129 	}
130 
131 	/* qtype and qclass */
132 	qinfo.qtype = sldns_get_rr_type_by_name(strtype);
133 	qinfo.qclass = sldns_get_rr_class_by_name(strclass);
134 
135 	/* clear local alias */
136 	qinfo.local_alias = NULL;
137 
138 	/* make query */
139 	qinfo_query_encode(buf, &qinfo);
140 	sldns_buffer_write_u16_at(buf, 0, id);
141 	sldns_buffer_write_u16_at(buf, 2, BIT_RD);
142 
143 	if(1) {
144 		/* add EDNS DO */
145 		struct edns_data edns;
146 		memset(&edns, 0, sizeof(edns));
147 		edns.edns_present = 1;
148 		edns.bits = EDNS_DO;
149 		edns.udp_size = 4096;
150 		if(sldns_buffer_capacity(buf) >=
151 			sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
152 			attach_edns_record(buf, &edns);
153 	}
154 
155 	/* send it */
156 	if(!udp) {
157 		len = (uint16_t)sldns_buffer_limit(buf);
158 		len = htons(len);
159 		if(ssl) {
160 			if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
161 				log_crypto_err("cannot SSL_write");
162 				exit(1);
163 			}
164 		} else {
165 			if(send(fd, (void*)&len, sizeof(len), 0) <
166 				(ssize_t)sizeof(len)){
167 #ifndef USE_WINSOCK
168 				perror("send() len failed");
169 #else
170 				printf("send len: %s\n",
171 					wsa_strerror(WSAGetLastError()));
172 #endif
173 				exit(1);
174 			}
175 		}
176 	}
177 	if(ssl) {
178 		if(SSL_write(ssl, (void*)sldns_buffer_begin(buf),
179 			(int)sldns_buffer_limit(buf)) <= 0) {
180 			log_crypto_err("cannot SSL_write");
181 			exit(1);
182 		}
183 	} else {
184 		if(send(fd, (void*)sldns_buffer_begin(buf),
185 			sldns_buffer_limit(buf), 0) <
186 			(ssize_t)sldns_buffer_limit(buf)) {
187 #ifndef USE_WINSOCK
188 			perror("send() data failed");
189 #else
190 			printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
191 #endif
192 			exit(1);
193 		}
194 	}
195 
196 	free(qinfo.qname);
197 }
198 
199 /** receive DNS datagram over TCP and print it */
200 static void
201 recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
202 {
203 	size_t i;
204 	char* pktstr;
205 	uint16_t len;
206 	if(!udp) {
207 		if(ssl) {
208 			int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
209 			if(sr == 0) {
210 				printf("ssl: stream closed\n");
211 				exit(1);
212 			}
213 			if(sr < 0) {
214 				log_crypto_err("could not SSL_read");
215 				exit(1);
216 			}
217 		} else {
218 			ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
219 			if(r == 0) {
220 				printf("recv: stream closed\n");
221 				exit(1);
222 			}
223 			if(r < (ssize_t)sizeof(len)) {
224 #ifndef USE_WINSOCK
225 				perror("read() len failed");
226 #else
227 				printf("read len: %s\n",
228 					wsa_strerror(WSAGetLastError()));
229 #endif
230 				exit(1);
231 			}
232 		}
233 		len = ntohs(len);
234 		sldns_buffer_clear(buf);
235 		sldns_buffer_set_limit(buf, len);
236 		if(ssl) {
237 			int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
238 				(int)len);
239 			if(r <= 0) {
240 				log_crypto_err("could not SSL_read");
241 				exit(1);
242 			}
243 			if(r != (int)len)
244 				fatal_exit("ssl_read %d of %d", r, len);
245 		} else {
246 			if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
247 				(ssize_t)len) {
248 #ifndef USE_WINSOCK
249 				perror("read() data failed");
250 #else
251 				printf("read data: %s\n",
252 					wsa_strerror(WSAGetLastError()));
253 #endif
254 				exit(1);
255 			}
256 		}
257 	} else {
258 		ssize_t l;
259 		sldns_buffer_clear(buf);
260 		if((l=recv(fd, (void*)sldns_buffer_begin(buf),
261 			sldns_buffer_capacity(buf), 0)) < 0) {
262 #ifndef USE_WINSOCK
263 			perror("read() data failed");
264 #else
265 			printf("read data: %s\n",
266 				wsa_strerror(WSAGetLastError()));
267 #endif
268 			exit(1);
269 		}
270 		sldns_buffer_set_limit(buf, (size_t)l);
271 		len = (size_t)l;
272 	}
273 	printf("\nnext received packet\n");
274 	printf("data[%d] ", (int)sldns_buffer_limit(buf));
275 	for(i=0; i<sldns_buffer_limit(buf); i++) {
276 		const char* hex = "0123456789ABCDEF";
277 		printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4],
278                         hex[sldns_buffer_read_u8_at(buf, i)&0x0f]);
279 	}
280 	printf("\n");
281 
282 	pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
283 	printf("%s", pktstr);
284 	free(pktstr);
285 }
286 
287 /** see if we can receive any results */
288 static void
289 print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
290 	int* num_answers, int wait_all)
291 {
292 	/* see if the fd can read, if so, print one answer, repeat */
293 	int ret;
294 	struct timeval tv, *waittv;
295 	fd_set rfd;
296 	while(*num_answers > 0) {
297 		memset(&rfd, 0, sizeof(rfd));
298 		memset(&tv, 0, sizeof(tv));
299 		FD_ZERO(&rfd);
300 		FD_SET(fd, &rfd);
301 		if(wait_all) waittv = NULL;
302 		else waittv = &tv;
303 		ret = select(fd+1, &rfd, NULL, NULL, waittv);
304 		if(ret < 0) {
305 			if(errno == EINTR || errno == EAGAIN) continue;
306 			perror("select() failed");
307 			exit(1);
308 		}
309 		if(ret == 0) {
310 			if(wait_all) continue;
311 			return;
312 		}
313 		(*num_answers) -= 1;
314 		recv_one(fd, udp, ssl, buf);
315 	}
316 }
317 
318 static int get_random(void)
319 {
320 	int r;
321 	if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
322 		return r;
323 	}
324 	return (int)arc4random();
325 }
326 
327 /** send the TCP queries and print answers */
328 static void
329 send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
330 	int delay, int num, char** qs)
331 {
332 	sldns_buffer* buf = sldns_buffer_new(65553);
333 	int fd = open_svr(svr, udp);
334 	int i, wait_results = 0;
335 	SSL_CTX* ctx = NULL;
336 	SSL* ssl = NULL;
337 	if(!buf) fatal_exit("out of memory");
338 	if(usessl) {
339 		ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
340 		if(!ctx) fatal_exit("cannot create ssl ctx");
341 		ssl = outgoing_ssl_fd(ctx, fd);
342 		if(!ssl) fatal_exit("cannot create ssl");
343 		while(1) {
344 			int r;
345 			ERR_clear_error();
346 			if( (r=SSL_do_handshake(ssl)) == 1)
347 				break;
348 			r = SSL_get_error(ssl, r);
349 			if(r != SSL_ERROR_WANT_READ &&
350 				r != SSL_ERROR_WANT_WRITE) {
351 				log_crypto_err("could not ssl_handshake");
352 				exit(1);
353 			}
354 		}
355 		if(1) {
356 			X509* x = SSL_get_peer_certificate(ssl);
357 			if(!x) printf("SSL: no peer certificate\n");
358 			else {
359 				X509_print_fp(stdout, x);
360 				X509_free(x);
361 			}
362 		}
363 	}
364 	for(i=0; i<num; i+=3) {
365 		if (delay != 0) {
366 #ifdef HAVE_SLEEP
367 			sleep((unsigned)delay);
368 #else
369 			Sleep(delay*1000);
370 #endif
371 		}
372 		printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
373 		write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
374 			qs[i+1], qs[i+2]);
375 		/* print at least one result */
376 		if(onarrival) {
377 			wait_results += 1; /* one more answer to fetch */
378 			print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
379 		} else if(!noanswer) {
380 			recv_one(fd, udp, ssl, buf);
381 		}
382 	}
383 	if(onarrival)
384 		print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
385 
386 	if(usessl) {
387 		SSL_shutdown(ssl);
388 		SSL_free(ssl);
389 		SSL_CTX_free(ctx);
390 	}
391 #ifndef USE_WINSOCK
392 	close(fd);
393 #else
394 	closesocket(fd);
395 #endif
396 	sldns_buffer_free(buf);
397 	printf("orderly exit\n");
398 }
399 
400 #ifdef SIGPIPE
401 /** SIGPIPE handler */
402 static RETSIGTYPE sigh(int sig)
403 {
404 	if(sig == SIGPIPE) {
405 		printf("got SIGPIPE, remote connection gone\n");
406 		exit(1);
407 	}
408 	printf("Got unhandled signal %d\n", sig);
409 	exit(1);
410 }
411 #endif /* SIGPIPE */
412 
413 /** getopt global, in case header files fail to declare it. */
414 extern int optind;
415 /** getopt global, in case header files fail to declare it. */
416 extern char* optarg;
417 
418 /** main program for streamtcp */
419 int main(int argc, char** argv)
420 {
421 	int c;
422 	const char* svr = "127.0.0.1";
423 	int udp = 0;
424 	int noanswer = 0;
425 	int onarrival = 0;
426 	int usessl = 0;
427 	int delay = 0;
428 
429 #ifdef USE_WINSOCK
430 	WSADATA wsa_data;
431 	if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
432 		printf("WSAStartup failed\n");
433 		return 1;
434 	}
435 #endif
436 
437 	/* lock debug start (if any) */
438 	log_init(0, 0, 0);
439 	checklock_start();
440 
441 #ifdef SIGPIPE
442 	if(signal(SIGPIPE, &sigh) == SIG_ERR) {
443 		perror("could not install signal handler");
444 		return 1;
445 	}
446 #endif
447 
448 	/* command line options */
449 	if(argc == 1) {
450 		usage(argv);
451 	}
452 	while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
453 		switch(c) {
454 			case 'f':
455 				svr = optarg;
456 				break;
457 			case 'a':
458 				onarrival = 1;
459 				break;
460 			case 'n':
461 				noanswer = 1;
462 				break;
463 			case 'u':
464 				udp = 1;
465 				break;
466 			case 's':
467 				usessl = 1;
468 				break;
469 			case 'd':
470 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
471 					printf("error parsing delay, "
472 					    "number expected: %s\n", optarg);
473 					return 1;
474 				}
475 				delay = atoi(optarg);
476 				break;
477 			case 'h':
478 			case '?':
479 			default:
480 				usage(argv);
481 		}
482 	}
483 	argc -= optind;
484 	argv += optind;
485 
486 	if(argc % 3 != 0) {
487 		printf("queries must be multiples of name,type,class\n");
488 		return 1;
489 	}
490 	if(usessl) {
491 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
492 		ERR_load_SSL_strings();
493 #endif
494 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
495 #  ifndef S_SPLINT_S
496 		OpenSSL_add_all_algorithms();
497 #  endif
498 #else
499 		OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
500 			| OPENSSL_INIT_ADD_ALL_DIGESTS
501 			| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
502 #endif
503 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
504 		(void)SSL_library_init();
505 #else
506 		(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
507 #endif
508 	}
509 	send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
510 	checklock_stop();
511 #ifdef USE_WINSOCK
512 	WSACleanup();
513 #endif
514 	return 0;
515 }
516