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/proxy_protocol.h" 53#include "util/data/msgencode.h" 54#include "util/data/msgparse.h" 55#include "util/data/msgreply.h" 56#include "util/data/dname.h" 57#include "sldns/sbuffer.h" 58#include "sldns/str2wire.h" 59#include "sldns/wire2str.h" 60#include <openssl/ssl.h> 61#include <openssl/rand.h> 62#include <openssl/err.h> 63 64#ifndef PF_INET6 65/** define in case streamtcp is compiled on legacy systems */ 66#define PF_INET6 10 67#endif 68 69/** usage information for streamtcp */ 70static void usage(char* argv[]) 71{ 72 printf("usage: %s [options] name type class ...\n", argv[0]); 73 printf(" sends the name-type-class queries over TCP.\n"); 74 printf("-f server what ipaddr@portnr to send the queries to\n"); 75 printf("-p client what ipaddr@portnr to include in PROXYv2\n"); 76 printf("-u use UDP. No retries are attempted.\n"); 77 printf("-n do not wait for an answer.\n"); 78 printf("-a print answers as they arrive.\n"); 79 printf("-d secs delay after connection before sending query\n"); 80 printf("-s use ssl\n"); 81 printf("-h this help text\n"); 82 printf("IXFR=N for the type, sends ixfr query with serial N.\n"); 83 printf("NOTIFY[=N] for the type, sends notify. Can set new zone serial N.\n"); 84 exit(1); 85} 86 87/** open TCP socket to svr */ 88static int 89open_svr(const char* svr, int udp, struct sockaddr_storage* addr, 90 socklen_t* addrlen) 91{ 92 int fd = -1; 93 /* svr can be ip@port */ 94 memset(addr, 0, sizeof(*addr)); 95 if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) { 96 printf("fatal: bad server specs '%s'\n", svr); 97 exit(1); 98 } 99 fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET, 100 udp?SOCK_DGRAM:SOCK_STREAM, 0); 101 if(fd == -1) { 102#ifndef USE_WINSOCK 103 perror("socket() error"); 104#else 105 printf("socket: %s\n", wsa_strerror(WSAGetLastError())); 106#endif 107 exit(1); 108 } 109 if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) { 110#ifndef USE_WINSOCK 111 perror("connect() error"); 112#else 113 printf("connect: %s\n", wsa_strerror(WSAGetLastError())); 114#endif 115 exit(1); 116 } 117 return fd; 118} 119 120/** Append a SOA record with serial number */ 121static void 122write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo, 123 uint32_t serial) 124{ 125 sldns_buffer_set_position(buf, sldns_buffer_limit(buf)); 126 sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf)); 127 /* Write compressed reference to the query */ 128 sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE)); 129 sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA); 130 sldns_buffer_write_u16(buf, qinfo->qclass); 131 sldns_buffer_write_u32(buf, 3600); /* TTL */ 132 sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */ 133 sldns_buffer_write_u8(buf, 0); /* primary "." */ 134 sldns_buffer_write_u8(buf, 0); /* email "." */ 135 sldns_buffer_write_u32(buf, serial); /* serial */ 136 sldns_buffer_write_u32(buf, 0); /* refresh */ 137 sldns_buffer_write_u32(buf, 0); /* retry */ 138 sldns_buffer_write_u32(buf, 0); /* expire */ 139 sldns_buffer_write_u32(buf, 0); /* minimum */ 140 sldns_buffer_flip(buf); 141} 142 143/** write a query over the TCP fd */ 144static void 145write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, 146 sldns_buffer* proxy_buf, int pp2_parsed, 147 const char* strname, const char* strtype, const char* strclass) 148{ 149 struct query_info qinfo; 150 size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf); 151 int have_serial = 0, is_notify = 0; 152 uint32_t serial = 0; 153 /* qname */ 154 qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); 155 if(!qinfo.qname) { 156 printf("cannot parse query name: '%s'\n", strname); 157 exit(1); 158 } 159 160 /* qtype */ 161 if(strncasecmp(strtype, "IXFR=", 5) == 0) { 162 serial = (uint32_t)atoi(strtype+5); 163 have_serial = 1; 164 qinfo.qtype = LDNS_RR_TYPE_IXFR; 165 } else if(strcasecmp(strtype, "NOTIFY") == 0) { 166 is_notify = 1; 167 qinfo.qtype = LDNS_RR_TYPE_SOA; 168 } else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) { 169 serial = (uint32_t)atoi(strtype+7); 170 have_serial = 1; 171 is_notify = 1; 172 qinfo.qtype = LDNS_RR_TYPE_SOA; 173 } else { 174 qinfo.qtype = sldns_get_rr_type_by_name(strtype); 175 if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) { 176 printf("cannot parse query type: '%s'\n", strtype); 177 exit(1); 178 } 179 } 180 /* qclass */ 181 qinfo.qclass = sldns_get_rr_class_by_name(strclass); 182 if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) { 183 printf("cannot parse query class: '%s'\n", strclass); 184 exit(1); 185 } 186 187 /* clear local alias */ 188 qinfo.local_alias = NULL; 189 190 /* make query */ 191 qinfo_query_encode(buf, &qinfo); 192 sldns_buffer_write_u16_at(buf, 0, id); 193 sldns_buffer_write_u16_at(buf, 2, BIT_RD); 194 195 if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) { 196 /* Attach serial to SOA record in the authority section. */ 197 write_soa_serial_to_buf(buf, &qinfo, serial); 198 LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1); 199 } 200 if(is_notify) { 201 LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY); 202 LDNS_RD_CLR(sldns_buffer_begin(buf)); 203 LDNS_AA_SET(sldns_buffer_begin(buf)); 204 if(have_serial) { 205 write_soa_serial_to_buf(buf, &qinfo, serial); 206 LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1); 207 } 208 } 209 210 if(1) { 211 /* add EDNS DO */ 212 struct edns_data edns; 213 memset(&edns, 0, sizeof(edns)); 214 edns.edns_present = 1; 215 edns.bits = EDNS_DO; 216 edns.udp_size = 4096; 217 if(sldns_buffer_capacity(buf) >= 218 sldns_buffer_limit(buf)+calc_edns_field_size(&edns)) 219 attach_edns_record(buf, &edns); 220 } 221 222 /* we need to send the PROXYv2 information in every UDP message */ 223 if(udp && pp2_parsed) { 224 /* append the proxy_buf with the buf's content 225 * and use that for sending */ 226 if(sldns_buffer_capacity(proxy_buf) < 227 sldns_buffer_limit(proxy_buf) + 228 sldns_buffer_limit(buf)) { 229 printf("buffer too small for packet + proxy"); 230 exit(1); 231 } 232 sldns_buffer_clear(proxy_buf); 233 sldns_buffer_skip(proxy_buf, proxy_buf_limit); 234 sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf), 235 sldns_buffer_limit(buf)); 236 sldns_buffer_flip(proxy_buf); 237 buf = proxy_buf; 238 } 239 240 /* send it */ 241 if(!udp) { 242 uint16_t len = (uint16_t)sldns_buffer_limit(buf); 243 len = htons(len); 244 if(ssl) { 245 if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { 246 log_crypto_err("cannot SSL_write"); 247 exit(1); 248 } 249 } else { 250 if(send(fd, (void*)&len, sizeof(len), 0) < 251 (ssize_t)sizeof(len)){ 252#ifndef USE_WINSOCK 253 perror("send() len failed"); 254#else 255 printf("send len: %s\n", 256 wsa_strerror(WSAGetLastError())); 257#endif 258 exit(1); 259 } 260 } 261 } 262 if(ssl) { 263 if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), 264 (int)sldns_buffer_limit(buf)) <= 0) { 265 log_crypto_err("cannot SSL_write"); 266 exit(1); 267 } 268 } else { 269 if(send(fd, (void*)sldns_buffer_begin(buf), 270 sldns_buffer_limit(buf), 0) < 271 (ssize_t)sldns_buffer_limit(buf)) { 272#ifndef USE_WINSOCK 273 perror("send() data failed"); 274#else 275 printf("send data: %s\n", 276 wsa_strerror(WSAGetLastError())); 277#endif 278 exit(1); 279 } 280 } 281 282 /* reset the proxy_buf for next packet */ 283 sldns_buffer_set_limit(proxy_buf, proxy_buf_limit); 284 free(qinfo.qname); 285} 286 287/** receive DNS datagram over TCP and print it */ 288static void 289recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf) 290{ 291 size_t i; 292 char* pktstr; 293 uint16_t len; 294 if(!udp) { 295 if(ssl) { 296 int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len)); 297 if(sr == 0) { 298 printf("ssl: stream closed\n"); 299 exit(1); 300 } 301 if(sr < 0) { 302 log_crypto_err("could not SSL_read"); 303 exit(1); 304 } 305 } else { 306 ssize_t r = recv(fd, (void*)&len, sizeof(len), 0); 307 if(r == 0) { 308 printf("recv: stream closed\n"); 309 exit(1); 310 } 311 if(r < (ssize_t)sizeof(len)) { 312#ifndef USE_WINSOCK 313 perror("read() len failed"); 314#else 315 printf("read len: %s\n", 316 wsa_strerror(WSAGetLastError())); 317#endif 318 exit(1); 319 } 320 } 321 len = ntohs(len); 322 sldns_buffer_clear(buf); 323 sldns_buffer_set_limit(buf, len); 324 if(ssl) { 325 int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf), 326 (int)len); 327 if(r <= 0) { 328 log_crypto_err("could not SSL_read"); 329 exit(1); 330 } 331 if(r != (int)len) 332 fatal_exit("ssl_read %d of %d", r, len); 333 } else { 334 if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) < 335 (ssize_t)len) { 336#ifndef USE_WINSOCK 337 perror("read() data failed"); 338#else 339 printf("read data: %s\n", 340 wsa_strerror(WSAGetLastError())); 341#endif 342 exit(1); 343 } 344 } 345 } else { 346 ssize_t l; 347 sldns_buffer_clear(buf); 348 if((l=recv(fd, (void*)sldns_buffer_begin(buf), 349 sldns_buffer_capacity(buf), 0)) < 0) { 350#ifndef USE_WINSOCK 351 perror("read() data failed"); 352#else 353 printf("read data: %s\n", 354 wsa_strerror(WSAGetLastError())); 355#endif 356 exit(1); 357 } 358 sldns_buffer_set_limit(buf, (size_t)l); 359 len = (size_t)l; 360 } 361 printf("\nnext received packet\n"); 362 printf("data[%d] ", (int)sldns_buffer_limit(buf)); 363 for(i=0; i<sldns_buffer_limit(buf); i++) { 364 const char* hex = "0123456789ABCDEF"; 365 printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4], 366 hex[sldns_buffer_read_u8_at(buf, i)&0x0f]); 367 } 368 printf("\n"); 369 370 pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len); 371 printf("%s", pktstr); 372 free(pktstr); 373} 374 375/** see if we can receive any results */ 376static void 377print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf, 378 int* num_answers, int wait_all) 379{ 380 /* see if the fd can read, if so, print one answer, repeat */ 381 int ret; 382 struct timeval tv, *waittv; 383 fd_set rfd; 384 while(*num_answers > 0) { 385 memset(&rfd, 0, sizeof(rfd)); 386 memset(&tv, 0, sizeof(tv)); 387 FD_ZERO(&rfd); 388 FD_SET(fd, &rfd); 389 if(wait_all) waittv = NULL; 390 else waittv = &tv; 391 ret = select(fd+1, &rfd, NULL, NULL, waittv); 392 if(ret < 0) { 393 if(errno == EINTR || errno == EAGAIN) continue; 394 perror("select() failed"); 395 exit(1); 396 } 397 if(ret == 0) { 398 if(wait_all) continue; 399 return; 400 } 401 (*num_answers) -= 1; 402 recv_one(fd, udp, ssl, buf); 403 } 404} 405 406static int get_random(void) 407{ 408 int r; 409 if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) { 410 return r; 411 } 412 return (int)arc4random(); 413} 414 415/* parse the pp2_client and populate the proxy_buffer 416 * It doesn't populate the destination parts. */ 417static int parse_pp2_client(const char* pp2_client, int udp, 418 sldns_buffer* proxy_buf) 419{ 420 struct sockaddr_storage pp2_addr; 421 size_t bytes_written; 422 socklen_t pp2_addrlen = 0; 423 memset(&pp2_addr, 0, sizeof(pp2_addr)); 424 if(*pp2_client == 0) return 0; 425 if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) { 426 printf("fatal: bad proxy client specs '%s'\n", pp2_client); 427 exit(1); 428 } 429 sldns_buffer_clear(proxy_buf); 430 bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf), 431 sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp); 432 sldns_buffer_set_position(proxy_buf, bytes_written); 433 sldns_buffer_flip(proxy_buf); 434 return 1; 435} 436 437/** send the TCP queries and print answers */ 438static void 439send_em(const char* svr, const char* pp2_client, int udp, int usessl, 440 int noanswer, int onarrival, int delay, int num, char** qs) 441{ 442 struct sockaddr_storage svr_addr; 443 socklen_t svr_addrlen; 444 int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen); 445 int i, wait_results = 0, pp2_parsed; 446 SSL_CTX* ctx = NULL; 447 SSL* ssl = NULL; 448 sldns_buffer* buf = sldns_buffer_new(65553); 449 sldns_buffer* proxy_buf = sldns_buffer_new(65553); 450 if(!buf || !proxy_buf) { 451 sldns_buffer_free(buf); 452 sldns_buffer_free(proxy_buf); 453 fatal_exit("out of memory"); 454 } 455 pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf); 456 if(usessl) { 457 ctx = connect_sslctx_create(NULL, NULL, NULL, 0); 458 if(!ctx) fatal_exit("cannot create ssl ctx"); 459 ssl = outgoing_ssl_fd(ctx, fd); 460 if(!ssl) fatal_exit("cannot create ssl"); 461 while(1) { 462 int r; 463 ERR_clear_error(); 464 if( (r=SSL_do_handshake(ssl)) == 1) 465 break; 466 r = SSL_get_error(ssl, r); 467 if(r != SSL_ERROR_WANT_READ && 468 r != SSL_ERROR_WANT_WRITE) { 469 log_crypto_err_io("could not ssl_handshake", r); 470 exit(1); 471 } 472 } 473 if(1) { 474 X509* x = SSL_get_peer_certificate(ssl); 475 if(!x) printf("SSL: no peer certificate\n"); 476 else { 477 X509_print_fp(stdout, x); 478 X509_free(x); 479 } 480 } 481 } 482 /* Send the PROXYv2 information once per stream */ 483 if(!udp && pp2_parsed) { 484 if(ssl) { 485 if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf), 486 (int)sldns_buffer_limit(proxy_buf)) <= 0) { 487 log_crypto_err("cannot SSL_write"); 488 exit(1); 489 } 490 } else { 491 if(send(fd, (void*)sldns_buffer_begin(proxy_buf), 492 sldns_buffer_limit(proxy_buf), 0) < 493 (ssize_t)sldns_buffer_limit(proxy_buf)) { 494#ifndef USE_WINSOCK 495 perror("send() data failed"); 496#else 497 printf("send data: %s\n", 498 wsa_strerror(WSAGetLastError())); 499#endif 500 exit(1); 501 } 502 } 503 } 504 for(i=0; i<num; i+=3) { 505 if (delay != 0) { 506#ifdef HAVE_SLEEP 507 sleep((unsigned)delay); 508#else 509 Sleep(delay*1000); 510#endif 511 } 512 printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]); 513 write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf, 514 pp2_parsed, 515 qs[i], qs[i+1], qs[i+2]); 516 /* print at least one result */ 517 if(onarrival) { 518 wait_results += 1; /* one more answer to fetch */ 519 print_any_answers(fd, udp, ssl, buf, &wait_results, 0); 520 } else if(!noanswer) { 521 recv_one(fd, udp, ssl, buf); 522 } 523 } 524 if(onarrival) 525 print_any_answers(fd, udp, ssl, buf, &wait_results, 1); 526 527 if(usessl) { 528 SSL_shutdown(ssl); 529 SSL_free(ssl); 530 SSL_CTX_free(ctx); 531 } 532 sock_close(fd); 533 sldns_buffer_free(buf); 534 sldns_buffer_free(proxy_buf); 535 printf("orderly exit\n"); 536} 537 538#ifdef SIGPIPE 539/** SIGPIPE handler */ 540static RETSIGTYPE sigh(int sig) 541{ 542 char str[] = "Got unhandled signal \n"; 543 if(sig == SIGPIPE) { 544 char* strpipe = "got SIGPIPE, remote connection gone\n"; 545 /* simple cast to void will not silence Wunused-result */ 546 (void)!write(STDOUT_FILENO, strpipe, strlen(strpipe)); 547 exit(1); 548 } 549 str[21] = '0' + (sig/10)%10; 550 str[22] = '0' + sig%10; 551 /* simple cast to void will not silence Wunused-result */ 552 (void)!write(STDOUT_FILENO, str, strlen(str)); 553 exit(1); 554} 555#endif /* SIGPIPE */ 556 557/** getopt global, in case header files fail to declare it. */ 558extern int optind; 559/** getopt global, in case header files fail to declare it. */ 560extern char* optarg; 561 562/** main program for streamtcp */ 563int main(int argc, char** argv) 564{ 565 int c; 566 const char* svr = "127.0.0.1"; 567 const char* pp2_client = ""; 568 int udp = 0; 569 int noanswer = 0; 570 int onarrival = 0; 571 int usessl = 0; 572 int delay = 0; 573 574#ifdef USE_WINSOCK 575 WSADATA wsa_data; 576 if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) { 577 printf("WSAStartup failed\n"); 578 return 1; 579 } 580#endif 581 582 /* lock debug start (if any) */ 583 checklock_start(); 584 log_init(0, 0, 0); 585 586#ifdef SIGPIPE 587 if(signal(SIGPIPE, &sigh) == SIG_ERR) { 588 perror("could not install signal handler"); 589 return 1; 590 } 591#endif 592 593 /* command line options */ 594 if(argc == 1) { 595 usage(argv); 596 } 597 while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) { 598 switch(c) { 599 case 'f': 600 svr = optarg; 601 break; 602 case 'p': 603 pp2_client = optarg; 604 pp_init(&sldns_write_uint16, 605 &sldns_write_uint32); 606 break; 607 case 'a': 608 onarrival = 1; 609 break; 610 case 'n': 611 noanswer = 1; 612 break; 613 case 'u': 614 udp = 1; 615 break; 616 case 's': 617 usessl = 1; 618 break; 619 case 'd': 620 if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) { 621 printf("error parsing delay, " 622 "number expected: %s\n", optarg); 623 return 1; 624 } 625 delay = atoi(optarg); 626 break; 627 case 'h': 628 case '?': 629 default: 630 usage(argv); 631 } 632 } 633 argc -= optind; 634 argv += optind; 635 636 if(argc % 3 != 0) { 637 printf("queries must be multiples of name,type,class\n"); 638 return 1; 639 } 640 if(usessl) { 641#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 642 ERR_load_SSL_strings(); 643#endif 644#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 645# ifndef S_SPLINT_S 646 OpenSSL_add_all_algorithms(); 647# endif 648#else 649 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 650 | OPENSSL_INIT_ADD_ALL_DIGESTS 651 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 652#endif 653#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 654 (void)SSL_library_init(); 655#else 656 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 657#endif 658 } 659 send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv); 660 checklock_stop(); 661#ifdef USE_WINSOCK 662 WSACleanup(); 663#endif 664 return 0; 665} 666