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