Merge pull request #1736 from nghttp2/bump-ngtcp2

Bump ngtcp2 and nghttp3
This commit is contained in:
Tatsuhiro Tsujikawa 2022-06-21 00:09:54 +09:00 committed by GitHub
commit ce66ac88c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 166 additions and 402 deletions

View File

@ -119,7 +119,7 @@ jobs:
- name: Build nghttp3 - name: Build nghttp3
if: matrix.http3 == 'http3' if: matrix.http3 == 'http3'
run: | run: |
git clone --depth 1 -b v0.4.1 https://github.com/ngtcp2/nghttp3 git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/nghttp3
cd nghttp3 cd nghttp3
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only ./configure --prefix=$PWD/build --enable-lib-only
@ -128,7 +128,7 @@ jobs:
- name: Build ngtcp2 - name: Build ngtcp2
if: matrix.http3 == 'http3' if: matrix.http3 == 'http3'
run: | run: |
git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/ngtcp2 git clone --depth 1 -b v0.6.0 https://github.com/ngtcp2/ngtcp2
cd ngtcp2 cd ngtcp2
autoreconf -i autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only PKG_CONFIG_PATH="../openssl/build/lib/pkgconfig" ./configure --prefix=$PWD/build --enable-lib-only PKG_CONFIG_PATH="../openssl/build/lib/pkgconfig"

View File

