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 (int)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 # ifndef S_SPLINT_S 489 OpenSSL_add_all_algorithms(); 490 # endif 491 #else 492 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 493 | OPENSSL_INIT_ADD_ALL_DIGESTS 494 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 495 #endif 496 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 497 (void)SSL_library_init(); 498 #else 499 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 500 #endif 501 } 502 send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv); 503 checklock_stop(); 504 #ifdef USE_WINSOCK 505 WSACleanup(); 506 #endif 507 return 0; 508 } 509