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