@ -154,7 +154,7 @@ following libraries are required:
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1o+quic>`_; or <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1o+quic>`_; or
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit `BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
36a41bf0bf2dd3176f8780e09c03585351f29963) 36a41bf0bf2dd3176f8780e09c03585351f29963)
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.5.0 * `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.6.0
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 0.4.0 * `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 0.4.0
Use ``--enable-http3`` configure option to enable HTTP/3 feature for Use ``--enable-http3`` configure option to enable HTTP/3 feature for
@ -366,7 +366,7 @@ Build nghttp3:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v0.4.1 https://github.com/ngtcp2/nghttp3 $ git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3 $ cd nghttp3
$ autoreconf -i $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only $ ./configure --prefix=$PWD/build --enable-lib-only
@ -378,7 +378,7 @@ Build ngtcp2:
.. code-block:: text .. code-block:: text
$ git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/ngtcp2 $ git clone --depth 1 -b v0.6.0 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2 $ cd ngtcp2
$ autoreconf -i $ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only \ $ ./configure --prefix=$PWD/build --enable-lib-only \

View File

@ -540,7 +540,7 @@ fi
# ngtcp2 (for src) # ngtcp2 (for src)
have_libngtcp2=no have_libngtcp2=no
if test "x${request_libngtcp2}" != "xno"; then if test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.5.0], [have_libngtcp2=yes], PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.6.0], [have_libngtcp2=yes],
[have_libngtcp2=no]) [have_libngtcp2=no])
if test "x${have_libngtcp2}" = "xno"; then if test "x${have_libngtcp2}" = "xno"; then
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS) AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
@ -557,7 +557,7 @@ have_libngtcp2_crypto_openssl=no
if test "x${have_ssl_is_quic}" = "xyes" && if test "x${have_ssl_is_quic}" = "xyes" &&
test "x${request_libngtcp2}" != "xno"; then test "x${request_libngtcp2}" != "xno"; then
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL], PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
[libngtcp2_crypto_openssl >= 0.5.0], [libngtcp2_crypto_openssl >= 0.6.0],
[have_libngtcp2_crypto_openssl=yes], [have_libngtcp2_crypto_openssl=yes],
[have_libngtcp2_crypto_openssl=no]) [have_libngtcp2_crypto_openssl=no])
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then

View File

@ -15,7 +15,7 @@ RUN git clone --depth 1 -b OpenSSL_1_1_1o+quic https://github.com/quictls/openss
cd .. && \ cd .. && \
rm -rf openssl rm -rf openssl
RUN git clone --depth 1 -b v0.4.1 https://github.com/ngtcp2/nghttp3 && \ RUN git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/nghttp3 && \
cd nghttp3 && \ cd nghttp3 && \
autoreconf -i && \ autoreconf -i && \
./configure --enable-lib-only && \ ./configure --enable-lib-only && \
@ -24,7 +24,7 @@ RUN git clone --depth 1 -b v0.4.1 https://github.com/ngtcp2/nghttp3 && \
cd .. && \ cd .. && \
rm -rf nghttp3 rm -rf nghttp3
RUN git clone --depth 1 -b v0.5.0 https://github.com/ngtcp2/ngtcp2 && \ RUN git clone --depth 1 -b v0.6.0 https://github.com/ngtcp2/ngtcp2 && \
cd ngtcp2 && \ cd ngtcp2 && \
autoreconf -i && \ autoreconf -i && \
./configure --enable-lib-only \ ./configure --enable-lib-only \

View File

@ -51,7 +51,12 @@
#include <openssl/err.h> #include <openssl/err.h>
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2.h> # ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
# include <ngtcp2/ngtcp2_crypto_openssl.h>
# endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
# ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
# include <ngtcp2/ngtcp2_crypto_boringssl.h>
# endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
#endif // ENABLE_HTTP3 #endif // ENABLE_HTTP3
#include "url-parser/url_parser.h" #include "url-parser/url_parser.h"
@ -724,6 +729,10 @@ void Client::disconnect() {
ev_io_stop(worker->loop, &wev); ev_io_stop(worker->loop, &wev);
ev_io_stop(worker->loop, &rev); ev_io_stop(worker->loop, &rev);
if (ssl) { if (ssl) {
if (config.is_quic()) {
SSL_free(ssl);
ssl = nullptr;
} else {
SSL_set_shutdown(ssl, SSL_get_shutdown(ssl) | SSL_RECEIVED_SHUTDOWN); SSL_set_shutdown(ssl, SSL_get_shutdown(ssl) | SSL_RECEIVED_SHUTDOWN);
ERR_clear_error(); ERR_clear_error();
@ -732,6 +741,7 @@ void Client::disconnect() {
ssl = nullptr; ssl = nullptr;
} }
} }
}
if (fd != -1) { if (fd != -1) {
shutdown(fd, SHUT_WR); shutdown(fd, SHUT_WR);
close(fd); close(fd);
@ -2878,8 +2888,20 @@ int main(int argc, char **argv) {
if (config.is_quic()) { if (config.is_quic()) {
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); # ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); if (ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) {
std::cerr << "ngtcp2_crypto_openssl_configure_client_context failed"
<< std::endl;
exit(EXIT_FAILURE);
}
# endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
# ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
if (ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
std::cerr << "ngtcp2_crypto_boringssl_configure_client_context failed"
<< std::endl;
exit(EXIT_FAILURE);
}
# endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
#endif // ENABLE_HTTP3 #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,

View File

@ -339,10 +339,10 @@ struct Client {
SSL *ssl; SSL *ssl;
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
struct { struct {
ngtcp2_crypto_conn_ref conn_ref;
ev_timer pkt_timer; ev_timer pkt_timer;
ngtcp2_conn *conn; ngtcp2_conn *conn;
ngtcp2_connection_close_error last_error; ngtcp2_connection_close_error last_error;
uint8_t tls_alert;
bool close_requested; bool close_requested;
FILE *qlog_file; FILE *qlog_file;
@ -495,17 +495,12 @@ struct Client {
int quic_stream_stop_sending(int64_t stream_id, uint64_t app_error_code); int quic_stream_stop_sending(int64_t stream_id, uint64_t app_error_code);
int quic_extend_max_local_streams(); int quic_extend_max_local_streams();
int quic_on_rx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen);
int quic_on_tx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen);
void quic_set_tls_alert(uint8_t alert);
int quic_write_client_handshake(ngtcp2_crypto_level level, int quic_write_client_handshake(ngtcp2_crypto_level level,
const uint8_t *data, size_t datalen); const uint8_t *data, size_t datalen);
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);
int quic_make_http3_session();
#endif // ENABLE_HTTP3 #endif // ENABLE_HTTP3
}; };

View File

@ -243,127 +243,6 @@ ngtcp2_tstamp timestamp(struct ev_loop *loop) {
} }
} // namespace } // namespace
#ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
namespace {
int set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *rx_secret, const uint8_t *tx_secret,
size_t secret_len) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
auto level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
if (c->quic_on_rx_secret(level, rx_secret, secret_len) != 0) {
return 0;
}
if (c->quic_on_tx_secret(level, tx_secret, secret_len) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *data, size_t len) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
if (c->quic_write_client_handshake(
ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level), data,
len) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int flush_flight(SSL *ssl) { return 1; }
} // namespace
namespace {
int send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
c->quic_set_tls_alert(alert);
return 1;
}
} // namespace
namespace {
auto quic_method = SSL_QUIC_METHOD{
set_encryption_secrets,
add_handshake_data,
flush_flight,
send_alert,
};
} // namespace
#endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
#ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
namespace {
int set_read_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secretlen) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
if (c->quic_on_rx_secret(
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), secret,
secretlen) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int set_write_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secretlen) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
if (c->quic_on_tx_secret(
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), secret,
secretlen) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int add_handshake_data(SSL *ssl, ssl_encryption_level_t ssl_level,
const uint8_t *data, size_t len) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
if (c->quic_write_client_handshake(
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), data,
len) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int flush_flight(SSL *ssl) { return 1; }
} // namespace
namespace {
int send_alert(SSL *ssl, ssl_encryption_level_t level, uint8_t alert) {
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
c->quic_set_tls_alert(alert);
return 1;
}
} // namespace
namespace {
auto quic_method = SSL_QUIC_METHOD{
set_read_secret, set_write_secret, add_handshake_data,
flush_flight, send_alert,
};
} // namespace
#endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
// qlog write callback -- excerpted from ngtcp2/examples/client_base.cc // qlog write callback -- excerpted from ngtcp2/examples/client_base.cc
namespace { namespace {
void qlog_write_cb(void *user_data, uint32_t flags, const void *data, void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
@ -385,6 +264,39 @@ void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) {
} }
} // namespace } // namespace
namespace {
int recv_rx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level, void *user_data) {
if (level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
return 0;
}
auto c = static_cast<Client *>(user_data);
if (c->quic_make_http3_session() != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Client::quic_make_http3_session() {
auto s = std::make_unique<Http3Session>(this);
if (s->init_conn() == -1) {
return -1;
}
session = std::move(s);
return 0;
}
namespace {
ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
auto c = static_cast<Client *>(conn_ref->user_data);
return c->quic.conn;
}
} // namespace
int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen, int Client::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) {
int rv; int rv;
@ -392,9 +304,11 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
if (!ssl) { if (!ssl) {
ssl = SSL_new(worker->ssl_ctx); ssl = SSL_new(worker->ssl_ctx);
SSL_set_app_data(ssl, this); quic.conn_ref.get_conn = get_conn;
quic.conn_ref.user_data = this;
SSL_set_app_data(ssl, &quic.conn_ref);
SSL_set_connect_state(ssl); SSL_set_connect_state(ssl);
SSL_set_quic_method(ssl, &quic_method);
SSL_set_quic_use_legacy_codepoint(ssl, 0); SSL_set_quic_use_legacy_codepoint(ssl, 0);
} }
@ -435,6 +349,9 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
nullptr, // lost_datagram nullptr, // lost_datagram
ngtcp2_crypto_get_path_challenge_data_cb, ngtcp2_crypto_get_path_challenge_data_cb,
h2load::stream_stop_sending, h2load::stream_stop_sending,
nullptr, // version_negotiation
h2load::recv_rx_key,
nullptr, // recv_tx_key
}; };
ngtcp2_cid scid, dcid; ngtcp2_cid scid, dcid;
@ -546,42 +463,6 @@ void Client::quic_close_connection() {
ps.path.remote.addrlen, buf.data(), nwrite, 0); ps.path.remote.addrlen, buf.data(), nwrite, 0);
} }
int Client::quic_on_rx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen) {
if (ngtcp2_crypto_derive_and_install_rx_key(quic.conn, nullptr, nullptr,
nullptr, level, secret,
secretlen) != 0) {
std::cerr << "ngtcp2_crypto_derive_and_install_rx_key() failed"
<< std::endl;
return -1;
}
if (level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
auto s = std::make_unique<Http3Session>(this);
if (s->init_conn() == -1) {
return -1;
}
session = std::move(s);
}
return 0;
}
int Client::quic_on_tx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen) {
if (ngtcp2_crypto_derive_and_install_tx_key(quic.conn, nullptr, nullptr,
nullptr, level, secret,
secretlen) != 0) {
std::cerr << "ngtcp2_crypto_derive_and_install_tx_key() failed"
<< std::endl;
return -1;
}
return 0;
}
void Client::quic_set_tls_alert(uint8_t alert) { quic.tls_alert = alert; }
int Client::quic_write_client_handshake(ngtcp2_crypto_level level, int Client::quic_write_client_handshake(ngtcp2_crypto_level level,
const uint8_t *data, size_t datalen) { const uint8_t *data, size_t datalen) {
int rv; int rv;
@ -670,7 +551,8 @@ int Client::read_quic() {
if (!quic.last_error.error_code) { if (!quic.last_error.error_code) {
if (rv == NGTCP2_ERR_CRYPTO) { if (rv == NGTCP2_ERR_CRYPTO) {
ngtcp2_connection_close_error_set_transport_error_tls_alert( ngtcp2_connection_close_error_set_transport_error_tls_alert(
&quic.last_error, quic.tls_alert, nullptr, 0); &quic.last_error, ngtcp2_conn_get_tls_alert(quic.conn), nullptr,
0);
} else { } else {
ngtcp2_connection_close_error_set_transport_error_liberr( ngtcp2_connection_close_error_set_transport_error_liberr(
&quic.last_error, rv, nullptr, 0); &quic.last_error, rv, nullptr, 0);

View File

@ -60,7 +60,11 @@ Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
IOCb readcb, TimerCb timeoutcb, void *data, IOCb readcb, TimerCb timeoutcb, void *data,
size_t tls_dyn_rec_warmup_threshold, size_t tls_dyn_rec_warmup_threshold,
ev_tstamp tls_dyn_rec_idle_timeout, Proto proto) ev_tstamp tls_dyn_rec_idle_timeout, Proto proto)
: tls{DefaultMemchunks(mcpool), DefaultPeekMemchunks(mcpool), :
#ifdef ENABLE_HTTP3
conn_ref{nullptr, this},
#endif // ENABLE_HTTP3
tls{DefaultMemchunks(mcpool), DefaultPeekMemchunks(mcpool),
DefaultMemchunks(mcpool)}, DefaultMemchunks(mcpool)},
wlimit(loop, &wev, write_limit.rate, write_limit.burst), wlimit(loop, &wev, write_limit.rate, write_limit.burst),
rlimit(loop, &rev, read_limit.rate, read_limit.burst, this), rlimit(loop, &rev, read_limit.rate, read_limit.burst, this),
@ -97,6 +101,7 @@ Connection::~Connection() { disconnect(); }
void Connection::disconnect() { void Connection::disconnect() {
if (tls.ssl) { if (tls.ssl) {
if (proto != Proto::HTTP3) {
SSL_set_shutdown(tls.ssl, SSL_set_shutdown(tls.ssl,
SSL_get_shutdown(tls.ssl) | SSL_RECEIVED_SHUTDOWN); SSL_get_shutdown(tls.ssl) | SSL_RECEIVED_SHUTDOWN);
ERR_clear_error(); ERR_clear_error();
@ -112,6 +117,8 @@ void Connection::disconnect() {
} }
SSL_shutdown(tls.ssl); SSL_shutdown(tls.ssl);
}
SSL_free(tls.ssl); SSL_free(tls.ssl);
tls.ssl = nullptr; tls.ssl = nullptr;

View File

@ -33,6 +33,10 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#ifdef ENABLE_HTTP3
# include <ngtcp2/ngtcp2_crypto.h>
#endif // ENABLE_HTTP3
#include "shrpx_rate_limit.h" #include "shrpx_rate_limit.h"
#include "shrpx_error.h" #include "shrpx_error.h"
#include "memchunk.h" #include "memchunk.h"
@ -155,6 +159,10 @@ struct Connection {
// Returns true if read timer expired. // Returns true if read timer expired.
bool expired_rt(); bool expired_rt();
#ifdef ENABLE_HTTP3
// This must be the first member of Connection.
ngtcp2_crypto_conn_ref conn_ref;
#endif // ENABLE_HTTP3
TLSConnection tls; TLSConnection tls;
ev_io wev; ev_io wev;
ev_io rev; ev_io rev;
@ -178,6 +186,11 @@ struct Connection {
ev_tstamp read_timeout; ev_tstamp read_timeout;
}; };
#ifdef ENABLE_HTTP3
static_assert(std::is_standard_layout<Connection>::value,
"Conneciton is not standard layout");
#endif // ENABLE_HTTP3
// Creates BIO_method shared by all SSL objects. // Creates BIO_method shared by all SSL objects.
BIO_METHOD *create_bio_method(); BIO_METHOD *create_bio_method();

View File

@ -100,12 +100,20 @@ size_t downstream_queue_size(Worker *worker) {
} }
} // namespace } // namespace
namespace {
ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
auto conn = static_cast<Connection *>(conn_ref->user_data);
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
return upstream->get_conn();
}
} // namespace
Http3Upstream::Http3Upstream(ClientHandler *handler) Http3Upstream::Http3Upstream(ClientHandler *handler)
: handler_{handler}, : handler_{handler},
qlog_fd_{-1}, qlog_fd_{-1},
hashed_scid_{}, hashed_scid_{},
conn_{nullptr}, conn_{nullptr},
tls_alert_{0},
httpconn_{nullptr}, httpconn_{nullptr},
downstream_queue_{downstream_queue_size(handler->get_worker()), downstream_queue_{downstream_queue_size(handler->get_worker()),
!get_config()->http2_proxy}, !get_config()->http2_proxy},
@ -113,6 +121,9 @@ Http3Upstream::Http3Upstream(ClientHandler *handler)
tx_{ tx_{
.data = std::unique_ptr<uint8_t[]>(new uint8_t[64_k]), .data = std::unique_ptr<uint8_t[]>(new uint8_t[64_k]),
} { } {
auto conn = handler_->get_connection();
conn->conn_ref.get_conn = shrpx::get_conn;
ev_timer_init(&timer_, timeoutcb, 0., 0.); ev_timer_init(&timer_, timeoutcb, 0., 0.);
timer_.data = this; timer_.data = this;
@ -493,6 +504,21 @@ int Http3Upstream::handshake_completed() {
return 0; return 0;
} }
namespace {
int recv_tx_key(ngtcp2_conn *conn, ngtcp2_crypto_level level, void *user_data) {
if (level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
return 0;
}
auto upstream = static_cast<Http3Upstream *>(user_data);
if (upstream->setup_httpconn() != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
} // namespace
int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
const Address &local_addr, const Address &local_addr,
const ngtcp2_pkt_hd &initial_hd, const ngtcp2_pkt_hd &initial_hd,
@ -540,6 +566,9 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
nullptr, // lost_datagram nullptr, // lost_datagram
ngtcp2_crypto_get_path_challenge_data_cb, ngtcp2_crypto_get_path_challenge_data_cb,
shrpx::stream_stop_sending, shrpx::stream_stop_sending,
nullptr, // version_negotiation
nullptr, // recv_rx_key
shrpx::recv_tx_key,
}; };
auto config = get_config(); auto config = get_config();
@ -1795,7 +1824,7 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
case NGTCP2_ERR_CRYPTO: case NGTCP2_ERR_CRYPTO:
if (!last_error_.error_code) { if (!last_error_.error_code) {
ngtcp2_connection_close_error_set_transport_error_tls_alert( ngtcp2_connection_close_error_set_transport_error_tls_alert(
&last_error_, tls_alert_, nullptr, 0); &last_error_, ngtcp2_conn_get_tls_alert(conn_), nullptr, 0);
} }
break; break;
case NGTCP2_ERR_DROP_CONN: case NGTCP2_ERR_DROP_CONN:
@ -1944,47 +1973,6 @@ int Http3Upstream::handle_error() {
return -1; return -1;
} }
int Http3Upstream::on_rx_secret(ngtcp2_crypto_level level,
const uint8_t *secret, size_t secretlen) {
if (ngtcp2_crypto_derive_and_install_rx_key(conn_, nullptr, nullptr, nullptr,
level, secret, secretlen) != 0) {
ULOG(ERROR, this) << "ngtcp2_crypto_derive_and_install_rx_key failed";
return -1;
}
return 0;
}
int Http3Upstream::on_tx_secret(ngtcp2_crypto_level level,
const uint8_t *secret, size_t secretlen) {
if (ngtcp2_crypto_derive_and_install_tx_key(conn_, nullptr, nullptr, nullptr,
level, secret, secretlen) != 0) {
ULOG(ERROR, this) << "ngtcp2_crypto_derive_and_install_tx_key failed";
return -1;
}
if (level == NGTCP2_CRYPTO_LEVEL_APPLICATION && setup_httpconn() != 0) {
return -1;
}
return 0;
}
int Http3Upstream::add_crypto_data(ngtcp2_crypto_level level,
const uint8_t *data, size_t datalen) {
int rv = ngtcp2_conn_submit_crypto_data(conn_, level, data, datalen);
if (rv != 0) {
ULOG(ERROR, this) << "ngtcp2_conn_submit_crypto_data: "
<< ngtcp2_strerror(rv);
return -1;
}
return 0;
}
void Http3Upstream::set_tls_alert(uint8_t alert) { tls_alert_ = alert; }
int Http3Upstream::handle_expiry() { int Http3Upstream::handle_expiry() {
int rv; int rv;
@ -2646,11 +2634,10 @@ int Http3Upstream::setup_httpconn() {
return -1; return -1;
} }
ngtcp2_transport_params params; auto params = ngtcp2_conn_get_local_transport_params(conn_);
ngtcp2_conn_get_local_transport_params(conn_, &params);
nghttp3_conn_set_max_client_streams_bidi(httpconn_, nghttp3_conn_set_max_client_streams_bidi(httpconn_,
params.initial_max_streams_bidi); params->initial_max_streams_bidi);
int64_t ctrl_stream_id; int64_t ctrl_stream_id;
@ -2933,4 +2920,6 @@ int Http3Upstream::open_qlog_file(const StringRef &dir,
return fd; return fd;
} }
ngtcp2_conn *Http3Upstream::get_conn() const { return conn_; }
} // namespace shrpx } // namespace shrpx

View File

@ -97,16 +97,6 @@ public:
int write_streams(); int write_streams();
int on_rx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen);
int on_tx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
size_t secretlen);
int add_crypto_data(ngtcp2_crypto_level level, const uint8_t *data,
size_t datalen);
void set_tls_alert(uint8_t alert);
int handle_error(); int handle_error();
int handle_expiry(); int handle_expiry();
@ -162,6 +152,8 @@ public:
int send_blocked_packet(); int send_blocked_packet();
void signal_write_upstream_addr(const UpstreamAddr *faddr); void signal_write_upstream_addr(const UpstreamAddr *faddr);
ngtcp2_conn *get_conn() const;
private: private:
ClientHandler *handler_; ClientHandler *handler_;
ev_timer timer_; ev_timer timer_;
@ -171,7 +163,6 @@ private:
ngtcp2_cid hashed_scid_; ngtcp2_cid hashed_scid_;
ngtcp2_conn *conn_; ngtcp2_conn *conn_;
ngtcp2_connection_close_error last_error_; ngtcp2_connection_close_error last_error_;
uint8_t tls_alert_;
nghttp3_conn *httpconn_; nghttp3_conn *httpconn_;
DownstreamQueue downstream_queue_; DownstreamQueue downstream_queue_;
bool retry_close_; bool retry_close_;

View File

@ -1219,149 +1219,6 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
} }
#ifdef ENABLE_HTTP3 #ifdef ENABLE_HTTP3
# ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
namespace {
int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *rx_secret,
const uint8_t *tx_secret, size_t secretlen) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
auto level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
if (upstream->on_rx_secret(level, rx_secret, secretlen) != 0) {
return 0;
}
if (tx_secret && upstream->on_tx_secret(level, tx_secret, secretlen) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
const uint8_t *data, size_t len) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
auto level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
upstream->add_crypto_data(level, data, len);
return 1;
}
} // namespace
namespace {
int quic_flush_flight(SSL *ssl) { return 1; }
} // namespace
namespace {
int quic_send_alert(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, uint8_t alert) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
if (!upstream) {
return 1;
}
upstream->set_tls_alert(alert);
return 1;
}
} // namespace
namespace {
auto quic_method = SSL_QUIC_METHOD{
quic_set_encryption_secrets,
quic_add_handshake_data,
quic_flush_flight,
quic_send_alert,
};
} // namespace
# endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
# ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
namespace {
int quic_set_read_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secretlen) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
auto level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level);
if (upstream->on_rx_secret(level, secret, secretlen) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int quic_set_write_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
const SSL_CIPHER *cipher, const uint8_t *secret,
size_t secretlen) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
auto level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level);
if (upstream->on_tx_secret(level, secret, secretlen) != 0) {
return 0;
}
return 1;
}
} // namespace
namespace {
int quic_add_handshake_data(SSL *ssl, ssl_encryption_level_t ssl_level,
const uint8_t *data, size_t len) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
auto level = ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level);
upstream->add_crypto_data(level, data, len);
return 1;
}
} // namespace
namespace {
int quic_flush_flight(SSL *ssl) { return 1; }
} // namespace
namespace {
int quic_send_alert(SSL *ssl, ssl_encryption_level_t level, uint8_t alert) {
auto conn = static_cast<Connection *>(SSL_get_app_data(ssl));
auto handler = static_cast<ClientHandler *>(conn->data);
auto upstream = static_cast<Http3Upstream *>(handler->get_upstream());
if (!upstream) {
return 1;
}
upstream->set_tls_alert(alert);
return 1;
}
} // namespace
namespace {
auto quic_method = SSL_QUIC_METHOD{
quic_set_read_secret, quic_set_write_secret, quic_add_handshake_data,
quic_flush_flight, quic_send_alert,
};
} // namespace
# endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
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
@ -1396,8 +1253,18 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file,
SSL_CTX_set_options(ssl_ctx, ssl_opts); SSL_CTX_set_options(ssl_ctx, ssl_opts);
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); # ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); if (ngtcp2_crypto_openssl_configure_server_context(ssl_ctx) != 0) {
LOG(FATAL) << "ngtcp2_crypto_openssl_configure_server_context failed";
DIE();
}
# endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
# ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
if (ngtcp2_crypto_boringssl_configure_server_context(ssl_ctx) != 0) {
LOG(FATAL) << "ngtcp2_crypto_boringssl_configure_server_context failed";
DIE();
}
# endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
const unsigned char sid_ctx[] = "shrpx"; const unsigned char sid_ctx[] = "shrpx";
SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1); SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1);
@ -1638,8 +1505,6 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file,
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);
return ssl_ctx; return ssl_ctx;
} }
#endif // ENABLE_HTTP3 #endif // ENABLE_HTTP3