Build without HTTP/3 support

This commit is contained in:
Tatsuhiro Tsujikawa 2021-08-21 19:00:43 +09:00
parent f46984d218
commit 4eced8a393
18 changed files with 365 additions and 107 deletions

View File

@ -448,6 +448,10 @@ foreach(name
configure_file("${name}.in" "${name}" @ONLY) configure_file("${name}.in" "${name}" @ONLY)
endforeach() endforeach()
if(APPLE)
add_definitions(-D__APPLE_USE_RFC_3542)
endif()
include_directories( include_directories(
"${CMAKE_CURRENT_BINARY_DIR}" # for config.h "${CMAKE_CURRENT_BINARY_DIR}" # for config.h
) )

View File

@ -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])], [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]) [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], AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [AS_HELP_STRING([--with-libxml2],
[Use libxml2 [default=check]])], [Use libxml2 [default=check]])],
@ -172,6 +177,16 @@ AC_ARG_WITH([cython],
[Use cython in given PATH])], [Use cython in given PATH])],
[cython_path=$withval], []) [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 dnl Define variables
AC_ARG_VAR([CYTHON], [the Cython executable]) AC_ARG_VAR([CYTHON], [the Cython executable])
@ -334,6 +349,13 @@ case "$host_os" in
;; ;;
esac esac
case "${build}" in
*-apple-darwin*)
EXTRA_DEFS="-D__APPLE_USE_RFC_3542"
AC_SUBST([EXTRA_DEFS])
;;
esac
# zlib # zlib
have_zlib=no have_zlib=no
if test "x${request_zlib}" != "xno"; then if test "x${request_zlib}" != "xno"; then
@ -455,26 +477,50 @@ if test "x${request_libcares}" = "xyes" &&
fi fi
# ngtcp2 (for src) # ngtcp2 (for src)
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.0.0], [have_libngtcp2=yes], have_libngtcp2=no
[have_libngtcp2=no]) if test "x${request_libngtcp2}" != "xno"; then
if test "x${have_libngtcp2}" = "xno"; then PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.0.0], [have_libngtcp2=yes],
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) [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 fi
# ngtcp2_crypto_openssl (for src) # ngtcp2_crypto_openssl (for src)
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL], have_libngtcp2_crypto_openssl=no
[libngtcp2_crypto_openssl >= 0.0.0], if test "x${request_libngtcp2}" != "xno"; then
[have_libngtcp2_crypto_openssl=yes], PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
[have_libngtcp2_crypto_openssl=no]) [libngtcp2_crypto_openssl >= 0.0.0],
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then [have_libngtcp2_crypto_openssl=yes],
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS) [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 fi
# nghttp3 (for src) # nghttp3 (for src)
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes], have_libnghttp3=no
[have_libnghttp3=no]) if test "x${request_libnghttp3}" != "xno"; then
if test "x${have_libnghttp3}" = "xno"; then PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.0.0], [have_libnghttp3=yes],
AC_MSG_NOTICE($LIBNGHTTP3_PKT_ERRORS) [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 fi
# libevent_openssl (for examples) # libevent_openssl (for examples)
@ -621,6 +667,23 @@ fi
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ]) 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 enable_hpack_tools=no
# HPACK tools requires jansson # HPACK tools requires jansson
if test "x${request_hpack_tools}" != "xno" && if test "x${request_hpack_tools}" != "xno" &&
@ -1058,4 +1121,5 @@ AC_MSG_NOTICE([summary of build options:
Examples: ${enable_examples} Examples: ${enable_examples}
Python bindings:${enable_python_bindings} Python bindings:${enable_python_bindings}
Threading: ${enable_threads} Threading: ${enable_threads}
HTTP/3 (EXPERIMENTAL): ${enable_http3}
]) ])

View File

@ -51,6 +51,7 @@ AM_CPPFLAGS = \
@LIBNGTCP2_CFLAGS@ \ @LIBNGTCP2_CFLAGS@ \
@JANSSON_CFLAGS@ \ @JANSSON_CFLAGS@ \
@ZLIB_CFLAGS@ \ @ZLIB_CFLAGS@ \
@EXTRA_DEFS@ \
@DEFS@ @DEFS@
AM_LDFLAGS = @LIBTOOL_LDFLAGS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@
@ -103,10 +104,14 @@ h2load_SOURCES = util.cc util.h \
tls.cc tls.h \ tls.cc tls.h \
h2load_session.h \ h2load_session.h \
h2load_http2_session.cc h2load_http2_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_http3_session.cc h2load_http3_session.h \
h2load_quic.cc h2load_quic.h \ h2load_quic.cc h2load_quic.h \
quic.cc quic.h quic.cc quic.h
endif # ENABLE_HTTP3
NGHTTPX_SRCS = \ NGHTTPX_SRCS = \
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \ 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_dns_resolver.cc shrpx_dns_resolver.h \
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \ shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \
shrpx_dns_tracker.cc shrpx_dns_tracker.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 \ buffer.h memchunk.h template.h allocator.h \
xsi_strerror.c xsi_strerror.h xsi_strerror.c xsi_strerror.h
@ -171,6 +170,16 @@ NGHTTPX_SRCS += \
shrpx_mruby_module_response.cc shrpx_mruby_module_response.h shrpx_mruby_module_response.cc shrpx_mruby_module_response.h
endif # HAVE_MRUBY 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 noinst_LIBRARIES = libnghttpx.a
libnghttpx_a_SOURCES = ${NGHTTPX_SRCS} libnghttpx_a_SOURCES = ${NGHTTPX_SRCS}
libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS} libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS}

View File

