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 /* 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 arc4random(); 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 } 419