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