nghttpx: Add sni keyword to --backend option

The --backend-tls-sni-field is deprecated in favor of sni keyword.
--backend-tls-sni-field still works, and it overrides all sni keyword
in --backend option.  But it will be removed in the future release.
This commit is contained in:
Tatsuhiro Tsujikawa 2016-04-29 14:42:18 +09:00
parent 99f7e7e2a5
commit fd801864e3
10 changed files with 54 additions and 34 deletions

View File

@ -1263,13 +1263,13 @@ Connections:
Several parameters <PARAM> are accepted after <PATTERN>. Several parameters <PARAM> are accepted after <PATTERN>.
The parameters are delimited by ";". The available The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls", "fall=<N>", and parameters are: "proto=<PROTO>", "tls",
"rise=<N>". The parameter consists of keyword, and "sni=<SNI_HOST>", "fall=<N>", and "rise=<N>". The
optionally followed by "=" and value. For example, the parameter consists of keyword, and optionally followed
parameter "proto=h2" consists of the keyword "proto" and by "=" and value. For example, the parameter "proto=h2"
value "h2". The parameter "tls" consists of the keyword consists of the keyword "proto" and value "h2". The
"tls" without value. Each parameter is described as parameter "tls" consists of the keyword "tls" without
follows. value. Each parameter is described as follows.
The backend application protocol can be specified using The backend application protocol can be specified using
optional "proto" keyword, and in the form of optional "proto" keyword, and in the form of
@ -1284,6 +1284,10 @@ Connections:
TLS can be enabled by specifying optional "tls" keyword. TLS can be enabled by specifying optional "tls" keyword.
TLS is not enabled by default. TLS is not enabled by default.
With "sni=<SNI_HOST>" parameter, it can override the TLS
SNI field value with given <SNI_HOST>. This will
default to the backend <HOST> name
The feature to detect whether backend is online or The feature to detect whether backend is online or
offline can be enabled using optional "fall" and "rise" offline can be enabled using optional "fall" and "rise"
parameters. Using "fall=<N>" parameter, if nghttpx parameters. Using "fall=<N>" parameter, if nghttpx
@ -1503,9 +1507,6 @@ SSL/TLS:
indicated by client using TLS SNI extension. This indicated by client using TLS SNI extension. This
option can be used multiple times. To make OCSP option can be used multiple times. To make OCSP
stapling work, <CERTPATH> must be absolute path. stapling work, <CERTPATH> must be absolute path.
--backend-tls-sni-field=<HOST>
Explicitly set the content of the TLS SNI extension.
This will default to the backend HOST name.
--dh-param-file=<PATH> --dh-param-file=<PATH>
Path to file that contains DH parameters in PEM format. Path to file that contains DH parameters in PEM format.
Without this option, DHE cipher suites are not Without this option, DHE cipher suites are not
@ -2168,6 +2169,17 @@ void process_options(int argc, char **argv,
} }
} }
// backward compatibility: override all SNI fields with the option
// value --backend-tls-sni-field
if (!tlsconf.backend_sni_name.empty()) {
auto &sni = tlsconf.backend_sni_name;
for (auto &addr_group : addr_groups) {
for (auto &addr : addr_group.addrs) {
addr.sni = sni;
}
}
}
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
LOG(INFO) << "Resolving backend address"; LOG(INFO) << "Resolving backend address";
} }

View File

