xref: /openbsd-src/usr.sbin/unbound/testcode/streamtcp.c (revision a43524d9cc222a049058246319ec6a29f2d9ca78)
1712b2f30Ssthen /*
2712b2f30Ssthen  * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp.
3712b2f30Ssthen  *
4712b2f30Ssthen  * Copyright (c) 2008, NLnet Labs. All rights reserved.
5712b2f30Ssthen  *
6712b2f30Ssthen  * This software is open source.
7712b2f30Ssthen  *
8712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9712b2f30Ssthen  * modification, are permitted provided that the following conditions
10712b2f30Ssthen  * are met:
11712b2f30Ssthen  *
12712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13712b2f30Ssthen  * this list of conditions and the following disclaimer.
14712b2f30Ssthen  *
15712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17712b2f30Ssthen  * and/or other materials provided with the distribution.
18712b2f30Ssthen  *
19712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21712b2f30Ssthen  * specific prior written permission.
22712b2f30Ssthen  *
23712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34712b2f30Ssthen  */
35712b2f30Ssthen 
36712b2f30Ssthen /**
37712b2f30Ssthen  * \file
38712b2f30Ssthen  *
39712b2f30Ssthen  * This program performs multiple DNS queries on a TCP stream.
40712b2f30Ssthen  */
41712b2f30Ssthen 
42712b2f30Ssthen #include "config.h"
43712b2f30Ssthen #ifdef HAVE_GETOPT_H
44712b2f30Ssthen #include <getopt.h>
45712b2f30Ssthen #endif
46712b2f30Ssthen #include <signal.h>
477bc20e6dSsthen #include <stdlib.h>
487bc20e6dSsthen #include <unistd.h>
49712b2f30Ssthen #include "util/locks.h"
50712b2f30Ssthen #include "util/log.h"
51712b2f30Ssthen #include "util/net_help.h"
520e9b6f9fSsthen #include "util/proxy_protocol.h"
53712b2f30Ssthen #include "util/data/msgencode.h"
54712b2f30Ssthen #include "util/data/msgparse.h"
55712b2f30Ssthen #include "util/data/msgreply.h"
56712b2f30Ssthen #include "util/data/dname.h"
57712b2f30Ssthen #include "sldns/sbuffer.h"
58712b2f30Ssthen #include "sldns/str2wire.h"
59712b2f30Ssthen #include "sldns/wire2str.h"
60712b2f30Ssthen #include <openssl/ssl.h>
61712b2f30Ssthen #include <openssl/rand.h>
62712b2f30Ssthen #include <openssl/err.h>
63712b2f30Ssthen 
64712b2f30Ssthen #ifndef PF_INET6
65712b2f30Ssthen /** define in case streamtcp is compiled on legacy systems */
66712b2f30Ssthen #define PF_INET6 10
67712b2f30Ssthen #endif
68712b2f30Ssthen 
69712b2f30Ssthen /** usage information for streamtcp */
70712b2f30Ssthen static void usage(char* argv[])
71712b2f30Ssthen {
72712b2f30Ssthen 	printf("usage: %s [options] name type class ...\n", argv[0]);
73712b2f30Ssthen 	printf("	sends the name-type-class queries over TCP.\n");
74712b2f30Ssthen 	printf("-f server	what ipaddr@portnr to send the queries to\n");
750e9b6f9fSsthen 	printf("-p client	what ipaddr@portnr to include in PROXYv2\n");
76712b2f30Ssthen 	printf("-u 		use UDP. No retries are attempted.\n");
77712b2f30Ssthen 	printf("-n 		do not wait for an answer.\n");
7866a34dc2Ssthen 	printf("-a 		print answers as they arrive.\n");
797bc20e6dSsthen 	printf("-d secs		delay after connection before sending query\n");
80712b2f30Ssthen 	printf("-s		use ssl\n");
81712b2f30Ssthen 	printf("-h 		this help text\n");
829c7f0a49Ssthen 	printf("IXFR=N 		for the type, sends ixfr query with serial N.\n");
839c7f0a49Ssthen 	printf("NOTIFY[=N] 	for the type, sends notify. Can set new zone serial N.\n");
84712b2f30Ssthen 	exit(1);
85712b2f30Ssthen }
86712b2f30Ssthen 
87712b2f30Ssthen /** open TCP socket to svr */
88712b2f30Ssthen static int
890e9b6f9fSsthen open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
900e9b6f9fSsthen 	socklen_t* addrlen)
91712b2f30Ssthen {
92712b2f30Ssthen 	int fd = -1;
93712b2f30Ssthen 	/* svr can be ip@port */
940e9b6f9fSsthen 	memset(addr, 0, sizeof(*addr));
950e9b6f9fSsthen 	if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) {
96712b2f30Ssthen 		printf("fatal: bad server specs '%s'\n", svr);
97712b2f30Ssthen 		exit(1);
98712b2f30Ssthen 	}
990e9b6f9fSsthen 	fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET,
100712b2f30Ssthen 		udp?SOCK_DGRAM:SOCK_STREAM, 0);
101712b2f30Ssthen 	if(fd == -1) {
102712b2f30Ssthen #ifndef USE_WINSOCK
103712b2f30Ssthen 		perror("socket() error");
104712b2f30Ssthen #else
105712b2f30Ssthen 		printf("socket: %s\n", wsa_strerror(WSAGetLastError()));
106712b2f30Ssthen #endif
107712b2f30Ssthen 		exit(1);
108712b2f30Ssthen 	}
1090e9b6f9fSsthen 	if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) {
110712b2f30Ssthen #ifndef USE_WINSOCK
111712b2f30Ssthen 		perror("connect() error");
112712b2f30Ssthen #else
113712b2f30Ssthen 		printf("connect: %s\n", wsa_strerror(WSAGetLastError()));
114712b2f30Ssthen #endif
115712b2f30Ssthen 		exit(1);
116712b2f30Ssthen 	}
117712b2f30Ssthen 	return fd;
118712b2f30Ssthen }
119712b2f30Ssthen 
1209c7f0a49Ssthen /** Append a SOA record with serial number */
1219c7f0a49Ssthen static void
1229c7f0a49Ssthen write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo,
1239c7f0a49Ssthen 	uint32_t serial)
1249c7f0a49Ssthen {
1259c7f0a49Ssthen 	sldns_buffer_set_position(buf, sldns_buffer_limit(buf));
1269c7f0a49Ssthen 	sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf));
1279c7f0a49Ssthen 	/* Write compressed reference to the query */
1289c7f0a49Ssthen 	sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE));
1299c7f0a49Ssthen 	sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA);
1309c7f0a49Ssthen 	sldns_buffer_write_u16(buf, qinfo->qclass);
1319c7f0a49Ssthen 	sldns_buffer_write_u32(buf, 3600); /* TTL */
1329c7f0a49Ssthen 	sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */
1339c7f0a49Ssthen 	sldns_buffer_write_u8(buf, 0); /* primary "." */
1349c7f0a49Ssthen 	sldns_buffer_write_u8(buf, 0); /* email "." */
1359c7f0a49Ssthen 	sldns_buffer_write_u32(buf, serial); /* serial */
1369c7f0a49Ssthen 	sldns_buffer_write_u32(buf, 0); /* refresh */
1379c7f0a49Ssthen 	sldns_buffer_write_u32(buf, 0); /* retry */
1389c7f0a49Ssthen 	sldns_buffer_write_u32(buf, 0); /* expire */
1399c7f0a49Ssthen 	sldns_buffer_write_u32(buf, 0); /* minimum */
1409c7f0a49Ssthen 	sldns_buffer_flip(buf);
1419c7f0a49Ssthen }
1429c7f0a49Ssthen 
143712b2f30Ssthen /** write a query over the TCP fd */
144712b2f30Ssthen static void
145712b2f30Ssthen write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
1460e9b6f9fSsthen 	sldns_buffer* proxy_buf, int pp2_parsed,
147712b2f30Ssthen 	const char* strname, const char* strtype, const char* strclass)
148712b2f30Ssthen {
149712b2f30Ssthen 	struct query_info qinfo;
1500e9b6f9fSsthen 	size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
1519c7f0a49Ssthen 	int have_serial = 0, is_notify = 0;
1529c7f0a49Ssthen 	uint32_t serial = 0;
153712b2f30Ssthen 	/* qname */
154712b2f30Ssthen 	qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
155712b2f30Ssthen 	if(!qinfo.qname) {
156712b2f30Ssthen 		printf("cannot parse query name: '%s'\n", strname);
157712b2f30Ssthen 		exit(1);
158712b2f30Ssthen 	}
159712b2f30Ssthen 
1609c7f0a49Ssthen 	/* qtype */
1619c7f0a49Ssthen 	if(strncasecmp(strtype, "IXFR=", 5) == 0) {
1629c7f0a49Ssthen 		serial = (uint32_t)atoi(strtype+5);
1639c7f0a49Ssthen 		have_serial = 1;
1649c7f0a49Ssthen 		qinfo.qtype = LDNS_RR_TYPE_IXFR;
1659c7f0a49Ssthen 	} else if(strcasecmp(strtype, "NOTIFY") == 0) {
1669c7f0a49Ssthen 		is_notify = 1;
1679c7f0a49Ssthen 		qinfo.qtype = LDNS_RR_TYPE_SOA;
1689c7f0a49Ssthen 	} else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) {
1699c7f0a49Ssthen 		serial = (uint32_t)atoi(strtype+7);
1709c7f0a49Ssthen 		have_serial = 1;
1719c7f0a49Ssthen 		is_notify = 1;
1729c7f0a49Ssthen 		qinfo.qtype = LDNS_RR_TYPE_SOA;
1739c7f0a49Ssthen 	} else {
174712b2f30Ssthen 		qinfo.qtype = sldns_get_rr_type_by_name(strtype);
175437d2860Ssthen 		if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
176437d2860Ssthen 			printf("cannot parse query type: '%s'\n", strtype);
177437d2860Ssthen 			exit(1);
178437d2860Ssthen 		}
1799c7f0a49Ssthen 	}
1809c7f0a49Ssthen 	/* qclass */
181712b2f30Ssthen 	qinfo.qclass = sldns_get_rr_class_by_name(strclass);
182437d2860Ssthen 	if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
183437d2860Ssthen 		printf("cannot parse query class: '%s'\n", strclass);
184437d2860Ssthen 		exit(1);
185437d2860Ssthen 	}
186712b2f30Ssthen 
187712b2f30Ssthen 	/* clear local alias */
188712b2f30Ssthen 	qinfo.local_alias = NULL;
189712b2f30Ssthen 
190712b2f30Ssthen 	/* make query */
191712b2f30Ssthen 	qinfo_query_encode(buf, &qinfo);
192712b2f30Ssthen 	sldns_buffer_write_u16_at(buf, 0, id);
193712b2f30Ssthen 	sldns_buffer_write_u16_at(buf, 2, BIT_RD);
194712b2f30Ssthen 
1959c7f0a49Ssthen 	if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) {
1969c7f0a49Ssthen 		/* Attach serial to SOA record in the authority section. */
1979c7f0a49Ssthen 		write_soa_serial_to_buf(buf, &qinfo, serial);
1989c7f0a49Ssthen 		LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1);
1999c7f0a49Ssthen 	}
2009c7f0a49Ssthen 	if(is_notify) {
2019c7f0a49Ssthen 		LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY);
2029c7f0a49Ssthen 		LDNS_RD_CLR(sldns_buffer_begin(buf));
2039c7f0a49Ssthen 		LDNS_AA_SET(sldns_buffer_begin(buf));
2049c7f0a49Ssthen 		if(have_serial) {
2059c7f0a49Ssthen 			write_soa_serial_to_buf(buf, &qinfo, serial);
2069c7f0a49Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1);
2079c7f0a49Ssthen 		}
2089c7f0a49Ssthen 	}
2099c7f0a49Ssthen 
210712b2f30Ssthen 	if(1) {
211712b2f30Ssthen 		/* add EDNS DO */
212712b2f30Ssthen 		struct edns_data edns;
213712b2f30Ssthen 		memset(&edns, 0, sizeof(edns));
214712b2f30Ssthen 		edns.edns_present = 1;
215712b2f30Ssthen 		edns.bits = EDNS_DO;
216712b2f30Ssthen 		edns.udp_size = 4096;
217712b2f30Ssthen 		if(sldns_buffer_capacity(buf) >=
218712b2f30Ssthen 			sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
219712b2f30Ssthen 			attach_edns_record(buf, &edns);
220712b2f30Ssthen 	}
221712b2f30Ssthen 
2220e9b6f9fSsthen 	/* we need to send the PROXYv2 information in every UDP message */
2230e9b6f9fSsthen 	if(udp && pp2_parsed) {
2240e9b6f9fSsthen 		/* append the proxy_buf with the buf's content
2250e9b6f9fSsthen 		 * and use that for sending */
2260e9b6f9fSsthen 		if(sldns_buffer_capacity(proxy_buf) <
2270e9b6f9fSsthen 			sldns_buffer_limit(proxy_buf) +
2280e9b6f9fSsthen 			sldns_buffer_limit(buf)) {
2290e9b6f9fSsthen 			printf("buffer too small for packet + proxy");
2300e9b6f9fSsthen 			exit(1);
2310e9b6f9fSsthen 		}
2320e9b6f9fSsthen 		sldns_buffer_clear(proxy_buf);
2330e9b6f9fSsthen 		sldns_buffer_skip(proxy_buf, proxy_buf_limit);
2340e9b6f9fSsthen 		sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
2350e9b6f9fSsthen 			sldns_buffer_limit(buf));
2360e9b6f9fSsthen 		sldns_buffer_flip(proxy_buf);
2370e9b6f9fSsthen 		buf = proxy_buf;
2380e9b6f9fSsthen 	}
2390e9b6f9fSsthen 
240712b2f30Ssthen 	/* send it */
241712b2f30Ssthen 	if(!udp) {
2420e9b6f9fSsthen 		uint16_t len = (uint16_t)sldns_buffer_limit(buf);
243712b2f30Ssthen 		len = htons(len);
244712b2f30Ssthen 		if(ssl) {
245712b2f30Ssthen 			if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
246712b2f30Ssthen 				log_crypto_err("cannot SSL_write");
247712b2f30Ssthen 				exit(1);
248712b2f30Ssthen 			}
249712b2f30Ssthen 		} else {
250712b2f30Ssthen 			if(send(fd, (void*)&len, sizeof(len), 0) <
251712b2f30Ssthen 				(ssize_t)sizeof(len)){
252712b2f30Ssthen #ifndef USE_WINSOCK
253712b2f30Ssthen 				perror("send() len failed");
254712b2f30Ssthen #else
255712b2f30Ssthen 				printf("send len: %s\n",
256712b2f30Ssthen 					wsa_strerror(WSAGetLastError()));
257712b2f30Ssthen #endif
258712b2f30Ssthen 				exit(1);
259712b2f30Ssthen 			}
260712b2f30Ssthen 		}
261712b2f30Ssthen 	}
262712b2f30Ssthen 	if(ssl) {
263712b2f30Ssthen 		if(SSL_write(ssl, (void*)sldns_buffer_begin(buf),
264712b2f30Ssthen 			(int)sldns_buffer_limit(buf)) <= 0) {
265712b2f30Ssthen 			log_crypto_err("cannot SSL_write");
266712b2f30Ssthen 			exit(1);
267712b2f30Ssthen 		}
268712b2f30Ssthen 	} else {
269712b2f30Ssthen 		if(send(fd, (void*)sldns_buffer_begin(buf),
270712b2f30Ssthen 			sldns_buffer_limit(buf), 0) <
271712b2f30Ssthen 			(ssize_t)sldns_buffer_limit(buf)) {
272712b2f30Ssthen #ifndef USE_WINSOCK
273712b2f30Ssthen 			perror("send() data failed");
274712b2f30Ssthen #else
2750e9b6f9fSsthen 			printf("send data: %s\n",
2760e9b6f9fSsthen 				wsa_strerror(WSAGetLastError()));
277712b2f30Ssthen #endif
278712b2f30Ssthen 			exit(1);
279712b2f30Ssthen 		}
280712b2f30Ssthen 	}
281712b2f30Ssthen 
2820e9b6f9fSsthen 	/* reset the proxy_buf for next packet */
2830e9b6f9fSsthen 	sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
284712b2f30Ssthen 	free(qinfo.qname);
285712b2f30Ssthen }
286712b2f30Ssthen 
287712b2f30Ssthen /** receive DNS datagram over TCP and print it */
288712b2f30Ssthen static void
289712b2f30Ssthen recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
290712b2f30Ssthen {
291d7b4a113Ssthen 	size_t i;
292712b2f30Ssthen 	char* pktstr;
293712b2f30Ssthen 	uint16_t len;
294712b2f30Ssthen 	if(!udp) {
295712b2f30Ssthen 		if(ssl) {
29666a34dc2Ssthen 			int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
29766a34dc2Ssthen 			if(sr == 0) {
29866a34dc2Ssthen 				printf("ssl: stream closed\n");
29966a34dc2Ssthen 				exit(1);
30066a34dc2Ssthen 			}
30166a34dc2Ssthen 			if(sr < 0) {
302712b2f30Ssthen 				log_crypto_err("could not SSL_read");
303712b2f30Ssthen 				exit(1);
304712b2f30Ssthen 			}
305712b2f30Ssthen 		} else {
30666a34dc2Ssthen 			ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
30766a34dc2Ssthen 			if(r == 0) {
30866a34dc2Ssthen 				printf("recv: stream closed\n");
30966a34dc2Ssthen 				exit(1);
31066a34dc2Ssthen 			}
31166a34dc2Ssthen 			if(r < (ssize_t)sizeof(len)) {
312712b2f30Ssthen #ifndef USE_WINSOCK
313712b2f30Ssthen 				perror("read() len failed");
314712b2f30Ssthen #else
315712b2f30Ssthen 				printf("read len: %s\n",
316712b2f30Ssthen 					wsa_strerror(WSAGetLastError()));
317712b2f30Ssthen #endif
318712b2f30Ssthen 				exit(1);
319712b2f30Ssthen 			}
320712b2f30Ssthen 		}
321712b2f30Ssthen 		len = ntohs(len);
322712b2f30Ssthen 		sldns_buffer_clear(buf);
323712b2f30Ssthen 		sldns_buffer_set_limit(buf, len);
324712b2f30Ssthen 		if(ssl) {
325712b2f30Ssthen 			int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
326712b2f30Ssthen 				(int)len);
327712b2f30Ssthen 			if(r <= 0) {
328712b2f30Ssthen 				log_crypto_err("could not SSL_read");
329712b2f30Ssthen 				exit(1);
330712b2f30Ssthen 			}
331712b2f30Ssthen 			if(r != (int)len)
332712b2f30Ssthen 				fatal_exit("ssl_read %d of %d", r, len);
333712b2f30Ssthen 		} else {
334712b2f30Ssthen 			if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
335712b2f30Ssthen 				(ssize_t)len) {
336712b2f30Ssthen #ifndef USE_WINSOCK
337712b2f30Ssthen 				perror("read() data failed");
338712b2f30Ssthen #else
339712b2f30Ssthen 				printf("read data: %s\n",
340712b2f30Ssthen 					wsa_strerror(WSAGetLastError()));
341712b2f30Ssthen #endif
342712b2f30Ssthen 				exit(1);
343712b2f30Ssthen 			}
344712b2f30Ssthen 		}
345712b2f30Ssthen 	} else {
346712b2f30Ssthen 		ssize_t l;
347712b2f30Ssthen 		sldns_buffer_clear(buf);
348712b2f30Ssthen 		if((l=recv(fd, (void*)sldns_buffer_begin(buf),
349712b2f30Ssthen 			sldns_buffer_capacity(buf), 0)) < 0) {
350712b2f30Ssthen #ifndef USE_WINSOCK
351712b2f30Ssthen 			perror("read() data failed");
352712b2f30Ssthen #else
353712b2f30Ssthen 			printf("read data: %s\n",
354712b2f30Ssthen 				wsa_strerror(WSAGetLastError()));
355712b2f30Ssthen #endif
356712b2f30Ssthen 			exit(1);
357712b2f30Ssthen 		}
358712b2f30Ssthen 		sldns_buffer_set_limit(buf, (size_t)l);
359712b2f30Ssthen 		len = (size_t)l;
360712b2f30Ssthen 	}
361712b2f30Ssthen 	printf("\nnext received packet\n");
362d7b4a113Ssthen 	printf("data[%d] ", (int)sldns_buffer_limit(buf));
363d7b4a113Ssthen 	for(i=0; i<sldns_buffer_limit(buf); i++) {
364d7b4a113Ssthen 		const char* hex = "0123456789ABCDEF";
365d7b4a113Ssthen 		printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4],
366d7b4a113Ssthen                         hex[sldns_buffer_read_u8_at(buf, i)&0x0f]);
367d7b4a113Ssthen 	}
368d7b4a113Ssthen 	printf("\n");
369712b2f30Ssthen 
370712b2f30Ssthen 	pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
371712b2f30Ssthen 	printf("%s", pktstr);
372712b2f30Ssthen 	free(pktstr);
373712b2f30Ssthen }
374712b2f30Ssthen 
37566a34dc2Ssthen /** see if we can receive any results */
37666a34dc2Ssthen static void
37766a34dc2Ssthen print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
37866a34dc2Ssthen 	int* num_answers, int wait_all)
37966a34dc2Ssthen {
38066a34dc2Ssthen 	/* see if the fd can read, if so, print one answer, repeat */
38166a34dc2Ssthen 	int ret;
38266a34dc2Ssthen 	struct timeval tv, *waittv;
38366a34dc2Ssthen 	fd_set rfd;
38466a34dc2Ssthen 	while(*num_answers > 0) {
38566a34dc2Ssthen 		memset(&rfd, 0, sizeof(rfd));
38666a34dc2Ssthen 		memset(&tv, 0, sizeof(tv));
38766a34dc2Ssthen 		FD_ZERO(&rfd);
38866a34dc2Ssthen 		FD_SET(fd, &rfd);
38966a34dc2Ssthen 		if(wait_all) waittv = NULL;
39066a34dc2Ssthen 		else waittv = &tv;
39166a34dc2Ssthen 		ret = select(fd+1, &rfd, NULL, NULL, waittv);
39266a34dc2Ssthen 		if(ret < 0) {
39366a34dc2Ssthen 			if(errno == EINTR || errno == EAGAIN) continue;
39466a34dc2Ssthen 			perror("select() failed");
39566a34dc2Ssthen 			exit(1);
39666a34dc2Ssthen 		}
39766a34dc2Ssthen 		if(ret == 0) {
39866a34dc2Ssthen 			if(wait_all) continue;
39966a34dc2Ssthen 			return;
40066a34dc2Ssthen 		}
40166a34dc2Ssthen 		(*num_answers) -= 1;
40266a34dc2Ssthen 		recv_one(fd, udp, ssl, buf);
40366a34dc2Ssthen 	}
40466a34dc2Ssthen }
40566a34dc2Ssthen 
406712b2f30Ssthen static int get_random(void)
407712b2f30Ssthen {
408712b2f30Ssthen 	int r;
409712b2f30Ssthen 	if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
410712b2f30Ssthen 		return r;
411712b2f30Ssthen 	}
412b0dfc31bSsthen 	return (int)arc4random();
413712b2f30Ssthen }
414712b2f30Ssthen 
4150e9b6f9fSsthen /* parse the pp2_client and populate the proxy_buffer
4160e9b6f9fSsthen  * It doesn't populate the destination parts. */
4170e9b6f9fSsthen static int parse_pp2_client(const char* pp2_client, int udp,
4180e9b6f9fSsthen 	sldns_buffer* proxy_buf)
4190e9b6f9fSsthen {
4200e9b6f9fSsthen 	struct sockaddr_storage pp2_addr;
4219c7f0a49Ssthen 	size_t bytes_written;
4220e9b6f9fSsthen 	socklen_t pp2_addrlen = 0;
4230e9b6f9fSsthen 	memset(&pp2_addr, 0, sizeof(pp2_addr));
4240e9b6f9fSsthen 	if(*pp2_client == 0) return 0;
4250e9b6f9fSsthen 	if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
4260e9b6f9fSsthen 		printf("fatal: bad proxy client specs '%s'\n", pp2_client);
4270e9b6f9fSsthen 		exit(1);
4280e9b6f9fSsthen 	}
4290e9b6f9fSsthen 	sldns_buffer_clear(proxy_buf);
4309c7f0a49Ssthen 	bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf),
4319c7f0a49Ssthen 		sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp);
4329c7f0a49Ssthen 	sldns_buffer_set_position(proxy_buf, bytes_written);
4330e9b6f9fSsthen 	sldns_buffer_flip(proxy_buf);
4340e9b6f9fSsthen 	return 1;
4350e9b6f9fSsthen }
4360e9b6f9fSsthen 
437712b2f30Ssthen /** send the TCP queries and print answers */
438712b2f30Ssthen static void
4390e9b6f9fSsthen send_em(const char* svr, const char* pp2_client, int udp, int usessl,
4400e9b6f9fSsthen 	int noanswer, int onarrival, int delay, int num, char** qs)
441712b2f30Ssthen {
4420e9b6f9fSsthen 	struct sockaddr_storage svr_addr;
4430e9b6f9fSsthen 	socklen_t svr_addrlen;
4440e9b6f9fSsthen 	int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
4450e9b6f9fSsthen 	int i, wait_results = 0, pp2_parsed;
446712b2f30Ssthen 	SSL_CTX* ctx = NULL;
447712b2f30Ssthen 	SSL* ssl = NULL;
448437d2860Ssthen 	sldns_buffer* buf = sldns_buffer_new(65553);
449437d2860Ssthen 	sldns_buffer* proxy_buf = sldns_buffer_new(65553);
450437d2860Ssthen 	if(!buf || !proxy_buf) {
451437d2860Ssthen 		sldns_buffer_free(buf);
452437d2860Ssthen 		sldns_buffer_free(proxy_buf);
453437d2860Ssthen 		fatal_exit("out of memory");
454437d2860Ssthen 	}
4550e9b6f9fSsthen 	pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
456712b2f30Ssthen 	if(usessl) {
457712b2f30Ssthen 		ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
458712b2f30Ssthen 		if(!ctx) fatal_exit("cannot create ssl ctx");
459712b2f30Ssthen 		ssl = outgoing_ssl_fd(ctx, fd);
460712b2f30Ssthen 		if(!ssl) fatal_exit("cannot create ssl");
461712b2f30Ssthen 		while(1) {
462712b2f30Ssthen 			int r;
463712b2f30Ssthen 			ERR_clear_error();
464712b2f30Ssthen 			if( (r=SSL_do_handshake(ssl)) == 1)
465712b2f30Ssthen 				break;
466712b2f30Ssthen 			r = SSL_get_error(ssl, r);
467712b2f30Ssthen 			if(r != SSL_ERROR_WANT_READ &&
468712b2f30Ssthen 				r != SSL_ERROR_WANT_WRITE) {
4699c7f0a49Ssthen 				log_crypto_err_io("could not ssl_handshake", r);
470712b2f30Ssthen 				exit(1);
471712b2f30Ssthen 			}
472712b2f30Ssthen 		}
473712b2f30Ssthen 		if(1) {
474*a43524d9Ssthen #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
475*a43524d9Ssthen 			X509* x = SSL_get1_peer_certificate(ssl);
476*a43524d9Ssthen #else
477712b2f30Ssthen 			X509* x = SSL_get_peer_certificate(ssl);
478*a43524d9Ssthen #endif
479712b2f30Ssthen 			if(!x) printf("SSL: no peer certificate\n");
480712b2f30Ssthen 			else {
481712b2f30Ssthen 				X509_print_fp(stdout, x);
482712b2f30Ssthen 				X509_free(x);
483712b2f30Ssthen 			}
484712b2f30Ssthen 		}
485712b2f30Ssthen 	}
4860e9b6f9fSsthen 	/* Send the PROXYv2 information once per stream */
4870e9b6f9fSsthen 	if(!udp && pp2_parsed) {
4880e9b6f9fSsthen 		if(ssl) {
4890e9b6f9fSsthen 			if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
4900e9b6f9fSsthen 				(int)sldns_buffer_limit(proxy_buf)) <= 0) {
4910e9b6f9fSsthen 				log_crypto_err("cannot SSL_write");
4920e9b6f9fSsthen 				exit(1);
4930e9b6f9fSsthen 			}
4940e9b6f9fSsthen 		} else {
4950e9b6f9fSsthen 			if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
4960e9b6f9fSsthen 				sldns_buffer_limit(proxy_buf), 0) <
4970e9b6f9fSsthen 				(ssize_t)sldns_buffer_limit(proxy_buf)) {
4980e9b6f9fSsthen #ifndef USE_WINSOCK
4990e9b6f9fSsthen 				perror("send() data failed");
5000e9b6f9fSsthen #else
5010e9b6f9fSsthen 				printf("send data: %s\n",
5020e9b6f9fSsthen 					wsa_strerror(WSAGetLastError()));
5030e9b6f9fSsthen #endif
5040e9b6f9fSsthen 				exit(1);
5050e9b6f9fSsthen 			}
5060e9b6f9fSsthen 		}
5070e9b6f9fSsthen 	}
508712b2f30Ssthen 	for(i=0; i<num; i+=3) {
5097bc20e6dSsthen 		if (delay != 0) {
5107bc20e6dSsthen #ifdef HAVE_SLEEP
5117bc20e6dSsthen 			sleep((unsigned)delay);
5127bc20e6dSsthen #else
5137bc20e6dSsthen 			Sleep(delay*1000);
5147bc20e6dSsthen #endif
5157bc20e6dSsthen 		}
516712b2f30Ssthen 		printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
5170e9b6f9fSsthen 		write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
5180e9b6f9fSsthen 			pp2_parsed,
5190e9b6f9fSsthen 			qs[i], qs[i+1], qs[i+2]);
520712b2f30Ssthen 		/* print at least one result */
52166a34dc2Ssthen 		if(onarrival) {
52266a34dc2Ssthen 			wait_results += 1; /* one more answer to fetch */
52366a34dc2Ssthen 			print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
52466a34dc2Ssthen 		} else if(!noanswer) {
525712b2f30Ssthen 			recv_one(fd, udp, ssl, buf);
526712b2f30Ssthen 		}
52766a34dc2Ssthen 	}
52866a34dc2Ssthen 	if(onarrival)
52966a34dc2Ssthen 		print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
530712b2f30Ssthen 
531712b2f30Ssthen 	if(usessl) {
532712b2f30Ssthen 		SSL_shutdown(ssl);
533712b2f30Ssthen 		SSL_free(ssl);
534712b2f30Ssthen 		SSL_CTX_free(ctx);
535712b2f30Ssthen 	}
536e2a0f313Ssthen 	sock_close(fd);
537712b2f30Ssthen 	sldns_buffer_free(buf);
5380e9b6f9fSsthen 	sldns_buffer_free(proxy_buf);
539712b2f30Ssthen 	printf("orderly exit\n");
540712b2f30Ssthen }
541712b2f30Ssthen 
542712b2f30Ssthen #ifdef SIGPIPE
543712b2f30Ssthen /** SIGPIPE handler */
544712b2f30Ssthen static RETSIGTYPE sigh(int sig)
545712b2f30Ssthen {
546a6cc1574Ssthen 	char str[] = "Got unhandled signal   \n";
547712b2f30Ssthen 	if(sig == SIGPIPE) {
548a6cc1574Ssthen 		char* strpipe = "got SIGPIPE, remote connection gone\n";
549a6cc1574Ssthen 		/* simple cast to void will not silence Wunused-result */
550a6cc1574Ssthen 		(void)!write(STDOUT_FILENO, strpipe, strlen(strpipe));
551712b2f30Ssthen 		exit(1);
552712b2f30Ssthen 	}
553a6cc1574Ssthen 	str[21] = '0' + (sig/10)%10;
554a6cc1574Ssthen 	str[22] = '0' + sig%10;
555a6cc1574Ssthen 	/* simple cast to void will not silence Wunused-result */
556a6cc1574Ssthen 	(void)!write(STDOUT_FILENO, str, strlen(str));
557712b2f30Ssthen 	exit(1);
558712b2f30Ssthen }
559712b2f30Ssthen #endif /* SIGPIPE */
560712b2f30Ssthen 
561712b2f30Ssthen /** getopt global, in case header files fail to declare it. */
562712b2f30Ssthen extern int optind;
563712b2f30Ssthen /** getopt global, in case header files fail to declare it. */
564712b2f30Ssthen extern char* optarg;
565712b2f30Ssthen 
566712b2f30Ssthen /** main program for streamtcp */
567712b2f30Ssthen int main(int argc, char** argv)
568712b2f30Ssthen {
569712b2f30Ssthen 	int c;
570712b2f30Ssthen 	const char* svr = "127.0.0.1";
5710e9b6f9fSsthen 	const char* pp2_client = "";
572712b2f30Ssthen 	int udp = 0;
573712b2f30Ssthen 	int noanswer = 0;
57466a34dc2Ssthen 	int onarrival = 0;
575712b2f30Ssthen 	int usessl = 0;
5767bc20e6dSsthen 	int delay = 0;
577712b2f30Ssthen 
578712b2f30Ssthen #ifdef USE_WINSOCK
579712b2f30Ssthen 	WSADATA wsa_data;
580712b2f30Ssthen 	if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
581712b2f30Ssthen 		printf("WSAStartup failed\n");
582712b2f30Ssthen 		return 1;
583712b2f30Ssthen 	}
584712b2f30Ssthen #endif
585712b2f30Ssthen 
586712b2f30Ssthen 	/* lock debug start (if any) */
587712b2f30Ssthen 	checklock_start();
58883152a15Ssthen 	log_init(0, 0, 0);
589712b2f30Ssthen 
590712b2f30Ssthen #ifdef SIGPIPE
591712b2f30Ssthen 	if(signal(SIGPIPE, &sigh) == SIG_ERR) {
592712b2f30Ssthen 		perror("could not install signal handler");
593712b2f30Ssthen 		return 1;
594712b2f30Ssthen 	}
595712b2f30Ssthen #endif
596712b2f30Ssthen 
597712b2f30Ssthen 	/* command line options */
598712b2f30Ssthen 	if(argc == 1) {
599712b2f30Ssthen 		usage(argv);
600712b2f30Ssthen 	}
6010e9b6f9fSsthen 	while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
602712b2f30Ssthen 		switch(c) {
603712b2f30Ssthen 			case 'f':
604712b2f30Ssthen 				svr = optarg;
605712b2f30Ssthen 				break;
6060e9b6f9fSsthen 			case 'p':
6070e9b6f9fSsthen 				pp2_client = optarg;
6089c7f0a49Ssthen 				pp_init(&sldns_write_uint16,
6099c7f0a49Ssthen 					&sldns_write_uint32);
6100e9b6f9fSsthen 				break;
61166a34dc2Ssthen 			case 'a':
61266a34dc2Ssthen 				onarrival = 1;
61366a34dc2Ssthen 				break;
614712b2f30Ssthen 			case 'n':
615712b2f30Ssthen 				noanswer = 1;
616712b2f30Ssthen 				break;
617712b2f30Ssthen 			case 'u':
618712b2f30Ssthen 				udp = 1;
619712b2f30Ssthen 				break;
620712b2f30Ssthen 			case 's':
621712b2f30Ssthen 				usessl = 1;
622712b2f30Ssthen 				break;
6237bc20e6dSsthen 			case 'd':
6247bc20e6dSsthen 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
6257bc20e6dSsthen 					printf("error parsing delay, "
6267bc20e6dSsthen 					    "number expected: %s\n", optarg);
6277bc20e6dSsthen 					return 1;
6287bc20e6dSsthen 				}
6297bc20e6dSsthen 				delay = atoi(optarg);
6307bc20e6dSsthen 				break;
631712b2f30Ssthen 			case 'h':
632712b2f30Ssthen 			case '?':
633712b2f30Ssthen 			default:
634712b2f30Ssthen 				usage(argv);
635712b2f30Ssthen 		}
636712b2f30Ssthen 	}
637712b2f30Ssthen 	argc -= optind;
638712b2f30Ssthen 	argv += optind;
639712b2f30Ssthen 
640712b2f30Ssthen 	if(argc % 3 != 0) {
641712b2f30Ssthen 		printf("queries must be multiples of name,type,class\n");
642712b2f30Ssthen 		return 1;
643712b2f30Ssthen 	}
644712b2f30Ssthen 	if(usessl) {
645712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
646712b2f30Ssthen 		ERR_load_SSL_strings();
647712b2f30Ssthen #endif
648712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
649b0dfc31bSsthen #  ifndef S_SPLINT_S
650712b2f30Ssthen 		OpenSSL_add_all_algorithms();
651b0dfc31bSsthen #  endif
652712b2f30Ssthen #else
653712b2f30Ssthen 		OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
654712b2f30Ssthen 			| OPENSSL_INIT_ADD_ALL_DIGESTS
655712b2f30Ssthen 			| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
656712b2f30Ssthen #endif
657712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
658712b2f30Ssthen 		(void)SSL_library_init();
659712b2f30Ssthen #else
660712b2f30Ssthen 		(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
661712b2f30Ssthen #endif
662712b2f30Ssthen 	}
6630e9b6f9fSsthen 	send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
664712b2f30Ssthen 	checklock_stop();
665712b2f30Ssthen #ifdef USE_WINSOCK
666712b2f30Ssthen 	WSACleanup();
667712b2f30Ssthen #endif
668712b2f30Ssthen 	return 0;
669712b2f30Ssthen }
670