2 * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp.
4 * Copyright (c) 2008, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
39 * This program performs multiple DNS queries on a TCP stream.
49 #include "util/locks.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>
64 /** define in case streamtcp is compiled on legacy systems */
68 /** usage information for streamtcp */
69 static void usage(char* argv[])
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");
83 /** open TCP socket to svr */
85 open_svr(const char* svr, int udp)
87 struct sockaddr_storage addr;
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);
96 fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
97 udp?SOCK_DGRAM:SOCK_STREAM, 0);
100 perror("socket() error");
102 printf("socket: %s\n", wsa_strerror(WSAGetLastError()));
106 if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
108 perror("connect() error");
110 printf("connect: %s\n", wsa_strerror(WSAGetLastError()));
117 /** write a query over the TCP fd */
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)
122 struct query_info qinfo;
125 qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
127 printf("cannot parse query name: '%s'\n", strname);
131 /* qtype and qclass */
132 qinfo.qtype = sldns_get_rr_type_by_name(strtype);
133 qinfo.qclass = sldns_get_rr_class_by_name(strclass);
135 /* clear local alias */
136 qinfo.local_alias = NULL;
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);
145 struct edns_data edns;
146 memset(&edns, 0, sizeof(edns));
147 edns.edns_present = 1;
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);
157 len = (uint16_t)sldns_buffer_limit(buf);
160 if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
161 log_crypto_err("cannot SSL_write");
165 if(send(fd, (void*)&len, sizeof(len), 0) <
166 (ssize_t)sizeof(len)){
168 perror("send() len failed");
170 printf("send len: %s\n",
171 wsa_strerror(WSAGetLastError()));
178 if(SSL_write(ssl, (void*)sldns_buffer_begin(buf),
179 (int)sldns_buffer_limit(buf)) <= 0) {
180 log_crypto_err("cannot SSL_write");
184 if(send(fd, (void*)sldns_buffer_begin(buf),
185 sldns_buffer_limit(buf), 0) <
186 (ssize_t)sldns_buffer_limit(buf)) {
188 perror("send() data failed");
190 printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
199 /** receive DNS datagram over TCP and print it */
201 recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
208 int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
210 printf("ssl: stream closed\n");
214 log_crypto_err("could not SSL_read");
218 ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
220 printf("recv: stream closed\n");
223 if(r < (ssize_t)sizeof(len)) {
225 perror("read() len failed");
227 printf("read len: %s\n",
228 wsa_strerror(WSAGetLastError()));
234 sldns_buffer_clear(buf);
235 sldns_buffer_set_limit(buf, len);
237 int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
240 log_crypto_err("could not SSL_read");
244 fatal_exit("ssl_read %d of %d", r, len);
246 if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
249 perror("read() data failed");
251 printf("read data: %s\n",
252 wsa_strerror(WSAGetLastError()));
259 sldns_buffer_clear(buf);
260 if((l=recv(fd, (void*)sldns_buffer_begin(buf),
261 sldns_buffer_capacity(buf), 0)) < 0) {
263 perror("read() data failed");
265 printf("read data: %s\n",
266 wsa_strerror(WSAGetLastError()));
270 sldns_buffer_set_limit(buf, (size_t)l);
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]);
282 pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
283 printf("%s", pktstr);
287 /** see if we can receive any results */
289 print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
290 int* num_answers, int wait_all)
292 /* see if the fd can read, if so, print one answer, repeat */
294 struct timeval tv, *waittv;
296 while(*num_answers > 0) {
297 memset(&rfd, 0, sizeof(rfd));
298 memset(&tv, 0, sizeof(tv));
301 if(wait_all) waittv = NULL;
303 ret = select(fd+1, &rfd, NULL, NULL, waittv);
305 if(errno == EINTR || errno == EAGAIN) continue;
306 perror("select() failed");
310 if(wait_all) continue;
314 recv_one(fd, udp, ssl, buf);
318 static int get_random(void)
321 if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
324 return (int)arc4random();
327 /** send the TCP queries and print answers */
329 send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
330 int delay, int num, char** qs)
332 sldns_buffer* buf = sldns_buffer_new(65553);
333 int fd = open_svr(svr, udp);
334 int i, wait_results = 0;
337 if(!buf) fatal_exit("out of memory");
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");
346 if( (r=SSL_do_handshake(ssl)) == 1)
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");
356 X509* x = SSL_get_peer_certificate(ssl);
357 if(!x) printf("SSL: no peer certificate\n");
359 X509_print_fp(stdout, x);
364 for(i=0; i<num; i+=3) {
367 sleep((unsigned)delay);
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],
375 /* print at least one result */
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);
384 print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
392 sldns_buffer_free(buf);
393 printf("orderly exit\n");
397 /** SIGPIPE handler */
398 static RETSIGTYPE sigh(int sig)
401 printf("got SIGPIPE, remote connection gone\n");
404 printf("Got unhandled signal %d\n", sig);
409 /** getopt global, in case header files fail to declare it. */
411 /** getopt global, in case header files fail to declare it. */
414 /** main program for streamtcp */
415 int main(int argc, char** argv)
418 const char* svr = "127.0.0.1";
427 if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
428 printf("WSAStartup failed\n");
433 /* lock debug start (if any) */
438 if(signal(SIGPIPE, &sigh) == SIG_ERR) {
439 perror("could not install signal handler");
444 /* command line options */
448 while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
466 if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
467 printf("error parsing delay, "
468 "number expected: %s\n", optarg);
471 delay = atoi(optarg);
483 printf("queries must be multiples of name,type,class\n");
487 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
488 ERR_load_SSL_strings();
490 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
492 OpenSSL_add_all_algorithms();
495 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
496 | OPENSSL_INIT_ADD_ALL_DIGESTS
497 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
499 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
500 (void)SSL_library_init();
502 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
505 send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);