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