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>.
The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls", "fall=<N>", and
"rise=<N>". The parameter consists of keyword, and
optionally followed by "=" and value. For example, the
parameter "proto=h2" consists of the keyword "proto" and
value "h2". The parameter "tls" consists of the keyword
"tls" without value. Each parameter is described as
follows.
parameters are: "proto=<PROTO>", "tls",
"sni=<SNI_HOST>", "fall=<N>", and "rise=<N>". The
parameter consists of keyword, and optionally followed
by "=" and value. For example, the parameter "proto=h2"
consists of the keyword "proto" and value "h2". The
parameter "tls" consists of the keyword "tls" without
value. Each parameter is described as follows.
The backend application protocol can be specified using
optional "proto" keyword, and in the form of
@ -1284,6 +1284,10 @@ Connections:
TLS can be enabled by specifying optional "tls" keyword.
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
offline can be enabled using optional "fall" and "rise"
parameters. Using "fall=<N>" parameter, if nghttpx
@ -1503,9 +1507,6 @@ SSL/TLS:
indicated by client using TLS SNI extension. This
option can be used multiple times. To make OCSP
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>
Path to file that contains DH parameters in PEM format.
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)) {
LOG(INFO) << "Resolving backend address";
}

View File

@ -644,6 +644,7 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
} // namespace
struct DownstreamParams {
StringRef sni;
size_t fall;
size_t rise;
shrpx_proto proto;
@ -709,6 +710,8 @@ int parse_downstream_params(DownstreamParams &out,
out.tls = true;
} else if (util::strieq_l("no-tls", param)) {
out.tls = false;
} else if (util::istarts_with_l(param, "sni=")) {
out.sni = StringRef{first + str_size("sni="), end};
} else if (!param.empty()) {
LOG(ERROR) << "backend: " << param << ": unknown keyword";
return -1;
@ -750,6 +753,7 @@ int parse_mapping(DownstreamAddrConfig addr, const StringRef &src_pattern,
addr.fall = params.fall;
addr.rise = params.rise;
addr.sni = ImmutableString{std::begin(params.sni), std::end(params.sni)};
for (const auto &raw_pattern : mapping) {
auto done = false;
@ -2050,6 +2054,9 @@ int parse_config(const StringRef &opt, const StringRef &optarg,
"default. See also " << SHRPX_OPT_BACKEND_TLS;
return 0;
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();
return 0;

View File

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

View File

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

View File

@ -239,9 +239,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
addr_ = &addr;
if (ssl_ctx_) {
auto sni_name = !get_config()->tls.backend_sni_name.empty()
? StringRef(get_config()->tls.backend_sni_name)
: StringRef(addr_->host);
auto sni_name =
addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
if (!util::numeric_host(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_) {
auto sni_name = !get_config()->tls.backend_sni_name.empty()
? StringRef(get_config()->tls.backend_sni_name)
: StringRef(addr_->host);
auto sni_name =
addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
if (!util::numeric_host(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) {
auto &backend_sni_name = get_config()->tls.backend_sni_name;
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
: StringRef(addr->host);
auto hostname =
addr->sni.empty() ? StringRef{addr->host} : StringRef{addr->sni};
return check_cert(ssl, &addr->addr, hostname);
}

View File

@ -83,7 +83,7 @@ bool match_shared_downstream_addr(
auto &b = rhs->addrs[i];
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;
}
}
@ -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.port = src_addr.port;
dst_addr.host_unix = src_addr.host_unix;
dst_addr.sni = src_addr.sni;
dst_addr.fall = src_addr.fall;
dst_addr.rise = src_addr.rise;

View File

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

View File

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