]> git.saurik.com Git - apple/network_cmds.git/blob - unbound/testcode/streamtcp.c
d93ab966d564343e6507b0110f4e567d7e2522f4
[apple/network_cmds.git] / unbound / 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 }