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