1 /*
2 * testcode/dohclient.c - debug program. Perform multiple DNS queries using DoH.
3 *
4 * Copyright (c) 2020, 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 * Simple DNS-over-HTTPS client. For testing and debugging purposes.
40 * No authentication of TLS cert.
41 */
42
43 #include "config.h"
44 #ifdef HAVE_GETOPT_H
45 #include <getopt.h>
46 #endif
47 #include "sldns/wire2str.h"
48 #include "sldns/sbuffer.h"
49 #include "sldns/str2wire.h"
50 #include "sldns/parseutil.h"
51 #include "util/data/msgencode.h"
52 #include "util/data/msgreply.h"
53 #include "util/data/msgparse.h"
54 #include "util/net_help.h"
55 #include <openssl/ssl.h>
56 #include <openssl/err.h>
57 #ifdef HAVE_NGHTTP2
58 #include <nghttp2/nghttp2.h>
59
60 struct http2_session {
61 nghttp2_session* session;
62 SSL* ssl;
63 int fd;
64 int query_count;
65 /* Use POST :method if 1 */
66 int post;
67 int block_select;
68 const char* authority;
69 const char* endpoint;
70 const char* content_type;
71 };
72
73 struct http2_stream {
74 int32_t stream_id;
75 int res_status;
76 struct sldns_buffer* buf;
77 char* path;
78 };
79
usage(char * argv[])80 static void usage(char* argv[])
81 {
82 printf("usage: %s [options] name type class ...\n", argv[0]);
83 printf(" sends the name-type-class queries over "
84 "DNS-over-HTTPS.\n");
85 printf("-s server IP address to send the queries to, "
86 "default: 127.0.0.1\n");
87 printf("-p Port to connect to, default: %d\n",
88 UNBOUND_DNS_OVER_HTTPS_PORT);
89 printf("-P Use POST method instead of default GET\n");
90 printf("-e HTTP endpoint, default: /dns-query\n");
91 printf("-c Content-type in request, default: "
92 "application/dns-message\n");
93 printf("-n no-tls, TLS is disabled\n");
94 printf("-h This help text\n");
95 exit(1);
96 }
97
98 /** open TCP socket to svr */
99 static int
open_svr(const char * svr,int port)100 open_svr(const char* svr, int port)
101 {
102 struct sockaddr_storage addr;
103 socklen_t addrlen;
104 int fd = -1;
105 int r;
106 if(!ipstrtoaddr(svr, port, &addr, &addrlen)) {
107 printf("fatal: bad server specs '%s'\n", svr);
108 exit(1);
109 }
110
111 fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
112 SOCK_STREAM, 0);
113 if(fd == -1) {
114 perror("socket() error");
115 exit(1);
116 }
117 r = connect(fd, (struct sockaddr*)&addr, addrlen);
118 if(r < 0 && r != EINPROGRESS) {
119 perror("connect() error");
120 exit(1);
121 }
122 return fd;
123 }
124
http2_submit_request_read_cb(nghttp2_session * ATTR_UNUSED (session),int32_t ATTR_UNUSED (stream_id),uint8_t * buf,size_t length,uint32_t * data_flags,nghttp2_data_source * source,void * ATTR_UNUSED (cb_arg))125 static ssize_t http2_submit_request_read_cb(
126 nghttp2_session* ATTR_UNUSED(session),
127 int32_t ATTR_UNUSED(stream_id), uint8_t* buf, size_t length,
128 uint32_t* data_flags, nghttp2_data_source* source,
129 void* ATTR_UNUSED(cb_arg))
130 {
131 if(length > sldns_buffer_remaining(source->ptr))
132 length = sldns_buffer_remaining(source->ptr);
133
134 memcpy(buf, sldns_buffer_current(source->ptr), length);
135 sldns_buffer_skip(source->ptr, length);
136
137 if(sldns_buffer_remaining(source->ptr) == 0) {
138 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
139 }
140
141 return length;
142 }
143
144 static void
submit_query(struct http2_session * h2_session,struct sldns_buffer * buf)145 submit_query(struct http2_session* h2_session, struct sldns_buffer* buf)
146 {
147 int32_t stream_id;
148 struct http2_stream* h2_stream;
149 nghttp2_nv headers[5];
150 char* qb64;
151 size_t qb64_size;
152 size_t qb64_expected_size;
153 size_t i;
154 nghttp2_data_provider data_prd;
155
156 h2_stream = calloc(1, sizeof(*h2_stream));
157 if(!h2_stream)
158 fatal_exit("could not malloc http2 stream");
159 h2_stream->buf = buf;
160
161 if(h2_session->post) {
162 data_prd.source.ptr = buf;
163 data_prd.read_callback = http2_submit_request_read_cb;
164 h2_stream->path = (char*)h2_session->endpoint;
165 } else {
166 qb64_expected_size = sldns_b64_ntop_calculate_size(
167 sldns_buffer_remaining(buf));
168 qb64 = malloc(qb64_expected_size);
169 if(!qb64) fatal_exit("out of memory");
170 qb64_size = sldns_b64url_ntop(sldns_buffer_begin(buf),
171 sldns_buffer_remaining(buf), qb64, qb64_expected_size);
172 h2_stream->path = malloc(strlen(
173 h2_session->endpoint)+strlen("?dns=")+qb64_size+1);
174 if(!h2_stream->path) fatal_exit("out of memory");
175 snprintf(h2_stream->path, strlen(h2_session->endpoint)+
176 strlen("?dns=")+qb64_size+1, "%s?dns=%s",
177 h2_session->endpoint, qb64);
178 free(qb64);
179 }
180
181 headers[0].name = (uint8_t*)":method";
182 if(h2_session->post)
183 headers[0].value = (uint8_t*)"POST";
184 else
185 headers[0].value = (uint8_t*)"GET";
186 headers[1].name = (uint8_t*)":path";
187 headers[1].value = (uint8_t*)h2_stream->path;
188 headers[2].name = (uint8_t*)":scheme";
189 if(h2_session->ssl)
190 headers[2].value = (uint8_t*)"https";
191 else
192 headers[2].value = (uint8_t*)"http";
193 headers[3].name = (uint8_t*)":authority";
194 headers[3].value = (uint8_t*)h2_session->authority;
195 headers[4].name = (uint8_t*)"content-type";
196 headers[4].value = (uint8_t*)h2_session->content_type;
197
198 printf("Request headers\n");
199 for(i=0; i<sizeof(headers)/sizeof(headers[0]); i++) {
200 headers[i].namelen = strlen((char*)headers[i].name);
201 headers[i].valuelen = strlen((char*)headers[i].value);
202 headers[i].flags = NGHTTP2_NV_FLAG_NONE;
203 printf("%s: %s\n", headers[i].name, headers[i].value);
204 }
205
206 stream_id = nghttp2_submit_request(h2_session->session, NULL, headers,
207 sizeof(headers)/sizeof(headers[0]),
208 (h2_session->post) ? &data_prd : NULL, h2_stream);
209 if(stream_id < 0) {
210 printf("Failed to submit nghttp2 request");
211 exit(1);
212 }
213 h2_session->query_count++;
214 h2_stream->stream_id = stream_id;
215 }
216
217 static sldns_buffer*
make_query(char * qname,char * qtype,char * qclass)218 make_query(char* qname, char* qtype, char* qclass)
219 {
220 struct query_info qinfo;
221 struct edns_data edns;
222 sldns_buffer* buf = sldns_buffer_new(65553);
223 if(!buf) fatal_exit("out of memory");
224 qinfo.qname = sldns_str2wire_dname(qname, &qinfo.qname_len);
225 if(!qinfo.qname) {
226 printf("cannot parse query name: '%s'\n", qname);
227 exit(1);
228 }
229 qinfo.qtype = sldns_get_rr_type_by_name(qtype);
230 if(qinfo.qtype == 0 && strcmp(qtype, "TYPE0") != 0) {
231 printf("cannot parse query type: '%s'\n", qtype);
232 exit(1);
233 }
234 qinfo.qclass = sldns_get_rr_class_by_name(qclass);
235 if(qinfo.qclass == 0 && strcmp(qclass, "CLASS0") != 0) {
236 printf("cannot parse query class: '%s'\n", qclass);
237 exit(1);
238 }
239 qinfo.local_alias = NULL;
240
241 qinfo_query_encode(buf, &qinfo); /* flips buffer */
242 free(qinfo.qname);
243 sldns_buffer_write_u16_at(buf, 0, 0x0000);
244 sldns_buffer_write_u16_at(buf, 2, BIT_RD);
245 memset(&edns, 0, sizeof(edns));
246 edns.edns_present = 1;
247 edns.bits = EDNS_DO;
248 edns.udp_size = 4096;
249 if(sldns_buffer_capacity(buf) >=
250 sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
251 attach_edns_record(buf, &edns);
252 return buf;
253 }
254
http2_recv_cb(nghttp2_session * ATTR_UNUSED (session),uint8_t * buf,size_t len,int ATTR_UNUSED (flags),void * cb_arg)255 static ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session),
256 uint8_t* buf, size_t len, int ATTR_UNUSED(flags), void* cb_arg)
257 {
258 struct http2_session* h2_session = (struct http2_session*)cb_arg;
259 int r;
260 ssize_t ret;
261 struct timeval tv, *waittv;
262 fd_set rfd;
263 ERR_clear_error();
264
265 memset(&tv, 0, sizeof(tv));
266
267 if(h2_session->block_select && h2_session->query_count <= 0) {
268 return NGHTTP2_ERR_WOULDBLOCK;
269 }
270 if(h2_session->block_select)
271 waittv = NULL;
272 else
273 waittv = &tv;
274 memset(&rfd, 0, sizeof(rfd));
275 FD_ZERO(&rfd);
276 FD_SET(h2_session->fd, &rfd);
277 r = select(h2_session->fd+1, &rfd, NULL, NULL, waittv);
278 if(r <= 0) {
279 return NGHTTP2_ERR_WOULDBLOCK;
280 }
281
282 if(h2_session->ssl) {
283 r = SSL_read(h2_session->ssl, buf, len);
284 if(r <= 0) {
285 int want = SSL_get_error(h2_session->ssl, r);
286 if(want == SSL_ERROR_ZERO_RETURN) {
287 return NGHTTP2_ERR_EOF;
288 }
289 log_crypto_err_io("could not SSL_read", want);
290 return NGHTTP2_ERR_EOF;
291 }
292 return r;
293 }
294
295 ret = read(h2_session->fd, buf, len);
296 if(ret == 0) {
297 return NGHTTP2_ERR_EOF;
298 } else if(ret < 0) {
299 log_err("could not http2 read: %s", strerror(errno));
300 return NGHTTP2_ERR_EOF;
301 }
302 return ret;
303 }
304
http2_send_cb(nghttp2_session * ATTR_UNUSED (session),const uint8_t * buf,size_t len,int ATTR_UNUSED (flags),void * cb_arg)305 static ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session),
306 const uint8_t* buf, size_t len, int ATTR_UNUSED(flags), void* cb_arg)
307 {
308 struct http2_session* h2_session = (struct http2_session*)cb_arg;
309 ssize_t ret;
310
311 if(h2_session->ssl) {
312 int r;
313 ERR_clear_error();
314 r = SSL_write(h2_session->ssl, buf, len);
315 if(r <= 0) {
316 int want = SSL_get_error(h2_session->ssl, r);
317 if(want == SSL_ERROR_ZERO_RETURN) {
318 return NGHTTP2_ERR_CALLBACK_FAILURE;
319 }
320 log_crypto_err_io("could not SSL_write", want);
321 return NGHTTP2_ERR_CALLBACK_FAILURE;
322 }
323 return r;
324 }
325
326 ret = write(h2_session->fd, buf, len);
327 if(ret == 0) {
328 return NGHTTP2_ERR_CALLBACK_FAILURE;
329 } else if(ret < 0) {
330 log_err("could not http2 write: %s", strerror(errno));
331 return NGHTTP2_ERR_CALLBACK_FAILURE;
332 }
333 return ret;
334 }
335
http2_stream_close_cb(nghttp2_session * ATTR_UNUSED (session),int32_t ATTR_UNUSED (stream_id),nghttp2_error_code ATTR_UNUSED (error_code),void * cb_arg)336 static int http2_stream_close_cb(nghttp2_session* ATTR_UNUSED(session),
337 int32_t ATTR_UNUSED(stream_id),
338 nghttp2_error_code ATTR_UNUSED(error_code), void *cb_arg)
339 {
340 struct http2_session* h2_session = (struct http2_session*)cb_arg;
341 struct http2_stream* h2_stream;
342 if(!(h2_stream = nghttp2_session_get_stream_user_data(
343 h2_session->session, stream_id))) {
344 return 0;
345 }
346 h2_session->query_count--;
347 sldns_buffer_free(h2_stream->buf);
348 if(!h2_session->post)
349 free(h2_stream->path);
350 free(h2_stream);
351 h2_stream = NULL;
352 return 0;
353 }
354
http2_data_chunk_recv_cb(nghttp2_session * ATTR_UNUSED (session),uint8_t ATTR_UNUSED (flags),int32_t stream_id,const uint8_t * data,size_t len,void * cb_arg)355 static int http2_data_chunk_recv_cb(nghttp2_session* ATTR_UNUSED(session),
356 uint8_t ATTR_UNUSED(flags), int32_t stream_id, const uint8_t* data,
357 size_t len, void* cb_arg)
358 {
359 struct http2_session* h2_session = (struct http2_session*)cb_arg;
360 struct http2_stream* h2_stream;
361
362 if(!(h2_stream = nghttp2_session_get_stream_user_data(
363 h2_session->session, stream_id))) {
364 return 0;
365 }
366
367 if(sldns_buffer_remaining(h2_stream->buf) < len) {
368 log_err("received data chunk does not fit into buffer");
369 return NGHTTP2_ERR_CALLBACK_FAILURE;
370 }
371
372 sldns_buffer_write(h2_stream->buf, data, len);
373
374 return 0;
375 }
376
http2_frame_recv_cb(nghttp2_session * session,const nghttp2_frame * frame,void * ATTR_UNUSED (cb_arg))377 static int http2_frame_recv_cb(nghttp2_session *session,
378 const nghttp2_frame *frame, void* ATTR_UNUSED(cb_arg))
379 {
380 struct http2_stream* h2_stream;
381
382 if(!(h2_stream = nghttp2_session_get_stream_user_data(
383 session, frame->hd.stream_id)))
384 return 0;
385 if(frame->hd.type == NGHTTP2_HEADERS &&
386 frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
387 sldns_buffer_clear(h2_stream->buf);
388 }
389 if(((frame->hd.type != NGHTTP2_DATA &&
390 frame->hd.type != NGHTTP2_HEADERS) ||
391 frame->hd.flags & NGHTTP2_FLAG_END_STREAM) &&
392 h2_stream->res_status == 200) {
393 char* pktstr;
394 sldns_buffer_flip(h2_stream->buf);
395 pktstr = sldns_wire2str_pkt(
396 sldns_buffer_begin(h2_stream->buf),
397 sldns_buffer_limit(h2_stream->buf));
398 printf("%s\n", pktstr);
399 free(pktstr);
400 return 0;
401 }
402 return 0;
403 }
http2_header_cb(nghttp2_session * ATTR_UNUSED (session),const nghttp2_frame * frame,const uint8_t * name,size_t namelen,const uint8_t * value,size_t ATTR_UNUSED (valuelen),uint8_t ATTR_UNUSED (flags),void * cb_arg)404 static int http2_header_cb(nghttp2_session* ATTR_UNUSED(session),
405 const nghttp2_frame* frame, const uint8_t* name, size_t namelen,
406 const uint8_t* value, size_t ATTR_UNUSED(valuelen),
407 uint8_t ATTR_UNUSED(flags), void* cb_arg)
408 {
409 struct http2_stream* h2_stream;
410 struct http2_session* h2_session = (struct http2_session*)cb_arg;
411 printf("%s %s\n", name, value);
412 if(namelen == 7 && memcmp(":status", name, namelen) == 0) {
413 if(!(h2_stream = nghttp2_session_get_stream_user_data(
414 h2_session->session, frame->hd.stream_id))) {
415 return 0;
416 }
417 h2_stream->res_status = atoi((char*)value);
418 }
419 return 0;
420 }
421
422 static struct http2_session*
http2_session_create()423 http2_session_create()
424 {
425 struct http2_session* h2_session = calloc(1,
426 sizeof(struct http2_session));
427 nghttp2_session_callbacks* callbacks;
428 if(!h2_session)
429 fatal_exit("out of memory");
430
431 if(nghttp2_session_callbacks_new(&callbacks) == NGHTTP2_ERR_NOMEM) {
432 log_err("failed to initialize nghttp2 callback");
433 free(h2_session);
434 return NULL;
435 }
436 nghttp2_session_callbacks_set_recv_callback(callbacks, http2_recv_cb);
437 nghttp2_session_callbacks_set_send_callback(callbacks, http2_send_cb);
438 nghttp2_session_callbacks_set_on_stream_close_callback(callbacks,
439 http2_stream_close_cb);
440 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks,
441 http2_data_chunk_recv_cb);
442 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
443 http2_frame_recv_cb);
444 nghttp2_session_callbacks_set_on_header_callback(callbacks,
445 http2_header_cb);
446 nghttp2_session_client_new(&h2_session->session, callbacks, h2_session);
447 nghttp2_session_callbacks_del(callbacks);
448 return h2_session;
449 }
450
451 static void
http2_session_delete(struct http2_session * h2_session)452 http2_session_delete(struct http2_session* h2_session)
453 {
454 nghttp2_session_del(h2_session->session);
455 free(h2_session);
456 }
457
458 static void
http2_submit_setting(struct http2_session * h2_session)459 http2_submit_setting(struct http2_session* h2_session)
460 {
461 int ret;
462 nghttp2_settings_entry settings[1] = {
463 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
464 100}};
465
466 ret = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
467 settings, 1);
468 if(ret) {
469 printf("http2: submit_settings failed, "
470 "error: %s\n", nghttp2_strerror(ret));
471 exit(1);
472 }
473 }
474
475 static void
http2_write(struct http2_session * h2_session)476 http2_write(struct http2_session* h2_session)
477 {
478 if(nghttp2_session_want_write(h2_session->session)) {
479 if(nghttp2_session_send(h2_session->session)) {
480 printf("nghttp2 session send failed\n");
481 exit(1);
482 }
483 }
484 }
485
486 static void
http2_read(struct http2_session * h2_session)487 http2_read(struct http2_session* h2_session)
488 {
489 if(nghttp2_session_want_read(h2_session->session)) {
490 if(nghttp2_session_recv(h2_session->session)) {
491 printf("nghttp2 session mem_recv failed\n");
492 exit(1);
493 }
494 }
495 }
496
497 static void
run(struct http2_session * h2_session,int port,int no_tls,int count,char ** q)498 run(struct http2_session* h2_session, int port, int no_tls, int count, char** q)
499 {
500 int i;
501 SSL_CTX* ctx = NULL;
502 SSL* ssl = NULL;
503 int fd;
504 struct sldns_buffer* buf = NULL;
505
506 fd = open_svr(h2_session->authority, port);
507 h2_session->fd = fd;
508
509 if(!no_tls) {
510 ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
511 if(!ctx) fatal_exit("cannot create ssl ctx");
512 #ifdef HAVE_SSL_CTX_SET_ALPN_PROTOS
513 SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)"\x02h2", 3);
514 #endif
515 ssl = outgoing_ssl_fd(ctx, fd);
516 if(!ssl) {
517 printf("cannot create ssl\n");
518 exit(1);
519 }
520 h2_session->ssl = ssl;
521 while(1) {
522 int r;
523 ERR_clear_error();
524 if( (r=SSL_do_handshake(ssl)) == 1)
525 break;
526 r = SSL_get_error(ssl, r);
527 if(r != SSL_ERROR_WANT_READ &&
528 r != SSL_ERROR_WANT_WRITE) {
529 log_crypto_err_io("could not ssl_handshake", r);
530 exit(1);
531 }
532 }
533 }
534
535 http2_submit_setting(h2_session);
536 http2_write(h2_session);
537 http2_read(h2_session); /* Read setting from remote peer */
538
539 h2_session->block_select = 1;
540
541 /* handle query */
542 for(i=0; i<count; i+=3) {
543 buf = make_query(q[i], q[i+1], q[i+2]);
544 submit_query(h2_session, buf);
545 }
546 http2_write(h2_session);
547 while(h2_session->query_count) {
548 http2_read(h2_session);
549 http2_write(h2_session);
550 }
551
552 /* shutdown */
553 http2_session_delete(h2_session);
554 if(ssl) {
555 SSL_shutdown(ssl);
556 SSL_free(ssl);
557 }
558 if(ctx) {
559 SSL_CTX_free(ctx);
560 }
561 sock_close(fd);
562 }
563
564 /** getopt global, in case header files fail to declare it. */
565 extern int optind;
566 /** getopt global, in case header files fail to declare it. */
567 extern char* optarg;
main(int argc,char ** argv)568 int main(int argc, char** argv)
569 {
570 int c;
571 int port = UNBOUND_DNS_OVER_HTTPS_PORT, no_tls = 0;
572 struct http2_session* h2_session;
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 checklock_start();
582 log_init(0, 0, 0);
583 log_ident_set("dohclient");
584
585 h2_session = http2_session_create();
586 if(!h2_session) fatal_exit("out of memory");
587 if(argc == 1) {
588 usage(argv);
589 }
590
591 h2_session->authority = "127.0.0.1";
592 h2_session->post = 0;
593 h2_session->endpoint = "/dns-query";
594 h2_session->content_type = "application/dns-message";
595
596 while((c=getopt(argc, argv, "c:e:hns:p:P")) != -1) {
597 switch(c) {
598 case 'c':
599 h2_session->content_type = optarg;
600 break;
601 case 'e':
602 h2_session->endpoint = optarg;
603 break;
604 case 'n':
605 no_tls = 1;
606 break;
607 case 'p':
608 if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
609 printf("error parsing port, "
610 "number expected: %s\n", optarg);
611 return 1;
612 }
613 port = atoi(optarg);
614 break;
615 case 'P':
616 h2_session->post = 1;
617 break;
618 case 's':
619 h2_session->authority = optarg;
620 break;
621 case 'h':
622 case '?':
623 default:
624 usage(argv);
625 }
626 }
627 argc -= optind;
628 argv += optind;
629 if(argc%3!=0) {
630 printf("Invalid input. Specify qname, qtype, and qclass.\n");
631 return 1;
632 }
633
634 if(!no_tls) {
635 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
636 ERR_load_SSL_strings();
637 #endif
638 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
639 # ifndef S_SPLINT_S
640 OpenSSL_add_all_algorithms();
641 # endif
642 #else
643 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
644 | OPENSSL_INIT_ADD_ALL_DIGESTS
645 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
646 #endif
647 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
648 (void)SSL_library_init();
649 #else
650 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
651 #endif
652 }
653 run(h2_session, port, no_tls, argc, argv);
654
655 checklock_stop();
656 #ifdef USE_WINSOCK
657 WSACleanup();
658 #endif
659 return 0;
660 }
661 #else
main(int ATTR_UNUSED (argc),char ** ATTR_UNUSED (argv))662 int main(int ATTR_UNUSED(argc), char** ATTR_UNUSED(argv))
663 {
664 printf("Compiled without nghttp2, cannot run test.\n");
665 return 1;
666 }
667 #endif /* HAVE_NGHTTP2 */
668