]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - testcode/streamtcp.c
Vendor import of Unbound 1.9.0.
[FreeBSD/FreeBSD.git] / testcode / streamtcp.c
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         char* pktstr;
204         uint16_t len;
205         if(!udp) {
206                 if(ssl) {
207                         int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
208                         if(sr == 0) {
209                                 printf("ssl: stream closed\n");
210                                 exit(1);
211                         }
212                         if(sr < 0) {
213                                 log_crypto_err("could not SSL_read");
214                                 exit(1);
215                         }
216                 } else {
217                         ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
218                         if(r == 0) {
219                                 printf("recv: stream closed\n");
220                                 exit(1);
221                         }       
222                         if(r < (ssize_t)sizeof(len)) {
223 #ifndef USE_WINSOCK
224                                 perror("read() len failed");
225 #else
226                                 printf("read len: %s\n", 
227                                         wsa_strerror(WSAGetLastError()));
228 #endif
229                                 exit(1);
230                         }
231                 }
232                 len = ntohs(len);
233                 sldns_buffer_clear(buf);
234                 sldns_buffer_set_limit(buf, len);
235                 if(ssl) {
236                         int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf),
237                                 (int)len);
238                         if(r <= 0) {
239                                 log_crypto_err("could not SSL_read");
240                                 exit(1);
241                         }
242                         if(r != (int)len)
243                                 fatal_exit("ssl_read %d of %d", r, len);
244                 } else {
245                         if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) < 
246                                 (ssize_t)len) {
247 #ifndef USE_WINSOCK
248                                 perror("read() data failed");
249 #else
250                                 printf("read data: %s\n", 
251                                         wsa_strerror(WSAGetLastError()));
252 #endif
253                                 exit(1);
254                         }
255                 }
256         } else {
257                 ssize_t l;
258                 sldns_buffer_clear(buf);
259                 if((l=recv(fd, (void*)sldns_buffer_begin(buf), 
260                         sldns_buffer_capacity(buf), 0)) < 0) {
261 #ifndef USE_WINSOCK
262                         perror("read() data failed");
263 #else
264                         printf("read data: %s\n", 
265                                 wsa_strerror(WSAGetLastError()));
266 #endif
267                         exit(1);
268                 }
269                 sldns_buffer_set_limit(buf, (size_t)l);
270                 len = (size_t)l;
271         }
272         printf("\nnext received packet\n");
273         log_buf(0, "data", buf);
274
275         pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len);
276         printf("%s", pktstr);
277         free(pktstr);
278 }
279
280 /** see if we can receive any results */
281 static void
282 print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
283         int* num_answers, int wait_all)
284 {
285         /* see if the fd can read, if so, print one answer, repeat */
286         int ret;
287         struct timeval tv, *waittv;
288         fd_set rfd;
289         while(*num_answers > 0) {
290                 memset(&rfd, 0, sizeof(rfd));
291                 memset(&tv, 0, sizeof(tv));
292                 FD_ZERO(&rfd);
293                 FD_SET(fd, &rfd);
294                 if(wait_all) waittv = NULL;
295                 else waittv = &tv;
296                 ret = select(fd+1, &rfd, NULL, NULL, waittv);
297                 if(ret < 0) {
298                         if(errno == EINTR || errno == EAGAIN) continue;
299                         perror("select() failed");
300                         exit(1);
301                 }
302                 if(ret == 0) {
303                         if(wait_all) continue;
304                         return;
305                 }
306                 (*num_answers) -= 1;
307                 recv_one(fd, udp, ssl, buf);
308         }
309 }
310
311 static int get_random(void)
312 {
313         int r;
314         if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) {
315                 return r;
316         }
317         return arc4random();
318 }
319
320 /** send the TCP queries and print answers */
321 static void
322 send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
323         int delay, int num, char** qs)
324 {
325         sldns_buffer* buf = sldns_buffer_new(65553);
326         int fd = open_svr(svr, udp);
327         int i, wait_results = 0;
328         SSL_CTX* ctx = NULL;
329         SSL* ssl = NULL;
330         if(!buf) fatal_exit("out of memory");
331         if(usessl) {
332                 ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
333                 if(!ctx) fatal_exit("cannot create ssl ctx");
334                 ssl = outgoing_ssl_fd(ctx, fd);
335                 if(!ssl) fatal_exit("cannot create ssl");
336                 while(1) {
337                         int r;
338                         ERR_clear_error();
339                         if( (r=SSL_do_handshake(ssl)) == 1)
340                                 break;
341                         r = SSL_get_error(ssl, r);
342                         if(r != SSL_ERROR_WANT_READ &&
343                                 r != SSL_ERROR_WANT_WRITE) {
344                                 log_crypto_err("could not ssl_handshake");
345                                 exit(1);
346                         }
347                 }
348                 if(1) {
349                         X509* x = SSL_get_peer_certificate(ssl);
350                         if(!x) printf("SSL: no peer certificate\n");
351                         else {
352                                 X509_print_fp(stdout, x);
353                                 X509_free(x);
354                         }
355                 }
356         }
357         for(i=0; i<num; i+=3) {
358                 if (delay != 0) {
359 #ifdef HAVE_SLEEP
360                         sleep((unsigned)delay);
361 #else
362                         Sleep(delay*1000);
363 #endif
364                 }
365                 printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
366                 write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
367                         qs[i+1], qs[i+2]);
368                 /* print at least one result */
369                 if(onarrival) {
370                         wait_results += 1; /* one more answer to fetch */
371                         print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
372                 } else if(!noanswer) {
373                         recv_one(fd, udp, ssl, buf);
374                 }
375         }
376         if(onarrival)
377                 print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
378
379         if(usessl) {
380                 SSL_shutdown(ssl);
381                 SSL_free(ssl);
382                 SSL_CTX_free(ctx);
383         }
384 #ifndef USE_WINSOCK
385         close(fd);
386 #else
387         closesocket(fd);
388 #endif
389         sldns_buffer_free(buf);
390         printf("orderly exit\n");
391 }
392
393 #ifdef SIGPIPE
394 /** SIGPIPE handler */
395 static RETSIGTYPE sigh(int sig)
396 {
397         if(sig == SIGPIPE) {
398                 printf("got SIGPIPE, remote connection gone\n");
399                 exit(1);
400         }
401         printf("Got unhandled signal %d\n", sig);
402         exit(1);
403 }
404 #endif /* SIGPIPE */
405
406 /** getopt global, in case header files fail to declare it. */
407 extern int optind;
408 /** getopt global, in case header files fail to declare it. */
409 extern char* optarg;
410
411 /** main program for streamtcp */
412 int main(int argc, char** argv) 
413 {
414         int c;
415         const char* svr = "127.0.0.1";
416         int udp = 0;
417         int noanswer = 0;
418         int onarrival = 0;
419         int usessl = 0;
420         int delay = 0;
421
422 #ifdef USE_WINSOCK
423         WSADATA wsa_data;
424         if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
425                 printf("WSAStartup failed\n");
426                 return 1;
427         }
428 #endif
429
430         /* lock debug start (if any) */
431         log_init(0, 0, 0);
432         checklock_start();
433
434 #ifdef SIGPIPE
435         if(signal(SIGPIPE, &sigh) == SIG_ERR) {
436                 perror("could not install signal handler");
437                 return 1;
438         }
439 #endif
440
441         /* command line options */
442         if(argc == 1) {
443                 usage(argv);
444         }
445         while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
446                 switch(c) {
447                         case 'f':
448                                 svr = optarg;
449                                 break;
450                         case 'a':
451                                 onarrival = 1;
452                                 break;
453                         case 'n':
454                                 noanswer = 1;
455                                 break;
456                         case 'u':
457                                 udp = 1;
458                                 break;
459                         case 's':
460                                 usessl = 1;
461                                 break;
462                         case 'd':
463                                 if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
464                                         printf("error parsing delay, "
465                                             "number expected: %s\n", optarg);
466                                         return 1;
467                                 }
468                                 delay = atoi(optarg);
469                                 break;
470                         case 'h':
471                         case '?':
472                         default:
473                                 usage(argv);
474                 }
475         }
476         argc -= optind;
477         argv += optind;
478
479         if(argc % 3 != 0) {
480                 printf("queries must be multiples of name,type,class\n");
481                 return 1;
482         }
483         if(usessl) {
484 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
485                 ERR_load_SSL_strings();
486 #endif
487 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
488                 OpenSSL_add_all_algorithms();
489 #else
490                 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
491                         | OPENSSL_INIT_ADD_ALL_DIGESTS
492                         | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
493 #endif
494 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
495                 (void)SSL_library_init();
496 #else
497                 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
498 #endif
499         }
500         send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
501         checklock_stop();
502 #ifdef USE_WINSOCK
503         WSACleanup();
504 #endif
505         return 0;
506 }