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