@ -50,14 +50,18 @@
#include <openssl/err.h> #include <openssl/err.h>
#include <ngtcp2/ngtcp2.h> #ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2.h>
#endif // ENABLE_HTTP3
#include "url-parser/url_parser.h" #include "url-parser/url_parser.h"
#include "h2load_http1_session.h" #include "h2load_http1_session.h"
#include "h2load_http2_session.h" #include "h2load_http2_session.h"
#include "h2load_http3_session.h" #ifdef ENABLE_HTTP3
#include "h2load_quic.h" # include "h2load_http3_session.h"
# include "h2load_quic.h"
#endif // ENABLE_HTTP3
#include "tls.h" #include "tls.h"
#include "http2.h" #include "http2.h"
#include "util.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::has_base_uri() const { return (!this->base_uri.empty()); }
bool Config::rps_enabled() const { return this->rps > 0.0; } bool Config::rps_enabled() const { return this->rps > 0.0; }
bool Config::is_quic() const { bool Config::is_quic() const {
#ifdef ENABLE_HTTP3
return !npn_list.empty() && return !npn_list.empty() &&
(npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29"); (npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
#else // !ENABLE_HTTP3
return false;
#endif // !ENABLE_HTTP3
} }
Config config; Config config;
@ -435,7 +443,9 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
cstat{}, cstat{},
worker(worker), worker(worker),
ssl(nullptr), ssl(nullptr),
#ifdef ENABLE_HTTP3
quic{}, quic{},
#endif // ENABLE_HTTP3
next_addr(config.addrs), next_addr(config.addrs),
current_addr(nullptr), current_addr(nullptr),
reqidx(0), 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.); ev_timer_init(&rps_watcher, rps_cb, 0., 0.);
rps_watcher.data = this; rps_watcher.data = this;
#ifdef ENABLE_HTTP3
ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.); ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.);
quic.pkt_timer.data = this; quic.pkt_timer.data = this;
#endif // ENABLE_HTTP3
} }
Client::~Client() { Client::~Client() {
disconnect(); disconnect();
#ifdef ENABLE_HTTP3
if (config.is_quic()) { if (config.is_quic()) {
quic_free(); quic_free();
} }
#endif // ENABLE_HTTP3
if (ssl) { if (ssl) {
SSL_free(ssl); SSL_free(ssl);
@ -504,6 +518,7 @@ int Client::make_socket(addrinfo *addr) {
int rv; int rv;
if (config.is_quic()) { if (config.is_quic()) {
#ifdef ENABLE_HTTP3
fd = util::create_nonblock_udp_socket(addr->ai_family); fd = util::create_nonblock_udp_socket(addr->ai_family);
if (fd == -1) { if (fd == -1) {
return -1; return -1;
@ -528,6 +543,7 @@ int Client::make_socket(addrinfo *addr) {
std::cerr << "quic_init failed" << std::endl; std::cerr << "quic_init failed" << std::endl;
return -1; return -1;
} }
#endif // ENABLE_HTTP3
} else { } else {
fd = util::create_nonblock_socket(addr->ai_family); fd = util::create_nonblock_socket(addr->ai_family);
if (fd == -1) { if (fd == -1) {
@ -614,10 +630,12 @@ int Client::connect() {
ev_io_start(worker->loop, &wev); ev_io_start(worker->loop, &wev);
if (config.is_quic()) { if (config.is_quic()) {
#ifdef ENABLE_HTTP3
ev_io_start(worker->loop, &rev); ev_io_start(worker->loop, &rev);
readfn = &Client::read_quic; readfn = &Client::read_quic;
writefn = &Client::write_quic; writefn = &Client::write_quic;
#endif // ENABLE_HTTP3
} else { } else {
writefn = &Client::connected; writefn = &Client::connected;
} }
@ -676,11 +694,15 @@ void Client::fail() {
void Client::disconnect() { void Client::disconnect() {
record_client_end_time(); record_client_end_time();
#ifdef ENABLE_HTTP3
if (config.is_quic()) { if (config.is_quic()) {
quic_close_connection(); quic_close_connection();
} }
#endif // ENABLE_HTTP3
#ifdef ENABLE_HTTP3
ev_timer_stop(worker->loop, &quic.pkt_timer); 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_inactivity_watcher);
ev_timer_stop(worker->loop, &conn_active_watcher); ev_timer_stop(worker->loop, &conn_active_watcher);
ev_timer_stop(worker->loop, &rps_watcher); ev_timer_stop(worker->loop, &rps_watcher);
@ -843,9 +865,11 @@ void Client::report_app_info() {
} }
void Client::terminate_session() { void Client::terminate_session() {
#ifdef ENABLE_HTTP3
if (config.is_quic()) { if (config.is_quic()) {
quic.close_requested = true; quic.close_requested = true;
} }
#endif // ENABLE_HTTP3
if (session) { if (session) {
session->terminate(); session->terminate();
} }
@ -1047,11 +1071,13 @@ int Client::connection_made() {
if (next_proto) { if (next_proto) {
auto proto = StringRef{next_proto, next_proto_len}; auto proto = StringRef{next_proto, next_proto_len};
if (config.is_quic()) { if (config.is_quic()) {
#ifdef ENABLE_HTTP3
assert(session); assert(session);
if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) && if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) &&
!util::streq_l("h3-29", proto)) { !util::streq_l("h3-29", proto)) {
return -1; return -1;
} }
#endif // ENABLE_HTTP3
} else if (util::check_h2_is_selected(proto)) { } else if (util::check_h2_is_selected(proto)) {
session = std::make_unique<Http2Session>(this); session = std::make_unique<Http2Session>(this);
} else if (util::streq(NGHTTP2_H1_1, proto)) { } else if (util::streq(NGHTTP2_H1_1, proto)) {
@ -1377,6 +1403,7 @@ int Client::write_tls() {
return 0; return 0;
} }
#ifdef ENABLE_HTTP3
int Client::write_udp(const sockaddr *addr, socklen_t addrlen, int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
const uint8_t *data, size_t datalen, size_t gso_size) { const uint8_t *data, size_t datalen, size_t gso_size) {
iovec msg_iov; iovec msg_iov;
@ -1389,7 +1416,7 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
msg.msg_iov = &msg_iov; msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
#ifdef UDP_SEGMENT # ifdef UDP_SEGMENT
std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{}; std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{};
if (gso_size && datalen > gso_size) { if (gso_size && datalen > gso_size) {
msg.msg_control = msg_ctrl.data(); 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)); cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
*(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size; *(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
} }
#endif // UDP_SEGMENT # endif // UDP_SEGMENT
auto nwrite = sendmsg(fd, &msg, 0); auto nwrite = sendmsg(fd, &msg, 0);
if (nwrite < 0) { if (nwrite < 0) {
@ -1414,6 +1441,7 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
return 0; return 0;
} }
#endif // ENABLE_HTTP3
void Client::record_request_time(RequestStat *req_stat) { void Client::record_request_time(RequestStat *req_stat) {
req_stat->request_time = std::chrono::steady_clock::now(); 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." << "Warning: --qlog-file-base: only effective in quic, ignoring."
<< std::endl; << std::endl;
} else { } else {
#ifdef ENABLE_HTTP3
config.qlog_file_base = qlog_base; 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); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (config.is_quic()) { if (config.is_quic()) {
#ifdef ENABLE_HTTP3
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_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( } else if (nghttp2::tls::ssl_ctx_set_proto_versions(
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION, ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) { nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
@ -2780,12 +2812,14 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#if OPENSSL_1_1_1_API
if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) { if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) {
std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr) << " failed: " << ERR_error_string(ERR_get_error(), nullptr)
<< std::endl; << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#endif // OPENSSL_1_1_1_API
if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) { if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) {
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl; 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()); SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if OPENSSL_1_1_1_API
auto keylog_filename = getenv("SSLKEYLOGFILE"); auto keylog_filename = getenv("SSLKEYLOGFILE");
if (keylog_filename) { if (keylog_filename) {
keylog_file.open(keylog_filename, std::ios_base::app); 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); SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
} }
} }
#endif // OPENSSL_1_1_1_API
std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION; std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
Headers shared_nva; Headers shared_nva;
@ -3093,10 +3129,12 @@ traffic: )" << util::utos_funit(stats.bytes_total)
<< ") headers (space savings " << header_space_savings * 100 << ") headers (space savings " << header_space_savings * 100
<< "%), " << util::utos_funit(stats.bytes_body) << "B (" << "%), " << util::utos_funit(stats.bytes_body) << "B ("
<< stats.bytes_body << R"() data)" << std::endl; << stats.bytes_body << R"() data)" << std::endl;
#ifdef ENABLE_HTTP3
if (config.is_quic()) { if (config.is_quic()) {
std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, " std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, "
<< stats.udp_dgram_recv << " received" << std::endl; << stats.udp_dgram_recv << " received" << std::endl;
} }
#endif // ENABLE_HTTP3
std::cout std::cout
<< R"( min max mean sd +/- sd << R"( min max mean sd +/- sd
time for request: )" time for request: )"

View File

@ -45,15 +45,19 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include <ngtcp2/ngtcp2.h> #ifdef ENABLE_HTTP3
#include <ngtcp2/ngtcp2_crypto.h> # include <ngtcp2/ngtcp2.h>
# include <ngtcp2/ngtcp2_crypto.h>
#endif // ENABLE_HTTP3
#include <ev.h> #include <ev.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include "http2.h" #include "http2.h"
#include "quic.h" #ifdef ENABLE_HTTP3
# include "quic.h"
#endif // ENABLE_HTTP3
#include "memchunk.h" #include "memchunk.h"
#include "template.h" #include "template.h"
@ -327,6 +331,7 @@ struct Client {
std::function<int(Client &)> readfn, writefn; std::function<int(Client &)> readfn, writefn;
Worker *worker; Worker *worker;
SSL *ssl; SSL *ssl;
#ifdef ENABLE_HTTP3
struct { struct {
ev_timer pkt_timer; ev_timer pkt_timer;
ngtcp2_conn *conn; ngtcp2_conn *conn;
@ -335,6 +340,7 @@ struct Client {
bool close_requested; bool close_requested;
FILE *qlog_file; FILE *qlog_file;
} quic; } quic;
#endif // ENABLE_HTTP3
ev_timer request_timeout_watcher; ev_timer request_timeout_watcher;
addrinfo *next_addr; addrinfo *next_addr;
// Address for the current address. When try_new_connection() is // Address for the current address. When try_new_connection() is
@ -447,6 +453,7 @@ struct Client {
void signal_write(); void signal_write();
#ifdef ENABLE_HTTP3
// QUIC // QUIC
int quic_init(const sockaddr *local_addr, socklen_t local_addrlen, int quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
const sockaddr *remote_addr, socklen_t remote_addrlen); const sockaddr *remote_addr, socklen_t remote_addrlen);
@ -475,6 +482,7 @@ struct Client {
int quic_pkt_timeout(); int quic_pkt_timeout();
void quic_restart_pkt_timer(); void quic_restart_pkt_timer();
void quic_write_qlog(const void *data, size_t datalen); void quic_write_qlog(const void *data, size_t datalen);
#endif // ENABLE_HTTP3
}; };
} // namespace h2load } // namespace h2load

View File

@ -1548,6 +1548,7 @@ void fill_default_config(Config *config) {
downstreamconf.option, downstreamconf.encoder_dynamic_table_size); downstreamconf.option, downstreamconf.encoder_dynamic_table_size);
} }
#ifdef ENABLE_HTTP3
auto &quicconf = config->quic; auto &quicconf = config->quic;
{ {
quicconf.timeout.idle = 30_s; quicconf.timeout.idle = 30_s;
@ -1560,6 +1561,7 @@ void fill_default_config(Config *config) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
#endif // ENABLE_HTTP3
auto &loggingconf = config->logging; auto &loggingconf = config->logging;
{ {

View File

@ -51,7 +51,9 @@
#include "shrpx_api_downstream_connection.h" #include "shrpx_api_downstream_connection.h"
#include "shrpx_health_monitor_downstream_connection.h" #include "shrpx_health_monitor_downstream_connection.h"
#include "shrpx_null_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 "shrpx_log.h"
#include "util.h" #include "util.h"
#include "template.h" #include "template.h"
@ -287,6 +289,7 @@ int ClientHandler::write_tls() {
} }
} }
#ifdef ENABLE_HTTP3
int ClientHandler::read_quic(const UpstreamAddr *faddr, int ClientHandler::read_quic(const UpstreamAddr *faddr,
const Address &remote_addr, const Address &remote_addr,
const Address &local_addr, const uint8_t *data, 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(); } int ClientHandler::write_quic() { return upstream_->on_write(); }
#endif // ENABLE_HTTP3
int ClientHandler::upstream_noop() { return 0; } int ClientHandler::upstream_noop() { return 0; }
@ -509,12 +513,14 @@ void ClientHandler::setup_upstream_io_callback() {
} }
} }
#ifdef ENABLE_HTTP3
void ClientHandler::setup_http3_upstream( void ClientHandler::setup_http3_upstream(
std::unique_ptr<Http3Upstream> &&upstream) { std::unique_ptr<Http3Upstream> &&upstream) {
upstream_ = std::move(upstream); upstream_ = std::move(upstream);
alpn_ = StringRef::from_lit("h3"); alpn_ = StringRef::from_lit("h3");
write_ = &ClientHandler::write_quic; write_ = &ClientHandler::write_quic;
} }
#endif // ENABLE_HTTP3
ClientHandler::~ClientHandler() { ClientHandler::~ClientHandler() {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {

View File

@ -53,7 +53,9 @@ class Downstream;
struct WorkerStat; struct WorkerStat;
struct DownstreamAddrGroup; struct DownstreamAddrGroup;
struct DownstreamAddr; struct DownstreamAddr;
#ifdef ENABLE_HTTP3
class Http3Upstream; class Http3Upstream;
#endif // ENABLE_HTTP3
class ClientHandler { class ClientHandler {
public: public:
@ -71,9 +73,6 @@ public:
int read_tls(); int read_tls();
int write_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_noop();
int upstream_read(); int upstream_read();
int upstream_http2_connhd_read(); int upstream_http2_connhd_read();
@ -147,8 +146,12 @@ public:
void setup_upstream_io_callback(); void setup_upstream_io_callback();
#ifdef ENABLE_HTTP3
void setup_http3_upstream(std::unique_ptr<Http3Upstream> &&upstream); void setup_http3_upstream(std::unique_ptr<Http3Upstream> &&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(); int write_quic();
#endif // ENABLE_HTTP3
// Returns string suitable for use in "by" parameter of Forwarded // Returns string suitable for use in "by" parameter of Forwarded
// header field. // header field.

View File

@ -821,7 +821,11 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
} else if (util::strieq_l("proxyproto", param)) { } else if (util::strieq_l("proxyproto", param)) {
out.proxyproto = true; out.proxyproto = true;
} else if (util::strieq_l("quic", param)) { } else if (util::strieq_l("quic", param)) {
#ifdef ENABLE_HTTP3
out.quic = true; out.quic = true;
#else // !ENABLE_HTTP3
LOG(ERROR) << "quic: QUIC is disabled at compile time";
#endif // !ENABLE_HTTP3
} else if (!param.empty()) { } else if (!param.empty()) {
LOG(ERROR) << "frontend: " << param << ": unknown keyword"; LOG(ERROR) << "frontend: " << param << ": unknown keyword";
return -1; return -1;
@ -2674,8 +2678,12 @@ int parse_config(Config *config, int optid, const StringRef &opt,
apiconf.enabled = true; apiconf.enabled = true;
} }
#ifdef ENABLE_HTTP3
auto &addrs = params.quic ? config->conn.quic_listener.addrs auto &addrs = params.quic ? config->conn.quic_listener.addrs
: config->conn.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)) { if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size(); auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size();

View File

@ -704,6 +704,7 @@ struct TLSConfig {
bool no_postpone_early_data; bool no_postpone_early_data;
}; };
#ifdef ENABLE_HTTP3
struct QUICConfig { struct QUICConfig {
struct { struct {
std::array<uint8_t, 32> secret; std::array<uint8_t, 32> secret;
@ -715,6 +716,7 @@ struct QUICConfig {
bool log; bool log;
} debug; } debug;
}; };
#endif // ENABLE_HTTP3
// custom error page // custom error page
struct ErrorPage { struct ErrorPage {
@ -921,9 +923,11 @@ struct ConnectionConfig {
int fastopen; int fastopen;
} listener; } listener;
#ifdef ENABLE_HTTP3
struct { struct {
std::vector<UpstreamAddr> addrs; std::vector<UpstreamAddr> addrs;
} quic_listener; } quic_listener;
#endif // ENABLE_HTTP3
struct { struct {
struct { struct {
@ -968,7 +972,9 @@ struct Config {
http{}, http{},
http2{}, http2{},
tls{}, tls{},
#ifdef ENABLE_HTTP3
quic{}, quic{},
#endif // ENABLE_HTTP3
logging{}, logging{},
conn{}, conn{},
api{}, api{},
@ -986,7 +992,8 @@ struct Config {
single_process{false}, single_process{false},
single_thread{false}, single_thread{false},
ignore_per_pattern_mruby_error{false}, ignore_per_pattern_mruby_error{false},
ev_loop_flags{0} {} ev_loop_flags{0} {
}
~Config(); ~Config();
Config(Config &&) = delete; Config(Config &&) = delete;
@ -1002,7 +1009,9 @@ struct Config {
HttpConfig http; HttpConfig http;
Http2Config http2; Http2Config http2;
TLSConfig tls; TLSConfig tls;
#ifdef ENABLE_HTTP3
QUICConfig quic; QUICConfig quic;
#endif // ENABLE_HTTP3
LoggingConfig logging; LoggingConfig logging;
ConnectionConfig conn; ConnectionConfig conn;
APIConfig api; APIConfig api;

View File

@ -156,6 +156,7 @@ ConnectionHandler::~ConnectionHandler() {
ev_timer_stop(loop_, &ocsp_timer_); ev_timer_stop(loop_, &ocsp_timer_);
ev_timer_stop(loop_, &disable_acceptor_timer_); ev_timer_stop(loop_, &disable_acceptor_timer_);
#ifdef ENABLE_HTTP3
for (auto ssl_ctx : quic_all_ssl_ctx_) { for (auto ssl_ctx : quic_all_ssl_ctx_) {
if (ssl_ctx == nullptr) { if (ssl_ctx == nullptr) {
continue; continue;
@ -166,6 +167,7 @@ ConnectionHandler::~ConnectionHandler() {
delete tls_ctx_data; delete tls_ctx_data;
SSL_CTX_free(ssl_ctx); SSL_CTX_free(ssl_ctx);
} }
#endif // ENABLE_HTTP3
for (auto ssl_ctx : all_ssl_ctx_) { for (auto ssl_ctx : all_ssl_ctx_) {
auto tls_ctx_data = auto tls_ctx_data =
@ -221,14 +223,16 @@ int ConnectionHandler::create_single_worker() {
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
); );
#ifdef ENABLE_HTTP3
quic_cert_tree_ = tls::create_cert_lookup_tree(); quic_cert_tree_ = tls::create_cert_lookup_tree();
auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context( auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context(
quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get() quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get()
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
nb_ nb_
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
#endif // ENABLE_HTTP3
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context( auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
@ -238,7 +242,9 @@ int ConnectionHandler::create_single_worker() {
if (cl_ssl_ctx) { if (cl_ssl_ctx) {
all_ssl_ctx_.push_back(cl_ssl_ctx); all_ssl_ctx_.push_back(cl_ssl_ctx);
#ifdef ENABLE_HTTP3
quic_all_ssl_ctx_.push_back(nullptr); quic_all_ssl_ctx_.push_back(nullptr);
#endif // ENABLE_HTTP3
} }
auto config = get_config(); auto config = get_config();
@ -255,22 +261,29 @@ int ConnectionHandler::create_single_worker() {
tlsconf.cacert, memcachedconf.cert_file, tlsconf.cacert, memcachedconf.cert_file,
memcachedconf.private_key_file, nullptr); memcachedconf.private_key_file, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx); all_ssl_ctx_.push_back(session_cache_ssl_ctx);
#ifdef ENABLE_HTTP3
quic_all_ssl_ctx_.push_back(nullptr); quic_all_ssl_ctx_.push_back(nullptr);
#endif // ENABLE_HTTP3
} }
} }
single_worker_ = std::make_unique<Worker>( single_worker_ = std::make_unique<Worker>(
loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(), 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, #ifdef ENABLE_HTTP3
config->conn.downstream); quic_sv_ssl_ctx, quic_cert_tree_.get(),
#endif // ENABLE_HTTP3
ticket_keys_, this, config->conn.downstream);
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
if (single_worker_->create_mruby_context() != 0) { if (single_worker_->create_mruby_context() != 0) {
return -1; return -1;
} }
#endif // HAVE_MRUBY #endif // HAVE_MRUBY
#ifdef ENABLE_HTTP3
if (single_worker_->setup_quic_server_socket() != 0) { if (single_worker_->setup_quic_server_socket() != 0) {
return -1; return -1;
} }
#endif // ENABLE_HTTP3
return 0; return 0;
} }
@ -288,14 +301,16 @@ int ConnectionHandler::create_worker_thread(size_t num) {
# endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
# ifdef ENABLE_HTTP3
quic_cert_tree_ = tls::create_cert_lookup_tree(); quic_cert_tree_ = tls::create_cert_lookup_tree();
auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context( auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context(
quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get() quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get()
# ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
nb_ nb_
# endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
# endif // ENABLE_HTTP3
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context( auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
# ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
@ -305,7 +320,9 @@ int ConnectionHandler::create_worker_thread(size_t num) {
if (cl_ssl_ctx) { if (cl_ssl_ctx) {
all_ssl_ctx_.push_back(cl_ssl_ctx); all_ssl_ctx_.push_back(cl_ssl_ctx);
# ifdef ENABLE_HTTP3
quic_all_ssl_ctx_.push_back(nullptr); quic_all_ssl_ctx_.push_back(nullptr);
# endif // ENABLE_HTTP3
} }
auto config = get_config(); auto config = get_config();
@ -329,7 +346,9 @@ int ConnectionHandler::create_worker_thread(size_t num) {
tlsconf.cacert, memcachedconf.cert_file, tlsconf.cacert, memcachedconf.cert_file,
memcachedconf.private_key_file, nullptr); memcachedconf.private_key_file, nullptr);
all_ssl_ctx_.push_back(session_cache_ssl_ctx); all_ssl_ctx_.push_back(session_cache_ssl_ctx);
# ifdef ENABLE_HTTP3
quic_all_ssl_ctx_.push_back(nullptr); 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<Worker>( auto worker = std::make_unique<Worker>(
loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(), 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, # ifdef ENABLE_HTTP3
config->conn.downstream); quic_sv_ssl_ctx, quic_cert_tree_.get(),
# endif // ENABLE_HTTP3
ticket_keys_, this, config->conn.downstream);
# ifdef HAVE_MRUBY # ifdef HAVE_MRUBY
if (worker->create_mruby_context() != 0) { if (worker->create_mruby_context() != 0) {
return -1; return -1;
} }
# endif // HAVE_MRUBY # endif // HAVE_MRUBY
# ifdef ENABLE_HTTP3
if ((!apiconf.enabled || i != 0) && if ((!apiconf.enabled || i != 0) &&
worker->setup_quic_server_socket() != 0) { worker->setup_quic_server_socket() != 0) {
return -1; return -1;
} }
# endif // ENABLE_HTTP3
workers_.push_back(std::move(worker)); workers_.push_back(std::move(worker));
worker_loops_.push_back(loop); worker_loops_.push_back(loop);
@ -646,7 +670,9 @@ void ConnectionHandler::handle_ocsp_complete() {
ev_child_stop(loop_, &ocsp_.chldev); ev_child_stop(loop_, &ocsp_.chldev);
assert(ocsp_.next < all_ssl_ctx_.size()); assert(ocsp_.next < all_ssl_ctx_.size());
#ifdef ENABLE_HTTP3
assert(all_ssl_ctx_.size() == quic_all_ssl_ctx_.size()); assert(all_ssl_ctx_.size() == quic_all_ssl_ctx_.size());
#endif // ENABLE_HTTP3
auto ssl_ctx = all_ssl_ctx_[ocsp_.next]; auto ssl_ctx = all_ssl_ctx_[ocsp_.next];
auto tls_ctx_data = auto tls_ctx_data =
@ -674,6 +700,7 @@ void ConnectionHandler::handle_ocsp_complete() {
if (tlsconf.ocsp.no_verify || if (tlsconf.ocsp.no_verify ||
tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(), tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
ocsp_.resp.size()) == 0) { ocsp_.resp.size()) == 0) {
#ifdef ENABLE_HTTP3
// We have list of SSL_CTX with the same certificate in // We have list of SSL_CTX with the same certificate in
// quic_all_ssl_ctx_ as well. Some SSL_CTXs are missing there in // quic_all_ssl_ctx_ as well. Some SSL_CTXs are missing there in
// that case we get nullptr. // that case we get nullptr.
@ -681,21 +708,22 @@ void ConnectionHandler::handle_ocsp_complete() {
if (quic_ssl_ctx) { if (quic_ssl_ctx) {
auto quic_tls_ctx_data = static_cast<tls::TLSContextData *>( auto quic_tls_ctx_data = static_cast<tls::TLSContextData *>(
SSL_CTX_get_app_data(quic_ssl_ctx)); SSL_CTX_get_app_data(quic_ssl_ctx));
#ifndef OPENSSL_IS_BORINGSSL # ifndef OPENSSL_IS_BORINGSSL
# ifdef HAVE_ATOMIC_STD_SHARED_PTR # ifdef HAVE_ATOMIC_STD_SHARED_PTR
std::atomic_store_explicit( std::atomic_store_explicit(
&quic_tls_ctx_data->ocsp_data, &quic_tls_ctx_data->ocsp_data,
std::make_shared<std::vector<uint8_t>>(ocsp_.resp), std::make_shared<std::vector<uint8_t>>(ocsp_.resp),
std::memory_order_release); std::memory_order_release);
# else // !HAVE_ATOMIC_STD_SHARED_PTR # else // !HAVE_ATOMIC_STD_SHARED_PTR
std::lock_guard<std::mutex> g(quic_tls_ctx_data->mu); std::lock_guard<std::mutex> g(quic_tls_ctx_data->mu);
quic_tls_ctx_data->ocsp_data = quic_tls_ctx_data->ocsp_data =
std::make_shared<std::vector<uint8_t>>(ocsp_.resp); std::make_shared<std::vector<uint8_t>>(ocsp_.resp);
# endif // !HAVE_ATOMIC_STD_SHARED_PTR # endif // !HAVE_ATOMIC_STD_SHARED_PTR
#else // OPENSSL_IS_BORINGSSL # else // OPENSSL_IS_BORINGSSL
SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size()); 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 #ifndef OPENSSL_IS_BORINGSSL
# ifdef HAVE_ATOMIC_STD_SHARED_PTR # ifdef HAVE_ATOMIC_STD_SHARED_PTR
@ -877,7 +905,9 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
nullptr); nullptr);
all_ssl_ctx_.push_back(ssl_ctx); all_ssl_ctx_.push_back(ssl_ctx);
#ifdef ENABLE_HTTP3
quic_all_ssl_ctx_.push_back(nullptr); quic_all_ssl_ctx_.push_back(nullptr);
#endif // ENABLE_HTTP3
return ssl_ctx; return ssl_ctx;
} }
@ -940,10 +970,12 @@ ConnectionHandler::get_indexed_ssl_ctx(size_t idx) const {
return indexed_ssl_ctx_[idx]; return indexed_ssl_ctx_[idx];
} }
#ifdef ENABLE_HTTP3
const std::vector<SSL_CTX *> & const std::vector<SSL_CTX *> &
ConnectionHandler::get_quic_indexed_ssl_ctx(size_t idx) const { ConnectionHandler::get_quic_indexed_ssl_ctx(size_t idx) const {
return quic_indexed_ssl_ctx_[idx]; return quic_indexed_ssl_ctx_[idx];
} }
#endif // ENABLE_HTTP3
void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) { void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) {
enable_acceptor_on_ocsp_completion_ = f; enable_acceptor_on_ocsp_completion_ = f;

View File

@ -159,7 +159,9 @@ public:
SSL_CTX *get_ssl_ctx(size_t idx) const; SSL_CTX *get_ssl_ctx(size_t idx) const;
const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const; const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const;
#ifdef ENABLE_HTTP3
const std::vector<SSL_CTX *> &get_quic_indexed_ssl_ctx(size_t idx) const; const std::vector<SSL_CTX *> &get_quic_indexed_ssl_ctx(size_t idx) const;
#endif // ENABLE_HTTP3
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED
void set_neverbleed(neverbleed_t *nb); void set_neverbleed(neverbleed_t *nb);
@ -188,8 +190,10 @@ private:
// selection among them are performed by hostname presented by SNI, // selection among them are performed by hostname presented by SNI,
// and signature algorithm presented by client. // and signature algorithm presented by client.
std::vector<std::vector<SSL_CTX *>> indexed_ssl_ctx_; std::vector<std::vector<SSL_CTX *>> indexed_ssl_ctx_;
#ifdef ENABLE_HTTP3
std::vector<SSL_CTX *> quic_all_ssl_ctx_; std::vector<SSL_CTX *> quic_all_ssl_ctx_;
std::vector<std::vector<SSL_CTX *>> quic_indexed_ssl_ctx_; std::vector<std::vector<SSL_CTX *>> quic_indexed_ssl_ctx_;
#endif // ENABLE_HTTP3
OCSPUpdateContext ocsp_; OCSPUpdateContext ocsp_;
std::mt19937 &gen_; std::mt19937 &gen_;
// ev_loop for each worker // ev_loop for each worker
@ -206,7 +210,9 @@ private:
// Otherwise, nullptr and workers_ has instances of Worker instead. // Otherwise, nullptr and workers_ has instances of Worker instead.
std::unique_ptr<Worker> single_worker_; std::unique_ptr<Worker> single_worker_;
std::unique_ptr<tls::CertLookupTree> cert_tree_; std::unique_ptr<tls::CertLookupTree> cert_tree_;
#ifdef ENABLE_HTTP3
std::unique_ptr<tls::CertLookupTree> quic_cert_tree_; std::unique_ptr<tls::CertLookupTree> quic_cert_tree_;
#endif // ENABLE_HTTP3
std::unique_ptr<MemcachedDispatcher> tls_ticket_key_memcached_dispatcher_; std::unique_ptr<MemcachedDispatcher> tls_ticket_key_memcached_dispatcher_;
// Current TLS session ticket keys. Note that TLS connection does // Current TLS session ticket keys. Note that TLS connection does
// not refer to this field directly. They use TicketKeys object in // not refer to this field directly. They use TicketKeys object in

View File

@ -165,7 +165,9 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
downstream_wtimer_.data = this; downstream_wtimer_.data = this;
rcbufs_.reserve(32); rcbufs_.reserve(32);
#ifdef ENABLE_HTTP3
rcbufs3_.reserve(32); rcbufs3_.reserve(32);
#endif // ENABLE_HTTP3
} }
Downstream::~Downstream() { Downstream::~Downstream() {
@ -205,9 +207,11 @@ Downstream::~Downstream() {
// explicitly. // explicitly.
dconn_.reset(); dconn_.reset();
#ifdef ENABLE_HTTP3
for (auto rcbuf : rcbufs3_) { for (auto rcbuf : rcbufs3_) {
nghttp3_rcbuf_decref(rcbuf); nghttp3_rcbuf_decref(rcbuf);
} }
#endif // ENABLE_HTTP3
for (auto rcbuf : rcbufs_) { for (auto rcbuf : rcbufs_) {
nghttp2_rcbuf_decref(rcbuf); nghttp2_rcbuf_decref(rcbuf);
@ -1134,10 +1138,12 @@ void Downstream::add_rcbuf(nghttp2_rcbuf *rcbuf) {
rcbufs_.push_back(rcbuf); rcbufs_.push_back(rcbuf);
} }
#ifdef ENABLE_HTTP3
void Downstream::add_rcbuf(nghttp3_rcbuf *rcbuf) { void Downstream::add_rcbuf(nghttp3_rcbuf *rcbuf) {
nghttp3_rcbuf_incref(rcbuf); nghttp3_rcbuf_incref(rcbuf);
rcbufs3_.push_back(rcbuf); rcbufs3_.push_back(rcbuf);
} }
#endif // ENABLE_HTTP3
void Downstream::set_downstream_addr_group( void Downstream::set_downstream_addr_group(
const std::shared_ptr<DownstreamAddrGroup> &group) { const std::shared_ptr<DownstreamAddrGroup> &group) {

View File

@ -38,7 +38,9 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include <nghttp3/nghttp3.h> #ifdef ENABLE_HTTP3
# include <nghttp3/nghttp3.h>
#endif // ENABLE_HTTP3
#include "llhttp.h" #include "llhttp.h"
@ -490,7 +492,9 @@ public:
BlockAllocator &get_block_allocator(); BlockAllocator &get_block_allocator();
void add_rcbuf(nghttp2_rcbuf *rcbuf); void add_rcbuf(nghttp2_rcbuf *rcbuf);
#ifdef ENABLE_HTTP3
void add_rcbuf(nghttp3_rcbuf *rcbuf); void add_rcbuf(nghttp3_rcbuf *rcbuf);
#endif // ENABLE_HTTP3
void void
set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group); set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group);
@ -533,7 +537,9 @@ private:
BlockAllocator balloc_; BlockAllocator balloc_;
std::vector<nghttp2_rcbuf *> rcbufs_; std::vector<nghttp2_rcbuf *> rcbufs_;
#ifdef ENABLE_HTTP3
std::vector<nghttp3_rcbuf *> rcbufs3_; std::vector<nghttp3_rcbuf *> rcbufs3_;
#endif // ENABLE_HTTP3
Request req_; Request req_;
Response resp_; Response resp_;

View File

@ -51,9 +51,11 @@
#include <nghttp2/nghttp2.h> #include <nghttp2/nghttp2.h>
#include <ngtcp2/ngtcp2.h> #ifdef ENABLE_HTTP3
#include <ngtcp2/ngtcp2_crypto.h> # include <ngtcp2/ngtcp2.h>
#include <ngtcp2/ngtcp2_crypto_openssl.h> # include <ngtcp2/ngtcp2_crypto.h>
# include <ngtcp2/ngtcp2_crypto_openssl.h>
#endif // ENABLE_HTTP3
#include "shrpx_log.h" #include "shrpx_log.h"
#include "shrpx_client_handler.h" #include "shrpx_client_handler.h"
@ -64,7 +66,9 @@
#include "shrpx_memcached_request.h" #include "shrpx_memcached_request.h"
#include "shrpx_memcached_dispatcher.h" #include "shrpx_memcached_dispatcher.h"
#include "shrpx_connection_handler.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 "util.h"
#include "tls.h" #include "tls.h"
#include "template.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}; auto hostname = StringRef{std::begin(buf), end_buf};
#ifdef ENABLE_HTTP3
auto cert_tree = SSL_is_quic(ssl) ? worker->get_quic_cert_lookup_tree() auto cert_tree = SSL_is_quic(ssl) ? worker->get_quic_cert_lookup_tree()
: worker->get_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); auto idx = cert_tree->lookup(hostname);
if (idx == -1) { if (idx == -1) {
@ -197,9 +205,14 @@ int servername_callback(SSL *ssl, int *al, void *arg) {
auto conn_handler = worker->get_connection_handler(); auto conn_handler = worker->get_connection_handler();
#ifdef ENABLE_HTTP3
const auto &ssl_ctx_list = SSL_is_quic(ssl) const auto &ssl_ctx_list = SSL_is_quic(ssl)
? conn_handler->get_quic_indexed_ssl_ctx(idx) ? conn_handler->get_quic_indexed_ssl_ctx(idx)
: conn_handler->get_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()); assert(!ssl_ctx_list.empty());
#if !defined(OPENSSL_IS_BORINGSSL) && !LIBRESSL_IN_USE && \ #if !defined(OPENSSL_IS_BORINGSSL) && !LIBRESSL_IN_USE && \
@ -608,7 +621,8 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
} // namespace } // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #ifdef ENABLE_HTTP3
# if OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace { namespace {
int quic_alpn_select_proto_cb(SSL *ssl, const unsigned char **out, int quic_alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in, 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; return SSL_TLSEXT_ERR_NOACK;
} }
} // namespace } // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L # endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#endif // ENABLE_HTTP3
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L #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; return ssl_ctx;
} }
#ifdef ENABLE_HTTP3
namespace { namespace {
int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *rx_secret, 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, SSL_CTX *create_quic_ssl_context(const char *private_key_file,
const char *cert_file, const char *cert_file,
const std::vector<uint8_t> &sct_data const std::vector<uint8_t> &sct_data
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
neverbleed_t *nb neverbleed_t *nb
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
) { ) {
auto ssl_ctx = SSL_CTX_new(TLS_server_method()); auto ssl_ctx = SSL_CTX_new(TLS_server_method());
if (!ssl_ctx) { 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_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_SINGLE_ECDH_USE |
SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_DH_USE |
SSL_OP_CIPHER_SERVER_PREFERENCE 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 // The reason for disabling built-in anti-replay in OpenSSL is
// that it only works if client gets back to the same server. // that it only works if client gets back to the same server.
// The freshness check described in // The freshness check described in
// https://tools.ietf.org/html/rfc8446#section-8.3 is still // https://tools.ietf.org/html/rfc8446#section-8.3 is still
// performed. // performed.
| SSL_OP_NO_ANTI_REPLAY | SSL_OP_NO_ANTI_REPLAY
#endif // OPENSSL_1_1_1_API # endif // OPENSSL_1_1_1_API
; ;
auto config = mod_config(); auto config = mod_config();
@ -1194,27 +1210,27 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file,
DIE(); 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) { if (SSL_CTX_set_ciphersuites(ssl_ctx, tlsconf.tls13_ciphers.c_str()) == 0) {
LOG(FATAL) << "SSL_CTX_set_ciphersuites " << tlsconf.tls13_ciphers LOG(FATAL) << "SSL_CTX_set_ciphersuites " << tlsconf.tls13_ciphers
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr); << " failed: " << ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
#endif // OPENSSL_1_1_1_API # endif // OPENSSL_1_1_1_API
#ifndef OPENSSL_NO_EC # ifndef OPENSSL_NO_EC
# if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L # if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L
if (SSL_CTX_set1_curves_list(ssl_ctx, tlsconf.ecdh_curves.c_str()) != 1) { if (SSL_CTX_set1_curves_list(ssl_ctx, tlsconf.ecdh_curves.c_str()) != 1) {
LOG(FATAL) << "SSL_CTX_set1_curves_list " << tlsconf.ecdh_curves LOG(FATAL) << "SSL_CTX_set1_curves_list " << tlsconf.ecdh_curves
<< " failed"; << " failed";
DIE(); 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 // It looks like we need this function call for OpenSSL 1.0.2. This
// function was deprecated in OpenSSL 1.1.0 and BoringSSL. // function was deprecated in OpenSSL 1.1.0 and BoringSSL.
SSL_CTX_set_ecdh_auto(ssl_ctx, 1); SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
# endif // !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API # endif // !defined(OPENSSL_IS_BORINGSSL) && !OPENSSL_1_1_API
# else // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L # else // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L
// Use P-256, which is sufficiently secure at the time of this // Use P-256, which is sufficiently secure at the time of this
// writing. // writing.
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 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); SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
EC_KEY_free(ecdh); EC_KEY_free(ecdh);
# endif // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L # endif // LIBRESSL_LEGACY_API || OPENSSL_VERSION_NUBMER < 0x10002000L
#endif // OPENSSL_NO_EC # endif // OPENSSL_NO_EC
if (!tlsconf.dh_param_file.empty()) { if (!tlsconf.dh_param_file.empty()) {
// Read DH parameters from file // 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); 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, if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key_file,
SSL_FILETYPE_PEM) != 1) { SSL_FILETYPE_PEM) != 1) {
LOG(FATAL) << "SSL_CTX_use_PrivateKey_file failed: " LOG(FATAL) << "SSL_CTX_use_PrivateKey_file failed: "
<< ERR_error_string(ERR_get_error(), nullptr); << ERR_error_string(ERR_get_error(), nullptr);
} }
#else // HAVE_NEVERBLEED # else // HAVE_NEVERBLEED
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf; std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf;
if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file, if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file,
errbuf.data()) != 1) { errbuf.data()) != 1) {
LOG(FATAL) << "neverbleed_load_private_key_file failed: " << errbuf.data(); LOG(FATAL) << "neverbleed_load_private_key_file failed: " << errbuf.data();
DIE(); DIE();
} }
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
LOG(FATAL) << "SSL_CTX_use_certificate_file failed: " 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_servername_callback(ssl_ctx, servername_callback);
SSL_CTX_set_tlsext_ticket_key_cb(ssl_ctx, ticket_key_cb); 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); 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); 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 // ALPN selection callback
SSL_CTX_set_alpn_select_cb(ssl_ctx, quic_alpn_select_proto_cb, nullptr); 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 && \ # if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \
!defined(OPENSSL_IS_BORINGSSL) !defined(OPENSSL_IS_BORINGSSL)
// SSL_extension_supported(TLSEXT_TYPE_signed_certificate_timestamp) // SSL_extension_supported(TLSEXT_TYPE_signed_certificate_timestamp)
// returns 1, which means OpenSSL internally handles it. But // returns 1, which means OpenSSL internally handles it. But
// OpenSSL handles signed_certificate_timestamp extension specially, // OpenSSL handles signed_certificate_timestamp extension specially,
// and it lets custom handler to process the extension. // and it lets custom handler to process the extension.
if (!sct_data.empty()) { 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 // It is not entirely clear to me that SSL_EXT_CLIENT_HELLO is
// required here. sct_parse_cb is called without // required here. sct_parse_cb is called without
// SSL_EXT_CLIENT_HELLO being set. But the passed context value // 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); << ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
# else // !OPENSSL_1_1_1_API # else // !OPENSSL_1_1_1_API
if (SSL_CTX_add_server_custom_ext( if (SSL_CTX_add_server_custom_ext(
ssl_ctx, TLSEXT_TYPE_signed_certificate_timestamp, ssl_ctx, TLSEXT_TYPE_signed_certificate_timestamp,
legacy_sct_add_cb, legacy_sct_free_cb, nullptr, legacy_sct_parse_cb, 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); << ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
# endif // !OPENSSL_1_1_1_API # endif // !OPENSSL_1_1_1_API
} }
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && # endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L &&
// !defined(OPENSSL_IS_BORINGSSL) // !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, if (SSL_CTX_set_max_early_data(ssl_ctx,
std::numeric_limits<uint32_t>::max()) != 1) { std::numeric_limits<uint32_t>::max()) != 1) {
LOG(FATAL) << "SSL_CTX_set_max_early_data failed: " LOG(FATAL) << "SSL_CTX_set_max_early_data failed: "
<< ERR_error_string(ERR_get_error(), nullptr); << ERR_error_string(ERR_get_error(), nullptr);
DIE(); 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); 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); 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; return ssl_ctx;
} }
#endif // ENABLE_HTTP3
namespace { namespace {
int select_h2_next_proto_cb(SSL *ssl, unsigned char **out, int select_h2_next_proto_cb(SSL *ssl, unsigned char **out,
@ -2101,9 +2118,11 @@ bool in_proto_list(const std::vector<StringRef> &protos,
} }
bool upstream_tls_enabled(const ConnectionConfig &connconf) { bool upstream_tls_enabled(const ConnectionConfig &connconf) {
#ifdef ENABLE_HTTP3
if (connconf.quic_listener.addrs.size()) { if (connconf.quic_listener.addrs.size()) {
return true; return true;
} }
#endif // ENABLE_HTTP3
const auto &faddrs = connconf.listener.addrs; const auto &faddrs = connconf.listener.addrs;
return std::any_of(std::begin(faddrs), std::end(faddrs), return std::any_of(std::begin(faddrs), std::end(faddrs),
@ -2184,14 +2203,15 @@ setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
return ssl_ctx; return ssl_ctx;
} }
#ifdef ENABLE_HTTP3
SSL_CTX *setup_quic_server_ssl_context( SSL_CTX *setup_quic_server_ssl_context(
std::vector<SSL_CTX *> &all_ssl_ctx, std::vector<SSL_CTX *> &all_ssl_ctx,
std::vector<std::vector<SSL_CTX *>> &indexed_ssl_ctx, std::vector<std::vector<SSL_CTX *>> &indexed_ssl_ctx,
CertLookupTree *cert_tree CertLookupTree *cert_tree
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
neverbleed_t *nb neverbleed_t *nb
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
) { ) {
auto config = get_config(); auto config = get_config();
@ -2204,10 +2224,10 @@ SSL_CTX *setup_quic_server_ssl_context(
auto ssl_ctx = auto ssl_ctx =
create_quic_ssl_context(tlsconf.private_key_file.c_str(), create_quic_ssl_context(tlsconf.private_key_file.c_str(),
tlsconf.cert_file.c_str(), tlsconf.sct_data tlsconf.cert_file.c_str(), tlsconf.sct_data
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
nb nb
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
all_ssl_ctx.push_back(ssl_ctx); all_ssl_ctx.push_back(ssl_ctx);
@ -2222,10 +2242,10 @@ SSL_CTX *setup_quic_server_ssl_context(
for (auto &c : tlsconf.subcerts) { for (auto &c : tlsconf.subcerts) {
auto ssl_ctx = create_quic_ssl_context(c.private_key_file.c_str(), auto ssl_ctx = create_quic_ssl_context(c.private_key_file.c_str(),
c.cert_file.c_str(), c.sct_data c.cert_file.c_str(), c.sct_data
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
nb nb
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
all_ssl_ctx.push_back(ssl_ctx); all_ssl_ctx.push_back(ssl_ctx);
@ -2238,6 +2258,7 @@ SSL_CTX *setup_quic_server_ssl_context(
return ssl_ctx; return ssl_ctx;
} }
#endif // ENABLE_HTTP3
SSL_CTX *setup_downstream_client_ssl_context( SSL_CTX *setup_downstream_client_ssl_context(
#ifdef HAVE_NEVERBLEED #ifdef HAVE_NEVERBLEED

View File

@ -100,15 +100,17 @@ SSL_CTX *create_ssl_client_context(
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)); unsigned int inlen, void *arg));
#ifdef ENABLE_HTTP3
SSL_CTX *create_quic_ssl_client_context( SSL_CTX *create_quic_ssl_client_context(
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
neverbleed_t *nb, neverbleed_t *nb,
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
const StringRef &cacert, const StringRef &cert_file, const StringRef &cacert, const StringRef &cert_file,
const StringRef &private_key_file, const StringRef &private_key_file,
int (*next_proto_select_cb)(SSL *s, unsigned char **out, int (*next_proto_select_cb)(SSL *s, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)); unsigned int inlen, void *arg));
#endif // ENABLE_HTTP3
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr, ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
int addrlen, const UpstreamAddr *faddr); int addrlen, const UpstreamAddr *faddr);
@ -227,15 +229,17 @@ setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
); );
#ifdef ENABLE_HTTP3
SSL_CTX *setup_quic_server_ssl_context( SSL_CTX *setup_quic_server_ssl_context(
std::vector<SSL_CTX *> &all_ssl_ctx, std::vector<SSL_CTX *> &all_ssl_ctx,
std::vector<std::vector<SSL_CTX *>> &indexed_ssl_ctx, std::vector<std::vector<SSL_CTX *>> &indexed_ssl_ctx,
CertLookupTree *cert_tree CertLookupTree *cert_tree
#ifdef HAVE_NEVERBLEED # ifdef HAVE_NEVERBLEED
, ,
neverbleed_t *nb neverbleed_t *nb
#endif // HAVE_NEVERBLEED # endif // HAVE_NEVERBLEED
); );
#endif // ENABLE_HTTP3
// Setups client side SSL_CTX. // Setups client side SSL_CTX.
SSL_CTX *setup_downstream_client_ssl_context( SSL_CTX *setup_downstream_client_ssl_context(

View File

@ -39,8 +39,10 @@
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
# include "shrpx_mruby.h" # include "shrpx_mruby.h"
#endif // HAVE_MRUBY #endif // HAVE_MRUBY
#include "shrpx_quic.h" #ifdef ENABLE_HTTP3
#include "shrpx_quic_listener.h" # include "shrpx_quic.h"
# include "shrpx_quic_listener.h"
#endif // ENABLE_HTTP3
#include "util.h" #include "util.h"
#include "template.h" #include "template.h"
@ -132,23 +134,29 @@ create_downstream_key(const std::shared_ptr<SharedDownstreamAddr> &shared_addr,
Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
SSL_CTX *tls_session_cache_memcached_ssl_ctx, SSL_CTX *tls_session_cache_memcached_ssl_ctx,
tls::CertLookupTree *cert_tree, SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *cert_tree,
tls::CertLookupTree *quic_cert_tree, #ifdef ENABLE_HTTP3
SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *quic_cert_tree,
#endif // ENABLE_HTTP3
const std::shared_ptr<TicketKeys> &ticket_keys, const std::shared_ptr<TicketKeys> &ticket_keys,
ConnectionHandler *conn_handler, ConnectionHandler *conn_handler,
std::shared_ptr<DownstreamConfig> downstreamconf) std::shared_ptr<DownstreamConfig> downstreamconf)
: randgen_(util::make_mt19937()), : randgen_(util::make_mt19937()),
worker_stat_{}, worker_stat_{},
dns_tracker_(loop), dns_tracker_(loop),
#ifdef ENABLE_HTTP3
quic_upstream_addrs_{get_config()->conn.quic_listener.addrs}, quic_upstream_addrs_{get_config()->conn.quic_listener.addrs},
#endif // ENABLE_HTTP3
loop_(loop), loop_(loop),
sv_ssl_ctx_(sv_ssl_ctx), sv_ssl_ctx_(sv_ssl_ctx),
cl_ssl_ctx_(cl_ssl_ctx), cl_ssl_ctx_(cl_ssl_ctx),
cert_tree_(cert_tree), cert_tree_(cert_tree),
conn_handler_(conn_handler), conn_handler_(conn_handler),
#ifdef ENABLE_HTTP3
quic_sv_ssl_ctx_{quic_sv_ssl_ctx}, quic_sv_ssl_ctx_{quic_sv_ssl_ctx},
quic_cert_tree_{quic_cert_tree}, quic_cert_tree_{quic_cert_tree},
quic_conn_handler_{this}, quic_conn_handler_{this},
#endif // ENABLE_HTTP3
ticket_keys_(ticket_keys), ticket_keys_(ticket_keys),
connect_blocker_( connect_blocker_(
std::make_unique<ConnectBlocker>(randgen_, loop_, nullptr, nullptr)), std::make_unique<ConnectBlocker>(randgen_, loop_, nullptr, nullptr)),
@ -511,9 +519,11 @@ void Worker::process_events() {
tls::CertLookupTree *Worker::get_cert_lookup_tree() const { return cert_tree_; } tls::CertLookupTree *Worker::get_cert_lookup_tree() const { return cert_tree_; }
#ifdef ENABLE_HTTP3
tls::CertLookupTree *Worker::get_quic_cert_lookup_tree() const { tls::CertLookupTree *Worker::get_quic_cert_lookup_tree() const {
return quic_cert_tree_; return quic_cert_tree_;
} }
#endif // ENABLE_HTTP3
std::shared_ptr<TicketKeys> Worker::get_ticket_keys() { std::shared_ptr<TicketKeys> Worker::get_ticket_keys() {
#ifdef HAVE_ATOMIC_STD_SHARED_PTR #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_; } 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_; } 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; } void Worker::set_graceful_shutdown(bool f) { graceful_shutdown_ = f; }
@ -591,12 +603,15 @@ ConnectionHandler *Worker::get_connection_handler() const {
return conn_handler_; return conn_handler_;
} }
#ifdef ENABLE_HTTP3
QUICConnectionHandler *Worker::get_quic_connection_handler() { QUICConnectionHandler *Worker::get_quic_connection_handler() {
return &quic_conn_handler_; return &quic_conn_handler_;
} }
#endif // ENABLE_HTTP3
DNSTracker *Worker::get_dns_tracker() { return &dns_tracker_; } DNSTracker *Worker::get_dns_tracker() { return &dns_tracker_; }
#ifdef ENABLE_HTTP3
int Worker::setup_quic_server_socket() { int Worker::setup_quic_server_socket() {
for (auto &addr : quic_upstream_addrs_) { for (auto &addr : quic_upstream_addrs_) {
assert(!addr.host_unix); assert(!addr.host_unix);
@ -609,6 +624,7 @@ int Worker::setup_quic_server_socket() {
return 0; return 0;
} }
#endif // ENABLE_HTTP3
namespace { namespace {
size_t match_downstream_addr_group_host( size_t match_downstream_addr_group_host(

View File

@ -50,7 +50,9 @@
#include "shrpx_live_check.h" #include "shrpx_live_check.h"
#include "shrpx_connect_blocker.h" #include "shrpx_connect_blocker.h"
#include "shrpx_dns_tracker.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" #include "allocator.h"
using namespace nghttp2; using namespace nghttp2;
@ -62,7 +64,9 @@ class ConnectBlocker;
class MemcachedDispatcher; class MemcachedDispatcher;
struct UpstreamAddr; struct UpstreamAddr;
class ConnectionHandler; class ConnectionHandler;
#ifdef ENABLE_HTTP3
class QUICListener; class QUICListener;
#endif // ENABLE_HTTP3
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
namespace mruby { namespace mruby {
@ -271,8 +275,10 @@ class Worker {
public: public:
Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx, Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
SSL_CTX *tls_session_cache_memcached_ssl_ctx, SSL_CTX *tls_session_cache_memcached_ssl_ctx,
tls::CertLookupTree *cert_tree, SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *cert_tree,
tls::CertLookupTree *quic_cert_tree, #ifdef ENABLE_HTTP3
SSL_CTX *quic_sv_ssl_ctx, tls::CertLookupTree *quic_cert_tree,
#endif // ENABLE_HTTP3
const std::shared_ptr<TicketKeys> &ticket_keys, const std::shared_ptr<TicketKeys> &ticket_keys,
ConnectionHandler *conn_handler, ConnectionHandler *conn_handler,
std::shared_ptr<DownstreamConfig> downstreamconf); std::shared_ptr<DownstreamConfig> downstreamconf);
@ -283,7 +289,9 @@ public:
void send(const WorkerEvent &event); void send(const WorkerEvent &event);
tls::CertLookupTree *get_cert_lookup_tree() const; tls::CertLookupTree *get_cert_lookup_tree() const;
#ifdef ENABLE_HTTP3
tls::CertLookupTree *get_quic_cert_lookup_tree() const; tls::CertLookupTree *get_quic_cert_lookup_tree() const;
#endif // ENABLE_HTTP3
// These 2 functions make a lock m_ to get/set ticket keys // These 2 functions make a lock m_ to get/set ticket keys
// atomically. // atomically.
@ -294,7 +302,9 @@ public:
struct ev_loop *get_loop() const; struct ev_loop *get_loop() const;
SSL_CTX *get_sv_ssl_ctx() const; SSL_CTX *get_sv_ssl_ctx() const;
SSL_CTX *get_cl_ssl_ctx() const; SSL_CTX *get_cl_ssl_ctx() const;
#ifdef ENABLE_HTTP3
SSL_CTX *get_quic_sv_ssl_ctx() const; SSL_CTX *get_quic_sv_ssl_ctx() const;
#endif // ENABLE_HTTP3
void set_graceful_shutdown(bool f); void set_graceful_shutdown(bool f);
bool get_graceful_shutdown() const; bool get_graceful_shutdown() const;
@ -324,11 +334,13 @@ public:
ConnectionHandler *get_connection_handler() const; ConnectionHandler *get_connection_handler() const;
#ifdef ENABLE_HTTP3
QUICConnectionHandler *get_quic_connection_handler(); QUICConnectionHandler *get_quic_connection_handler();
DNSTracker *get_dns_tracker();
int setup_quic_server_socket(); int setup_quic_server_socket();
#endif // ENABLE_HTTP3
DNSTracker *get_dns_tracker();
private: private:
#ifndef NOTHREADS #ifndef NOTHREADS
@ -344,8 +356,10 @@ private:
WorkerStat worker_stat_; WorkerStat worker_stat_;
DNSTracker dns_tracker_; DNSTracker dns_tracker_;
#ifdef ENABLE_HTTP3
std::vector<UpstreamAddr> quic_upstream_addrs_; std::vector<UpstreamAddr> quic_upstream_addrs_;
std::vector<std::unique_ptr<QUICListener>> quic_listeners_; std::vector<std::unique_ptr<QUICListener>> quic_listeners_;
#endif // ENABLE_HTTP3
std::shared_ptr<DownstreamConfig> downstreamconf_; std::shared_ptr<DownstreamConfig> downstreamconf_;
std::unique_ptr<MemcachedDispatcher> session_cache_memcached_dispatcher_; std::unique_ptr<MemcachedDispatcher> session_cache_memcached_dispatcher_;
@ -360,10 +374,12 @@ private:
SSL_CTX *cl_ssl_ctx_; SSL_CTX *cl_ssl_ctx_;
tls::CertLookupTree *cert_tree_; tls::CertLookupTree *cert_tree_;
ConnectionHandler *conn_handler_; ConnectionHandler *conn_handler_;
#ifdef ENABLE_HTTP3
SSL_CTX *quic_sv_ssl_ctx_; SSL_CTX *quic_sv_ssl_ctx_;
tls::CertLookupTree *quic_cert_tree_; tls::CertLookupTree *quic_cert_tree_;
QUICConnectionHandler quic_conn_handler_; QUICConnectionHandler quic_conn_handler_;
#endif // ENABLE_HTTP3
#ifndef HAVE_ATOMIC_STD_SHARED_PTR #ifndef HAVE_ATOMIC_STD_SHARED_PTR
std::mutex ticket_keys_m_; std::mutex ticket_keys_m_;