nghttpx: Enable/disable TLS per frontend address

This change allows user to disable TLS per frontend address using
no-tls keyword in --frontend option.  We removed --frontend-no-tls in
favor of this new feature.
This commit is contained in:
Tatsuhiro Tsujikawa 2016-03-23 23:56:09 +09:00
parent 58b06f32a2
commit eec0b04a33
6 changed files with 89 additions and 27 deletions

View File

@ -432,7 +432,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
});
if (found != std::end(iaddrs)) {
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host;
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
<< (faddr.tls ? ", tls" : "");
(*found).used = true;
faddr.fd = (*found).fd;
faddr.hostport = "localhost";
@ -496,7 +497,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
return -1;
}
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host;
LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
<< (faddr.tls ? ", tls" : "");
faddr.fd = fd;
faddr.hostport = "localhost";
@ -652,7 +654,8 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
faddr.fd = fd;
faddr.hostport = util::make_http_hostport(StringRef{host.data()}, faddr.port);
LOG(NOTICE) << "Listening on " << faddr.hostport;
LOG(NOTICE) << "Listening on " << faddr.hostport
<< (faddr.tls ? ", tls" : "");
return 0;
}
@ -1274,13 +1277,17 @@ Connections:
Default: )" << DEFAULT_DOWNSTREAM_HOST << ","
<< DEFAULT_DOWNSTREAM_PORT << R"(
-f, --frontend=(<HOST>,<PORT>|unix:<PATH>)
-f, --frontend=(<HOST>,<PORT>|unix:<PATH>)[;no-tls]
Set frontend host and port. If <HOST> is '*', it
assumes all addresses including both IPv4 and IPv6.
UNIX domain socket can be specified by prefixing path
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
This option can be used multiple times to listen to
multiple addresses.
Optionally, TLS can be disabled by specifying "no-tls"
keyword. TLS is enabled by default.
Default: *,3000
--backlog=<N>
Set listen backlog size.
@ -1652,8 +1659,6 @@ HTTP/2 and SPDY:
2**<N>-1. For SPDY, the size is 2**<N>.
Default: )" << get_config()->http2.upstream.connection_window_bits
<< R"(
--frontend-no-tls
Disable SSL/TLS on frontend connections.
--backend-http2-window-bits=<N>
Sets the initial window size of HTTP/2 backend
connection to 2**<N>-1.
@ -2040,6 +2045,7 @@ void process_options(
UpstreamAddr addr{};
addr.host = "*";
addr.port = 3000;
addr.tls = true;
addr.family = AF_INET;
listenerconf.addrs.push_back(addr);
addr.family = AF_INET6;
@ -2050,14 +2056,14 @@ void process_options(
upstreamconf.worker_connections = std::numeric_limits<size_t>::max();
}
if (!upstreamconf.no_tls &&
if (ssl::upstream_tls_enabled() &&
(tlsconf.private_key_file.empty() || tlsconf.cert_file.empty())) {
print_usage(std::cerr);
LOG(FATAL) << "Too few arguments";
exit(EXIT_FAILURE);
}
if (!upstreamconf.no_tls && !tlsconf.ocsp.disabled) {
if (ssl::upstream_tls_enabled() && !tlsconf.ocsp.disabled) {
struct stat buf;
if (stat(tlsconf.ocsp.fetch_ocsp_response_file.c_str(), &buf) != 0) {
tlsconf.ocsp.disabled = true;

View File

@ -568,6 +568,40 @@ int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
}
} // namespace
struct UpstreamParams {
bool tls;
};
namespace {
// Parses upstream configuration parameter |src_params|, and stores
// parsed results into |out|. This function returns 0 if it succeeds,
// or -1.
int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
auto last = std::end(src_params);
for (auto first = std::begin(src_params); first != last;) {
auto end = std::find(first, last, ';');
auto param = StringRef{first, end};
if (util::strieq_l("tls", param)) {
out.tls = true;
} else if (util::strieq_l("no-tls", param)) {
out.tls = false;
} else if (!param.empty()) {
LOG(ERROR) << "frontend: " << param << ": unknown keyword";
return -1;
}
if (end == last) {
break;
}
first = end + 1;
}
return 0;
}
} // namespace
struct DownstreamParams {
shrpx_proto proto;
bool tls;
@ -1683,7 +1717,7 @@ int parse_config(const char *opt, const char *optarg,
addr.host = ImmutableString(path, addr_end);
addr.host_unix = true;
} else {
if (split_host_port(host, sizeof(host), &port, &src[0],
if (split_host_port(host, sizeof(host), &port, src.c_str(),
addr_end - std::begin(src)) == -1) {
return -1;
}
@ -1707,12 +1741,24 @@ int parse_config(const char *opt, const char *optarg,
case SHRPX_OPTID_FRONTEND: {
auto &listenerconf = mod_config()->conn.listener;
auto src = StringRef{optarg};
auto addr_end = std::find(std::begin(src), std::end(src), ';');
auto src_params = StringRef{addr_end, std::end(src)};
UpstreamParams params{};
params.tls = true;
if (parse_upstream_params(params, src_params) != 0) {
return -1;
}
UpstreamAddr addr{};
addr.fd = -1;
addr.tls = params.tls;
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
addr.host = ImmutableString(path);
if (util::istarts_with_l(src, SHRPX_UNIX_PATH_PREFIX)) {
auto path = std::begin(src) + str_size(SHRPX_UNIX_PATH_PREFIX);
addr.host = ImmutableString{path, addr_end};
addr.host_unix = true;
listenerconf.addrs.push_back(std::move(addr));
@ -1720,8 +1766,8 @@ int parse_config(const char *opt, const char *optarg,
return 0;
}
if (split_host_port(host, sizeof(host), &port, optarg, strlen(optarg)) ==
-1) {
if (split_host_port(host, sizeof(host), &port, src.c_str(),
addr_end - std::begin(src)) == -1) {
return -1;
}
@ -1920,8 +1966,8 @@ int parse_config(const char *opt, const char *optarg,
return 0;
}
case SHRPX_OPTID_FRONTEND_NO_TLS:
mod_config()->conn.upstream.no_tls = util::strieq(optarg, "yes");
LOG(WARN) << opt << ": deprecated. Use no-tls keyword in "
<< SHRPX_OPT_FRONTEND;
return 0;
case SHRPX_OPTID_BACKEND_NO_TLS:
LOG(WARN) << opt << ": deprecated. backend connection is not encrypted by "

View File

@ -277,6 +277,8 @@ struct UpstreamAddr {
int family;
// true if |host| contains UNIX domain socket path.
bool host_unix;
// true if TLS is enabled.
bool tls;
int fd;
};
@ -558,7 +560,6 @@ struct ConnectionConfig {
RateLimitConfig write;
} ratelimit;
size_t worker_connections;
bool no_tls;
bool accept_proxy_protocol;
} upstream;

View File

@ -800,8 +800,11 @@ ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
}
}
SSL *ssl = nullptr;
if (faddr->tls) {
auto ssl_ctx = worker->get_sv_ssl_ctx();
if (ssl_ctx) {
assert(ssl_ctx);
ssl = create_ssl(ssl_ctx);
if (!ssl) {
return nullptr;
@ -1245,6 +1248,12 @@ bool in_proto_list(const std::vector<std::string> &protos,
return false;
}
bool upstream_tls_enabled() {
const auto &faddrs = get_config()->conn.listener.addrs;
return std::any_of(std::begin(faddrs), std::end(faddrs),
[](const UpstreamAddr &faddr) { return faddr.tls; });
}
SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
CertLookupTree *cert_tree
#ifdef HAVE_NEVERBLEED
@ -1252,7 +1261,7 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
neverbleed_t *nb
#endif // HAVE_NEVERBLEED
) {
if (get_config()->conn.upstream.no_tls) {
if (!upstream_tls_enabled()) {
return nullptr;
}
@ -1346,8 +1355,7 @@ void setup_downstream_http1_alpn(SSL *ssl) {
}
CertLookupTree *create_cert_lookup_tree() {
if (get_config()->conn.upstream.no_tls ||
get_config()->tls.subcerts.empty()) {
if (!upstream_tls_enabled() || get_config()->tls.subcerts.empty()) {
return nullptr;
}
return new ssl::CertLookupTree();

View File

@ -213,6 +213,9 @@ CertLookupTree *create_cert_lookup_tree();
SSL *create_ssl(SSL_CTX *ssl_ctx);
// Returns true if SSL/TLS is enabled on upstream
bool upstream_tls_enabled();
// Returns true if SSL/TLS is enabled on downstream
bool downstream_tls_enabled();

View File

@ -393,10 +393,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
conn_handler.add_acceptor(make_unique<AcceptHandler>(&addr, &conn_handler));
}
auto &upstreamconf = get_config()->conn.upstream;
#ifdef HAVE_NEVERBLEED
if (!upstreamconf.no_tls || ssl::downstream_tls_enabled()) {
if (ssl::upstream_tls_enabled() || ssl::downstream_tls_enabled()) {
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf;
auto nb = make_unique<neverbleed_t>();
if (neverbleed_init(nb.get(), errbuf.data()) != 0) {
@ -423,7 +421,7 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
MemchunkPool mcpool;
ev_timer renew_ticket_key_timer;
if (!upstreamconf.no_tls) {
if (ssl::upstream_tls_enabled()) {
auto &ticketconf = get_config()->tls.ticket;
auto &memcachedconf = ticketconf.memcached;
@ -522,7 +520,7 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
ipcev.data = &conn_handler;
ev_io_start(loop, &ipcev);
if (!upstreamconf.no_tls && !get_config()->tls.ocsp.disabled) {
if (ssl::upstream_tls_enabled() && !get_config()->tls.ocsp.disabled) {
conn_handler.proceed_next_cert_ocsp();
}