Merge branch 'neverbleed'

This commit is contained in:
Tatsuhiro Tsujikawa 2015-09-26 19:02:24 +09:00
commit 45366ae9dc
13 changed files with 203 additions and 32 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "third-party/mruby"] [submodule "third-party/mruby"]
path = third-party/mruby path = third-party/mruby
url = https://github.com/mruby/mruby url = https://github.com/mruby/mruby
[submodule "third-party/neverbleed"]
path = third-party/neverbleed
url = https://github.com/h2o/neverbleed.git

View File

@ -124,6 +124,11 @@ AC_ARG_WITH([mruby],
[Use mruby [default=no]])], [Use mruby [default=no]])],
[request_mruby=$withval], [request_mruby=no]) [request_mruby=$withval], [request_mruby=no])
AC_ARG_WITH([neverbleed],
[AS_HELP_STRING([--with-neverbleed],
[Use neverbleed [default=no]])],
[request_neverbleed=$withval], [request_neverbleed=no])
AC_ARG_WITH([cython], AC_ARG_WITH([cython],
[AS_HELP_STRING([--with-cython=PATH], [AS_HELP_STRING([--with-cython=PATH],
[Use cython in given PATH])], [Use cython in given PATH])],
@ -391,6 +396,15 @@ fi
AM_CONDITIONAL([HAVE_MRUBY], [test "x${have_mruby}" = "xyes"]) AM_CONDITIONAL([HAVE_MRUBY], [test "x${have_mruby}" = "xyes"])
# neverbleed (for src/nghttpx)
have_neverbleed=no
if test "x${request_neverbleed}" = "xyes"; then
have_neverbleed=yes
AC_DEFINE([HAVE_NEVERBLEED], [1], [Define to 1 if you have `neverbleed` library.])
fi
AM_CONDITIONAL([HAVE_NEVERBLEED], [test "x${have_neverbleed}" = "xyes"])
# Check Boost Asio library # Check Boost Asio library
have_asio_lib=no have_asio_lib=no
@ -755,6 +769,7 @@ AC_MSG_NOTICE([summary of build options:
Libevent(SSL): ${have_libevent_openssl} Libevent(SSL): ${have_libevent_openssl}
Spdylay: ${have_spdylay} Spdylay: ${have_spdylay}
MRuby: ${have_mruby} MRuby: ${have_mruby}
Neverbleed: ${have_neverbleed}
Jansson: ${have_jansson} Jansson: ${have_jansson}
Jemalloc: ${have_jemalloc} Jemalloc: ${have_jemalloc}
Zlib: ${have_zlib} Zlib: ${have_zlib}

View File

@ -157,6 +157,11 @@ libnghttpx_a_CPPFLAGS += \
nghttpx_LDADD += -L${top_builddir}/third-party/mruby/build/lib @LIBMRUBY_LIBS@ nghttpx_LDADD += -L${top_builddir}/third-party/mruby/build/lib @LIBMRUBY_LIBS@
endif # HAVE_MRUBY endif # HAVE_MRUBY
if HAVE_NEVERBLEED
libnghttpx_a_CPPFLAGS += -I${top_srcdir}/third-party/neverbleed
nghttpx_LDADD += ${top_builddir}/third-party/libneverbleed.la
endif # HAVE_NEVERBLEED
if HAVE_CUNIT if HAVE_CUNIT
check_PROGRAMS += nghttpx-unittest check_PROGRAMS += nghttpx-unittest
nghttpx_unittest_SOURCES = shrpx-unittest.cc \ nghttpx_unittest_SOURCES = shrpx-unittest.cc \
@ -180,6 +185,11 @@ nghttpx_unittest_LDADD += \
-L${top_builddir}/third-party/mruby/build/lib @LIBMRUBY_LIBS@ -L${top_builddir}/third-party/mruby/build/lib @LIBMRUBY_LIBS@
endif # HAVE_MRUBY endif # HAVE_MRUBY
if HAVE_NEVERBLEED
nghttpx_unittest_CPPFLAGS += -I${top_srcdir}/third-party/neverbleed
nghttpx_unittest_LDADD += ${top_builddir}/third-party/libneverbleed.la
endif # HAVE_NEVERBLEED
TESTS += nghttpx-unittest TESTS += nghttpx-unittest
endif # HAVE_CUNIT endif # HAVE_CUNIT

View File

@ -408,26 +408,9 @@ void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
namespace { namespace {
void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) { void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
std::string signalstr; log_chld(w->rpid, w->rstatus, "Worker process");
if (WIFSIGNALED(w->rstatus)) {
signalstr += "; signal ";
auto sig = WTERMSIG(w->rstatus);
auto s = strsignal(sig);
if (s) {
signalstr += s;
signalstr += "(";
} else {
signalstr += "UNKNOWN(";
}
signalstr += util::utos(sig);
signalstr += ")";
}
LOG(NOTICE) << "Worker process (" << w->rpid << ") exited " ev_child_stop(loop, w);
<< (WIFEXITED(w->rstatus) ? "normally" : "abnormally")
<< " with status " << std::hex << w->rstatus << std::oct
<< "; exit status " << WEXITSTATUS(w->rstatus)
<< (signalstr.empty() ? "" : signalstr.c_str());
ev_break(loop); ev_break(loop);
} }
@ -744,7 +727,7 @@ pid_t fork_worker_process(SignalServer *ssv) {
close(ssv->ipc_fd[0]); close(ssv->ipc_fd[0]);
LOG(NOTICE) << "Worker process (" << pid << ") spawned"; LOG(NOTICE) << "Worker process [" << pid << "] spawned";
return pid; return pid;
} }

View File

@ -159,7 +159,12 @@ void ConnectionHandler::worker_reopen_log_files() {
int ConnectionHandler::create_single_worker() { int ConnectionHandler::create_single_worker() {
auto cert_tree = ssl::create_cert_lookup_tree(); auto cert_tree = ssl::create_cert_lookup_tree();
auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree); auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree
#ifdef HAVE_NEVERBLEED
,
nb_.get()
#endif // HAVE_NEVERBLEED
);
auto cl_ssl_ctx = ssl::setup_client_ssl_context(); auto cl_ssl_ctx = ssl::setup_client_ssl_context();
if (cl_ssl_ctx) { if (cl_ssl_ctx) {
@ -182,7 +187,12 @@ int ConnectionHandler::create_worker_thread(size_t num) {
assert(workers_.size() == 0); assert(workers_.size() == 0);
auto cert_tree = ssl::create_cert_lookup_tree(); auto cert_tree = ssl::create_cert_lookup_tree();
auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree); auto sv_ssl_ctx = ssl::setup_server_ssl_context(all_ssl_ctx_, cert_tree
#ifdef HAVE_NEVERBLEED
,
nb_.get()
#endif // HAVE_NEVERBLEED
);
auto cl_ssl_ctx = ssl::setup_client_ssl_context(); auto cl_ssl_ctx = ssl::setup_client_ssl_context();
if (cl_ssl_ctx) { if (cl_ssl_ctx) {
@ -703,4 +713,13 @@ ConnectionHandler::schedule_next_tls_ticket_key_memcached_get(ev_timer *w) {
ev_timer_start(loop_, w); ev_timer_start(loop_, w);
} }
#ifdef HAVE_NEVERBLEED
void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) {
nb_ = std::move(nb);
}
neverbleed_t *ConnectionHandler::get_neverbleed() const { return nb_.get(); }
#endif // HAVE_NEVERBLEED
} // namespace shrpx } // namespace shrpx

View File

@ -39,6 +39,10 @@
#include <ev.h> #include <ev.h>
#ifdef HAVE_NEVERBLEED
#include <neverbleed.h>
#endif // HAVE_NEVERBLEED
#include "shrpx_downstream_connection_pool.h" #include "shrpx_downstream_connection_pool.h"
namespace shrpx { namespace shrpx {
@ -123,6 +127,11 @@ public:
ev_timer *w); ev_timer *w);
void schedule_next_tls_ticket_key_memcached_get(ev_timer *w); void schedule_next_tls_ticket_key_memcached_get(ev_timer *w);
#ifdef HAVE_NEVERBLEED
void set_neverbleed(std::unique_ptr<neverbleed_t> nb);
neverbleed_t *get_neverbleed() const;
#endif // HAVE_NEVERBLEED
private: private:
// Stores all SSL_CTX objects. // Stores all SSL_CTX objects.
std::vector<SSL_CTX *> all_ssl_ctx_; std::vector<SSL_CTX *> all_ssl_ctx_;
@ -144,6 +153,9 @@ private:
std::unique_ptr<AcceptHandler> acceptor_; std::unique_ptr<AcceptHandler> acceptor_;
// acceptor for IPv6 address // acceptor for IPv6 address
std::unique_ptr<AcceptHandler> acceptor6_; std::unique_ptr<AcceptHandler> acceptor6_;
#ifdef HAVE_NEVERBLEED
std::unique_ptr<neverbleed_t> nb_;
#endif // HAVE_NEVERBLEED
ev_timer disable_acceptor_timer_; ev_timer disable_acceptor_timer_;
ev_timer ocsp_timer_; ev_timer ocsp_timer_;
size_t tls_ticket_key_memcached_get_retry_count_; size_t tls_ticket_key_memcached_get_retry_count_;

View File

@ -370,6 +370,29 @@ int reopen_log_files() {
return res; return res;
} }
void log_chld(pid_t pid, int rstatus, const char *msg) {
std::string signalstr;
if (WIFSIGNALED(rstatus)) {
signalstr += "; signal ";
auto sig = WTERMSIG(rstatus);
auto s = strsignal(sig);
if (s) {
signalstr += s;
signalstr += "(";
} else {
signalstr += "UNKNOWN(";
}
signalstr += util::utos(sig);
signalstr += ")";
}
LOG(NOTICE) << msg << ": [" << pid << "] exited "
<< (WIFEXITED(rstatus) ? "normally" : "abnormally")
<< " with status " << std::hex << rstatus << std::oct
<< "; exit status " << WEXITSTATUS(rstatus)
<< (signalstr.empty() ? "" : signalstr.c_str());
}
void redirect_stderr_to_errorlog() { void redirect_stderr_to_errorlog() {
auto lgconf = log_config(); auto lgconf = log_config();

View File

@ -156,6 +156,10 @@ void upstream_accesslog(const std::vector<LogFragment> &lf,
int reopen_log_files(); int reopen_log_files();
// Logs message when process whose pid is |pid| and exist status is
// |rstatus| exited. The |msg| is prepended to the log message.
void log_chld(pid_t pid, int rstatus, const char *msg);
void redirect_stderr_to_errorlog(); void redirect_stderr_to_errorlog();
} // namespace shrpx } // namespace shrpx

View File

@ -456,8 +456,12 @@ long int create_tls_proto_mask(const std::vector<std::string> &tls_proto_list) {
return res; return res;
} }
SSL_CTX *create_ssl_context(const char *private_key_file, SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
const char *cert_file) { #ifdef HAVE_NEVERBLEED
,
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
) {
auto ssl_ctx = SSL_CTX_new(SSLv23_server_method()); auto ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (!ssl_ctx) { if (!ssl_ctx) {
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr); LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
@ -543,12 +547,22 @@ SSL_CTX *create_ssl_context(const char *private_key_file,
SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb); SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)get_config()); SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)get_config());
} }
#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
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf;
if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file,
errbuf.data()) != 1) {
LOG(FATAL) << "neverbleed_load_private_key_file failed: " << errbuf.data();
DIE(); DIE();
} }
#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: "
<< ERR_error_string(ERR_get_error(), nullptr); << ERR_error_string(ERR_get_error(), nullptr);
@ -1096,13 +1110,23 @@ bool in_proto_list(const std::vector<std::string> &protos,
} }
SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx, SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
CertLookupTree *cert_tree) { CertLookupTree *cert_tree
#ifdef HAVE_NEVERBLEED
,
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
) {
if (get_config()->upstream_no_tls) { if (get_config()->upstream_no_tls) {
return nullptr; return nullptr;
} }
auto ssl_ctx = ssl::create_ssl_context(get_config()->private_key_file.get(), auto ssl_ctx = ssl::create_ssl_context(get_config()->private_key_file.get(),
get_config()->cert_file.get()); get_config()->cert_file.get()
#ifdef HAVE_NEVERBLEED
,
nb
#endif // HAVE_NEVERBLEED
);
all_ssl_ctx.push_back(ssl_ctx); all_ssl_ctx.push_back(ssl_ctx);
@ -1118,7 +1142,12 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
for (auto &keycert : get_config()->subcerts) { for (auto &keycert : get_config()->subcerts) {
auto ssl_ctx = auto ssl_ctx =
ssl::create_ssl_context(keycert.first.c_str(), keycert.second.c_str()); ssl::create_ssl_context(keycert.first.c_str(), keycert.second.c_str()
#ifdef HAVE_NEVERBLEED
,
nb
#endif // HAVE_NEVERBLEED
);
all_ssl_ctx.push_back(ssl_ctx); all_ssl_ctx.push_back(ssl_ctx);
if (ssl::cert_lookup_tree_add_cert_from_file( if (ssl::cert_lookup_tree_add_cert_from_file(
cert_tree, ssl_ctx, keycert.second.c_str()) == -1) { cert_tree, ssl_ctx, keycert.second.c_str()) == -1) {

View File

@ -35,6 +35,10 @@
#include <ev.h> #include <ev.h>
#ifdef HAVE_NEVERBLEED
#include <neverbleed.h>
#endif // HAVE_NEVERBLEED
namespace shrpx { namespace shrpx {
class ClientHandler; class ClientHandler;
@ -57,8 +61,12 @@ struct TLSContextData {
}; };
// Create server side SSL_CTX // Create server side SSL_CTX
SSL_CTX *create_ssl_context(const char *private_key_file, SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
const char *cert_file); #ifdef HAVE_NEVERBLEED
,
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
);
// Create client side SSL_CTX // Create client side SSL_CTX
SSL_CTX *create_ssl_client_context(); SSL_CTX *create_ssl_client_context();
@ -161,7 +169,12 @@ set_alpn_prefs(const std::vector<std::string> &protos);
// object as |cert_tree| parameter, otherwise SNI does not work. All // object as |cert_tree| parameter, otherwise SNI does not work. All
// the created SSL_CTX is stored into |all_ssl_ctx|. // the created SSL_CTX is stored into |all_ssl_ctx|.
SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx, SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
CertLookupTree *cert_tree); CertLookupTree *cert_tree
#ifdef HAVE_NEVERBLEED
,
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
);
// Setups client side SSL_CTX. This function inspects get_config() // Setups client side SSL_CTX. This function inspects get_config()
// and if downstream_no_tls is true, returns nullptr. Otherwise, only // and if downstream_no_tls is true, returns nullptr. Otherwise, only

View File

@ -57,7 +57,11 @@ using namespace nghttp2;
namespace shrpx { namespace shrpx {
namespace { namespace {
void drop_privileges() { void drop_privileges(
#ifdef HAVE_NEVERBLEED
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
) {
if (getuid() == 0 && get_config()->uid != 0) { if (getuid() == 0 && get_config()->uid != 0) {
if (initgroups(get_config()->user.get(), get_config()->gid) != 0) { if (initgroups(get_config()->user.get(), get_config()->gid) != 0) {
auto error = errno; auto error = errno;
@ -79,6 +83,9 @@ void drop_privileges() {
LOG(FATAL) << "Still have root privileges?"; LOG(FATAL) << "Still have root privileges?";
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifdef HAVE_NEVERBLEED
neverbleed_setuidgid(nb, get_config()->user.get(), 1);
#endif // HAVE_NEVERBLEED
} }
} }
} // namespace } // namespace
@ -359,6 +366,20 @@ void memcached_get_ticket_key_cb(struct ev_loop *loop, ev_timer *w,
} // namespace } // namespace
#ifdef HAVE_NEVERBLEED
namespace {
void nb_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
log_chld(w->rpid, w->rstatus, "neverbleed process");
ev_child_stop(loop, w);
LOG(FATAL) << "neverbleed process exitted; aborting now";
_Exit(EXIT_FAILURE);
}
} // namespace
#endif // HAVE_NEVERBLEED
int worker_process_event_loop(WorkerProcessConfig *wpconf) { int worker_process_event_loop(WorkerProcessConfig *wpconf) {
if (reopen_log_files() != 0) { if (reopen_log_files() != 0) {
LOG(FATAL) << "Failed to open log file"; LOG(FATAL) << "Failed to open log file";
@ -378,6 +399,29 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
make_unique<AcceptHandler>(wpconf->server_fd, &conn_handler)); make_unique<AcceptHandler>(wpconf->server_fd, &conn_handler));
} }
#ifdef HAVE_NEVERBLEED
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf;
{
auto nb = make_unique<neverbleed_t>();
if (neverbleed_init(nb.get(), errbuf.data()) != 0) {
LOG(FATAL) << "neverbleed_init failed: " << errbuf.data();
return -1;
}
LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned";
conn_handler.set_neverbleed(std::move(nb));
}
auto nb = conn_handler.get_neverbleed();
ev_child nb_childev;
ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0);
nb_childev.data = nullptr;
ev_child_start(loop, &nb_childev);
#endif // HAVE_NEVERBLEED
ev_timer renew_ticket_key_timer; ev_timer renew_ticket_key_timer;
if (!get_config()->upstream_no_tls) { if (!get_config()->upstream_no_tls) {
if (get_config()->tls_ticket_key_memcached_host) { if (get_config()->tls_ticket_key_memcached_host) {
@ -458,7 +502,11 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
#endif // !NOTHREADS #endif // !NOTHREADS
} }
drop_privileges(); drop_privileges(
#ifdef HAVE_NEVERBLEED
nb
#endif // HAVE_NEVERBLEED
);
ev_io ipcev; ev_io ipcev;
ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ); ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ);
@ -478,6 +526,12 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
conn_handler.join_worker(); conn_handler.join_worker();
conn_handler.cancel_ocsp_update(); conn_handler.cancel_ocsp_update();
#ifdef HAVE_NEVERBLEED
if (nb && nb->daemon_pid != -1) {
kill(nb->daemon_pid, SIGTERM);
}
#endif // HAVE_NEVERBLEED
return 0; return 0;
} }

View File

@ -30,6 +30,11 @@ libhttp_parser_la_SOURCES = \
http-parser/http_parser.c \ http-parser/http_parser.c \
http-parser/http_parser.h http-parser/http_parser.h
if HAVE_NEVERBLEED
noinst_LTLIBRARIES += libneverbleed.la
libneverbleed_la_SOURCES = neverbleed/neverbleed.c neverbleed/neverbleed.h
endif # HAVE_NEVERBLEED
if HAVE_MRUBY if HAVE_MRUBY
EXTRA_DIST = build_config.rb mruby/* EXTRA_DIST = build_config.rb mruby/*

1
third-party/neverbleed vendored Submodule

@ -0,0 +1 @@
Subproject commit 81eff20bd84b4d0dce2cbbd1a5ad1384d086423b