prog.c revision 9a690580
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#ifndef WIN32 4#include <arpa/inet.h> 5#include <netinet/in.h> 6#include <signal.h> 7#endif 8#include <errno.h> 9#include <limits.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <sys/types.h> 14#include <sys/stat.h> 15#include <sys/queue.h> 16#ifndef WIN32 17#include <unistd.h> 18#else 19#include <getopt.h> 20#pragma warning(disable:4028) 21#endif// WIN32 22 23#include <event2/event.h> 24 25#include <lsquic.h> 26 27#include <openssl/ssl.h> 28 29#include "../src/liblsquic/lsquic_hash.h" 30#include "../src/liblsquic/lsquic_int_types.h" 31#include "../src/liblsquic/lsquic_util.h" 32#include "../src/liblsquic/lsquic_logger.h" 33 34#include "test_config.h" 35#include "test_cert.h" 36#include "test_common.h" 37#include "prog.h" 38 39static int prog_stopped; 40 41static SSL_CTX * get_ssl_ctx (void *); 42 43static const struct lsquic_packout_mem_if pmi = { 44 .pmi_allocate = pba_allocate, 45 .pmi_release = pba_release, 46 .pmi_return = pba_release, 47}; 48 49 50void 51prog_init (struct prog *prog, unsigned flags, 52 struct sport_head *sports, 53 const struct lsquic_stream_if *stream_if, void *stream_if_ctx) 54{ 55 /* prog-specific initialization: */ 56 memset(prog, 0, sizeof(*prog)); 57 prog->prog_engine_flags = flags; 58 prog->prog_sports = sports; 59 lsquic_engine_init_settings(&prog->prog_settings, flags); 60#if ECN_SUPPORTED 61 prog->prog_settings.es_ecn = LSQUIC_DF_ECN; 62#else 63 prog->prog_settings.es_ecn = 0; 64#endif 65 66 prog->prog_api.ea_settings = &prog->prog_settings; 67 prog->prog_api.ea_stream_if = stream_if; 68 prog->prog_api.ea_stream_if_ctx = stream_if_ctx; 69 prog->prog_api.ea_packets_out = sport_packets_out; 70 prog->prog_api.ea_packets_out_ctx 71 = prog; 72 prog->prog_api.ea_pmi = &pmi; 73 prog->prog_api.ea_pmi_ctx = &prog->prog_pba; 74 prog->prog_api.ea_get_ssl_ctx = get_ssl_ctx; 75#if LSQUIC_PREFERRED_ADDR 76 if (getenv("LSQUIC_PREFERRED_ADDR4") || getenv("LSQUIC_PREFERRED_ADDR6")) 77 prog->prog_flags |= PROG_SEARCH_ADDRS; 78#endif 79 80 /* Non prog-specific initialization: */ 81 lsquic_global_init(flags & LSENG_SERVER ? LSQUIC_GLOBAL_SERVER : 82 LSQUIC_GLOBAL_CLIENT); 83 lsquic_log_to_fstream(stderr, LLTS_HHMMSSMS); 84 lsquic_logger_lopt("=notice"); 85} 86 87 88static int 89prog_add_sport (struct prog *prog, const char *arg) 90{ 91 struct service_port *sport; 92 sport = sport_new(arg, prog); 93 if (!sport) 94 return -1; 95 /* Default settings: */ 96 sport->sp_flags = prog->prog_dummy_sport.sp_flags; 97 sport->sp_sndbuf = prog->prog_dummy_sport.sp_sndbuf; 98 sport->sp_rcvbuf = prog->prog_dummy_sport.sp_rcvbuf; 99 TAILQ_INSERT_TAIL(prog->prog_sports, sport, next_sport); 100 return 0; 101} 102 103 104void 105prog_print_common_options (const struct prog *prog, FILE *out) 106{ 107 fprintf(out, 108#if HAVE_REGEX 109" -s SVCPORT Service port. Takes on the form of host:port, host,\n" 110" or port. If host is not an IPv4 or IPv6 address, it is\n" 111" resolved. If host is not set, the value of SNI is\n" 112" used (see the -H flag). If port is not set, the default\n" 113" is 443.\n" 114#else 115" -s SVCPORT Service port. Takes on the form of host:port or host.\n" 116" If host is not an IPv4 or IPv6 address, it is resolved.\n" 117" If port is not set, the default is 443.\n" 118#endif 119" Examples:\n" 120" 127.0.0.1:12345\n" 121" ::1:443\n" 122" example.com\n" 123" example.com:8443\n" 124#if HAVE_REGEX 125" 8443\n" 126#endif 127" If no -s option is given, 0.0.0.0:12345 address\n" 128" is used.\n" 129#if LSQUIC_DONTFRAG_SUPPORTED 130" -D Do not set `do not fragment' flag on outgoing UDP packets\n" 131#endif 132" -z BYTES Maximum size of outgoing UDP packets. The default is 1370\n" 133" bytes for IPv4 socket and 1350 bytes for IPv6 socket\n" 134" -L LEVEL Log level for all modules. Possible values are `debug',\n" 135" `info', `notice', `warn', `error', `alert', `emerg',\n" 136" and `crit'.\n" 137" -l LEVELS Log levels for modules, e.g.\n" 138" -l event=info,engine=debug\n" 139" Can be specified more than once.\n" 140" -m MAX Maximum number of outgoing packet buffers that can be\n" 141" assigned at any one time. By default, there is no max.\n" 142" -y style Timestamp style used in log messages. The following styles\n" 143" are supported:\n" 144" 0 No timestamp\n" 145" 1 Millisecond time (this is the default).\n" 146" Example: 11:04:05.196\n" 147" 2 Full date and millisecond time.\n" 148" Example: 2017-03-21 13:43:46.671\n" 149" 3 Chrome-like timestamp: date/time.microseconds.\n" 150" Example: 1223/104613.946956\n" 151" 4 Microsecond time.\n" 152" Example: 11:04:05.196308\n" 153" 5 Full date and microsecond time.\n" 154" Example: 2017-03-21 13:43:46.671345\n" 155" -S opt=val Socket options. Supported options:\n" 156" sndbuf=12345 # Sets SO_SNDBUF\n" 157" rcvbuf=12345 # Sets SO_RCVBUF\n" 158" -W Use stock PMI (malloc & free)\n" 159 ); 160 161#if HAVE_SENDMMSG 162 fprintf(out, 163" -g Use sendmmsg() to send packets.\n" 164 ); 165#endif 166#if HAVE_RECVMMSG 167 fprintf(out, 168" -j Use recvmmsg() to receive packets.\n" 169 ); 170#endif 171 172 if (prog->prog_engine_flags & LSENG_SERVER) 173 fprintf(out, 174" -c CERTSPEC Service specification. The specification is three values\n" 175" separated by commas. The values are:\n" 176" * Domain name\n" 177" * File containing cert in PEM format\n" 178" * File containing private key in DER or PEM format\n" 179" Example:\n" 180" -c www.example.com,/tmp/cert.pem,/tmp/key.pkcs8\n" 181 ); 182 else 183 { 184 if (prog->prog_engine_flags & LSENG_HTTP) 185 fprintf(out, 186" -H host Value of `host' HTTP header. This is also used as SNI\n" 187" in Client Hello. This option is used to override the\n" 188" `host' part of the address specified using -s flag.\n" 189 ); 190 else 191 fprintf(out, 192" -H host Value of SNI in CHLO.\n" 193 ); 194 } 195 196#ifndef WIN32 197 fprintf(out, 198" -G dir SSL keys will be logged to files in this directory.\n" 199 ); 200#endif 201 202 203 fprintf(out, 204" -k Connect UDP socket. Only meant to be used with clients\n" 205" to pick up ICMP errors.\n" 206" -i USECS Clock granularity in microseconds. Defaults to %u.\n", 207 LSQUIC_DF_CLOCK_GRANULARITY 208 ); 209 fprintf(out, 210" -h Print this help screen and exit\n" 211 ); 212} 213 214 215int 216prog_set_opt (struct prog *prog, int opt, const char *arg) 217{ 218 struct stat st; 219 int s; 220 221 switch (opt) 222 { 223#if LSQUIC_DONTFRAG_SUPPORTED 224 case 'D': 225 { 226 struct service_port *sport = TAILQ_LAST(prog->prog_sports, sport_head); 227 if (!sport) 228 sport = &prog->prog_dummy_sport; 229 sport->sp_flags |= SPORT_FRAGMENT_OK; 230 } 231 return 0; 232#endif 233#if HAVE_SENDMMSG 234 case 'g': 235 prog->prog_use_sendmmsg = 1; 236 return 0; 237#endif 238#if HAVE_RECVMMSG 239 case 'j': 240 prog->prog_use_recvmmsg = 1; 241 return 0; 242#endif 243 case 'm': 244 prog->prog_packout_max = atoi(arg); 245 return 0; 246 case 'z': 247 prog->prog_max_packet_size = atoi(arg); 248 return 0; 249 case 'W': 250 prog->prog_use_stock_pmi = 1; 251 return 0; 252 case 'c': 253 if (prog->prog_engine_flags & LSENG_SERVER) 254 { 255 if (!prog->prog_certs) 256 prog->prog_certs = lsquic_hash_create(); 257 return load_cert(prog->prog_certs, arg); 258 } 259 else 260 return -1; 261 case 'H': 262 if (prog->prog_engine_flags & LSENG_SERVER) 263 return -1; 264 prog->prog_hostname = arg; 265 return 0; 266 case 'y': 267 lsquic_log_to_fstream(stderr, atoi(arg)); 268 return 0; 269 case 'L': 270 return lsquic_set_log_level(arg); 271 case 'l': 272 return lsquic_logger_lopt(arg); 273 case 'o': 274 return set_engine_option(&prog->prog_settings, 275 &prog->prog_version_cleared, arg); 276 case 'i': 277 prog->prog_settings.es_clock_granularity = atoi(arg); 278 return 0; 279 case 's': 280 if (0 == (prog->prog_engine_flags & LSENG_SERVER) && 281 !TAILQ_EMPTY(prog->prog_sports)) 282 return -1; 283 return prog_add_sport(prog, arg); 284 case 'S': 285 { 286 struct service_port *sport = TAILQ_LAST(prog->prog_sports, sport_head); 287 if (!sport) 288 sport = &prog->prog_dummy_sport; 289 char *const name = strdup(optarg); 290 char *val = strchr(name, '='); 291 if (!val) 292 { 293 free(name); 294 return -1; 295 } 296 *val = '\0'; 297 ++val; 298 if (0 == strcasecmp(name, "sndbuf")) 299 { 300 sport->sp_flags |= SPORT_SET_SNDBUF; 301 sport->sp_sndbuf = atoi(val); 302 free(name); 303 return 0; 304 } 305 else if (0 == strcasecmp(name, "rcvbuf")) 306 { 307 sport->sp_flags |= SPORT_SET_RCVBUF; 308 sport->sp_rcvbuf = atoi(val); 309 free(name); 310 return 0; 311 } 312 else 313 { 314 free(name); 315 return -1; 316 } 317 } 318 case 'k': 319 { 320 struct service_port *sport = TAILQ_LAST(prog->prog_sports, sport_head); 321 if (!sport) 322 sport = &prog->prog_dummy_sport; 323 sport->sp_flags |= SPORT_CONNECT; 324 } 325 return 0; 326 case 'G': 327#ifndef WIN32 328 if (0 == stat(optarg, &st)) 329 { 330 if (!S_ISDIR(st.st_mode)) 331 { 332 LSQ_ERROR("%s is not a directory", optarg); 333 return -1; 334 } 335 } 336 else 337 { 338 s = mkdir(optarg, 0700); 339 if (s != 0) 340 { 341 LSQ_ERROR("cannot create directory %s: %s", optarg, 342 strerror(errno)); 343 return -1; 344 } 345 } 346 prog->prog_keylog_dir = optarg; 347 return 0; 348#else 349 LSQ_ERROR("key logging is not supported on Windows"); 350 return -1; 351#endif 352 default: 353 return 1; 354 } 355} 356 357 358struct event_base * 359prog_eb (struct prog *prog) 360{ 361 return prog->prog_eb; 362} 363 364 365int 366prog_connect (struct prog *prog, unsigned char *zero_rtt, size_t zero_rtt_len) 367{ 368 struct service_port *sport; 369 370 sport = TAILQ_FIRST(prog->prog_sports); 371 if (NULL == lsquic_engine_connect(prog->prog_engine, N_LSQVER, 372 (struct sockaddr *) &sport->sp_local_addr, 373 (struct sockaddr *) &sport->sas, sport, NULL, 374 prog->prog_hostname ? prog->prog_hostname 375 /* SNI is required for HTTP */ 376 : prog->prog_engine_flags & LSENG_HTTP ? sport->host 377 : NULL, 378 prog->prog_max_packet_size, zero_rtt, zero_rtt_len, 379 sport->sp_token_buf, sport->sp_token_sz)) 380 return -1; 381 382 prog_process_conns(prog); 383 return 0; 384} 385 386 387static int 388prog_init_client (struct prog *prog) 389{ 390 struct service_port *sport; 391 392 sport = TAILQ_FIRST(prog->prog_sports); 393 if (0 != sport_init_client(sport, prog->prog_engine, prog->prog_eb)) 394 return -1; 395 396 return 0; 397} 398 399 400static SSL_CTX * 401get_ssl_ctx (void *peer_ctx) 402{ 403 const struct service_port *const sport = peer_ctx; 404 return sport->sp_prog->prog_ssl_ctx; 405} 406 407 408static int 409prog_init_server (struct prog *prog) 410{ 411 struct service_port *sport; 412 unsigned char ticket_keys[48]; 413 414 prog->prog_ssl_ctx = SSL_CTX_new(TLS_method()); 415 if (prog->prog_ssl_ctx) 416 { 417 SSL_CTX_set_min_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION); 418 SSL_CTX_set_max_proto_version(prog->prog_ssl_ctx, TLS1_3_VERSION); 419 SSL_CTX_set_default_verify_paths(prog->prog_ssl_ctx); 420 421 /* This is obviously test code: the key is just an array of NUL bytes */ 422 memset(ticket_keys, 0, sizeof(ticket_keys)); 423 if (1 != SSL_CTX_set_tlsext_ticket_keys(prog->prog_ssl_ctx, 424 ticket_keys, sizeof(ticket_keys))) 425 { 426 LSQ_ERROR("SSL_CTX_set_tlsext_ticket_keys failed"); 427 return -1; 428 } 429 } 430 else 431 LSQ_WARN("cannot create SSL context"); 432 433 TAILQ_FOREACH(sport, prog->prog_sports, next_sport) 434 if (0 != sport_init_server(sport, prog->prog_engine, prog->prog_eb)) 435 return -1; 436 437 return 0; 438} 439 440 441void 442prog_process_conns (struct prog *prog) 443{ 444 int diff; 445 struct timeval timeout; 446 447 lsquic_engine_process_conns(prog->prog_engine); 448 449 if (lsquic_engine_earliest_adv_tick(prog->prog_engine, &diff)) 450 { 451 if (diff < 0 452 || (unsigned) diff < prog->prog_settings.es_clock_granularity) 453 { 454 timeout.tv_sec = 0; 455 timeout.tv_usec = prog->prog_settings.es_clock_granularity; 456 } 457 else 458 { 459 timeout.tv_sec = (unsigned) diff / 1000000; 460 timeout.tv_usec = (unsigned) diff % 1000000; 461 } 462 463 if (!prog_is_stopped()) 464 event_add(prog->prog_timer, &timeout); 465 } 466} 467 468 469static void 470prog_timer_handler (int fd, short what, void *arg) 471{ 472 struct prog *const prog = arg; 473 if (!prog_is_stopped()) 474 prog_process_conns(prog); 475} 476 477 478static void 479prog_usr1_handler (int fd, short what, void *arg) 480{ 481 LSQ_NOTICE("Got SIGUSR1, stopping engine"); 482 prog_stop(arg); 483} 484 485 486static void 487prog_usr2_handler (int fd, short what, void *arg) 488{ 489 struct prog *const prog = arg; 490 491 LSQ_NOTICE("Got SIGUSR2, cool down engine"); 492 prog->prog_flags |= PROG_FLAG_COOLDOWN; 493 lsquic_engine_cooldown(prog->prog_engine); 494 prog_process_conns(prog); 495} 496 497 498int 499prog_run (struct prog *prog) 500{ 501#ifndef WIN32 502 prog->prog_usr1 = evsignal_new(prog->prog_eb, SIGUSR1, 503 prog_usr1_handler, prog); 504 evsignal_add(prog->prog_usr1, NULL); 505 prog->prog_usr2 = evsignal_new(prog->prog_eb, SIGUSR2, 506 prog_usr2_handler, prog); 507 evsignal_add(prog->prog_usr2, NULL); 508#endif 509 510 event_base_loop(prog->prog_eb, 0); 511 512 return 0; 513} 514 515 516void 517prog_cleanup (struct prog *prog) 518{ 519 lsquic_engine_destroy(prog->prog_engine); 520 event_base_free(prog->prog_eb); 521 if (!prog->prog_use_stock_pmi) 522 pba_cleanup(&prog->prog_pba); 523 if (prog->prog_ssl_ctx) 524 SSL_CTX_free(prog->prog_ssl_ctx); 525 if (prog->prog_certs) 526 delete_certs(prog->prog_certs); 527 lsquic_global_cleanup(); 528} 529 530 531void 532prog_stop (struct prog *prog) 533{ 534 struct service_port *sport; 535 536 prog_stopped = 1; 537 538 while ((sport = TAILQ_FIRST(prog->prog_sports))) 539 { 540 TAILQ_REMOVE(prog->prog_sports, sport, next_sport); 541 sport_destroy(sport); 542 } 543 544 if (prog->prog_timer) 545 { 546 event_del(prog->prog_timer); 547 event_free(prog->prog_timer); 548 prog->prog_timer = NULL; 549 } 550 if (prog->prog_usr1) 551 { 552 event_del(prog->prog_usr1); 553 event_free(prog->prog_usr1); 554 prog->prog_usr1 = NULL; 555 } 556 if (prog->prog_usr2) 557 { 558 event_del(prog->prog_usr2); 559 event_free(prog->prog_usr2); 560 prog->prog_usr2 = NULL; 561 } 562} 563 564 565static void * 566keylog_open (void *ctx, lsquic_conn_t *conn) 567{ 568 const struct prog *const prog = ctx; 569 const lsquic_cid_t *cid; 570 FILE *fh; 571 int sz; 572 char id_str[MAX_CID_LEN * 2 + 1]; 573 char path[PATH_MAX]; 574 575 cid = lsquic_conn_id(conn); 576 lsquic_hexstr(cid->idbuf, cid->len, id_str, sizeof(id_str)); 577 sz = snprintf(path, sizeof(path), "%s/%s.keys", prog->prog_keylog_dir, 578 id_str); 579 if ((size_t) sz >= sizeof(path)) 580 { 581 LSQ_WARN("%s: file too long", __func__); 582 return NULL; 583 } 584 fh = fopen(path, "w"); 585 if (!fh) 586 LSQ_WARN("could not open %s for writing: %s", path, strerror(errno)); 587 return fh; 588} 589 590 591static void 592keylog_log_line (void *handle, const char *line) 593{ 594 size_t len; 595 596 len = strlen(line); 597 if (len < sizeof("QUIC_") - 1 || strncmp(line, "QUIC_", 5)) 598 fputs("QUIC_", handle); 599 fputs(line, handle); 600 fputs("\n", handle); 601 fflush(handle); 602} 603 604 605static void 606keylog_close (void *handle) 607{ 608 fclose(handle); 609} 610 611 612static const struct lsquic_keylog_if keylog_if = 613{ 614 .kli_open = keylog_open, 615 .kli_log_line = keylog_log_line, 616 .kli_close = keylog_close, 617}; 618 619 620static struct ssl_ctx_st * 621no_cert (void *cert_lu_ctx, const struct sockaddr *sa_UNUSED, const char *sni) 622{ 623 return NULL; 624} 625 626 627int 628prog_prep (struct prog *prog) 629{ 630 int s; 631 char err_buf[100]; 632 633 if (prog->prog_keylog_dir) 634 { 635 prog->prog_api.ea_keylog_if = &keylog_if; 636 prog->prog_api.ea_keylog_ctx = prog; 637 } 638 639 if (0 != lsquic_engine_check_settings(prog->prog_api.ea_settings, 640 prog->prog_engine_flags, err_buf, sizeof(err_buf))) 641 { 642 LSQ_ERROR("Error in settings: %s", err_buf); 643 return -1; 644 } 645 646 if (!prog->prog_use_stock_pmi) 647 pba_init(&prog->prog_pba, prog->prog_packout_max); 648 else 649 { 650 prog->prog_api.ea_pmi = NULL; 651 prog->prog_api.ea_pmi_ctx = NULL; 652 } 653 654 if (TAILQ_EMPTY(prog->prog_sports)) 655 { 656 if (prog->prog_hostname) 657 s = prog_add_sport(prog, prog->prog_hostname); 658 else 659 s = prog_add_sport(prog, "0.0.0.0:12345"); 660 if (0 != s) 661 return -1; 662 } 663 664 if (prog->prog_certs) 665 { 666 prog->prog_api.ea_lookup_cert = lookup_cert; 667 prog->prog_api.ea_cert_lu_ctx = prog->prog_certs; 668 } 669 else 670 { 671 if (prog->prog_engine_flags & LSENG_SERVER) 672 LSQ_WARN("Not a single service specified. Use -c option."); 673 prog->prog_api.ea_lookup_cert = no_cert; 674 } 675 676 prog->prog_eb = event_base_new(); 677 prog->prog_engine = lsquic_engine_new(prog->prog_engine_flags, 678 &prog->prog_api); 679 if (!prog->prog_engine) 680 return -1; 681 682 prog->prog_timer = event_new(prog->prog_eb, -1, 0, 683 prog_timer_handler, prog); 684 685 if (prog->prog_engine_flags & LSENG_SERVER) 686 s = prog_init_server(prog); 687 else 688 s = prog_init_client(prog); 689 690 if (s != 0) 691 return -1; 692 693 return 0; 694} 695 696 697int 698prog_is_stopped (void) 699{ 700 return prog_stopped != 0; 701} 702 703 704static void 705send_unsent (evutil_socket_t fd, short what, void *arg) 706{ 707 struct prog *const prog = arg; 708 assert(prog->prog_send); 709 event_del(prog->prog_send); 710 event_free(prog->prog_send); 711 prog->prog_send = NULL; 712 LSQ_DEBUG("on_write event fires"); 713 lsquic_engine_send_unsent_packets(prog->prog_engine); 714} 715 716 717void 718prog_sport_cant_send (struct prog *prog, int fd) 719{ 720 assert(!prog->prog_send); 721 LSQ_DEBUG("cannot send: register on_write event"); 722 prog->prog_send = event_new(prog->prog_eb, fd, EV_WRITE, send_unsent, prog); 723 event_add(prog->prog_send, NULL); 724} 725