diff --git a/CMakeLists.txt b/CMakeLists.txt index eab2a177..579d0365 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -448,6 +448,10 @@ foreach(name configure_file("${name}.in" "${name}" @ONLY) endforeach() +if(APPLE) + add_definitions(-D__APPLE_USE_RFC_3542) +endif() + include_directories( "${CMAKE_CURRENT_BINARY_DIR}" # for config.h ) diff --git a/configure.ac b/configure.ac index def91ae8..37256518 100644 --- a/configure.ac +++ b/configure.ac @@ -107,6 +107,11 @@ AC_ARG_ENABLE([lib-only], [Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])], [request_lib_only=$enableval], [request_lib_only=no]) +AC_ARG_ENABLE([http3], + [AS_HELP_STRING([--enable-http3], + [(EXPERIMENTAL) Enable HTTP/3. This requires ngtcp2, nghttp3, and a custom OpenSSL.])], + [request_http3=$enableval], [request_http3=no]) + AC_ARG_WITH([libxml2], [AS_HELP_STRING([--with-libxml2], [Use libxml2 [default=check]])], @@ -172,6 +177,16 @@ AC_ARG_WITH([cython], [Use cython in given PATH])], [cython_path=$withval], []) +AC_ARG_WITH([libngtcp2], + [AS_HELP_STRING([--with-libngtcp2], + [Use libngtcp2 [default=check]])], + [request_libngtcp2=$withval], [request_libngtcp2=check]) + +AC_ARG_WITH([libnghttp3], + [AS_HELP_STRING([--with-libnghttp3], + [Use libnghttp3 [default=check]])], + [request_libnghttp3=$withval], [request_libnghttp3=check]) + dnl Define variables AC_ARG_VAR([CYTHON], [the Cython executable]) @@ -334,6 +349,13 @@ case "$host_os" in ;; esac +case "${build}" in + *-apple-darwin*) + EXTRA_DEFS="-D__APPLE_USE_RFC_3542" + AC_SUBST([EXTRA_DEFS]) + ;; +esac + # zlib have_zlib=no if test "x${request_zlib}" != "xno"; then @@ -455,26 +477,50 @@ if test "x${request_libcares}" = "xyes" && fi # ngtcp2 (for src) -PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.0.0], [have_libngtcp2=yes], - [have_libngtcp2=no]) -if test "x${have_libngtcp2}" = "xno"; then - AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) +have_libngtcp2=no +if test "x${request_libngtcp2}" != "xno"; then + PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.0.0], [have_libngtcp2=yes], + [have_libngtcp2=no]) + if test "x${have_libngtcp2}" = "xno"; then + AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) + fi +fi + +if test "x${request_libngtcp2}" = "xyes" && + test "x${have_libngtcp2}" != "xyes"; then + AC_MSG_ERROR([libngtcp2 was requested (--with-libngtcp2) but not found]) fi # ngtcp2_crypto_openssl (for src) -PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL], - [libngtcp2_crypto_openssl >= 0.0.0], - [have_libngtcp2_crypto_openssl=yes], - [have_libngtcp2_crypto_openssl=no]) -if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then - AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS) +have_libngtcp2_crypto_openssl=no +if test "x${request_libngtcp2}" != "xno"; then + PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL], + [libngtcp2_crypto_openssl >= 0.0.0], + [have_libngtcp2_crypto_openssl=yes], + [have_libngtcp2_crypto_openssl=no]) + if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then + AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS) + fi +fi + +if test "x${request_libngtcp2}" = "xyes" && + test "x${have_libngtcp2_crypto_openssl}" != "xyes"; then + AC_MSG_ERROR([libngtcp2_crypto_openssl was requested (--with-libngtcp2) but not found]) fi # nghttp3 (for src) -PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes], - [have_libnghttp3=no]) -if test "x${have_libnghttp3}" = "xno"; then - AC_MSG_NOTICE($LIBNGHTTP3_PKT_ERRORS) +have_libnghttp3=no +if test "x${request_libnghttp3}" != "xno"; then + PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes], + [have_libnghttp3=no]) + if test "x${have_libnghttp3}" = "xno"; then + AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS) + fi +fi + +if test "x${request_libnghttp3}" = "xyes" && + test "x${have_libnghttp3}" != "xyes"; then + AC_MSG_ERROR([libnghttp3 was requested (--with-libnghttp3) but not found]) fi # libevent_openssl (for examples) @@ -621,6 +667,23 @@ fi AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ]) +# Check HTTP/3 support +enable_http3=no +if test "x${request_http3}" != "xno" && + test "x${have_libngtcp2}" = "xyes" && + test "x${have_libngtcp2_crypto_openssl}" = "xyes" && + test "x${have_libnghttp3}" = "xyes"; then + enable_http3=yes + AC_DEFINE([ENABLE_HTTP3], [1], [Define to 1 if HTTP/3 is enabled.]) +fi + +if test "x${request_http3}" = "xyes" && + test "x${enable_http3}" != "xyes"; then + AC_MSG_ERROR([HTTP/3 was requested (--enable-http3) but dependencies are not met.]) +fi + +AM_CONDITIONAL([ENABLE_HTTP3], [ test "x${enable_http3}" = "xyes" ]) + enable_hpack_tools=no # HPACK tools requires jansson if test "x${request_hpack_tools}" != "xno" && @@ -1058,4 +1121,5 @@ AC_MSG_NOTICE([summary of build options: Examples: ${enable_examples} Python bindings:${enable_python_bindings} Threading: ${enable_threads} + HTTP/3 (EXPERIMENTAL): ${enable_http3} ]) diff --git a/src/Makefile.am b/src/Makefile.am index 9226ed31..eb763fb6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ AM_CPPFLAGS = \ @LIBNGTCP2_CFLAGS@ \ @JANSSON_CFLAGS@ \ @ZLIB_CFLAGS@ \ + @EXTRA_DEFS@ \ @DEFS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@ @@ -103,10 +104,14 @@ h2load_SOURCES = util.cc util.h \ tls.cc tls.h \ h2load_session.h \ h2load_http2_session.cc h2load_http2_session.h \ - h2load_http1_session.cc h2load_http1_session.h \ + h2load_http1_session.cc h2load_http1_session.h + +if ENABLE_HTTP3 +h2load_SOURCES += \ h2load_http3_session.cc h2load_http3_session.h \ h2load_quic.cc h2load_quic.h \ quic.cc quic.h +endif # ENABLE_HTTP3 NGHTTPX_SRCS = \ util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \ @@ -153,12 +158,6 @@ NGHTTPX_SRCS = \ shrpx_dns_resolver.cc shrpx_dns_resolver.h \ shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \ shrpx_dns_tracker.cc shrpx_dns_tracker.h \ - shrpx_quic.cc shrpx_quic.h \ - shrpx_quic_listener.cc shrpx_quic_listener.h \ - shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \ - shrpx_http3_upstream.cc shrpx_http3_upstream.h \ - http3.cc http3.h \ - quic.cc quic.h \ buffer.h memchunk.h template.h allocator.h \ xsi_strerror.c xsi_strerror.h @@ -171,6 +170,16 @@ NGHTTPX_SRCS += \ shrpx_mruby_module_response.cc shrpx_mruby_module_response.h endif # HAVE_MRUBY +if ENABLE_HTTP3 +NGHTTPX_SRCS += \ + shrpx_quic.cc shrpx_quic.h \ + shrpx_quic_listener.cc shrpx_quic_listener.h \ + shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \ + shrpx_http3_upstream.cc shrpx_http3_upstream.h \ + http3.cc http3.h \ + quic.cc quic.h +endif # ENABLE_HTTP3 + noinst_LIBRARIES = libnghttpx.a libnghttpx_a_SOURCES = ${NGHTTPX_SRCS} libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS} diff --git a/src/h2load.cc b/src/h2load.cc index d08cff61..2b3f529b 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -50,14 +50,18 @@ #include -#include +#ifdef ENABLE_HTTP3 +# include +#endif // ENABLE_HTTP3 #include "url-parser/url_parser.h" #include "h2load_http1_session.h" #include "h2load_http2_session.h" -#include "h2load_http3_session.h" -#include "h2load_quic.h" +#ifdef ENABLE_HTTP3 +# include "h2load_http3_session.h" +# include "h2load_quic.h" +#endif // ENABLE_HTTP3 #include "tls.h" #include "http2.h" #include "util.h" @@ -141,8 +145,12 @@ bool Config::is_timing_based_mode() const { return (this->duration > 0); } bool Config::has_base_uri() const { return (!this->base_uri.empty()); } bool Config::rps_enabled() const { return this->rps > 0.0; } bool Config::is_quic() const { +#ifdef ENABLE_HTTP3 return !npn_list.empty() && (npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29"); +#else // !ENABLE_HTTP3 + return false; +#endif // !ENABLE_HTTP3 } Config config; @@ -435,7 +443,9 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo) cstat{}, worker(worker), ssl(nullptr), +#ifdef ENABLE_HTTP3 quic{}, +#endif // ENABLE_HTTP3 next_addr(config.addrs), current_addr(nullptr), reqidx(0), @@ -478,16 +488,20 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo) ev_timer_init(&rps_watcher, rps_cb, 0., 0.); rps_watcher.data = this; +#ifdef ENABLE_HTTP3 ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.); quic.pkt_timer.data = this; +#endif // ENABLE_HTTP3 } Client::~Client() { disconnect(); +#ifdef ENABLE_HTTP3 if (config.is_quic()) { quic_free(); } +#endif // ENABLE_HTTP3 if (ssl) { SSL_free(ssl); @@ -504,6 +518,7 @@ int Client::make_socket(addrinfo *addr) { int rv; if (config.is_quic()) { +#ifdef ENABLE_HTTP3 fd = util::create_nonblock_udp_socket(addr->ai_family); if (fd == -1) { return -1; @@ -528,6 +543,7 @@ int Client::make_socket(addrinfo *addr) { std::cerr << "quic_init failed" << std::endl; return -1; } +#endif // ENABLE_HTTP3 } else { fd = util::create_nonblock_socket(addr->ai_family); if (fd == -1) { @@ -614,10 +630,12 @@ int Client::connect() { ev_io_start(worker->loop, &wev); if (config.is_quic()) { +#ifdef ENABLE_HTTP3 ev_io_start(worker->loop, &rev); readfn = &Client::read_quic; writefn = &Client::write_quic; +#endif // ENABLE_HTTP3 } else { writefn = &Client::connected; } @@ -676,11 +694,15 @@ void Client::fail() { void Client::disconnect() { record_client_end_time(); +#ifdef ENABLE_HTTP3 if (config.is_quic()) { quic_close_connection(); } +#endif // ENABLE_HTTP3 +#ifdef ENABLE_HTTP3 ev_timer_stop(worker->loop, &quic.pkt_timer); +#endif // ENABLE_HTTP3 ev_timer_stop(worker->loop, &conn_inactivity_watcher); ev_timer_stop(worker->loop, &conn_active_watcher); ev_timer_stop(worker->loop, &rps_watcher); @@ -843,9 +865,11 @@ void Client::report_app_info() { } void Client::terminate_session() { +#ifdef ENABLE_HTTP3 if (config.is_quic()) { quic.close_requested = true; } +#endif // ENABLE_HTTP3 if (session) { session->terminate(); } @@ -1047,11 +1071,13 @@ int Client::connection_made() { if (next_proto) { auto proto = StringRef{next_proto, next_proto_len}; if (config.is_quic()) { +#ifdef ENABLE_HTTP3 assert(session); if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) && !util::streq_l("h3-29", proto)) { return -1; } +#endif // ENABLE_HTTP3 } else if (util::check_h2_is_selected(proto)) { session = std::make_unique(this); } else if (util::streq(NGHTTP2_H1_1, proto)) { @@ -1377,6 +1403,7 @@ int Client::write_tls() { return 0; } +#ifdef ENABLE_HTTP3 int Client::write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data, size_t datalen, size_t gso_size) { iovec msg_iov; @@ -1389,7 +1416,7 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen, msg.msg_iov = &msg_iov; msg.msg_iovlen = 1; -#ifdef UDP_SEGMENT +# ifdef UDP_SEGMENT std::array msg_ctrl{}; if (gso_size && datalen > gso_size) { msg.msg_control = msg_ctrl.data(); @@ -1401,7 +1428,7 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen, cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); *(reinterpret_cast(CMSG_DATA(cm))) = gso_size; } -#endif // UDP_SEGMENT +# endif // UDP_SEGMENT auto nwrite = sendmsg(fd, &msg, 0); if (nwrite < 0) { @@ -1414,6 +1441,7 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen, return 0; } +#endif // ENABLE_HTTP3 void Client::record_request_time(RequestStat *req_stat) { req_stat->request_time = std::chrono::steady_clock::now(); @@ -2740,7 +2768,9 @@ int main(int argc, char **argv) { << "Warning: --qlog-file-base: only effective in quic, ignoring." << std::endl; } else { +#ifdef ENABLE_HTTP3 config.qlog_file_base = qlog_base; +#endif // ENABLE_HTTP3 } } @@ -2764,8 +2794,10 @@ int main(int argc, char **argv) { SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); if (config.is_quic()) { +#ifdef ENABLE_HTTP3 SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); +#endif // ENABLE_HTTP3 } else if (nghttp2::tls::ssl_ctx_set_proto_versions( ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION, nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) { @@ -2780,12 +2812,14 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } +#if OPENSSL_1_1_1_API if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) { std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers << " failed: " << ERR_error_string(ERR_get_error(), nullptr) << std::endl; exit(EXIT_FAILURE); } +#endif // OPENSSL_1_1_1_API if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) { std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; @@ -2806,6 +2840,7 @@ int main(int argc, char **argv) { SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size()); #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L +#if OPENSSL_1_1_1_API auto keylog_filename = getenv("SSLKEYLOGFILE"); if (keylog_filename) { keylog_file.open(keylog_filename, std::ios_base::app); @@ -2813,6 +2848,7 @@ int main(int argc, char **argv) { SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); } } +#endif // OPENSSL_1_1_1_API std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION; Headers shared_nva; @@ -3093,10 +3129,12 @@ traffic: )" << util::utos_funit(stats.bytes_total) << ") headers (space savings " << header_space_savings * 100 << "%), " << util::utos_funit(stats.bytes_body) << "B (" << stats.bytes_body << R"() data)" << std::endl; +#ifdef ENABLE_HTTP3 if (config.is_quic()) { std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, " << stats.udp_dgram_recv << " received" << std::endl; } +#endif // ENABLE_HTTP3 std::cout << R"( min max mean sd +/- sd time for request: )" diff --git a/src/h2load.h b/src/h2load.h index 061c776f..92c0e2ac 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -45,15 +45,19 @@ #include -#include -#include +#ifdef ENABLE_HTTP3 +# include +# include +#endif // ENABLE_HTTP3 #include #include #include "http2.h" -#include "quic.h" +#ifdef ENABLE_HTTP3 +# include "quic.h" +#endif // ENABLE_HTTP3 #include "memchunk.h" #include "template.h" @@ -327,6 +331,7 @@ struct Client { std::function readfn, writefn; Worker *worker; SSL *ssl; +#ifdef ENABLE_HTTP3 struct { ev_timer pkt_timer; ngtcp2_conn *conn; @@ -335,6 +340,7 @@ struct Client { bool close_requested; FILE *qlog_file; } quic; +#endif // ENABLE_HTTP3 ev_timer request_timeout_watcher; addrinfo *next_addr; // Address for the current address. When try_new_connection() is @@ -447,6 +453,7 @@ struct Client { void signal_write(); +#ifdef ENABLE_HTTP3 // QUIC int quic_init(const sockaddr *local_addr, socklen_t local_addrlen, const sockaddr *remote_addr, socklen_t remote_addrlen); @@ -475,6 +482,7 @@ struct Client { int quic_pkt_timeout(); void quic_restart_pkt_timer(); void quic_write_qlog(const void *data, size_t datalen); +#endif // ENABLE_HTTP3 }; } // namespace h2load diff --git a/src/shrpx.cc b/src/shrpx.cc index 62c0abc0..a619fe77 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1548,6 +1548,7 @@ void fill_default_config(Config *config) { downstreamconf.option, downstreamconf.encoder_dynamic_table_size); } +#ifdef ENABLE_HTTP3 auto &quicconf = config->quic; { quicconf.timeout.idle = 30_s; @@ -1560,6 +1561,7 @@ void fill_default_config(Config *config) { exit(EXIT_FAILURE); } } +#endif // ENABLE_HTTP3 auto &loggingconf = config->logging; { diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index 341566b6..d58c9a5f 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -51,7 +51,9 @@ #include "shrpx_api_downstream_connection.h" #include "shrpx_health_monitor_downstream_connection.h" #include "shrpx_null_downstream_connection.h" -#include "shrpx_http3_upstream.h" +#ifdef ENABLE_HTTP3 +# include "shrpx_http3_upstream.h" +#endif // ENABLE_HTTP3 #include "shrpx_log.h" #include "util.h" #include "template.h" @@ -287,6 +289,7 @@ int ClientHandler::write_tls() { } } +#ifdef ENABLE_HTTP3 int ClientHandler::read_quic(const UpstreamAddr *faddr, const Address &remote_addr, const Address &local_addr, const uint8_t *data, @@ -297,6 +300,7 @@ int ClientHandler::read_quic(const UpstreamAddr *faddr, } int ClientHandler::write_quic() { return upstream_->on_write(); } +#endif // ENABLE_HTTP3 int ClientHandler::upstream_noop() { return 0; } @@ -509,12 +513,14 @@ void ClientHandler::setup_upstream_io_callback() { } } +#ifdef ENABLE_HTTP3 void ClientHandler::setup_http3_upstream( std::unique_ptr &&upstream) { upstream_ = std::move(upstream); alpn_ = StringRef::from_lit("h3"); write_ = &ClientHandler::write_quic; } +#endif // ENABLE_HTTP3 ClientHandler::~ClientHandler() { if (LOG_ENABLED(INFO)) { diff --git a/src/shrpx_client_handler.h b/src/shrpx_client_handler.h index ef467810..0c013973 100644 --- a/src/shrpx_client_handler.h +++ b/src/shrpx_client_handler.h @@ -53,7 +53,9 @@ class Downstream; struct WorkerStat; struct DownstreamAddrGroup; struct DownstreamAddr; +#ifdef ENABLE_HTTP3 class Http3Upstream; +#endif // ENABLE_HTTP3 class ClientHandler { public: @@ -71,9 +73,6 @@ public: int read_tls(); int write_tls(); - int read_quic(const UpstreamAddr *faddr, const Address &remote_addr, - const Address &local_addr, const uint8_t *data, size_t datalen); - int upstream_noop(); int upstream_read(); int upstream_http2_connhd_read(); @@ -147,8 +146,12 @@ public: void setup_upstream_io_callback(); +#ifdef ENABLE_HTTP3 void setup_http3_upstream(std::unique_ptr &&upstream); + int read_quic(const UpstreamAddr *faddr, const Address &remote_addr, + const Address &local_addr, const uint8_t *data, size_t datalen); int write_quic(); +#endif // ENABLE_HTTP3 // Returns string suitable for use in "by" parameter of Forwarded // header field. diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 8742ad6a..c3eb218a 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -821,7 +821,11 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) { } else if (util::strieq_l("proxyproto", param)) { out.proxyproto = true; } else if (util::strieq_l("quic", param)) { +#ifdef ENABLE_HTTP3 out.quic = true; +#else // !ENABLE_HTTP3 + LOG(ERROR) << "quic: QUIC is disabled at compile time"; +#endif // !ENABLE_HTTP3 } else if (!param.empty()) { LOG(ERROR) << "frontend: " << param << ": unknown keyword"; return -1; @@ -2674,8 +2678,12 @@ int parse_config(Config *config, int optid, const StringRef &opt, apiconf.enabled = true; } +#ifdef ENABLE_HTTP3 auto &addrs = params.quic ? config->conn.quic_listener.addrs : config->conn.listener.addrs; +#else // !ENABLE_HTTP3 + auto &addrs = config->conn.listener.addrs; +#endif // !ENABLE_HTTP3 if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) { auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size(); diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 291e25e6..d3a22baa 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -704,6 +704,7 @@ struct TLSConfig { bool no_postpone_early_data; }; +#ifdef ENABLE_HTTP3 struct QUICConfig { struct { std::array secret; @@ -715,6 +716,7 @@ struct QUICConfig { bool log; } debug; }; +#endif // ENABLE_HTTP3 // custom error page struct ErrorPage { @@ -921,9 +923,11 @@ struct ConnectionConfig { int fastopen; } listener; +#ifdef ENABLE_HTTP3 struct { std::vector addrs; } quic_listener; +#endif // ENABLE_HTTP3 struct { struct { @@ -968,7 +972,9 @@ struct Config { http{}, http2{}, tls{}, +#ifdef ENABLE_HTTP3 quic{}, +#endif // ENABLE_HTTP3 logging{}, conn{}, api{}, @@ -986,7 +992,8 @@ struct Config { single_process{false}, single_thread{false}, ignore_per_pattern_mruby_error{false}, - ev_loop_flags{0} {} + ev_loop_flags{0} { + } ~Config(); Config(Config &&) = delete; @@ -1002,7 +1009,9 @@ struct Config { HttpConfig http; Http2Config http2; TLSConfig tls; +#ifdef ENABLE_HTTP3 QUICConfig quic; +#endif // ENABLE_HTTP3 LoggingConfig logging; ConnectionConfig conn; APIConfig api; diff --git a/src/shrpx_connection_handler.cc b/src/shrpx_connection_handler.cc index 03f74594..39ea08cd 100644 --- a/src/shrpx_connection_handler.cc +++ b/src/shrpx_connection_handler.cc @@ -156,6 +156,7 @@ ConnectionHandler::~ConnectionHandler() { ev_timer_stop(loop_, &ocsp_timer_); ev_timer_stop(loop_, &disable_acceptor_timer_); +#ifdef ENABLE_HTTP3 for (auto ssl_ctx : quic_all_ssl_ctx_) { if (ssl_ctx == nullptr) { continue; @@ -166,6 +167,7 @@ ConnectionHandler::~ConnectionHandler() { delete tls_ctx_data; SSL_CTX_free(ssl_ctx); } +#endif // ENABLE_HTTP3 for (auto ssl_ctx : all_ssl_ctx_) { auto tls_ctx_data = @@ -221,14 +223,16 @@ int ConnectionHandler::create_single_worker() { #endif // HAVE_NEVERBLEED ); +#ifdef ENABLE_HTTP3 quic_cert_tree_ = tls::create_cert_lookup_tree(); auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context( quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get() -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , nb_ -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ); +#endif // ENABLE_HTTP3 auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context( #ifdef HAVE_NEVERBLEED @@ -238,7 +242,9 @@ int ConnectionHandler::create_single_worker() { if (cl_ssl_ctx) { all_ssl_ctx_.push_back(cl_ssl_ctx); +#ifdef ENABLE_HTTP3 quic_all_ssl_ctx_.push_back(nullptr); +#endif // ENABLE_HTTP3 } auto config = get_config(); @@ -255,22 +261,29 @@ int ConnectionHandler::create_single_worker() { tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file, nullptr); all_ssl_ctx_.push_back(session_cache_ssl_ctx); +#ifdef ENABLE_HTTP3 quic_all_ssl_ctx_.push_back(nullptr); +#endif // ENABLE_HTTP3 } } single_worker_ = std::make_unique( loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(), - quic_sv_ssl_ctx, quic_cert_tree_.get(), ticket_keys_, this, - config->conn.downstream); +#ifdef ENABLE_HTTP3 + quic_sv_ssl_ctx, quic_cert_tree_.get(), +#endif // ENABLE_HTTP3 + ticket_keys_, this, config->conn.downstream); #ifdef HAVE_MRUBY if (single_worker_->create_mruby_context() != 0) { return -1; } #endif // HAVE_MRUBY + +#ifdef ENABLE_HTTP3 if (single_worker_->setup_quic_server_socket() != 0) { return -1; } +#endif // ENABLE_HTTP3 return 0; } @@ -288,14 +301,16 @@ int ConnectionHandler::create_worker_thread(size_t num) { # endif // HAVE_NEVERBLEED ); +# ifdef ENABLE_HTTP3 quic_cert_tree_ = tls::create_cert_lookup_tree(); auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context( quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get() -# ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , nb_ -# endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ); +# endif // ENABLE_HTTP3 auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context( # ifdef HAVE_NEVERBLEED @@ -305,7 +320,9 @@ int ConnectionHandler::create_worker_thread(size_t num) { if (cl_ssl_ctx) { all_ssl_ctx_.push_back(cl_ssl_ctx); +# ifdef ENABLE_HTTP3 quic_all_ssl_ctx_.push_back(nullptr); +# endif // ENABLE_HTTP3 } auto config = get_config(); @@ -329,7 +346,9 @@ int ConnectionHandler::create_worker_thread(size_t num) { tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file, nullptr); all_ssl_ctx_.push_back(session_cache_ssl_ctx); +# ifdef ENABLE_HTTP3 quic_all_ssl_ctx_.push_back(nullptr); +# endif // ENABLE_HTTP3 } } @@ -338,17 +357,22 @@ int ConnectionHandler::create_worker_thread(size_t num) { auto worker = std::make_unique( loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(), - quic_sv_ssl_ctx, quic_cert_tree_.get(), ticket_keys_, this, - config->conn.downstream); +# ifdef ENABLE_HTTP3 + quic_sv_ssl_ctx, quic_cert_tree_.get(), +# endif // ENABLE_HTTP3 + ticket_keys_, this, config->conn.downstream); # ifdef HAVE_MRUBY if (worker->create_mruby_context() != 0) { return -1; } # endif // HAVE_MRUBY + +# ifdef ENABLE_HTTP3 if ((!apiconf.enabled || i != 0) && worker->setup_quic_server_socket() != 0) { return -1; } +# endif // ENABLE_HTTP3 workers_.push_back(std::move(worker)); worker_loops_.push_back(loop); @@ -646,7 +670,9 @@ void ConnectionHandler::handle_ocsp_complete() { ev_child_stop(loop_, &ocsp_.chldev); assert(ocsp_.next < all_ssl_ctx_.size()); +#ifdef ENABLE_HTTP3 assert(all_ssl_ctx_.size() == quic_all_ssl_ctx_.size()); +#endif // ENABLE_HTTP3 auto ssl_ctx = all_ssl_ctx_[ocsp_.next]; auto tls_ctx_data = @@ -674,6 +700,7 @@ void ConnectionHandler::handle_ocsp_complete() { if (tlsconf.ocsp.no_verify || tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size()) == 0) { +#ifdef ENABLE_HTTP3 // We have list of SSL_CTX with the same certificate in // quic_all_ssl_ctx_ as well. Some SSL_CTXs are missing there in // that case we get nullptr. @@ -681,21 +708,22 @@ void ConnectionHandler::handle_ocsp_complete() { if (quic_ssl_ctx) { auto quic_tls_ctx_data = static_cast( SSL_CTX_get_app_data(quic_ssl_ctx)); -#ifndef OPENSSL_IS_BORINGSSL -# ifdef HAVE_ATOMIC_STD_SHARED_PTR +# ifndef OPENSSL_IS_BORINGSSL +# ifdef HAVE_ATOMIC_STD_SHARED_PTR std::atomic_store_explicit( &quic_tls_ctx_data->ocsp_data, std::make_shared>(ocsp_.resp), std::memory_order_release); -# else // !HAVE_ATOMIC_STD_SHARED_PTR +# else // !HAVE_ATOMIC_STD_SHARED_PTR std::lock_guard g(quic_tls_ctx_data->mu); quic_tls_ctx_data->ocsp_data = std::make_shared>(ocsp_.resp); -# endif // !HAVE_ATOMIC_STD_SHARED_PTR -#else // OPENSSL_IS_BORINGSSL +# endif // !HAVE_ATOMIC_STD_SHARED_PTR +# else // OPENSSL_IS_BORINGSSL SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size()); -#endif // OPENSSL_IS_BORINGSSL +# endif // OPENSSL_IS_BORINGSSL } +#endif // ENABLE_HTTP3 #ifndef OPENSSL_IS_BORINGSSL # ifdef HAVE_ATOMIC_STD_SHARED_PTR @@ -877,7 +905,9 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() { nullptr); all_ssl_ctx_.push_back(ssl_ctx); +#ifdef ENABLE_HTTP3 quic_all_ssl_ctx_.push_back(nullptr); +#endif // ENABLE_HTTP3 return ssl_ctx; } @@ -940,10 +970,12 @@ ConnectionHandler::get_indexed_ssl_ctx(size_t idx) const { return indexed_ssl_ctx_[idx]; } +#ifdef ENABLE_HTTP3 const std::vector & ConnectionHandler::get_quic_indexed_ssl_ctx(size_t idx) const { return quic_indexed_ssl_ctx_[idx]; } +#endif // ENABLE_HTTP3 void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) { enable_acceptor_on_ocsp_completion_ = f; diff --git a/src/shrpx_connection_handler.h b/src/shrpx_connection_handler.h index eb86b855..3e8a5406 100644 --- a/src/shrpx_connection_handler.h +++ b/src/shrpx_connection_handler.h @@ -159,7 +159,9 @@ public: SSL_CTX *get_ssl_ctx(size_t idx) const; const std::vector &get_indexed_ssl_ctx(size_t idx) const; +#ifdef ENABLE_HTTP3 const std::vector &get_quic_indexed_ssl_ctx(size_t idx) const; +#endif // ENABLE_HTTP3 #ifdef HAVE_NEVERBLEED void set_neverbleed(neverbleed_t *nb); @@ -188,8 +190,10 @@ private: // selection among them are performed by hostname presented by SNI, // and signature algorithm presented by client. std::vector> indexed_ssl_ctx_; +#ifdef ENABLE_HTTP3 std::vector quic_all_ssl_ctx_; std::vector> quic_indexed_ssl_ctx_; +#endif // ENABLE_HTTP3 OCSPUpdateContext ocsp_; std::mt19937 &gen_; // ev_loop for each worker @@ -206,7 +210,9 @@ private: // Otherwise, nullptr and workers_ has instances of Worker instead. std::unique_ptr single_worker_; std::unique_ptr cert_tree_; +#ifdef ENABLE_HTTP3 std::unique_ptr quic_cert_tree_; +#endif // ENABLE_HTTP3 std::unique_ptr tls_ticket_key_memcached_dispatcher_; // Current TLS session ticket keys. Note that TLS connection does // not refer to this field directly. They use TicketKeys object in diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index ca07f2f1..7c822ba8 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -165,7 +165,9 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool, downstream_wtimer_.data = this; rcbufs_.reserve(32); +#ifdef ENABLE_HTTP3 rcbufs3_.reserve(32); +#endif // ENABLE_HTTP3 } Downstream::~Downstream() { @@ -205,9 +207,11 @@ Downstream::~Downstream() { // explicitly. dconn_.reset(); +#ifdef ENABLE_HTTP3 for (auto rcbuf : rcbufs3_) { nghttp3_rcbuf_decref(rcbuf); } +#endif // ENABLE_HTTP3 for (auto rcbuf : rcbufs_) { nghttp2_rcbuf_decref(rcbuf); @@ -1134,10 +1138,12 @@ void Downstream::add_rcbuf(nghttp2_rcbuf *rcbuf) { rcbufs_.push_back(rcbuf); } +#ifdef ENABLE_HTTP3 void Downstream::add_rcbuf(nghttp3_rcbuf *rcbuf) { nghttp3_rcbuf_incref(rcbuf); rcbufs3_.push_back(rcbuf); } +#endif // ENABLE_HTTP3 void Downstream::set_downstream_addr_group( const std::shared_ptr &group) { diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 20ec54c4..2a50a974 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -38,7 +38,9 @@ #include -#include +#ifdef ENABLE_HTTP3 +# include +#endif // ENABLE_HTTP3 #include "llhttp.h" @@ -490,7 +492,9 @@ public: BlockAllocator &get_block_allocator(); void add_rcbuf(nghttp2_rcbuf *rcbuf); +#ifdef ENABLE_HTTP3 void add_rcbuf(nghttp3_rcbuf *rcbuf); +#endif // ENABLE_HTTP3 void set_downstream_addr_group(const std::shared_ptr &group); @@ -533,7 +537,9 @@ private: BlockAllocator balloc_; std::vector rcbufs_; +#ifdef ENABLE_HTTP3 std::vector rcbufs3_; +#endif // ENABLE_HTTP3 Request req_; Response resp_; diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index 79104d54..a86dc1a5 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -51,9 +51,11 @@ #include -#include -#include -#include +#ifdef ENABLE_HTTP3 +# include +# include +# include +#endif // ENABLE_HTTP3 #include "shrpx_log.h" #include "shrpx_client_handler.h" @@ -64,7 +66,9 @@ #include "shrpx_memcached_request.h" #include "shrpx_memcached_dispatcher.h" #include "shrpx_connection_handler.h" -#include "shrpx_http3_upstream.h" +#ifdef ENABLE_HTTP3 +# include "shrpx_http3_upstream.h" +#endif // ENABLE_HTTP3 #include "util.h" #include "tls.h" #include "template.h" @@ -185,8 +189,12 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto hostname = StringRef{std::begin(buf), end_buf}; +#ifdef ENABLE_HTTP3 auto cert_tree = SSL_is_quic(ssl) ? worker->get_quic_cert_lookup_tree() : worker->get_cert_lookup_tree(); +#else // !ENABLE_HTTP3 + auto cert_tree = worker->get_cert_lookup_tree(); +#endif // !ENABLE_HTTP3 auto idx = cert_tree->lookup(hostname); if (idx == -1) { @@ -197,9 +205,14 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto conn_handler = worker->get_connection_handler(); +#ifdef ENABLE_HTTP3 const auto &ssl_ctx_list = SSL_is_quic(ssl) ? conn_handler->get_quic_indexed_ssl_ctx(idx) : conn_handler->get_indexed_ssl_ctx(idx); +#else // !ENABLE_HTTP3 + const auto &ssl_ctx_list = conn_handler->get_indexed_ssl_ctx(idx); +#endif // !ENABLE_HTTP3 + assert(!ssl_ctx_list.empty()); #if !defined(OPENSSL_IS_BORINGSSL) && !LIBRESSL_IN_USE && \ @@ -608,7 +621,8 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, } // namespace #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L -#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#ifdef ENABLE_HTTP3 +# if OPENSSL_VERSION_NUMBER >= 0x10002000L namespace { int quic_alpn_select_proto_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, @@ -632,7 +646,8 @@ int quic_alpn_select_proto_cb(SSL *ssl, const unsigned char **out, return SSL_TLSEXT_ERR_NOACK; } } // namespace -#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L +# endif // OPENSSL_VERSION_NUMBER >= 0x10002000L +#endif // ENABLE_HTTP3 #if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L @@ -1076,6 +1091,7 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file, return ssl_ctx; } +#ifdef ENABLE_HTTP3 namespace { int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *rx_secret, @@ -1143,10 +1159,10 @@ auto quic_method = SSL_QUIC_METHOD{ SSL_CTX *create_quic_ssl_context(const char *private_key_file, const char *cert_file, const std::vector &sct_data -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , neverbleed_t *nb -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ) { auto ssl_ctx = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx) { @@ -1159,14 +1175,14 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE | SSL_OP_CIPHER_SERVER_PREFERENCE -#if OPENSSL_1_1_1_API +# if OPENSSL_1_1_1_API // The reason for disabling built-in anti-replay in OpenSSL is // that it only works if client gets back to the same server. // The freshness check described in // https://tools.ietf.org/html/rfc8446#section-8.3 is still // performed. | SSL_OP_NO_ANTI_REPLAY -#endif // OPENSSL_1_1_1_API +# endif // OPENSSL_1_1_1_API ; auto config = mod_config(); @@ -1194,27 +1210,27 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, DIE(); } -#if OPENSSL_1_1_1_API +# if OPENSSL_1_1_1_API if (SSL_CTX_set_ciphersuites(ssl_ctx, tlsconf.tls13_ciphers.c_str()) == 0) { LOG(FATAL) << "SSL_CTX_set_ciphersuites " << tlsconf.tls13_ciphers << " failed: " << ERR_error_string(ERR_get_error(), nullptr); DIE(); } -#endif // OPENSSL_1_1_1_API +# endif // OPENSSL_1_1_1_API -#ifndef OPENSSL_NO_EC -# if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L +# ifndef OPENSSL_NO_EC +# if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L if (SSL_CTX_set1_curves_list(ssl_ctx, tlsconf.ecdh_curves.c_str()) != 1) { LOG(FATAL) << "SSL_CTX_set1_curves_list " << tlsconf.ecdh_curves << " failed"; DIE(); } -# if !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API +# if !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API // It looks like we need this function call for OpenSSL 1.0.2. This // function was deprecated in OpenSSL 1.1.0 and BoringSSL. SSL_CTX_set_ecdh_auto(ssl_ctx, 1); -# endif // !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API -# else // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L +# endif // !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API +# else // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L // Use P-256, which is sufficiently secure at the time of this // writing. auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); @@ -1225,8 +1241,8 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, } SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh); EC_KEY_free(ecdh); -# endif // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L -#endif // OPENSSL_NO_EC +# endif // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L +# endif // OPENSSL_NO_EC if (!tlsconf.dh_param_file.empty()) { // Read DH parameters from file @@ -1269,20 +1285,20 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, config); } -#ifndef HAVE_NEVERBLEED +# ifndef HAVE_NEVERBLEED if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key_file, SSL_FILETYPE_PEM) != 1) { LOG(FATAL) << "SSL_CTX_use_PrivateKey_file failed: " << ERR_error_string(ERR_get_error(), nullptr); } -#else // HAVE_NEVERBLEED +# else // HAVE_NEVERBLEED std::array errbuf; if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file, errbuf.data()) != 1) { LOG(FATAL) << "neverbleed_load_private_key_file failed: " << errbuf.data(); DIE(); } -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { LOG(FATAL) << "SSL_CTX_use_certificate_file failed: " @@ -1324,27 +1340,27 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, } SSL_CTX_set_tlsext_servername_callback(ssl_ctx, servername_callback); SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx, ticket_key_cb); -#ifndef OPENSSL_IS_BORINGSSL +# ifndef OPENSSL_IS_BORINGSSL SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); -#endif // OPENSSL_IS_BORINGSSL +# endif // OPENSSL_IS_BORINGSSL -#ifdef OPENSSL_IS_BORINGSSL +# ifdef OPENSSL_IS_BORINGSSL SSL_CTX_set_early_data_enabled(ssl_ctx, 1); -#endif // OPENSSL_IS_BORINGSSL +# endif // OPENSSL_IS_BORINGSSL -#if OPENSSL_VERSION_NUMBER >= 0x10002000L +# if OPENSSL_VERSION_NUMBER >= 0x10002000L // ALPN selection callback SSL_CTX_set_alpn_select_cb(ssl_ctx, quic_alpn_select_proto_cb, nullptr); -#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L +# endif // OPENSSL_VERSION_NUMBER >= 0x10002000L -#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \ - !defined(OPENSSL_IS_BORINGSSL) +# if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \ + !defined(OPENSSL_IS_BORINGSSL) // SSL_extension_supported(TLSEXT_TYPE_signed_certificate_timestamp) // returns 1, which means OpenSSL internally handles it. But // OpenSSL handles signed_certificate_timestamp extension specially, // and it lets custom handler to process the extension. if (!sct_data.empty()) { -# if OPENSSL_1_1_1_API +# if OPENSSL_1_1_1_API // It is not entirely clear to me that SSL_EXT_CLIENT_HELLO is // required here. sct_parse_cb is called without // SSL_EXT_CLIENT_HELLO being set. But the passed context value @@ -1358,7 +1374,7 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, << ERR_error_string(ERR_get_error(), nullptr); DIE(); } -# else // !OPENSSL_1_1_1_API +# else // !OPENSSL_1_1_1_API if (SSL_CTX_add_server_custom_ext( ssl_ctx, TLSEXT_TYPE_signed_certificate_timestamp, legacy_sct_add_cb, legacy_sct_free_cb, nullptr, legacy_sct_parse_cb, @@ -1367,23 +1383,23 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, << ERR_error_string(ERR_get_error(), nullptr); DIE(); } -# endif // !OPENSSL_1_1_1_API +# endif // !OPENSSL_1_1_1_API } -#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && - // !defined(OPENSSL_IS_BORINGSSL) +# endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && + // !defined(OPENSSL_IS_BORINGSSL) -#if OPENSSL_1_1_1_API +# if OPENSSL_1_1_1_API if (SSL_CTX_set_max_early_data(ssl_ctx, std::numeric_limits::max()) != 1) { LOG(FATAL) << "SSL_CTX_set_max_early_data failed: " << ERR_error_string(ERR_get_error(), nullptr); DIE(); } -#endif // OPENSSL_1_1_1_API +# endif // OPENSSL_1_1_1_API -#ifndef OPENSSL_NO_PSK +# ifndef OPENSSL_NO_PSK SSL_CTX_set_psk_server_callback(ssl_ctx, psk_server_cb); -#endif // !LIBRESSL_NO_PSK +# endif // !LIBRESSL_NO_PSK SSL_CTX_set_quic_method(ssl_ctx, &quic_method); @@ -1395,6 +1411,7 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, return ssl_ctx; } +#endif // ENABLE_HTTP3 namespace { int select_h2_next_proto_cb(SSL *ssl, unsigned char **out, @@ -2101,9 +2118,11 @@ bool in_proto_list(const std::vector &protos, } bool upstream_tls_enabled(const ConnectionConfig &connconf) { +#ifdef ENABLE_HTTP3 if (connconf.quic_listener.addrs.size()) { return true; } +#endif // ENABLE_HTTP3 const auto &faddrs = connconf.listener.addrs; return std::any_of(std::begin(faddrs), std::end(faddrs), @@ -2184,14 +2203,15 @@ setup_server_ssl_context(std::vector &all_ssl_ctx, return ssl_ctx; } +#ifdef ENABLE_HTTP3 SSL_CTX *setup_quic_server_ssl_context( std::vector &all_ssl_ctx, std::vector> &indexed_ssl_ctx, CertLookupTree *cert_tree -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , neverbleed_t *nb -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ) { auto config = get_config(); @@ -2204,10 +2224,10 @@ SSL_CTX *setup_quic_server_ssl_context( auto ssl_ctx = create_quic_ssl_context(tlsconf.private_key_file.c_str(), tlsconf.cert_file.c_str(), tlsconf.sct_data -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , nb -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ); all_ssl_ctx.push_back(ssl_ctx); @@ -2222,10 +2242,10 @@ SSL_CTX *setup_quic_server_ssl_context( for (auto &c : tlsconf.subcerts) { auto ssl_ctx = create_quic_ssl_context(c.private_key_file.c_str(), c.cert_file.c_str(), c.sct_data -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , nb -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ); all_ssl_ctx.push_back(ssl_ctx); @@ -2238,6 +2258,7 @@ SSL_CTX *setup_quic_server_ssl_context( return ssl_ctx; } +#endif // ENABLE_HTTP3 SSL_CTX *setup_downstream_client_ssl_context( #ifdef HAVE_NEVERBLEED diff --git a/src/shrpx_tls.h b/src/shrpx_tls.h index ebc4aa27..5d751c0f 100644 --- a/src/shrpx_tls.h +++ b/src/shrpx_tls.h @@ -100,15 +100,17 @@ SSL_CTX *create_ssl_client_context( unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)); +#ifdef ENABLE_HTTP3 SSL_CTX *create_quic_ssl_client_context( -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED neverbleed_t *nb, -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED const StringRef &cacert, const StringRef &cert_file, const StringRef &private_key_file, int (*next_proto_select_cb)(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)); +#endif // ENABLE_HTTP3 ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr, int addrlen, const UpstreamAddr *faddr); @@ -227,15 +229,17 @@ setup_server_ssl_context(std::vector &all_ssl_ctx, #endif // HAVE_NEVERBLEED ); +#ifdef ENABLE_HTTP3 SSL_CTX *setup_quic_server_ssl_context( std::vector &all_ssl_ctx, std::vector> &indexed_ssl_ctx, CertLookupTree *cert_tree -#ifdef HAVE_NEVERBLEED +# ifdef HAVE_NEVERBLEED , neverbleed_t *nb -#endif // HAVE_NEVERBLEED +# endif // HAVE_NEVERBLEED ); +#endif // ENABLE_HTTP3 // Setups client side SSL_CTX. SSL_CTX *setup_downstream_client_ssl_context( diff --git a/src/shrpx_worker.cc b/src/shrpx_worker.cc index 0a4ed3c7..b153b0e6 100644 --- a/src/shrpx_worker.cc +++ b/src/shrpx_worker.cc @@ -39,8 +39,10 @@ #ifdef HAVE_MRUBY # include "shrpx_mruby.h" #endif // HAVE_MRUBY -#include "shrpx_quic.h" -#include "shrpx_quic_listener.h" +#ifdef ENABLE_HTTP3 +# include "shrpx_quic.h" +# include "shrpx_quic_listener.h" +#endif // ENABLE_HTTP3 #include "util.h" #include "template.h" @@ -132,23 +134,29 @@ create_downstream_key(const std::shared_ptr &shared_addr, Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, SSL_CTX *tls_session_cache_memcached_ssl_ctx, - tls::CertLookupTree *cert_tree, SSL_CTX *quic_sv_ssl_ctx, - tls::CertLookupTree *quic_cert_tree, + tls::CertLookupTree *cert_tree, +#ifdef ENABLE_HTTP3 + SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *quic_cert_tree, +#endif // ENABLE_HTTP3 const std::shared_ptr &ticket_keys, ConnectionHandler *conn_handler, std::shared_ptr downstreamconf) : randgen_(util::make_mt19937()), worker_stat_{}, dns_tracker_(loop), +#ifdef ENABLE_HTTP3 quic_upstream_addrs_{get_config()->conn.quic_listener.addrs}, +#endif // ENABLE_HTTP3 loop_(loop), sv_ssl_ctx_(sv_ssl_ctx), cl_ssl_ctx_(cl_ssl_ctx), cert_tree_(cert_tree), conn_handler_(conn_handler), +#ifdef ENABLE_HTTP3 quic_sv_ssl_ctx_{quic_sv_ssl_ctx}, quic_cert_tree_{quic_cert_tree}, quic_conn_handler_{this}, +#endif // ENABLE_HTTP3 ticket_keys_(ticket_keys), connect_blocker_( std::make_unique(randgen_, loop_, nullptr, nullptr)), @@ -511,9 +519,11 @@ void Worker::process_events() { tls::CertLookupTree *Worker::get_cert_lookup_tree() const { return cert_tree_; } +#ifdef ENABLE_HTTP3 tls::CertLookupTree *Worker::get_quic_cert_lookup_tree() const { return quic_cert_tree_; } +#endif // ENABLE_HTTP3 std::shared_ptr Worker::get_ticket_keys() { #ifdef HAVE_ATOMIC_STD_SHARED_PTR @@ -545,7 +555,9 @@ SSL_CTX *Worker::get_sv_ssl_ctx() const { return sv_ssl_ctx_; } SSL_CTX *Worker::get_cl_ssl_ctx() const { return cl_ssl_ctx_; } +#ifdef ENABLE_HTTP3 SSL_CTX *Worker::get_quic_sv_ssl_ctx() const { return quic_sv_ssl_ctx_; } +#endif // ENABLE_HTTP3 void Worker::set_graceful_shutdown(bool f) { graceful_shutdown_ = f; } @@ -591,12 +603,15 @@ ConnectionHandler *Worker::get_connection_handler() const { return conn_handler_; } +#ifdef ENABLE_HTTP3 QUICConnectionHandler *Worker::get_quic_connection_handler() { return &quic_conn_handler_; } +#endif // ENABLE_HTTP3 DNSTracker *Worker::get_dns_tracker() { return &dns_tracker_; } +#ifdef ENABLE_HTTP3 int Worker::setup_quic_server_socket() { for (auto &addr : quic_upstream_addrs_) { assert(!addr.host_unix); @@ -609,6 +624,7 @@ int Worker::setup_quic_server_socket() { return 0; } +#endif // ENABLE_HTTP3 namespace { size_t match_downstream_addr_group_host( diff --git a/src/shrpx_worker.h b/src/shrpx_worker.h index 02ece027..e4e83e6e 100644 --- a/src/shrpx_worker.h +++ b/src/shrpx_worker.h @@ -50,7 +50,9 @@ #include "shrpx_live_check.h" #include "shrpx_connect_blocker.h" #include "shrpx_dns_tracker.h" -#include "shrpx_quic_connection_handler.h" +#ifdef ENABLE_HTTP3 +# include "shrpx_quic_connection_handler.h" +#endif // ENABLE_HTTP3 #include "allocator.h" using namespace nghttp2; @@ -62,7 +64,9 @@ class ConnectBlocker; class MemcachedDispatcher; struct UpstreamAddr; class ConnectionHandler; +#ifdef ENABLE_HTTP3 class QUICListener; +#endif // ENABLE_HTTP3 #ifdef HAVE_MRUBY namespace mruby { @@ -271,8 +275,10 @@ class Worker { public: Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, SSL_CTX *tls_session_cache_memcached_ssl_ctx, - tls::CertLookupTree *cert_tree, SSL_CTX *quic_sv_ssl_ctx, - tls::CertLookupTree *quic_cert_tree, + tls::CertLookupTree *cert_tree, +#ifdef ENABLE_HTTP3 + SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *quic_cert_tree, +#endif // ENABLE_HTTP3 const std::shared_ptr &ticket_keys, ConnectionHandler *conn_handler, std::shared_ptr downstreamconf); @@ -283,7 +289,9 @@ public: void send(const WorkerEvent &event); tls::CertLookupTree *get_cert_lookup_tree() const; +#ifdef ENABLE_HTTP3 tls::CertLookupTree *get_quic_cert_lookup_tree() const; +#endif // ENABLE_HTTP3 // These 2 functions make a lock m_ to get/set ticket keys // atomically. @@ -294,7 +302,9 @@ public: struct ev_loop *get_loop() const; SSL_CTX *get_sv_ssl_ctx() const; SSL_CTX *get_cl_ssl_ctx() const; +#ifdef ENABLE_HTTP3 SSL_CTX *get_quic_sv_ssl_ctx() const; +#endif // ENABLE_HTTP3 void set_graceful_shutdown(bool f); bool get_graceful_shutdown() const; @@ -324,11 +334,13 @@ public: ConnectionHandler *get_connection_handler() const; +#ifdef ENABLE_HTTP3 QUICConnectionHandler *get_quic_connection_handler(); - DNSTracker *get_dns_tracker(); - int setup_quic_server_socket(); +#endif // ENABLE_HTTP3 + + DNSTracker *get_dns_tracker(); private: #ifndef NOTHREADS @@ -344,8 +356,10 @@ private: WorkerStat worker_stat_; DNSTracker dns_tracker_; +#ifdef ENABLE_HTTP3 std::vector quic_upstream_addrs_; std::vector> quic_listeners_; +#endif // ENABLE_HTTP3 std::shared_ptr downstreamconf_; std::unique_ptr session_cache_memcached_dispatcher_; @@ -360,10 +374,12 @@ private: SSL_CTX *cl_ssl_ctx_; tls::CertLookupTree *cert_tree_; ConnectionHandler *conn_handler_; +#ifdef ENABLE_HTTP3 SSL_CTX *quic_sv_ssl_ctx_; tls::CertLookupTree *quic_cert_tree_; QUICConnectionHandler quic_conn_handler_; +#endif // ENABLE_HTTP3 #ifndef HAVE_ATOMIC_STD_SHARED_PTR std::mutex ticket_keys_m_;