Merge branch 'nginx' (nginx-1.15.9). Change-Id: I95518364d57aef7427d33ea61a5c6f48545e402b Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags index 0f43222..1228a94 100644 --- a/.hgtags +++ b/.hgtags
@@ -434,3 +434,4 @@ 2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6 051a039ce1c7e09144de4a4846669ec7116cecea release-1.15.7 ee551e3f6dba336c0d875e266d7d55385f379b42 release-1.15.8 +d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9
diff --git a/BUILD b/BUILD index b1f4c83..a830a04 100644 --- a/BUILD +++ b/BUILD
@@ -1,4 +1,4 @@ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -1537,5 +1537,5 @@ preinst = "@nginx_pkgoss//:debian_preinst", prerm = "@nginx_pkgoss//:debian_prerm", section = "httpd", - version = "1.15.8", + version = "1.15.9", )
diff --git a/LICENSE b/LICENSE index e8d4bc5..7abb171 100644 --- a/LICENSE +++ b/LICENSE
@@ -1,7 +1,7 @@ /* - * Copyright (C) 2002-2018 Igor Sysoev - * Copyright (C) 2011-2018 Nginx, Inc. - * Copyright (C) 2015-2018 Google Inc. + * Copyright (C) 2002-2019 Igor Sysoev + * Copyright (C) 2011-2019 Nginx, Inc. + * Copyright (C) 2015-2019 Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md index 8ab737b..09da59b 100644 --- a/README.md +++ b/README.md
@@ -21,9 +21,9 @@ ## License - Copyright (C) 2002-2018 Igor Sysoev - Copyright (C) 2011-2018 Nginx, Inc. - Copyright (C) 2015-2018 Google Inc. + Copyright (C) 2002-2019 Igor Sysoev + Copyright (C) 2011-2019 Nginx, Inc. + Copyright (C) 2015-2019 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without
diff --git a/WORKSPACE b/WORKSPACE index abb72d5..513aac5 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -1,4 +1,4 @@ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without
diff --git a/auto/make b/auto/make index 7ddd100..34c40cd 100644 --- a/auto/make +++ b/auto/make
@@ -229,7 +229,7 @@ binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext $NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer - \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link + \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc $ngx_long_end
diff --git a/auto/os/win32 b/auto/os/win32 index a0c9862..3b6e2e8 100644 --- a/auto/os/win32 +++ b/auto/os/win32
@@ -11,6 +11,7 @@ OS_CONFIG="$WIN32_CONFIG" NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS +POLL_SRCS=$WIN32_POLL_SRCS ngx_pic_opt= ngx_binext=".exe" @@ -31,12 +32,7 @@ esac EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE" -EVENT_FOUND=YES - -if [ $EVENT_SELECT = NO ]; then - CORE_SRCS="$CORE_SRCS $SELECT_SRCS" - EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE" -fi +#EVENT_FOUND=YES have=NGX_HAVE_INET6 . $NGX_AUTO/have
diff --git a/auto/sources b/auto/sources index 9f9571e..8610764 100644 --- a/auto/sources +++ b/auto/sources
@@ -105,6 +105,7 @@ POLL_MODULE=ngx_poll_module POLL_SRCS=src/event/modules/ngx_poll_module.c +WIN32_POLL_SRCS=src/event/modules/ngx_win32_poll_module.c KQUEUE_MODULE=ngx_kqueue_module KQUEUE_SRCS=src/event/modules/ngx_kqueue_module.c
diff --git a/build.bzl b/build.bzl index 73549af..5f00eb8 100644 --- a/build.bzl +++ b/build.bzl
@@ -1,4 +1,4 @@ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -54,7 +54,7 @@ ] _NGX_BROTLI_BUILD_FILE = """ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -136,7 +136,7 @@ """ _PCRE_BUILD_FILE = """ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -268,7 +268,7 @@ """ _PKGOSS_BUILD_FILE = """ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -544,7 +544,7 @@ """ _ZLIB_BUILD_FILE = """ -# Copyright (C) 2015-2018 Google Inc. +# Copyright (C) 2015-2019 Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -673,9 +673,9 @@ name = "nginx_pkgoss", build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) + _PKGOSS_BUILD_FILE_TAIL, - commit = "2456bf617acaa11b06c11481082797909b300f45", # nginx-1.15.8 + commit = "894beef672e913605c6b93be022933c9ca22cd7b", # nginx-1.15.9 remote = "https://nginx.googlesource.com/nginx-pkgoss", - shallow_since = "1545733310 +0300", + shallow_since = "1551190491 +0300", ) def nginx_repositories_zlib(bind):
diff --git a/docs/text/LICENSE b/docs/text/LICENSE index 9401174..c63e0ba 100644 --- a/docs/text/LICENSE +++ b/docs/text/LICENSE
@@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2018 Igor Sysoev - * Copyright (C) 2011-2018 Nginx, Inc. + * Copyright (C) 2002-2019 Igor Sysoev + * Copyright (C) 2011-2019 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 4c471d8..e7dcf95 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,59 @@ <change_log title="nginx"> +<changes ver="1.15.9" date="2019-02-26"> + +<change type="feature"> +<para lang="ru"> +директивы ssl_certificate и ssl_certificate_key +поддерживают переменные. +</para> +<para lang="en"> +variables support +in the "ssl_certificate" and "ssl_certificate_key" directives. +</para> +</change> + +<change type="feature"> +<para lang="ru"> +метод poll теперь доступен на Windows +при использовании Windows Vista и новее. +</para> +<para lang="en"> +the "poll" method is now available on Windows +when using Windows Vista or newer. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +если при использовании метода select на Windows +происходила ошибка при установлении соединения с бэкендом, +nginx ожидал истечения таймаута на установление соединения. +</para> +<para lang="en"> +if the "select" method was used on Windows +and an error occurred while establishing a backend connection, +nginx waited for the connection establishment timeout to expire. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +директивы proxy_upload_rate и proxy_download_rate +в модуле stream +работали некорректно при проксировании UDP-пакетов. +</para> +<para lang="en"> +the "proxy_upload_rate" and "proxy_download_rate" directives +in the stream module +worked incorrectly when proxying UDP datagrams. +</para> +</change> + +</changes> + + <changes ver="1.15.8" date="2018-12-25"> <change type="feature">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile index d68ceca..bf91174 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@ CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.0.2q +OPENSSL = openssl-1.1.1b ZLIB = zlib-1.2.11 PCRE = pcre-8.42 @@ -65,7 +65,6 @@ --with-cc-opt=-DFD_SETSIZE=1024 \ --with-pcre=$(OBJS)/lib/$(PCRE) \ --with-zlib=$(OBJS)/lib/$(ZLIB) \ - --with-select_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_addition_module \
diff --git a/src/core/nginx.h b/src/core/nginx.h index b130fae..2795d87 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h
@@ -13,8 +13,8 @@ #define NGINX_NAME "nginx" #endif -#define nginx_version 1015008 -#define NGINX_VERSION "1.15.8" +#define nginx_version 1015009 +#define NGINX_VERSION "1.15.9" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION #ifdef NGX_BUILD
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index e92cd33..6d1629e 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c
@@ -310,7 +310,7 @@ goto failed; } - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", rv); goto failed; }
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 4023870..b8577ce 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c
@@ -635,10 +635,9 @@ goto fail; } - n = ((u_char *) p - pool->start) >> ngx_pagesize_shift; size = slab & ~NGX_SLAB_PAGE_START; - ngx_slab_free_pages(pool, &pool->pages[n], size); + ngx_slab_free_pages(pool, page, size); ngx_slab_junk(p, size << ngx_pagesize_shift);
diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c index 28c3c92..061c996 100644 --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c
@@ -250,9 +250,7 @@ ngx_memzero(&sev, sizeof(struct sigevent)); sev.sigev_notify = SIGEV_PORT; -#if !(NGX_TEST_BUILD_EVENTPORT) sev.sigev_value.sival_ptr = &pn; -#endif if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c index 83e5f8d..a12c112 100644 --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c
@@ -86,7 +86,7 @@ } if (event_list) { - ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents); + ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents); ngx_free(event_list); }
diff --git a/src/event/modules/ngx_win32_poll_module.c b/src/event/modules/ngx_win32_poll_module.c new file mode 100644 index 0000000..9fe867f --- /dev/null +++ b/src/event/modules/ngx_win32_poll_module.c
@@ -0,0 +1,435 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer); +static void ngx_poll_done(ngx_cycle_t *cycle); +static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); +static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); + + +static struct pollfd *event_list; +static ngx_connection_t **event_index; +static ngx_uint_t nevents; + + +static ngx_str_t poll_name = ngx_string("poll"); + +static ngx_event_module_t ngx_poll_module_ctx = { + &poll_name, + NULL, /* create configuration */ + ngx_poll_init_conf, /* init configuration */ + + { + ngx_poll_add_event, /* add an event */ + ngx_poll_del_event, /* delete an event */ + ngx_poll_add_event, /* enable an event */ + ngx_poll_del_event, /* disable an event */ + NULL, /* add an connection */ + NULL, /* delete an connection */ + NULL, /* trigger a notify */ + ngx_poll_process_events, /* process the events */ + ngx_poll_init, /* init the events */ + ngx_poll_done /* done the events */ + } + +}; + +ngx_module_t ngx_poll_module = { + NGX_MODULE_V1, + &ngx_poll_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_EVENT_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + + +static ngx_int_t +ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer) +{ + struct pollfd *list; + ngx_connection_t **index; + + if (event_list == NULL) { + nevents = 0; + } + + if (ngx_process >= NGX_PROCESS_WORKER + || cycle->old_cycle == NULL + || cycle->old_cycle->connection_n < cycle->connection_n) + { + list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, + cycle->log); + if (list == NULL) { + return NGX_ERROR; + } + + if (event_list) { + ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents); + ngx_free(event_list); + } + + event_list = list; + + index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n, + cycle->log); + if (index == NULL) { + return NGX_ERROR; + } + + if (event_index) { + ngx_memcpy(index, event_index, + sizeof(ngx_connection_t *) * nevents); + ngx_free(event_index); + } + + event_index = index; + } + + ngx_io = ngx_os_io; + + ngx_event_actions = ngx_poll_module_ctx.actions; + + ngx_event_flags = NGX_USE_LEVEL_EVENT; + + return NGX_OK; +} + + +static void +ngx_poll_done(ngx_cycle_t *cycle) +{ + ngx_free(event_list); + ngx_free(event_index); + + event_list = NULL; + event_index = NULL; +} + + +static ngx_int_t +ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 1; + + if (ev->index != NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "poll event fd:%d ev:%i is already set", c->fd, event); + return NGX_OK; + } + + if (event == NGX_READ_EVENT) { + e = c->write; +#if (NGX_READ_EVENT != POLLIN) + event = POLLIN; +#endif + + } else { + e = c->read; +#if (NGX_WRITE_EVENT != POLLOUT) + event = POLLOUT; +#endif + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll add event: fd:%d ev:%i", c->fd, event); + + if (e == NULL || e->index == NGX_INVALID_INDEX) { + + event_list[nevents].fd = c->fd; + event_list[nevents].events = (short) event; + event_list[nevents].revents = 0; + + event_index[nevents] = c; + + ev->index = nevents; + nevents++; + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll add index: %i", e->index); + + event_list[e->index].events |= (short) event; + ev->index = e->index; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 0; + + if (ev->index == NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "poll event fd:%d ev:%i is already deleted", + c->fd, event); + return NGX_OK; + } + + if (event == NGX_READ_EVENT) { + e = c->write; +#if (NGX_READ_EVENT != POLLIN) + event = POLLIN; +#endif + + } else { + e = c->read; +#if (NGX_WRITE_EVENT != POLLOUT) + event = POLLOUT; +#endif + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll del event: fd:%d ev:%i", c->fd, event); + + if (e == NULL || e->index == NGX_INVALID_INDEX) { + nevents--; + + if (ev->index < nevents) { + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "index: copy event %ui to %i", nevents, ev->index); + + event_list[ev->index] = event_list[nevents]; + event_index[ev->index] = event_index[nevents]; + + c = event_index[ev->index]; + + if (c->fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "unexpected last event"); + + } else { + if (c->read->index == nevents) { + c->read->index = ev->index; + } + + if (c->write->index == nevents) { + c->write->index = ev->index; + } + } + } + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "poll del index: %i", e->index); + + event_list[e->index].events &= (short) ~event; + } + + ev->index = NGX_INVALID_INDEX; + + return NGX_OK; +} + + +static ngx_int_t +ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) +{ + int ready, revents; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev; + ngx_queue_t *queue; + ngx_connection_t *c; + + /* NGX_TIMER_INFINITE == INFTIM */ + +#if (NGX_DEBUG0) + if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { + for (i = 0; i < nevents; i++) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd", + i, event_list[i].fd, event_list[i].events); + } + } +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer); + + ready = WSAPoll(event_list, (u_int) nevents, (int) timer); + + err = (ready == -1) ? ngx_errno : 0; + + if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { + ngx_time_update(); + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll ready %d of %ui", ready, nevents); + + if (err) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed"); + return NGX_ERROR; + } + + if (ready == 0) { + if (timer != NGX_TIMER_INFINITE) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "WSAPoll() returned no events without timeout"); + return NGX_ERROR; + } + + for (i = 0; i < nevents && ready; i++) { + + revents = event_list[i].revents; + +#if 1 + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", + i, event_list[i].fd, event_list[i].events, revents); +#else + if (revents) { + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "poll: %ui: fd:%d ev:%04Xd rev:%04Xd", + i, event_list[i].fd, event_list[i].events, revents); + } +#endif + + if (revents & POLLNVAL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "poll() error fd:%d ev:%04Xd rev:%04Xd", + event_list[i].fd, event_list[i].events, revents); + } + + if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "strange poll() events fd:%d ev:%04Xd rev:%04Xd", + event_list[i].fd, event_list[i].events, revents); + } + + if (event_list[i].fd == (ngx_socket_t) -1) { + /* + * the disabled event, a workaround for our possible bug, + * see the comment below + */ + continue; + } + + c = event_index[i]; + + if (c->fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event"); + + /* + * it is certainly our fault and it should be investigated, + * in the meantime we disable this event to avoid a CPU spinning + */ + + if (i == nevents - 1) { + nevents--; + } else { + event_list[i].fd = (ngx_socket_t) -1; + } + + continue; + } + + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + + /* + * if the error events were returned, add POLLIN and POLLOUT + * to handle the events at least in one active handler + */ + + revents |= POLLIN|POLLOUT; + } + + found = 0; + + if ((revents & POLLIN) && c->read->active) { + found = 1; + + ev = c->read; + ev->ready = 1; + + queue = ev->accept ? &ngx_posted_accept_events + : &ngx_posted_events; + + ngx_post_event(ev, queue); + } + + if ((revents & POLLOUT) && c->write->active) { + found = 1; + + ev = c->write; + ev->ready = 1; + + ngx_post_event(ev, &ngx_posted_events); + } + + if (found) { + ready--; + continue; + } + } + + if (ready != 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events"); + } + + return NGX_OK; +} + + +static char * +ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_event_conf_t *ecf; + + ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); + + if (ecf->use != ngx_poll_module.ctx_index) { + return NGX_CONF_OK; + } + +#if (NGX_LOAD_WSAPOLL) + + if (!ngx_have_wsapoll) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "poll is not available on this platform"); + return NGX_CONF_ERROR; + } + +#endif + + return NGX_CONF_OK; +}
diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c index ba98f07..c464805 100644 --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c
@@ -26,6 +26,7 @@ static fd_set master_write_fd_set; static fd_set work_read_fd_set; static fd_set work_write_fd_set; +static fd_set work_except_fd_set; static ngx_uint_t max_read; static ngx_uint_t max_write; @@ -253,9 +254,11 @@ work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; + work_except_fd_set = master_write_fd_set; if (max_read || max_write) { - ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + ready = select(0, &work_read_fd_set, &work_write_fd_set, + &work_except_fd_set, tp); } else { @@ -308,14 +311,20 @@ if (ev->write) { if (FD_ISSET(c->fd, &work_write_fd_set)) { - found = 1; + found++; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select write %d", c->fd); } + if (FD_ISSET(c->fd, &work_except_fd_set)) { + found++; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select except %d", c->fd); + } + } else { if (FD_ISSET(c->fd, &work_read_fd_set)) { - found = 1; + found++; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select read %d", c->fd); } @@ -329,7 +338,7 @@ ngx_post_event(ev, queue); - nready++; + nready += found; } }
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 7253ebb..d3b2378 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h
@@ -63,6 +63,7 @@ unsigned cached:1; unsigned transparent:1; unsigned so_keepalive:1; + unsigned down:1; /* ngx_connection_log_error_e */ unsigned log_error:2;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 958483d..b42b145 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c
@@ -18,6 +18,10 @@ } ngx_openssl_conf_t; +static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, + ngx_str_t *cert, STACK_OF(X509) **chain); +static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, + ngx_str_t *key, ngx_array_t *passwords); static int ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); @@ -50,7 +54,7 @@ static void ngx_ssl_clear_error(ngx_log_t *log); static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl, - ngx_str_t *sess_ctx); + ngx_str_t *sess_ctx, ngx_array_t *certificates); static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess); static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, @@ -68,6 +72,7 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); +static void ngx_ssl_session_ticket_keys_cleanup(void *data); #endif #ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT @@ -406,16 +411,209 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) { - BIO *bio; - X509 *x509; - u_long n; - ngx_str_t *pwd; - ngx_uint_t tries; + char *err; + X509 *x509; + EVP_PKEY *pkey; + STACK_OF(X509) *chain; - if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { + x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain); + if (x509 == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "cannot load certificate \"%s\": %s", + cert->data, err); + } + return NGX_ERROR; } + if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_certificate(\"%s\") failed", cert->data); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index, + SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index)) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + /* + * Note that x509 is not freed here, but will be instead freed in + * ngx_ssl_cleanup_ctx(). This is because we need to preserve all + * certificates to be able to iterate all of them through exdata + * (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index), + * while OpenSSL can free a certificate if it is replaced with another + * certificate of the same type. + */ + +#ifdef SSL_CTX_set0_chain + + if (SSL_CTX_set0_chain(ssl->ctx, chain) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set0_chain(\"%s\") failed", cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + +#else + { + int n; + + /* SSL_CTX_set0_chain() is only available in OpenSSL 1.0.2+ */ + + n = sk_X509_num(chain); + + while (n--) { + x509 = sk_X509_shift(chain); + + if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_add_extra_chain_cert(\"%s\") failed", + cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + } + + sk_X509_free(chain); + } +#endif + + pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords); + if (pkey == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "cannot load certificate key \"%s\": %s", + key->data, err); + } + + return NGX_ERROR; + } + + if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; +} + + +ngx_int_t +ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords) +{ + char *err; + X509 *x509; + EVP_PKEY *pkey; + STACK_OF(X509) *chain; + + x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain); + if (x509 == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "cannot load certificate \"%s\": %s", + cert->data, err); + } + + return NGX_ERROR; + } + + if (SSL_use_certificate(c->ssl->connection, x509) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_use_certificate(\"%s\") failed", cert->data); + X509_free(x509); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + + X509_free(x509); + +#ifdef SSL_set0_chain + + /* + * SSL_set0_chain() is only available in OpenSSL 1.0.2+, + * but this function is only called via certificate callback, + * which is only available in OpenSSL 1.0.2+ as well + */ + + if (SSL_set0_chain(c->ssl->connection, chain) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_set0_chain(\"%s\") failed", cert->data); + sk_X509_pop_free(chain, X509_free); + return NGX_ERROR; + } + +#endif + + pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords); + if (pkey == NULL) { + if (err != NULL) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "cannot load certificate key \"%s\": %s", + key->data, err); + } + + return NGX_ERROR; + } + + if (SSL_use_PrivateKey(c->ssl->connection, pkey) == 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_use_PrivateKey(\"%s\") failed", key->data); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; +} + + +static X509 * +ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert, + STACK_OF(X509) **chain) +{ + BIO *bio; + X509 *x509, *temp; + u_long n; + + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert) + != NGX_OK) + { + *err = NULL; + return NULL; + } + /* * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't * allow to access certificate later from SSL_CTX, so we reimplement @@ -424,62 +622,33 @@ bio = BIO_new_file((char *) cert->data, "r"); if (bio == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "BIO_new_file(\"%s\") failed", cert->data); - return NGX_ERROR; + *err = "BIO_new_file() failed"; + return NULL; } + /* certificate itself */ + x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (x509 == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data); + *err = "PEM_read_bio_X509_AUX() failed"; BIO_free(bio); - return NGX_ERROR; + return NULL; } - if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_certificate(\"%s\") failed", cert->data); + /* rest of the chain */ + + *chain = sk_X509_new_null(); + if (*chain == NULL) { + *err = "sk_X509_new_null() failed"; + BIO_free(bio); X509_free(x509); - BIO_free(bio); - return NGX_ERROR; + return NULL; } - if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); - X509_free(x509); - BIO_free(bio); - return NGX_ERROR; - } - - if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index, - SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index)) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed"); - X509_free(x509); - BIO_free(bio); - return NGX_ERROR; - } - - if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) - == 0) - { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_set_ex_data() failed"); - X509_free(x509); - BIO_free(bio); - return NGX_ERROR; - } - - /* read rest of the chain */ - for ( ;; ) { - x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (x509 == NULL) { + temp = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (temp == NULL) { n = ERR_peek_last_error(); if (ERR_GET_LIB(n) == ERR_LIB_PEM @@ -492,43 +661,38 @@ /* some real error */ - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509(\"%s\") failed", cert->data); + *err = "PEM_read_bio_X509() failed"; BIO_free(bio); - return NGX_ERROR; - } - -#ifdef SSL_CTRL_CHAIN_CERT - - /* - * SSL_CTX_add0_chain_cert() is needed to add chain to - * a particular certificate when multiple certificates are used; - * only available in OpenSSL 1.0.2+ - */ - - if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_add0_chain_cert(\"%s\") failed", - cert->data); X509_free(x509); - BIO_free(bio); - return NGX_ERROR; + sk_X509_pop_free(*chain, X509_free); + return NULL; } -#else - if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_add_extra_chain_cert(\"%s\") failed", - cert->data); - X509_free(x509); + if (sk_X509_push(*chain, temp) == 0) { + *err = "sk_X509_push() failed"; BIO_free(bio); - return NGX_ERROR; + X509_free(x509); + sk_X509_pop_free(*chain, X509_free); + return NULL; } -#endif } BIO_free(bio); + return x509; +} + + +static EVP_PKEY * +ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, + ngx_str_t *key, ngx_array_t *passwords) +{ + BIO *bio; + EVP_PKEY *pkey; + ngx_str_t *pwd; + ngx_uint_t tries; + pem_password_cb *cb; + if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) { #ifndef OPENSSL_NO_ENGINE @@ -541,9 +705,8 @@ last = (u_char *) ngx_strchr(p, ':'); if (last == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syntax in \"%V\"", key); - return NGX_ERROR; + *err = "invalid syntax"; + return NULL; } *last = '\0'; @@ -551,9 +714,8 @@ engine = ENGINE_by_id((char *) p); if (engine == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "ENGINE_by_id(\"%s\") failed", p); - return NGX_ERROR; + *err = "ENGINE_by_id() failed"; + return NULL; } *last++ = ':'; @@ -561,76 +723,69 @@ pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0); if (pkey == NULL) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "ENGINE_load_private_key(\"%s\") failed", last); + *err = "ENGINE_load_private_key() failed"; ENGINE_free(engine); - return NGX_ERROR; + return NULL; } ENGINE_free(engine); - if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_PrivateKey(\"%s\") failed", last); - EVP_PKEY_free(pkey); - return NGX_ERROR; - } - - EVP_PKEY_free(pkey); - - return NGX_OK; + return pkey; #else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "loading \"engine:...\" certificate keys " - "is not supported"); - return NGX_ERROR; + *err = "loading \"engine:...\" certificate keys is not supported"; + return NULL; #endif } - if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { - return NGX_ERROR; + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, key) + != NGX_OK) + { + *err = NULL; + return NULL; + } + + bio = BIO_new_file((char *) key->data, "r"); + if (bio == NULL) { + *err = "BIO_new_file() failed"; + return NULL; } if (passwords) { tries = passwords->nelts; pwd = passwords->elts; - - SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback); - SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd); + cb = ngx_ssl_password_callback; } else { tries = 1; -#if (NGX_SUPPRESS_WARN) pwd = NULL; -#endif + cb = NULL; } for ( ;; ) { - if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, - SSL_FILETYPE_PEM) - != 0) - { + pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd); + if (pkey != NULL) { break; } - if (--tries) { + if (tries-- > 1) { ERR_clear_error(); - SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd); + (void) BIO_reset(bio); + pwd++; continue; } - ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); - return NGX_ERROR; + *err = "PEM_read_bio_PrivateKey() failed"; + BIO_free(bio); + return NULL; } - SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL); + BIO_free(bio); - return NGX_OK; + return pkey; } @@ -645,6 +800,10 @@ return 0; } + if (pwd == NULL) { + return 0; + } + if (pwd->len > (size_t) size) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "password is truncated to %d bytes", size); @@ -969,10 +1128,13 @@ return NULL; } - cln = ngx_pool_cleanup_add(cf->temp_pool, 0); passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); + if (passwords == NULL) { + return NULL; + } - if (cln == NULL || passwords == NULL) { + cln = ngx_pool_cleanup_add(cf->temp_pool, 0); + if (cln == NULL) { return NULL; } @@ -1080,6 +1242,69 @@ } +ngx_array_t * +ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords) +{ + ngx_str_t *opwd, *pwd; + ngx_uint_t i; + ngx_array_t *pwds; + ngx_pool_cleanup_t *cln; + static ngx_array_t empty_passwords; + + if (passwords == NULL) { + + /* + * If there are no passwords, an empty array is used + * to make sure OpenSSL's default password callback + * won't block on reading from stdin. + */ + + return &empty_passwords; + } + + /* + * Passwords are normally allocated from the temporary pool + * and cleared after parsing configuration. To be used at + * runtime they have to be copied to the configuration pool. + */ + + pwds = ngx_array_create(cf->pool, passwords->nelts, sizeof(ngx_str_t)); + if (pwds == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_ssl_passwords_cleanup; + cln->data = pwds; + + opwd = passwords->elts; + + for (i = 0; i < passwords->nelts; i++) { + + pwd = ngx_array_push(pwds); + if (pwd == NULL) { + return NULL; + } + + pwd->len = opwd[i].len; + pwd->data = ngx_pnalloc(cf->pool, pwd->len); + + if (pwd->data == NULL) { + pwds->nelts--; + return NULL; + } + + ngx_memcpy(pwd->data, opwd[i].data, opwd[i].len); + } + + return pwds; +} + + static void ngx_ssl_passwords_cleanup(void *data) { @@ -2686,6 +2911,9 @@ #ifdef SSL_R_INAPPROPRIATE_FALLBACK || n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */ #endif +#ifdef SSL_R_CERT_CB_ERROR + || n == SSL_R_CERT_CB_ERROR /* 377 */ +#endif #ifdef SSL_R_VERSION_TOO_LOW || n == SSL_R_VERSION_TOO_LOW /* 396 */ #endif @@ -2765,53 +2993,60 @@ p = ngx_vslprintf(errstr, last - 1, fmt, args); va_end(args); - p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); + if (ERR_peek_error()) { + p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); - for ( ;; ) { + for ( ;; ) { - n = ERR_peek_error_line_data(NULL, NULL, &data, &flags); + n = ERR_peek_error_line_data(NULL, NULL, &data, &flags); - if (n == 0) { - break; + if (n == 0) { + break; + } + + /* ERR_error_string_n() requires at least one byte */ + + if (p >= last - 1) { + goto next; + } + + *p++ = ' '; + + ERR_error_string_n(n, (char *) p, last - p); + + while (p < last && *p) { + p++; + } + + if (p < last && *data && (flags & ERR_TXT_STRING)) { + *p++ = ':'; + p = ngx_cpystrn(p, (u_char *) data, last - p); + } + + next: + + (void) ERR_get_error(); } - /* ERR_error_string_n() requires at least one byte */ - - if (p >= last - 1) { - goto next; + if (p < last) { + *p++ = ')'; } - - *p++ = ' '; - - ERR_error_string_n(n, (char *) p, last - p); - - while (p < last && *p) { - p++; - } - - if (p < last && *data && (flags & ERR_TXT_STRING)) { - *p++ = ':'; - p = ngx_cpystrn(p, (u_char *) data, last - p); - } - - next: - - (void) ERR_get_error(); } - ngx_log_error(level, log, err, "%*s)", p - errstr, errstr); + ngx_log_error(level, log, err, "%*s", p - errstr, errstr); } ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, - ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout) + ngx_array_t *certificates, ssize_t builtin_session_cache, + ngx_shm_zone_t *shm_zone, time_t timeout) { long cache_mode; SSL_CTX_set_timeout(ssl->ctx, (long) timeout); - if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) { + if (ngx_ssl_session_id_context(ssl, sess_ctx, certificates) != NGX_OK) { return NGX_ERROR; } @@ -2877,11 +3112,14 @@ static ngx_int_t -ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) +ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, + ngx_array_t *certificates) { int n, i; X509 *cert; X509_NAME *name; + ngx_str_t *certs; + ngx_uint_t k; EVP_MD_CTX *md; unsigned int len; STACK_OF(X509_NAME) *list; @@ -2926,6 +3164,24 @@ } } + if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL) { + + /* + * If certificates are loaded dynamically, we use certificate + * names as specified in the configuration (with variables). + */ + + certs = certificates->elts; + for (k = 0; k < certificates->nelts; k++) { + + if (EVP_DigestUpdate(md, certs[k].data, certs[k].len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + } + } + list = SSL_CTX_get_client_CA_list(ssl->ctx); if (list != NULL) { @@ -2950,7 +3206,7 @@ if (EVP_DigestFinal_ex(md, buf, &len) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "EVP_DigestUpdate() failed"); + "EVP_DigestFinal_ex() failed"); goto failed; } @@ -3481,6 +3737,7 @@ ngx_uint_t i; ngx_array_t *keys; ngx_file_info_t fi; + ngx_pool_cleanup_t *cln; ngx_ssl_session_ticket_key_t *key; if (paths == NULL) { @@ -3493,6 +3750,14 @@ return NGX_ERROR; } + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_session_ticket_keys_cleanup; + cln->data = keys; + path = paths->elts; for (i = 0; i < paths->nelts; i++) { @@ -3564,6 +3829,8 @@ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " \"%V\" failed", &file.name); } + + ngx_explicit_memzero(&buf, 80); } if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys) @@ -3594,6 +3861,8 @@ ngx_close_file_n " \"%V\" failed", &file.name); } + ngx_explicit_memzero(&buf, 80); + return NGX_ERROR; } @@ -3722,6 +3991,16 @@ } } + +static void +ngx_ssl_session_ticket_keys_cleanup(void *data) +{ + ngx_array_t *keys = data; + + ngx_explicit_memzero(keys->elts, + keys->nelts * sizeof(ngx_ssl_session_ticket_key_t)); +} + #else ngx_int_t
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 2495e48..f34ccf9 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h
@@ -161,10 +161,14 @@ ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); + ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); +ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); + ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_uint_t prefer_server_ciphers); ngx_int_t ngx_ssl_alpn_protos(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -181,6 +185,8 @@ RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length); ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); +ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf, + ngx_array_t *passwords); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name); ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -188,7 +194,8 @@ ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, - ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout); + ngx_array_t *certificates, ssize_t builtin_session_cache, + ngx_shm_zone_t *shm_zone, time_t timeout); ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths); ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c index 65eb22f..5572830 100644 --- a/src/event/ngx_event_udp.c +++ b/src/event/ngx_event_udp.c
@@ -256,7 +256,9 @@ rev = c->read; c->udp->buffer = &buf; + rev->ready = 1; + rev->active = 0; rev->handler(rev); @@ -265,6 +267,7 @@ } rev->ready = 0; + rev->active = 1; goto next; } @@ -343,6 +346,7 @@ rev = c->read; wev = c->write; + rev->active = 1; wev->ready = 1; rev->log = log; @@ -453,7 +457,9 @@ ngx_memcpy(buf, b->pos, n); c->udp->buffer = NULL; + c->read->ready = 0; + c->read->active = 1; return n; }
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index dfff2b8..c184606 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c
@@ -39,6 +39,9 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf, + ngx_http_ssl_srv_conf_t *conf); + static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, @@ -548,6 +551,7 @@ * set by ngx_pcalloc(): * * sscf->protocols = 0; + * sscf->certificate_values = NULL; * sscf->dhparam = { 0, NULL }; * sscf->ecdh_curve = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; @@ -740,13 +744,38 @@ cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) - != NGX_OK) - { + if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } + if (conf->certificate_values) { + +#ifdef SSL_R_CERT_CB_ERROR + + /* install callback to lookup certificates */ + + SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_http_ssl_certificate, conf); + +#else + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "variables in " + "\"ssl_certificate\" and \"ssl_certificate_key\" " + "directives are not supported on this platform"); + return NGX_CONF_ERROR; +#endif + + } else { + + /* configure certificates */ + + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, conf->prefer_server_ciphers) != NGX_OK) @@ -801,7 +830,7 @@ } if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) { @@ -844,6 +873,90 @@ } +static ngx_int_t +ngx_http_ssl_compile_certificates(ngx_conf_t *cf, + ngx_http_ssl_srv_conf_t *conf) +{ + ngx_str_t *cert, *key; + ngx_uint_t i, nelts; + ngx_http_complex_value_t *cv; + ngx_http_compile_complex_value_t ccv; + + cert = conf->certificates->elts; + key = conf->certificate_keys->elts; + nelts = conf->certificates->nelts; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_script_variables_count(&cert[i])) { + goto found; + } + + if (ngx_http_script_variables_count(&key[i])) { + goto found; + } + } + + return NGX_OK; + +found: + + conf->certificate_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_http_complex_value_t)); + if (conf->certificate_values == NULL) { + return NGX_ERROR; + } + + conf->certificate_key_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_http_complex_value_t)); + if (conf->certificate_key_values == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < nelts; i++) { + + cv = ngx_array_push(conf->certificate_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &cert[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + + cv = ngx_array_push(conf->certificate_key_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &key[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + } + + conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords); + if (conf->passwords == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static char * ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index fb3219b..26fdccf 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h
@@ -36,6 +36,9 @@ ngx_array_t *certificates; ngx_array_t *certificate_keys; + ngx_array_t *certificate_values; + ngx_array_t *certificate_key_values; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate;
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index f6bece5..7758c0a 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h
@@ -96,6 +96,10 @@ #endif int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); #endif +#if (NGX_HTTP_SSL && defined SSL_R_CERT_CB_ERROR) +int ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); +#endif + ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index eb5ead5..3762aef 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c
@@ -11,6 +11,7 @@ static void ngx_http_wait_request_handler(ngx_event_t *ev); +static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c); static void ngx_http_process_request_line(ngx_event_t *rev); static void ngx_http_process_request_headers(ngx_event_t *rev); static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); @@ -503,17 +504,45 @@ ngx_http_request_t * ngx_http_create_request(ngx_connection_t *c) { + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + + r = ngx_http_alloc_request(c); + if (r == NULL) { + return NULL; + } + + c->requests++; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_set_connection_log(c, clcf->error_log); + + ctx = c->log->data; + ctx->request = r; + ctx->current_request = r; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); + r->stat_reading = 1; + (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); +#endif + + return r; +} + + +static ngx_http_request_t * +ngx_http_alloc_request(ngx_connection_t *c) +{ ngx_pool_t *pool; ngx_time_t *tp; ngx_http_request_t *r; - ngx_http_log_ctx_t *ctx; ngx_http_connection_t *hc; ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; - c->requests++; - hc = c->data; cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); @@ -541,10 +570,6 @@ r->read_event_handler = ngx_http_block_reading; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ngx_set_connection_log(r->connection, clcf->error_log); - r->header_in = hc->busy ? hc->busy->buf : c->buffer; if (ngx_list_init(&r->headers_out.headers, r->pool, 20, @@ -604,17 +629,8 @@ r->http_state = NGX_HTTP_READING_REQUEST_STATE; - ctx = c->log->data; - ctx->request = r; - ctx->current_request = r; r->log_handler = ngx_http_log_error_handler; -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); - r->stat_reading = 1; - (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); -#endif - return r; } @@ -833,6 +849,7 @@ ngx_http_close_connection(c); } + #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #if defined(OPENSSL_IS_BORINGSSL) @@ -1085,6 +1102,75 @@ #endif + +#ifdef SSL_R_CERT_CB_ERROR + +int +ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) +{ + ngx_str_t cert, key; + ngx_uint_t i, nelts; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_complex_value_t *certs, *keys; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + return 0; + } + + r = ngx_http_alloc_request(c); + if (r == NULL) { + return 0; + } + + r->logged = 1; + + sscf = arg; + + nelts = sscf->certificate_values->nelts; + certs = sscf->certificate_values->elts; + keys = sscf->certificate_key_values->elts; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl cert: \"%s\"", cert.data); + + if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + sscf->passwords) + != NGX_OK) + { + goto failed; + } + } + + ngx_http_free_request(r, 0); + c->destroyed = 0; + return 1; + +failed: + + ngx_http_free_request(r, 0); + c->destroyed = 0; + return 0; +} + +#endif + #endif @@ -3684,9 +3770,11 @@ r->headers_out.status = rc; } - log->action = "logging request"; + if (!r->logged) { + log->action = "logging request"; - ngx_http_log_request(r); + ngx_http_log_request(r); + } log->action = "closing request";
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 1a87735..4153889 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c
@@ -271,6 +271,34 @@ } +ngx_int_t +ngx_http_test_required_predicates(ngx_http_request_t *r, + ngx_array_t *predicates) +{ + ngx_str_t val; + ngx_uint_t i; + ngx_http_complex_value_t *cv; + + if (predicates == NULL) { + return NGX_OK; + } + + cv = predicates->elts; + + for (i = 0; i < predicates->nelts; i++) { + if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) { + return NGX_DECLINED; + } + } + + return NGX_OK; +} + + char * ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index a5116d7..25bb6d7 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h
@@ -214,6 +214,8 @@ ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates); +ngx_int_t ngx_http_test_required_predicates(ngx_http_request_t *r, + ngx_array_t *predicates); char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 7356bd1..fea4ea1 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c
@@ -850,7 +850,7 @@ ngx_http_file_cache_create_key(r); - if (r->cache->header_start + 256 >= u->conf->buffer_size) { + if (r->cache->header_start + 256 > u->conf->buffer_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V_buffer_size %uz is not enough for cache key, " "it should be increased to at least %uz",
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 4509597..10e982e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c
@@ -435,7 +435,7 @@ } if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) {
diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c index aedc3c9..bb60ee8 100644 --- a/src/os/unix/ngx_file_aio_read.c +++ b/src/os/unix/ngx_file_aio_read.c
@@ -110,7 +110,7 @@ #if (NGX_HAVE_KQUEUE) aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; - aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; + aio->aiocb.aio_sigevent.sigev_value.sival_ptr = ev; #endif ev->handler = ngx_file_aio_event_handler;
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h index b7da48c..c641108 100644 --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h
@@ -89,8 +89,14 @@ #if (NGX_HAVE_FILE_AIO) + #include <aio.h> typedef struct aiocb ngx_aiocb_t; + +#if (__FreeBSD_version < 700005 && !defined __DragonFly__) +#define sival_ptr sigval_ptr +#endif + #endif
diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h index a9e26c2..f8a453d 100644 --- a/src/os/win32/ngx_socket.h +++ b/src/os/win32/ngx_socket.h
@@ -200,6 +200,49 @@ extern LPFN_DISCONNECTEX ngx_disconnectex; +#if (NGX_HAVE_POLL && !defined POLLIN) + +/* + * WSAPoll() is only available if _WIN32_WINNT >= 0x0600. + * If it is not available during compilation, we try to + * load it dynamically at runtime. + */ + +#define NGX_LOAD_WSAPOLL 1 + +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + + SOCKET fd; + SHORT events; + SHORT revents; + +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +typedef int (WSAAPI *ngx_wsapoll_pt)( + LPWSAPOLLFD fdArray, + ULONG fds, + INT timeout + ); + +extern ngx_wsapoll_pt WSAPoll; +extern ngx_uint_t ngx_have_wsapoll; + +#endif + + int ngx_tcp_push(ngx_socket_t s); #define ngx_tcp_push_n "tcp_push()"
diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c index ec9b51e..70bee8e 100644 --- a/src/os/win32/ngx_win32_init.c +++ b/src/os/win32/ngx_win32_init.c
@@ -58,6 +58,12 @@ static GUID dx_guid = WSAID_DISCONNECTEX; +#if (NGX_LOAD_WSAPOLL) +ngx_wsapoll_pt WSAPoll; +ngx_uint_t ngx_have_wsapoll; +#endif + + ngx_int_t ngx_os_init(ngx_log_t *log) { @@ -223,6 +229,32 @@ ngx_close_socket_n " failed"); } +#if (NGX_LOAD_WSAPOLL) + { + HMODULE hmod; + + hmod = GetModuleHandle("ws2_32.dll"); + if (hmod == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetModuleHandle(\"ws2_32.dll\") failed"); + goto nopoll; + } + + WSAPoll = (ngx_wsapoll_pt) GetProcAddress(hmod, "WSAPoll"); + if (WSAPoll == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetProcAddress(\"WSAPoll\") failed"); + goto nopoll; + } + + ngx_have_wsapoll = 1; + + } + +nopoll: + +#endif + if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1) != 0) {
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 0949313..d7bdec2 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c
@@ -1593,7 +1593,7 @@ break; } - if ((off_t) size > limit) { + if (c->type == SOCK_STREAM && (off_t) size > limit) { size = (size_t) limit; } } @@ -1667,13 +1667,13 @@ flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { + if (ngx_handle_read_event(src->read, flags) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } if (dst) { - if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; }
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index dcc33e1..9266e99 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c
@@ -22,6 +22,9 @@ static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); +#ifdef SSL_R_CERT_CB_ERROR +static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); +#endif static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, @@ -32,6 +35,9 @@ static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, + ngx_stream_ssl_conf_t *conf); + static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, @@ -408,6 +414,62 @@ } +#ifdef SSL_R_CERT_CB_ERROR + +int +ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) +{ + ngx_str_t cert, key; + ngx_uint_t i, nelts; + ngx_connection_t *c; + ngx_stream_session_t *s; + ngx_stream_ssl_conf_t *sslcf; + ngx_stream_complex_value_t *certs, *keys; + + c = ngx_ssl_get_connection(ssl_conn); + + if (c->ssl->handshaked) { + return 0; + } + + s = c->data; + + sslcf = arg; + + nelts = sslcf->certificate_values->nelts; + certs = sslcf->certificate_values->elts; + keys = sslcf->certificate_key_values->elts; + + for (i = 0; i < nelts; i++) { + + if (ngx_stream_complex_value(s, &certs[i], &cert) != NGX_OK) { + return 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "ssl cert: \"%s\"", cert.data); + + if (ngx_stream_complex_value(s, &keys[i], &key) != NGX_OK) { + return 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + sslcf->passwords) + != NGX_OK) + { + return 0; + } + } + + return 1; +} + +#endif + + static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) @@ -505,6 +567,7 @@ * * scf->listen = 0; * scf->protocols = 0; + * scf->certificate_values = NULL; * scf->dhparam = { 0, NULL }; * scf->ecdh_curve = { 0, NULL }; * scf->client_certificate = { 0, NULL }; @@ -619,13 +682,38 @@ cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; - if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) - != NGX_OK) - { + if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } + if (conf->certificate_values) { + +#ifdef SSL_R_CERT_CB_ERROR + + /* install callback to lookup certificates */ + + SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_stream_ssl_certificate, conf); + +#else + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "variables in " + "\"ssl_certificate\" and \"ssl_certificate_key\" " + "directives are not supported on this platform"); + return NGX_CONF_ERROR; +#endif + + } else { + + /* configure certificates */ + + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, + conf->certificate_keys, conf->passwords) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, conf->prefer_server_ciphers) != NGX_OK) @@ -678,7 +766,7 @@ } if (ngx_ssl_session_cache(&conf->ssl, &ngx_stream_ssl_sess_id_ctx, - conf->builtin_session_cache, + conf->certificates, conf->builtin_session_cache, conf->shm_zone, conf->session_timeout) != NGX_OK) { @@ -707,6 +795,90 @@ } +static ngx_int_t +ngx_stream_ssl_compile_certificates(ngx_conf_t *cf, + ngx_stream_ssl_conf_t *conf) +{ + ngx_str_t *cert, *key; + ngx_uint_t i, nelts; + ngx_stream_complex_value_t *cv; + ngx_stream_compile_complex_value_t ccv; + + cert = conf->certificates->elts; + key = conf->certificate_keys->elts; + nelts = conf->certificates->nelts; + + for (i = 0; i < nelts; i++) { + + if (ngx_stream_script_variables_count(&cert[i])) { + goto found; + } + + if (ngx_stream_script_variables_count(&key[i])) { + goto found; + } + } + + return NGX_OK; + +found: + + conf->certificate_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_stream_complex_value_t)); + if (conf->certificate_values == NULL) { + return NGX_ERROR; + } + + conf->certificate_key_values = ngx_array_create(cf->pool, nelts, + sizeof(ngx_stream_complex_value_t)); + if (conf->certificate_key_values == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < nelts; i++) { + + cv = ngx_array_push(conf->certificate_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &cert[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + + cv = ngx_array_push(conf->certificate_key_values); + if (cv == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &key[i]; + ccv.complex_value = cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_ERROR; + } + } + + conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords); + if (conf->passwords == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static char * ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index 9f8f01c..6cb4140 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h
@@ -34,6 +34,9 @@ ngx_array_t *certificates; ngx_array_t *certificate_keys; + ngx_array_t *certificate_values; + ngx_array_t *certificate_key_values; + ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate;