nghttpx: Cache TLS session inside DownstreamAddr object
This commit is contained in:
parent
177d0a513f
commit
f2a7275700
|
@ -277,6 +277,14 @@ struct UpstreamAddr {
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TLSSessionCache {
|
||||||
|
// ASN1 representation of SSL_SESSION object. See
|
||||||
|
// i2d_SSL_SESSION(3SSL).
|
||||||
|
std::vector<uint8_t> session_data;
|
||||||
|
// The last time stamp when this cache entry is created or updated.
|
||||||
|
ev_tstamp last_updated;
|
||||||
|
};
|
||||||
|
|
||||||
struct DownstreamAddr {
|
struct DownstreamAddr {
|
||||||
Address addr;
|
Address addr;
|
||||||
// backend address. If |host_unix| is true, this is UNIX domain
|
// backend address. If |host_unix| is true, this is UNIX domain
|
||||||
|
@ -284,6 +292,8 @@ struct DownstreamAddr {
|
||||||
ImmutableString host;
|
ImmutableString host;
|
||||||
ImmutableString hostport;
|
ImmutableString hostport;
|
||||||
ConnectBlocker *connect_blocker;
|
ConnectBlocker *connect_blocker;
|
||||||
|
// Client side TLS session cache
|
||||||
|
TLSSessionCache tls_session_cache;
|
||||||
// backend port. 0 if |host_unix| is true.
|
// backend port. 0 if |host_unix| is true.
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
// true if |host| contains UNIX domain socket path.
|
// true if |host| contains UNIX domain socket path.
|
||||||
|
|
|
@ -129,15 +129,7 @@ HttpDownstreamConnection::HttpDownstreamConnection(
|
||||||
response_htp_{0},
|
response_htp_{0},
|
||||||
group_(group) {}
|
group_(group) {}
|
||||||
|
|
||||||
HttpDownstreamConnection::~HttpDownstreamConnection() {
|
HttpDownstreamConnection::~HttpDownstreamConnection() {}
|
||||||
if (conn_.tls.ssl && conn_.tls.initial_handshake_done) {
|
|
||||||
auto session = SSL_get0_session(conn_.tls.ssl);
|
|
||||||
if (session) {
|
|
||||||
worker_->cache_client_tls_session(&addr_->addr, session,
|
|
||||||
ev_now(conn_.loop));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
@ -241,7 +233,7 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||||
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
|
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session = worker_->reuse_client_tls_session(&addr_->addr);
|
auto session = ssl::reuse_tls_session(addr_);
|
||||||
if (session) {
|
if (session) {
|
||||||
SSL_set_session(conn_.tls.ssl, session);
|
SSL_set_session(conn_.tls.ssl, session);
|
||||||
SSL_SESSION_free(session);
|
SSL_SESSION_free(session);
|
||||||
|
@ -891,6 +883,13 @@ int HttpDownstreamConnection::tls_handshake() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SSL_session_reused(conn_.tls.ssl)) {
|
||||||
|
auto session = SSL_get0_session(conn_.tls.ssl);
|
||||||
|
if (session) {
|
||||||
|
ssl::try_cache_tls_session(addr_, session, ev_now(conn_.loop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do_read_ = &HttpDownstreamConnection::read_tls;
|
do_read_ = &HttpDownstreamConnection::read_tls;
|
||||||
do_write_ = &HttpDownstreamConnection::write_tls;
|
do_write_ = &HttpDownstreamConnection::write_tls;
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ private:
|
||||||
// nullptr if TLS is not used.
|
// nullptr if TLS is not used.
|
||||||
SSL_CTX *ssl_ctx_;
|
SSL_CTX *ssl_ctx_;
|
||||||
// Address of remote endpoint
|
// Address of remote endpoint
|
||||||
const DownstreamAddr *addr_;
|
DownstreamAddr *addr_;
|
||||||
IOControl ioctrl_;
|
IOControl ioctrl_;
|
||||||
http_parser response_htp_;
|
http_parser response_htp_;
|
||||||
size_t group_;
|
size_t group_;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
@ -1335,6 +1336,50 @@ CertLookupTree *create_cert_lookup_tree() {
|
||||||
return new ssl::CertLookupTree();
|
return new ssl::CertLookupTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::vector<uint8_t> serialize_ssl_session(SSL_SESSION *session) {
|
||||||
|
auto len = i2d_SSL_SESSION(session, nullptr);
|
||||||
|
auto buf = std::vector<uint8_t>(len);
|
||||||
|
auto p = buf.data();
|
||||||
|
i2d_SSL_SESSION(session, &p);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void try_cache_tls_session(DownstreamAddr *addr, SSL_SESSION *session,
|
||||||
|
ev_tstamp t) {
|
||||||
|
auto &cache = addr->tls_session_cache;
|
||||||
|
|
||||||
|
if (cache.last_updated + 1_min > t) {
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Cache for addr=" << util::to_numeric_addr(&addr->addr)
|
||||||
|
<< " is still host. Not updating.";
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Update cache entry for SSL_SESSION=" << session
|
||||||
|
<< ", addr=" << util::to_numeric_addr(&addr->addr)
|
||||||
|
<< ", timestamp=" << std::fixed << std::setprecision(6) << t;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.session_data = serialize_ssl_session(session);
|
||||||
|
cache.last_updated = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_SESSION *reuse_tls_session(const DownstreamAddr *addr) {
|
||||||
|
auto &cache = addr->tls_session_cache;
|
||||||
|
|
||||||
|
if (cache.session_data.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = cache.session_data.data();
|
||||||
|
return d2i_SSL_SESSION(nullptr, &p, cache.session_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ssl
|
} // namespace ssl
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -217,6 +217,17 @@ bool downstream_tls_enabled();
|
||||||
bool tls_hostname_match(const char *pattern, size_t plen, const char *hostname,
|
bool tls_hostname_match(const char *pattern, size_t plen, const char *hostname,
|
||||||
size_t hlen);
|
size_t hlen);
|
||||||
|
|
||||||
|
// Caches |session| which is associated to remote address |addr|.
|
||||||
|
// |session| is serialized into ASN1 representation, and stored. |t|
|
||||||
|
// is used as a time stamp. Depending on the existing cache's time
|
||||||
|
// stamp, |session| might not be cached.
|
||||||
|
void try_cache_tls_session(DownstreamAddr *addr, SSL_SESSION *session,
|
||||||
|
ev_tstamp t);
|
||||||
|
|
||||||
|
// Returns cached session associated |addr|. If no cache entry is
|
||||||
|
// found associated to |addr|, nullptr will be returned.
|
||||||
|
SSL_SESSION *reuse_tls_session(const DownstreamAddr *addr);
|
||||||
|
|
||||||
} // namespace ssl
|
} // namespace ssl
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#endif // HAVE_UNISTD_H
|
#endif // HAVE_UNISTD_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include "shrpx_ssl.h"
|
#include "shrpx_ssl.h"
|
||||||
#include "shrpx_log.h"
|
#include "shrpx_log.h"
|
||||||
|
@ -312,61 +311,6 @@ mruby::MRubyContext *Worker::get_mruby_context() const {
|
||||||
}
|
}
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
|
||||||
namespace {
|
|
||||||
std::vector<uint8_t> serialize_ssl_session(SSL_SESSION *session) {
|
|
||||||
auto len = i2d_SSL_SESSION(session, nullptr);
|
|
||||||
auto buf = std::vector<uint8_t>(len);
|
|
||||||
auto p = buf.data();
|
|
||||||
i2d_SSL_SESSION(session, &p);
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void Worker::cache_client_tls_session(const Address *addr, SSL_SESSION *session,
|
|
||||||
ev_tstamp t) {
|
|
||||||
auto it = client_tls_session_cache_.find(addr);
|
|
||||||
if (it == std::end(client_tls_session_cache_)) {
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
|
||||||
LOG(INFO) << "Create cache entry for SSL_SESSION=" << session
|
|
||||||
<< ", addr=" << util::to_numeric_addr(addr) << "(" << addr
|
|
||||||
<< "), timestamp=" << std::fixed << std::setprecision(6) << t;
|
|
||||||
}
|
|
||||||
client_tls_session_cache_.emplace(
|
|
||||||
addr, SessionCacheEntry{serialize_ssl_session(session), t});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &ent = (*it).second;
|
|
||||||
if (ent.last_updated + 1_min > t) {
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
|
||||||
LOG(INFO) << "Cache for addr=" << util::to_numeric_addr(addr) << "("
|
|
||||||
<< addr << ") is still host. Not updating.";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
|
||||||
LOG(INFO) << "Update cache entry for SSL_SESSION=" << session
|
|
||||||
<< ", addr=" << util::to_numeric_addr(addr) << "(" << addr
|
|
||||||
<< "), timestamp=" << std::fixed << std::setprecision(6) << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent.session_data = serialize_ssl_session(session);
|
|
||||||
ent.last_updated = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSL_SESSION *Worker::reuse_client_tls_session(const Address *addr) {
|
|
||||||
auto it = client_tls_session_cache_.find(addr);
|
|
||||||
if (it == std::end(client_tls_session_cache_)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &ent = (*it).second;
|
|
||||||
auto p = ent.session_data.data();
|
|
||||||
return d2i_SSL_SESSION(nullptr, &p, ent.session_data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<DownstreamAddrGroup> &Worker::get_downstream_addr_groups() {
|
std::vector<DownstreamAddrGroup> &Worker::get_downstream_addr_groups() {
|
||||||
return downstream_addr_groups_;
|
return downstream_addr_groups_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,14 +101,6 @@ struct WorkerEvent {
|
||||||
std::shared_ptr<TicketKeys> ticket_keys;
|
std::shared_ptr<TicketKeys> ticket_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SessionCacheEntry {
|
|
||||||
// ASN1 representation of SSL_SESSION object. See
|
|
||||||
// i2d_SSL_SESSION(3SSL).
|
|
||||||
std::vector<uint8_t> session_data;
|
|
||||||
// The last time stamp when this cache entry is created or updated.
|
|
||||||
ev_tstamp last_updated;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Worker {
|
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,
|
||||||
|
@ -153,16 +145,6 @@ public:
|
||||||
mruby::MRubyContext *get_mruby_context() const;
|
mruby::MRubyContext *get_mruby_context() const;
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
|
||||||
// Caches |session| which is associated to remote address |addr|.
|
|
||||||
// |session| is serialized into ASN1 representation, and stored.
|
|
||||||
// |t| is used as a time stamp. Depending on the existing cache's
|
|
||||||
// time stamp, |session| might not be cached.
|
|
||||||
void cache_client_tls_session(const Address *addr, SSL_SESSION *session,
|
|
||||||
ev_tstamp t);
|
|
||||||
// Returns cached session associated |addr|. If no cache entry is
|
|
||||||
// found associated to |addr|, nullptr will be returned.
|
|
||||||
SSL_SESSION *reuse_client_tls_session(const Address *addr);
|
|
||||||
|
|
||||||
std::vector<DownstreamAddrGroup> &get_downstream_addr_groups();
|
std::vector<DownstreamAddrGroup> &get_downstream_addr_groups();
|
||||||
|
|
||||||
ConnectBlocker *get_connect_blocker() const;
|
ConnectBlocker *get_connect_blocker() const;
|
||||||
|
@ -181,11 +163,6 @@ private:
|
||||||
WorkerStat worker_stat_;
|
WorkerStat worker_stat_;
|
||||||
std::vector<DownstreamGroup> dgrps_;
|
std::vector<DownstreamGroup> dgrps_;
|
||||||
|
|
||||||
// Client side SSL_SESSION cache. SSL_SESSION is associated to
|
|
||||||
// remote address.
|
|
||||||
std::unordered_map<const Address *, SessionCacheEntry>
|
|
||||||
client_tls_session_cache_;
|
|
||||||
|
|
||||||
std::unique_ptr<MemcachedDispatcher> session_cache_memcached_dispatcher_;
|
std::unique_ptr<MemcachedDispatcher> session_cache_memcached_dispatcher_;
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
std::unique_ptr<mruby::MRubyContext> mruby_ctx_;
|
std::unique_ptr<mruby::MRubyContext> mruby_ctx_;
|
||||||
|
|
Loading…
Reference in New Issue