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