nghttpx: SNI based backend server selection

This commit is contained in:
Tatsuhiro Tsujikawa 2017-04-16 23:47:10 +09:00
parent 5e00cf9620
commit c8a5f1e335
4 changed files with 43 additions and 23 deletions

View File

@ -1665,14 +1665,16 @@ Connections:
which only lacks trailing '/' (e.g., path "/foo/"
matches request path "/foo"). If it does not end with
"/", it performs exact match against the request path.
If host is given, it performs exact match against the
request host. If host alone is given, "/" is appended
to it, so that it matches all request paths under the
host (e.g., specifying "nghttp2.org" equals to
"nghttp2.org/"). CONNECT method is treated specially.
It does not have path, and we don't allow empty path.
To workaround this, we assume that CONNECT method has
"/" as path.
If host is given, it performs a match against the
request host. For a request received on the frontend
lister with "sni-fwd" parameter enabled, SNI host is
used instead of a request host. If host alone is given,
"/" is appended to it, so that it matches all request
paths under the host (e.g., specifying "nghttp2.org"
equals to "nghttp2.org/"). CONNECT method is treated
specially. It does not have path, and we don't allow
empty path. To workaround this, we assume that CONNECT
method has "/" as path.
Patterns with host take precedence over patterns with
just path. Then, longer patterns take precedence over
@ -1811,6 +1813,11 @@ Connections:
Optionally, TLS can be disabled by specifying "no-tls"
parameter. TLS is enabled by default.
If "sni-fwd" parameter is used, when performing a match
to select a backend server, SNI host name received from
the client is used instead of the request host. See
--backend option about the pattern match.
To make this frontend as API endpoint, specify "api"
parameter. This is disabled by default. It is
important to limit the access to the API frontend.

View File

@ -979,29 +979,30 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
auto &balloc = downstream->get_block_allocator();
// Fast path. If we have one group, it must be catch-all group.
// proxy mode falls in this case.
if (groups.size() == 1) {
group_idx = 0;
} else if (req.method == HTTP_CONNECT) {
// CONNECT method does not have path. But we requires path in
// host-path mapping. As workaround, we assume that path is "/".
group_idx = match_downstream_addr_group(routerconf, req.authority,
StringRef::from_lit("/"), groups,
catch_all, balloc);
} else {
if (!req.authority.empty()) {
group_idx = match_downstream_addr_group(
routerconf, req.authority, req.path, groups, catch_all, balloc);
StringRef authority;
if (faddr_->sni_fwd) {
authority = sni_;
} else if (!req.authority.empty()) {
authority = req.authority;
} else {
auto h = req.fs.header(http2::HD_HOST);
if (h) {
group_idx = match_downstream_addr_group(routerconf, h->value, req.path,
groups, catch_all, balloc);
} else {
group_idx = match_downstream_addr_group(
routerconf, StringRef{}, req.path, groups, catch_all, balloc);
authority = h->value;
}
}
StringRef path;
// CONNECT method does not have path. But we requires path in
// host-path mapping. As workaround, we assume that path is "/".
if (req.method != HTTP_CONNECT) {
path = req.path;
}
group_idx = match_downstream_addr_group(routerconf, authority, path, groups,
catch_all, balloc);
}
if (LOG_ENABLED(INFO)) {

View File

@ -693,6 +693,7 @@ int parse_memcached_connection_params(MemcachedConnectionParams &out,
struct UpstreamParams {
int alt_mode;
bool tls;
bool sni_fwd;
bool proxyproto;
};
@ -708,6 +709,8 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
if (util::strieq_l("tls", param)) {
out.tls = true;
} else if (util::strieq_l("sni-fwd", param)) {
out.sni_fwd = true;
} else if (util::strieq_l("no-tls", param)) {
out.tls = false;
} else if (util::strieq_l("api", param)) {
@ -2296,9 +2299,15 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return -1;
}
if (params.sni_fwd && !params.tls) {
LOG(ERROR) << "frontend: sni_fwd requires tls";
return -1;
}
UpstreamAddr addr{};
addr.fd = -1;
addr.tls = params.tls;
addr.sni_fwd = params.sni_fwd;
addr.alt_mode = params.alt_mode;
addr.accept_proxy_protocol = params.proxyproto;

View File

@ -404,6 +404,9 @@ struct UpstreamAddr {
bool host_unix;
// true if TLS is enabled.
bool tls;
// true if SNI host should be used as a host when selecting backend
// server.
bool sni_fwd;
// true if client is supposed to send PROXY protocol v1 header.
bool accept_proxy_protocol;
int fd;