1712b2f30Ssthen /* 2712b2f30Ssthen * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp. 3712b2f30Ssthen * 4712b2f30Ssthen * Copyright (c) 2008, NLnet Labs. All rights reserved. 5712b2f30Ssthen * 6712b2f30Ssthen * This software is open source. 7712b2f30Ssthen * 8712b2f30Ssthen * Redistribution and use in source and binary forms, with or without 9712b2f30Ssthen * modification, are permitted provided that the following conditions 10712b2f30Ssthen * are met: 11712b2f30Ssthen * 12712b2f30Ssthen * Redistributions of source code must retain the above copyright notice, 13712b2f30Ssthen * this list of conditions and the following disclaimer. 14712b2f30Ssthen * 15712b2f30Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16712b2f30Ssthen * this list of conditions and the following disclaimer in the documentation 17712b2f30Ssthen * and/or other materials provided with the distribution. 18712b2f30Ssthen * 19712b2f30Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20712b2f30Ssthen * be used to endorse or promote products derived from this software without 21712b2f30Ssthen * specific prior written permission. 22712b2f30Ssthen * 23712b2f30Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24712b2f30Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25712b2f30Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26712b2f30Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27712b2f30Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28712b2f30Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29712b2f30Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30712b2f30Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31712b2f30Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32712b2f30Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33712b2f30Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34712b2f30Ssthen */ 35712b2f30Ssthen 36712b2f30Ssthen /** 37712b2f30Ssthen * \file 38712b2f30Ssthen * 39712b2f30Ssthen * This program performs multiple DNS queries on a TCP stream. 40712b2f30Ssthen */ 41712b2f30Ssthen 42712b2f30Ssthen #include "config.h" 43712b2f30Ssthen #ifdef HAVE_GETOPT_H 44712b2f30Ssthen #include <getopt.h> 45712b2f30Ssthen #endif 46712b2f30Ssthen #include <signal.h> 477bc20e6dSsthen #include <stdlib.h> 487bc20e6dSsthen #include <unistd.h> 49712b2f30Ssthen #include "util/locks.h" 50712b2f30Ssthen #include "util/log.h" 51712b2f30Ssthen #include "util/net_help.h" 520e9b6f9fSsthen #include "util/proxy_protocol.h" 53712b2f30Ssthen #include "util/data/msgencode.h" 54712b2f30Ssthen #include "util/data/msgparse.h" 55712b2f30Ssthen #include "util/data/msgreply.h" 56712b2f30Ssthen #include "util/data/dname.h" 57712b2f30Ssthen #include "sldns/sbuffer.h" 58712b2f30Ssthen #include "sldns/str2wire.h" 59712b2f30Ssthen #include "sldns/wire2str.h" 60712b2f30Ssthen #include <openssl/ssl.h> 61712b2f30Ssthen #include <openssl/rand.h> 62712b2f30Ssthen #include <openssl/err.h> 63712b2f30Ssthen 64712b2f30Ssthen #ifndef PF_INET6 65712b2f30Ssthen /** define in case streamtcp is compiled on legacy systems */ 66712b2f30Ssthen #define PF_INET6 10 67712b2f30Ssthen #endif 68712b2f30Ssthen 69712b2f30Ssthen /** usage information for streamtcp */ 70712b2f30Ssthen static void usage(char* argv[]) 71712b2f30Ssthen { 72712b2f30Ssthen printf("usage: %s [options] name type class ...\n", argv[0]); 73712b2f30Ssthen printf(" sends the name-type-class queries over TCP.\n"); 74712b2f30Ssthen printf("-f server what ipaddr@portnr to send the queries to\n"); 750e9b6f9fSsthen printf("-p client what ipaddr@portnr to include in PROXYv2\n"); 76712b2f30Ssthen printf("-u use UDP. No retries are attempted.\n"); 77712b2f30Ssthen printf("-n do not wait for an answer.\n"); 7866a34dc2Ssthen printf("-a print answers as they arrive.\n"); 797bc20e6dSsthen printf("-d secs delay after connection before sending query\n"); 80712b2f30Ssthen printf("-s use ssl\n"); 81712b2f30Ssthen printf("-h this help text\n"); 829c7f0a49Ssthen printf("IXFR=N for the type, sends ixfr query with serial N.\n"); 839c7f0a49Ssthen printf("NOTIFY[=N] for the type, sends notify. Can set new zone serial N.\n"); 84712b2f30Ssthen exit(1); 85712b2f30Ssthen } 86712b2f30Ssthen 87712b2f30Ssthen /** open TCP socket to svr */ 88712b2f30Ssthen static int 890e9b6f9fSsthen open_svr(const char* svr, int udp, struct sockaddr_storage* addr, 900e9b6f9fSsthen socklen_t* addrlen) 91712b2f30Ssthen { 92712b2f30Ssthen int fd = -1; 93712b2f30Ssthen /* svr can be ip@port */ 940e9b6f9fSsthen memset(addr, 0, sizeof(*addr)); 950e9b6f9fSsthen if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) { 96712b2f30Ssthen printf("fatal: bad server specs '%s'\n", svr); 97712b2f30Ssthen exit(1); 98712b2f30Ssthen } 990e9b6f9fSsthen fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET, 100712b2f30Ssthen udp?SOCK_DGRAM:SOCK_STREAM, 0); 101712b2f30Ssthen if(fd == -1) { 102712b2f30Ssthen #ifndef USE_WINSOCK 103712b2f30Ssthen perror("socket() error"); 104712b2f30Ssthen #else 105712b2f30Ssthen printf("socket: %s\n", wsa_strerror(WSAGetLastError())); 106712b2f30Ssthen #endif 107712b2f30Ssthen exit(1); 108712b2f30Ssthen } 1090e9b6f9fSsthen if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) { 110712b2f30Ssthen #ifndef USE_WINSOCK 111712b2f30Ssthen perror("connect() error"); 112712b2f30Ssthen #else 113712b2f30Ssthen printf("connect: %s\n", wsa_strerror(WSAGetLastError())); 114712b2f30Ssthen #endif 115712b2f30Ssthen exit(1); 116712b2f30Ssthen } 117712b2f30Ssthen return fd; 118712b2f30Ssthen } 119712b2f30Ssthen 1209c7f0a49Ssthen /** Append a SOA record with serial number */ 1219c7f0a49Ssthen static void 1229c7f0a49Ssthen write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo, 1239c7f0a49Ssthen uint32_t serial) 1249c7f0a49Ssthen { 1259c7f0a49Ssthen sldns_buffer_set_position(buf, sldns_buffer_limit(buf)); 1269c7f0a49Ssthen sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf)); 1279c7f0a49Ssthen /* Write compressed reference to the query */ 1289c7f0a49Ssthen sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE)); 1299c7f0a49Ssthen sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA); 1309c7f0a49Ssthen sldns_buffer_write_u16(buf, qinfo->qclass); 1319c7f0a49Ssthen sldns_buffer_write_u32(buf, 3600); /* TTL */ 1329c7f0a49Ssthen sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */ 1339c7f0a49Ssthen sldns_buffer_write_u8(buf, 0); /* primary "." */ 1349c7f0a49Ssthen sldns_buffer_write_u8(buf, 0); /* email "." */ 1359c7f0a49Ssthen sldns_buffer_write_u32(buf, serial); /* serial */ 1369c7f0a49Ssthen sldns_buffer_write_u32(buf, 0); /* refresh */ 1379c7f0a49Ssthen sldns_buffer_write_u32(buf, 0); /* retry */ 1389c7f0a49Ssthen sldns_buffer_write_u32(buf, 0); /* expire */ 1399c7f0a49Ssthen sldns_buffer_write_u32(buf, 0); /* minimum */ 1409c7f0a49Ssthen sldns_buffer_flip(buf); 1419c7f0a49Ssthen } 1429c7f0a49Ssthen 143712b2f30Ssthen /** write a query over the TCP fd */ 144712b2f30Ssthen static void 145712b2f30Ssthen write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, 1460e9b6f9fSsthen sldns_buffer* proxy_buf, int pp2_parsed, 147712b2f30Ssthen const char* strname, const char* strtype, const char* strclass) 148712b2f30Ssthen { 149712b2f30Ssthen struct query_info qinfo; 1500e9b6f9fSsthen size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf); 1519c7f0a49Ssthen int have_serial = 0, is_notify = 0; 1529c7f0a49Ssthen uint32_t serial = 0; 153712b2f30Ssthen /* qname */ 154712b2f30Ssthen qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); 155712b2f30Ssthen if(!qinfo.qname) { 156712b2f30Ssthen printf("cannot parse query name: '%s'\n", strname); 157712b2f30Ssthen exit(1); 158712b2f30Ssthen } 159712b2f30Ssthen 1609c7f0a49Ssthen /* qtype */ 1619c7f0a49Ssthen if(strncasecmp(strtype, "IXFR=", 5) == 0) { 1629c7f0a49Ssthen serial = (uint32_t)atoi(strtype+5); 1639c7f0a49Ssthen have_serial = 1; 1649c7f0a49Ssthen qinfo.qtype = LDNS_RR_TYPE_IXFR; 1659c7f0a49Ssthen } else if(strcasecmp(strtype, "NOTIFY") == 0) { 1669c7f0a49Ssthen is_notify = 1; 1679c7f0a49Ssthen qinfo.qtype = LDNS_RR_TYPE_SOA; 1689c7f0a49Ssthen } else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) { 1699c7f0a49Ssthen serial = (uint32_t)atoi(strtype+7); 1709c7f0a49Ssthen have_serial = 1; 1719c7f0a49Ssthen is_notify = 1; 1729c7f0a49Ssthen qinfo.qtype = LDNS_RR_TYPE_SOA; 1739c7f0a49Ssthen } else { 174712b2f30Ssthen qinfo.qtype = sldns_get_rr_type_by_name(strtype); 175437d2860Ssthen if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) { 176437d2860Ssthen printf("cannot parse query type: '%s'\n", strtype); 177437d2860Ssthen exit(1); 178437d2860Ssthen } 1799c7f0a49Ssthen } 1809c7f0a49Ssthen /* qclass */ 181712b2f30Ssthen qinfo.qclass = sldns_get_rr_class_by_name(strclass); 182437d2860Ssthen if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) { 183437d2860Ssthen printf("cannot parse query class: '%s'\n", strclass); 184437d2860Ssthen exit(1); 185437d2860Ssthen } 186712b2f30Ssthen 187712b2f30Ssthen /* clear local alias */ 188712b2f30Ssthen qinfo.local_alias = NULL; 189712b2f30Ssthen 190712b2f30Ssthen /* make query */ 191712b2f30Ssthen qinfo_query_encode(buf, &qinfo); 192712b2f30Ssthen sldns_buffer_write_u16_at(buf, 0, id); 193712b2f30Ssthen sldns_buffer_write_u16_at(buf, 2, BIT_RD); 194712b2f30Ssthen 1959c7f0a49Ssthen if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) { 1969c7f0a49Ssthen /* Attach serial to SOA record in the authority section. */ 1979c7f0a49Ssthen write_soa_serial_to_buf(buf, &qinfo, serial); 1989c7f0a49Ssthen LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1); 1999c7f0a49Ssthen } 2009c7f0a49Ssthen if(is_notify) { 2019c7f0a49Ssthen LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY); 2029c7f0a49Ssthen LDNS_RD_CLR(sldns_buffer_begin(buf)); 2039c7f0a49Ssthen LDNS_AA_SET(sldns_buffer_begin(buf)); 2049c7f0a49Ssthen if(have_serial) { 2059c7f0a49Ssthen write_soa_serial_to_buf(buf, &qinfo, serial); 2069c7f0a49Ssthen LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1); 2079c7f0a49Ssthen } 2089c7f0a49Ssthen } 2099c7f0a49Ssthen 210712b2f30Ssthen if(1) { 211712b2f30Ssthen /* add EDNS DO */ 212712b2f30Ssthen struct edns_data edns; 213712b2f30Ssthen memset(&edns, 0, sizeof(edns)); 214712b2f30Ssthen edns.edns_present = 1; 215712b2f30Ssthen edns.bits = EDNS_DO; 216712b2f30Ssthen edns.udp_size = 4096; 217712b2f30Ssthen if(sldns_buffer_capacity(buf) >= 218712b2f30Ssthen sldns_buffer_limit(buf)+calc_edns_field_size(&edns)) 219712b2f30Ssthen attach_edns_record(buf, &edns); 220712b2f30Ssthen } 221712b2f30Ssthen 2220e9b6f9fSsthen /* we need to send the PROXYv2 information in every UDP message */ 2230e9b6f9fSsthen if(udp && pp2_parsed) { 2240e9b6f9fSsthen /* append the proxy_buf with the buf's content 2250e9b6f9fSsthen * and use that for sending */ 2260e9b6f9fSsthen if(sldns_buffer_capacity(proxy_buf) < 2270e9b6f9fSsthen sldns_buffer_limit(proxy_buf) + 2280e9b6f9fSsthen sldns_buffer_limit(buf)) { 2290e9b6f9fSsthen printf("buffer too small for packet + proxy"); 2300e9b6f9fSsthen exit(1); 2310e9b6f9fSsthen } 2320e9b6f9fSsthen sldns_buffer_clear(proxy_buf); 2330e9b6f9fSsthen sldns_buffer_skip(proxy_buf, proxy_buf_limit); 2340e9b6f9fSsthen sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf), 2350e9b6f9fSsthen sldns_buffer_limit(buf)); 2360e9b6f9fSsthen sldns_buffer_flip(proxy_buf); 2370e9b6f9fSsthen buf = proxy_buf; 2380e9b6f9fSsthen } 2390e9b6f9fSsthen 240712b2f30Ssthen /* send it */ 241712b2f30Ssthen if(!udp) { 2420e9b6f9fSsthen uint16_t len = (uint16_t)sldns_buffer_limit(buf); 243712b2f30Ssthen len = htons(len); 244712b2f30Ssthen if(ssl) { 245712b2f30Ssthen if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { 246712b2f30Ssthen log_crypto_err("cannot SSL_write"); 247712b2f30Ssthen exit(1); 248712b2f30Ssthen } 249712b2f30Ssthen } else { 250712b2f30Ssthen if(send(fd, (void*)&len, sizeof(len), 0) < 251712b2f30Ssthen (ssize_t)sizeof(len)){ 252712b2f30Ssthen #ifndef USE_WINSOCK 253712b2f30Ssthen perror("send() len failed"); 254712b2f30Ssthen #else 255712b2f30Ssthen printf("send len: %s\n", 256712b2f30Ssthen wsa_strerror(WSAGetLastError())); 257712b2f30Ssthen #endif 258712b2f30Ssthen exit(1); 259712b2f30Ssthen } 260712b2f30Ssthen } 261712b2f30Ssthen } 262712b2f30Ssthen if(ssl) { 263712b2f30Ssthen if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), 264712b2f30Ssthen (int)sldns_buffer_limit(buf)) <= 0) { 265712b2f30Ssthen log_crypto_err("cannot SSL_write"); 266712b2f30Ssthen exit(1); 267712b2f30Ssthen } 268712b2f30Ssthen } else { 269712b2f30Ssthen if(send(fd, (void*)sldns_buffer_begin(buf), 270712b2f30Ssthen sldns_buffer_limit(buf), 0) < 271712b2f30Ssthen (ssize_t)sldns_buffer_limit(buf)) { 272712b2f30Ssthen #ifndef USE_WINSOCK 273712b2f30Ssthen perror("send() data failed"); 274712b2f30Ssthen #else 2750e9b6f9fSsthen printf("send data: %s\n", 2760e9b6f9fSsthen wsa_strerror(WSAGetLastError())); 277712b2f30Ssthen #endif 278712b2f30Ssthen exit(1); 279712b2f30Ssthen } 280712b2f30Ssthen } 281712b2f30Ssthen 2820e9b6f9fSsthen /* reset the proxy_buf for next packet */ 2830e9b6f9fSsthen sldns_buffer_set_limit(proxy_buf, proxy_buf_limit); 284712b2f30Ssthen free(qinfo.qname); 285712b2f30Ssthen } 286712b2f30Ssthen 287712b2f30Ssthen /** receive DNS datagram over TCP and print it */ 288712b2f30Ssthen static void 289712b2f30Ssthen recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf) 290712b2f30Ssthen { 291d7b4a113Ssthen size_t i; 292712b2f30Ssthen char* pktstr; 293712b2f30Ssthen uint16_t len; 294712b2f30Ssthen if(!udp) { 295712b2f30Ssthen if(ssl) { 29666a34dc2Ssthen int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len)); 29766a34dc2Ssthen if(sr == 0) { 29866a34dc2Ssthen printf("ssl: stream closed\n"); 29966a34dc2Ssthen exit(1); 30066a34dc2Ssthen } 30166a34dc2Ssthen if(sr < 0) { 302712b2f30Ssthen log_crypto_err("could not SSL_read"); 303712b2f30Ssthen exit(1); 304712b2f30Ssthen } 305712b2f30Ssthen } else { 30666a34dc2Ssthen ssize_t r = recv(fd, (void*)&len, sizeof(len), 0); 30766a34dc2Ssthen if(r == 0) { 30866a34dc2Ssthen printf("recv: stream closed\n"); 30966a34dc2Ssthen exit(1); 31066a34dc2Ssthen } 31166a34dc2Ssthen if(r < (ssize_t)sizeof(len)) { 312712b2f30Ssthen #ifndef USE_WINSOCK 313712b2f30Ssthen perror("read() len failed"); 314712b2f30Ssthen #else 315712b2f30Ssthen printf("read len: %s\n", 316712b2f30Ssthen wsa_strerror(WSAGetLastError())); 317712b2f30Ssthen #endif 318712b2f30Ssthen exit(1); 319712b2f30Ssthen } 320712b2f30Ssthen } 321712b2f30Ssthen len = ntohs(len); 322712b2f30Ssthen sldns_buffer_clear(buf); 323712b2f30Ssthen sldns_buffer_set_limit(buf, len); 324712b2f30Ssthen if(ssl) { 325712b2f30Ssthen int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf), 326712b2f30Ssthen (int)len); 327712b2f30Ssthen if(r <= 0) { 328712b2f30Ssthen log_crypto_err("could not SSL_read"); 329712b2f30Ssthen exit(1); 330712b2f30Ssthen } 331712b2f30Ssthen if(r != (int)len) 332712b2f30Ssthen fatal_exit("ssl_read %d of %d", r, len); 333712b2f30Ssthen } else { 334712b2f30Ssthen if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) < 335712b2f30Ssthen (ssize_t)len) { 336712b2f30Ssthen #ifndef USE_WINSOCK 337712b2f30Ssthen perror("read() data failed"); 338712b2f30Ssthen #else 339712b2f30Ssthen printf("read data: %s\n", 340712b2f30Ssthen wsa_strerror(WSAGetLastError())); 341712b2f30Ssthen #endif 342712b2f30Ssthen exit(1); 343712b2f30Ssthen } 344712b2f30Ssthen } 345712b2f30Ssthen } else { 346712b2f30Ssthen ssize_t l; 347712b2f30Ssthen sldns_buffer_clear(buf); 348712b2f30Ssthen if((l=recv(fd, (void*)sldns_buffer_begin(buf), 349712b2f30Ssthen sldns_buffer_capacity(buf), 0)) < 0) { 350712b2f30Ssthen #ifndef USE_WINSOCK 351712b2f30Ssthen perror("read() data failed"); 352712b2f30Ssthen #else 353712b2f30Ssthen printf("read data: %s\n", 354712b2f30Ssthen wsa_strerror(WSAGetLastError())); 355712b2f30Ssthen #endif 356712b2f30Ssthen exit(1); 357712b2f30Ssthen } 358712b2f30Ssthen sldns_buffer_set_limit(buf, (size_t)l); 359712b2f30Ssthen len = (size_t)l; 360712b2f30Ssthen } 361712b2f30Ssthen printf("\nnext received packet\n"); 362d7b4a113Ssthen printf("data[%d] ", (int)sldns_buffer_limit(buf)); 363d7b4a113Ssthen for(i=0; i<sldns_buffer_limit(buf); i++) { 364d7b4a113Ssthen const char* hex = "0123456789ABCDEF"; 365d7b4a113Ssthen printf("%c%c", hex[(sldns_buffer_read_u8_at(buf, i)&0xf0)>>4], 366d7b4a113Ssthen hex[sldns_buffer_read_u8_at(buf, i)&0x0f]); 367d7b4a113Ssthen } 368d7b4a113Ssthen printf("\n"); 369712b2f30Ssthen 370712b2f30Ssthen pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len); 371712b2f30Ssthen printf("%s", pktstr); 372712b2f30Ssthen free(pktstr); 373712b2f30Ssthen } 374712b2f30Ssthen 37566a34dc2Ssthen /** see if we can receive any results */ 37666a34dc2Ssthen static void 37766a34dc2Ssthen print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf, 37866a34dc2Ssthen int* num_answers, int wait_all) 37966a34dc2Ssthen { 38066a34dc2Ssthen /* see if the fd can read, if so, print one answer, repeat */ 38166a34dc2Ssthen int ret; 38266a34dc2Ssthen struct timeval tv, *waittv; 38366a34dc2Ssthen fd_set rfd; 38466a34dc2Ssthen while(*num_answers > 0) { 38566a34dc2Ssthen memset(&rfd, 0, sizeof(rfd)); 38666a34dc2Ssthen memset(&tv, 0, sizeof(tv)); 38766a34dc2Ssthen FD_ZERO(&rfd); 38866a34dc2Ssthen FD_SET(fd, &rfd); 38966a34dc2Ssthen if(wait_all) waittv = NULL; 39066a34dc2Ssthen else waittv = &tv; 39166a34dc2Ssthen ret = select(fd+1, &rfd, NULL, NULL, waittv); 39266a34dc2Ssthen if(ret < 0) { 39366a34dc2Ssthen if(errno == EINTR || errno == EAGAIN) continue; 39466a34dc2Ssthen perror("select() failed"); 39566a34dc2Ssthen exit(1); 39666a34dc2Ssthen } 39766a34dc2Ssthen if(ret == 0) { 39866a34dc2Ssthen if(wait_all) continue; 39966a34dc2Ssthen return; 40066a34dc2Ssthen } 40166a34dc2Ssthen (*num_answers) -= 1; 40266a34dc2Ssthen recv_one(fd, udp, ssl, buf); 40366a34dc2Ssthen } 40466a34dc2Ssthen } 40566a34dc2Ssthen 406712b2f30Ssthen static int get_random(void) 407712b2f30Ssthen { 408712b2f30Ssthen int r; 409712b2f30Ssthen if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) { 410712b2f30Ssthen return r; 411712b2f30Ssthen } 412b0dfc31bSsthen return (int)arc4random(); 413712b2f30Ssthen } 414712b2f30Ssthen 4150e9b6f9fSsthen /* parse the pp2_client and populate the proxy_buffer 4160e9b6f9fSsthen * It doesn't populate the destination parts. */ 4170e9b6f9fSsthen static int parse_pp2_client(const char* pp2_client, int udp, 4180e9b6f9fSsthen sldns_buffer* proxy_buf) 4190e9b6f9fSsthen { 4200e9b6f9fSsthen struct sockaddr_storage pp2_addr; 4219c7f0a49Ssthen size_t bytes_written; 4220e9b6f9fSsthen socklen_t pp2_addrlen = 0; 4230e9b6f9fSsthen memset(&pp2_addr, 0, sizeof(pp2_addr)); 4240e9b6f9fSsthen if(*pp2_client == 0) return 0; 4250e9b6f9fSsthen if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) { 4260e9b6f9fSsthen printf("fatal: bad proxy client specs '%s'\n", pp2_client); 4270e9b6f9fSsthen exit(1); 4280e9b6f9fSsthen } 4290e9b6f9fSsthen sldns_buffer_clear(proxy_buf); 4309c7f0a49Ssthen bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf), 4319c7f0a49Ssthen sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp); 4329c7f0a49Ssthen sldns_buffer_set_position(proxy_buf, bytes_written); 4330e9b6f9fSsthen sldns_buffer_flip(proxy_buf); 4340e9b6f9fSsthen return 1; 4350e9b6f9fSsthen } 4360e9b6f9fSsthen 437712b2f30Ssthen /** send the TCP queries and print answers */ 438712b2f30Ssthen static void 4390e9b6f9fSsthen send_em(const char* svr, const char* pp2_client, int udp, int usessl, 4400e9b6f9fSsthen int noanswer, int onarrival, int delay, int num, char** qs) 441712b2f30Ssthen { 4420e9b6f9fSsthen struct sockaddr_storage svr_addr; 4430e9b6f9fSsthen socklen_t svr_addrlen; 4440e9b6f9fSsthen int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen); 4450e9b6f9fSsthen int i, wait_results = 0, pp2_parsed; 446712b2f30Ssthen SSL_CTX* ctx = NULL; 447712b2f30Ssthen SSL* ssl = NULL; 448437d2860Ssthen sldns_buffer* buf = sldns_buffer_new(65553); 449437d2860Ssthen sldns_buffer* proxy_buf = sldns_buffer_new(65553); 450437d2860Ssthen if(!buf || !proxy_buf) { 451437d2860Ssthen sldns_buffer_free(buf); 452437d2860Ssthen sldns_buffer_free(proxy_buf); 453437d2860Ssthen fatal_exit("out of memory"); 454437d2860Ssthen } 4550e9b6f9fSsthen pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf); 456712b2f30Ssthen if(usessl) { 457712b2f30Ssthen ctx = connect_sslctx_create(NULL, NULL, NULL, 0); 458712b2f30Ssthen if(!ctx) fatal_exit("cannot create ssl ctx"); 459712b2f30Ssthen ssl = outgoing_ssl_fd(ctx, fd); 460712b2f30Ssthen if(!ssl) fatal_exit("cannot create ssl"); 461712b2f30Ssthen while(1) { 462712b2f30Ssthen int r; 463712b2f30Ssthen ERR_clear_error(); 464712b2f30Ssthen if( (r=SSL_do_handshake(ssl)) == 1) 465712b2f30Ssthen break; 466712b2f30Ssthen r = SSL_get_error(ssl, r); 467712b2f30Ssthen if(r != SSL_ERROR_WANT_READ && 468712b2f30Ssthen r != SSL_ERROR_WANT_WRITE) { 4699c7f0a49Ssthen log_crypto_err_io("could not ssl_handshake", r); 470712b2f30Ssthen exit(1); 471712b2f30Ssthen } 472712b2f30Ssthen } 473712b2f30Ssthen if(1) { 474*a43524d9Ssthen #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE 475*a43524d9Ssthen X509* x = SSL_get1_peer_certificate(ssl); 476*a43524d9Ssthen #else 477712b2f30Ssthen X509* x = SSL_get_peer_certificate(ssl); 478*a43524d9Ssthen #endif 479712b2f30Ssthen if(!x) printf("SSL: no peer certificate\n"); 480712b2f30Ssthen else { 481712b2f30Ssthen X509_print_fp(stdout, x); 482712b2f30Ssthen X509_free(x); 483712b2f30Ssthen } 484712b2f30Ssthen } 485712b2f30Ssthen } 4860e9b6f9fSsthen /* Send the PROXYv2 information once per stream */ 4870e9b6f9fSsthen if(!udp && pp2_parsed) { 4880e9b6f9fSsthen if(ssl) { 4890e9b6f9fSsthen if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf), 4900e9b6f9fSsthen (int)sldns_buffer_limit(proxy_buf)) <= 0) { 4910e9b6f9fSsthen log_crypto_err("cannot SSL_write"); 4920e9b6f9fSsthen exit(1); 4930e9b6f9fSsthen } 4940e9b6f9fSsthen } else { 4950e9b6f9fSsthen if(send(fd, (void*)sldns_buffer_begin(proxy_buf), 4960e9b6f9fSsthen sldns_buffer_limit(proxy_buf), 0) < 4970e9b6f9fSsthen (ssize_t)sldns_buffer_limit(proxy_buf)) { 4980e9b6f9fSsthen #ifndef USE_WINSOCK 4990e9b6f9fSsthen perror("send() data failed"); 5000e9b6f9fSsthen #else 5010e9b6f9fSsthen printf("send data: %s\n", 5020e9b6f9fSsthen wsa_strerror(WSAGetLastError())); 5030e9b6f9fSsthen #endif 5040e9b6f9fSsthen exit(1); 5050e9b6f9fSsthen } 5060e9b6f9fSsthen } 5070e9b6f9fSsthen } 508712b2f30Ssthen for(i=0; i<num; i+=3) { 5097bc20e6dSsthen if (delay != 0) { 5107bc20e6dSsthen #ifdef HAVE_SLEEP 5117bc20e6dSsthen sleep((unsigned)delay); 5127bc20e6dSsthen #else 5137bc20e6dSsthen Sleep(delay*1000); 5147bc20e6dSsthen #endif 5157bc20e6dSsthen } 516712b2f30Ssthen printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]); 5170e9b6f9fSsthen write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf, 5180e9b6f9fSsthen pp2_parsed, 5190e9b6f9fSsthen qs[i], qs[i+1], qs[i+2]); 520712b2f30Ssthen /* print at least one result */ 52166a34dc2Ssthen if(onarrival) { 52266a34dc2Ssthen wait_results += 1; /* one more answer to fetch */ 52366a34dc2Ssthen print_any_answers(fd, udp, ssl, buf, &wait_results, 0); 52466a34dc2Ssthen } else if(!noanswer) { 525712b2f30Ssthen recv_one(fd, udp, ssl, buf); 526712b2f30Ssthen } 52766a34dc2Ssthen } 52866a34dc2Ssthen if(onarrival) 52966a34dc2Ssthen print_any_answers(fd, udp, ssl, buf, &wait_results, 1); 530712b2f30Ssthen 531712b2f30Ssthen if(usessl) { 532712b2f30Ssthen SSL_shutdown(ssl); 533712b2f30Ssthen SSL_free(ssl); 534712b2f30Ssthen SSL_CTX_free(ctx); 535712b2f30Ssthen } 536e2a0f313Ssthen sock_close(fd); 537712b2f30Ssthen sldns_buffer_free(buf); 5380e9b6f9fSsthen sldns_buffer_free(proxy_buf); 539712b2f30Ssthen printf("orderly exit\n"); 540712b2f30Ssthen } 541712b2f30Ssthen 542712b2f30Ssthen #ifdef SIGPIPE 543712b2f30Ssthen /** SIGPIPE handler */ 544712b2f30Ssthen static RETSIGTYPE sigh(int sig) 545712b2f30Ssthen { 546a6cc1574Ssthen char str[] = "Got unhandled signal \n"; 547712b2f30Ssthen if(sig == SIGPIPE) { 548a6cc1574Ssthen char* strpipe = "got SIGPIPE, remote connection gone\n"; 549a6cc1574Ssthen /* simple cast to void will not silence Wunused-result */ 550a6cc1574Ssthen (void)!write(STDOUT_FILENO, strpipe, strlen(strpipe)); 551712b2f30Ssthen exit(1); 552712b2f30Ssthen } 553a6cc1574Ssthen str[21] = '0' + (sig/10)%10; 554a6cc1574Ssthen str[22] = '0' + sig%10; 555a6cc1574Ssthen /* simple cast to void will not silence Wunused-result */ 556a6cc1574Ssthen (void)!write(STDOUT_FILENO, str, strlen(str)); 557712b2f30Ssthen exit(1); 558712b2f30Ssthen } 559712b2f30Ssthen #endif /* SIGPIPE */ 560712b2f30Ssthen 561712b2f30Ssthen /** getopt global, in case header files fail to declare it. */ 562712b2f30Ssthen extern int optind; 563712b2f30Ssthen /** getopt global, in case header files fail to declare it. */ 564712b2f30Ssthen extern char* optarg; 565712b2f30Ssthen 566712b2f30Ssthen /** main program for streamtcp */ 567712b2f30Ssthen int main(int argc, char** argv) 568712b2f30Ssthen { 569712b2f30Ssthen int c; 570712b2f30Ssthen const char* svr = "127.0.0.1"; 5710e9b6f9fSsthen const char* pp2_client = ""; 572712b2f30Ssthen int udp = 0; 573712b2f30Ssthen int noanswer = 0; 57466a34dc2Ssthen int onarrival = 0; 575712b2f30Ssthen int usessl = 0; 5767bc20e6dSsthen int delay = 0; 577712b2f30Ssthen 578712b2f30Ssthen #ifdef USE_WINSOCK 579712b2f30Ssthen WSADATA wsa_data; 580712b2f30Ssthen if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) { 581712b2f30Ssthen printf("WSAStartup failed\n"); 582712b2f30Ssthen return 1; 583712b2f30Ssthen } 584712b2f30Ssthen #endif 585712b2f30Ssthen 586712b2f30Ssthen /* lock debug start (if any) */ 587712b2f30Ssthen checklock_start(); 58883152a15Ssthen log_init(0, 0, 0); 589712b2f30Ssthen 590712b2f30Ssthen #ifdef SIGPIPE 591712b2f30Ssthen if(signal(SIGPIPE, &sigh) == SIG_ERR) { 592712b2f30Ssthen perror("could not install signal handler"); 593712b2f30Ssthen return 1; 594712b2f30Ssthen } 595712b2f30Ssthen #endif 596712b2f30Ssthen 597712b2f30Ssthen /* command line options */ 598712b2f30Ssthen if(argc == 1) { 599712b2f30Ssthen usage(argv); 600712b2f30Ssthen } 6010e9b6f9fSsthen while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) { 602712b2f30Ssthen switch(c) { 603712b2f30Ssthen case 'f': 604712b2f30Ssthen svr = optarg; 605712b2f30Ssthen break; 6060e9b6f9fSsthen case 'p': 6070e9b6f9fSsthen pp2_client = optarg; 6089c7f0a49Ssthen pp_init(&sldns_write_uint16, 6099c7f0a49Ssthen &sldns_write_uint32); 6100e9b6f9fSsthen break; 61166a34dc2Ssthen case 'a': 61266a34dc2Ssthen onarrival = 1; 61366a34dc2Ssthen break; 614712b2f30Ssthen case 'n': 615712b2f30Ssthen noanswer = 1; 616712b2f30Ssthen break; 617712b2f30Ssthen case 'u': 618712b2f30Ssthen udp = 1; 619712b2f30Ssthen break; 620712b2f30Ssthen case 's': 621712b2f30Ssthen usessl = 1; 622712b2f30Ssthen break; 6237bc20e6dSsthen case 'd': 6247bc20e6dSsthen if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) { 6257bc20e6dSsthen printf("error parsing delay, " 6267bc20e6dSsthen "number expected: %s\n", optarg); 6277bc20e6dSsthen return 1; 6287bc20e6dSsthen } 6297bc20e6dSsthen delay = atoi(optarg); 6307bc20e6dSsthen break; 631712b2f30Ssthen case 'h': 632712b2f30Ssthen case '?': 633712b2f30Ssthen default: 634712b2f30Ssthen usage(argv); 635712b2f30Ssthen } 636712b2f30Ssthen } 637712b2f30Ssthen argc -= optind; 638712b2f30Ssthen argv += optind; 639712b2f30Ssthen 640712b2f30Ssthen if(argc % 3 != 0) { 641712b2f30Ssthen printf("queries must be multiples of name,type,class\n"); 642712b2f30Ssthen return 1; 643712b2f30Ssthen } 644712b2f30Ssthen if(usessl) { 645712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 646712b2f30Ssthen ERR_load_SSL_strings(); 647712b2f30Ssthen #endif 648712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) 649b0dfc31bSsthen # ifndef S_SPLINT_S 650712b2f30Ssthen OpenSSL_add_all_algorithms(); 651b0dfc31bSsthen # endif 652712b2f30Ssthen #else 653712b2f30Ssthen OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS 654712b2f30Ssthen | OPENSSL_INIT_ADD_ALL_DIGESTS 655712b2f30Ssthen | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); 656712b2f30Ssthen #endif 657712b2f30Ssthen #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) 658712b2f30Ssthen (void)SSL_library_init(); 659712b2f30Ssthen #else 660712b2f30Ssthen (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); 661712b2f30Ssthen #endif 662712b2f30Ssthen } 6630e9b6f9fSsthen send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv); 664712b2f30Ssthen checklock_stop(); 665712b2f30Ssthen #ifdef USE_WINSOCK 666712b2f30Ssthen WSACleanup(); 667712b2f30Ssthen #endif 668712b2f30Ssthen return 0; 669712b2f30Ssthen } 670