@ -644,6 +644,7 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
} // namespace } // namespace
struct DownstreamParams { struct DownstreamParams {
StringRef sni;
size_t fall; size_t fall;
size_t rise; size_t rise;
shrpx_proto proto; shrpx_proto proto;
@ -709,6 +710,8 @@ int parse_downstream_params(DownstreamParams &out,
out.tls = true; out.tls = true;
} else if (util::strieq_l("no-tls", param)) { } else if (util::strieq_l("no-tls", param)) {
out.tls = false; out.tls = false;
} else if (util::istarts_with_l(param, "sni=")) {
out.sni = StringRef{first + str_size("sni="), end};
} else if (!param.empty()) { } else if (!param.empty()) {
LOG(ERROR) << "backend: " << param << ": unknown keyword"; LOG(ERROR) << "backend: " << param << ": unknown keyword";
return -1; return -1;
@ -750,6 +753,7 @@ int parse_mapping(DownstreamAddrConfig addr, const StringRef &src_pattern,
addr.fall = params.fall; addr.fall = params.fall;
addr.rise = params.rise; addr.rise = params.rise;
addr.sni = ImmutableString{std::begin(params.sni), std::end(params.sni)};
for (const auto &raw_pattern : mapping) { for (const auto &raw_pattern : mapping) {
auto done = false; auto done = false;
@ -2050,6 +2054,9 @@ int parse_config(const StringRef &opt, const StringRef &optarg,
"default. See also " << SHRPX_OPT_BACKEND_TLS; "default. See also " << SHRPX_OPT_BACKEND_TLS;
return 0; return 0;
case SHRPX_OPTID_BACKEND_TLS_SNI_FIELD: case SHRPX_OPTID_BACKEND_TLS_SNI_FIELD:
LOG(WARN) << opt << ": deprecated. Use sni keyword in --backend option. "
"For now, all sni values of all backends are "
"overridden by the given value " << optarg;
mod_config()->tls.backend_sni_name = optarg.str(); mod_config()->tls.backend_sni_name = optarg.str();
return 0; return 0;

View File

@ -327,6 +327,8 @@ struct DownstreamAddrConfig {
// <HOST>:<PORT>. This does not treat 80 and 443 specially. If // <HOST>:<PORT>. This does not treat 80 and 443 specially. If
// |host_unix| is true, this is "localhost". // |host_unix| is true, this is "localhost".
ImmutableString hostport; ImmutableString hostport;
// hostname sent as SNI field
ImmutableString sni;
size_t fall; size_t fall;
size_t rise; size_t rise;
// backend port. 0 if |host_unix| is true. // backend port. 0 if |host_unix| is true.

View File

@ -360,9 +360,8 @@ int Http2Session::initiate_connection() {
conn_.set_ssl(ssl); conn_.set_ssl(ssl);
auto sni_name = !get_config()->tls.backend_sni_name.empty() auto sni_name =
? StringRef(get_config()->tls.backend_sni_name) addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
: StringRef(addr_->host);
if (!util::numeric_host(sni_name.c_str())) { if (!util::numeric_host(sni_name.c_str())) {
// TLS extensions: SNI. There is no documentation about the return // TLS extensions: SNI. There is no documentation about the return

View File

@ -239,9 +239,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
addr_ = &addr; addr_ = &addr;
if (ssl_ctx_) { if (ssl_ctx_) {
auto sni_name = !get_config()->tls.backend_sni_name.empty() auto sni_name =
? StringRef(get_config()->tls.backend_sni_name) addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
: StringRef(addr_->host);
if (!util::numeric_host(sni_name.c_str())) { if (!util::numeric_host(sni_name.c_str())) {
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str()); SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
} }

View File

@ -192,9 +192,8 @@ int LiveCheck::initiate_connection() {
} }
if (ssl_ctx_) { if (ssl_ctx_) {
auto sni_name = !get_config()->tls.backend_sni_name.empty() auto sni_name =
? StringRef(get_config()->tls.backend_sni_name) addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
: StringRef(addr_->host);
if (!util::numeric_host(sni_name.c_str())) { if (!util::numeric_host(sni_name.c_str())) {
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str()); SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
} }

View File

@ -1064,10 +1064,8 @@ int check_cert(SSL *ssl, const Address *addr, const StringRef &host) {
} }
int check_cert(SSL *ssl, const DownstreamAddr *addr) { int check_cert(SSL *ssl, const DownstreamAddr *addr) {
auto &backend_sni_name = get_config()->tls.backend_sni_name; auto hostname =
addr->sni.empty() ? StringRef{addr->host} : StringRef{addr->sni};
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
: StringRef(addr->host);
return check_cert(ssl, &addr->addr, hostname); return check_cert(ssl, &addr->addr, hostname);
} }

View File

@ -83,7 +83,7 @@ bool match_shared_downstream_addr(
auto &b = rhs->addrs[i]; auto &b = rhs->addrs[i];
if (a.host == b.host && a.port == b.port && a.host_unix == b.host_unix && if (a.host == b.host && a.port == b.port && a.host_unix == b.host_unix &&
a.fall == b.fall && a.rise == b.rise) { a.sni == b.sni && a.fall == b.fall && a.rise == b.rise) {
break; break;
} }
} }
@ -159,6 +159,7 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
dst_addr.hostport = src_addr.hostport; dst_addr.hostport = src_addr.hostport;
dst_addr.port = src_addr.port; dst_addr.port = src_addr.port;
dst_addr.host_unix = src_addr.host_unix; dst_addr.host_unix = src_addr.host_unix;
dst_addr.sni = src_addr.sni;
dst_addr.fall = src_addr.fall; dst_addr.fall = src_addr.fall;
dst_addr.rise = src_addr.rise; dst_addr.rise = src_addr.rise;

View File

@ -80,6 +80,9 @@ struct DownstreamAddr {
// true if |host| contains UNIX domain socket path. // true if |host| contains UNIX domain socket path.
bool host_unix; bool host_unix;
// sni field to send remote server if TLS is enabled.
ImmutableString sni;
std::unique_ptr<ConnectBlocker> connect_blocker; std::unique_ptr<ConnectBlocker> connect_blocker;
std::unique_ptr<LiveCheck> live_check; std::unique_ptr<LiveCheck> live_check;
size_t fall; size_t fall;

View File

@ -254,15 +254,15 @@ public:
ImmutableString() : len(0), base("") {} ImmutableString() : len(0), base("") {}
ImmutableString(const char *s, size_t slen) ImmutableString(const char *s, size_t slen)
: len(slen), base(copystr(s, len)) {} : len(slen), base(copystr(s, s + len)) {}
ImmutableString(const char *s) : len(strlen(s)), base(copystr(s, len)) {} ImmutableString(const char *s) : len(strlen(s)), base(copystr(s, s + len)) {}
ImmutableString(const std::string &s) ImmutableString(const std::string &s)
: len(s.size()), base(copystr(s.c_str(), s.size())) {} : len(s.size()), base(copystr(std::begin(s), std::end(s))) {}
template <typename InputIt> template <typename InputIt>
ImmutableString(InputIt first, InputIt last) ImmutableString(InputIt first, InputIt last)
: len(std::distance(first, last)), base(copystr(first, len)) {} : len(std::distance(first, last)), base(copystr(first, last)) {}
ImmutableString(const ImmutableString &other) ImmutableString(const ImmutableString &other)
: len(other.len), base(copystr(other.base, other.len)) {} : len(other.len), base(copystr(std::begin(other), std::end(other))) {}
ImmutableString(ImmutableString &&other) noexcept : len(other.len), ImmutableString(ImmutableString &&other) noexcept : len(other.len),
base(other.base) { base(other.base) {
other.len = 0; other.len = 0;
@ -282,7 +282,7 @@ public:
delete[] base; delete[] base;
} }
len = other.len; len = other.len;
base = copystr(other.base, other.len); base = copystr(std::begin(other), std::end(other));
return *this; return *this;
} }
ImmutableString &operator=(ImmutableString &&other) noexcept { ImmutableString &operator=(ImmutableString &&other) noexcept {
@ -325,12 +325,12 @@ public:
const_reference operator[](size_type pos) const { return *(base + pos); } const_reference operator[](size_type pos) const { return *(base + pos); }
private: private:
const char *copystr(const char *s, size_t slen) { template <typename InputIt> const char *copystr(InputIt first, InputIt last) {
if (slen == 0) { if (first == last) {
return ""; return "";
} }
auto res = new char[slen + 1]; auto res = new char[std::distance(first, last) + 1];
*std::copy_n(s, slen, res) = '\0'; *std::copy(first, last, res) = '\0';
return res; return res;
} }