summaryrefslogtreecommitdiff
path: root/src/http/ngx_http_upstream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/ngx_http_upstream.c')
-rw-r--r--src/http/ngx_http_upstream.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 040bda106..af77e50e7 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -156,6 +156,8 @@ static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
ngx_http_upstream_t *u, ngx_connection_t *c);
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
+static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r,
+ ngx_http_upstream_t *u, ngx_connection_t *c);
#endif
@@ -581,9 +583,16 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
if (u->resolved == NULL) {
uscf = u->conf->upstream;
+#if (NGX_HTTP_SSL)
+ u->ssl_name = uscf->host;
+#endif
} else {
+#if (NGX_HTTP_SSL)
+ u->ssl_name = u->resolved->host;
+#endif
+
if (u->resolved->sockaddr) {
if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
@@ -1355,6 +1364,14 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
c->sendfile = 0;
u->output.sendfile = 0;
+ if (u->conf->ssl_server_name || u->conf->ssl_verify) {
+ if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ }
+
if (u->conf->ssl_session_reuse) {
if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
@@ -1379,6 +1396,7 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
static void
ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
{
+ long rc;
ngx_http_request_t *r;
ngx_http_upstream_t *u;
@@ -1387,6 +1405,24 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
if (c->ssl->handshaked) {
+ if (u->conf->ssl_verify) {
+ rc = SSL_get_verify_result(c->ssl->connection);
+
+ if (rc != X509_V_OK) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "upstream SSL certificate verify error: (%l:%s)",
+ rc, X509_verify_cert_error_string(rc));
+ goto failed;
+ }
+
+ if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "upstream SSL certificate does not match \"%V\"",
+ &u->ssl_name);
+ goto failed;
+ }
+ }
+
if (u->conf->ssl_session_reuse) {
u->peer.save_session(&u->peer, u->peer.data);
}
@@ -1402,6 +1438,8 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
return;
}
+failed:
+
c = r->connection;
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
@@ -1409,6 +1447,97 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
ngx_http_run_posted_requests(c);
}
+
+static ngx_int_t
+ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u,
+ ngx_connection_t *c)
+{
+ u_char *p, *last;
+ ngx_str_t name;
+
+ if (u->conf->ssl_name) {
+ if (ngx_http_complex_value(r, u->conf->ssl_name, &name) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ } else {
+ name = u->ssl_name;
+ }
+
+ if (name.len == 0) {
+ goto done;
+ }
+
+ /*
+ * ssl name here may contain port, notably if derived from $proxy_host
+ * or $http_host; we have to strip it
+ */
+
+ p = name.data;
+ last = name.data + name.len;
+
+ if (*p == '[') {
+ p = ngx_strlchr(p, last, ']');
+
+ if (p == NULL) {
+ p = name.data;
+ }
+ }
+
+ p = ngx_strlchr(p, last, ':');
+
+ if (p != NULL) {
+ name.len = p - name.data;
+ }
+
+ if (!u->conf->ssl_server_name) {
+ goto done;
+ }
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+
+ /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */
+
+ if (name.len == 0 || *name.data == '[') {
+ goto done;
+ }
+
+ if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) {
+ goto done;
+ }
+
+ /*
+ * SSL_set_tlsext_host_name() needs a null-terminated string,
+ * hence we explicitly null-terminate name here
+ */
+
+ p = ngx_pnalloc(r->pool, name.len + 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn(p, name.data, name.len + 1);
+
+ name.data = p;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "upstream SSL server name: \"%s\"", name.data);
+
+ if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) == 0) {
+ ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0,
+ "SSL_set_tlsext_host_name(\"%s\") failed", name.data);
+ return NGX_ERROR;
+ }
+
+#endif
+
+done:
+
+ u->ssl_name = name;
+
+ return NGX_OK;
+}
+
#endif