Compare commits

...

22 Commits

Author SHA1 Message Date
Maxim Dounin 994edecbb5 release-1.8.1 tag 2016-01-26 17:39:31 +03:00
Maxim Dounin 620cb8ebb3 nginx-1.8.1-RELEASE 2016-01-26 17:39:30 +03:00
Ruslan Ermilov fa8de0e110 Resolver: limited CNAME recursion.
Previously, the recursion was only limited for cached responses.
2016-01-26 16:47:14 +03:00
Roman Arutyunyan 8e2ba53330 Resolver: fixed use-after-free memory accesses with CNAME.
When several requests were waiting for a response, then after getting
a CNAME response only the last request's context had the name updated.
Contexts of other requests had the wrong name.  This name was used by
ngx_resolve_name_done() to find the node to remove the request context
from.  When the name was wrong, the request could not be properly
cancelled, its context was freed but stayed linked to the node's waiting
list.  This happened e.g. when the first request was aborted or timed
out before the resolving completed.  When it completed, this triggered
a use-after-free memory access by calling ctx->handler of already freed
request context.  The bug manifests itself by
"could not cancel <name> resolving" alerts in error_log.

When a request was responded with a CNAME, the request context kept
the pointer to the original node's rn->u.cname.  If the original node
expired before the resolving timed out or completed with an error,
this would trigger a use-after-free memory access via ctx->name in
ctx->handler().

The fix is to keep ctx->name unmodified.  The name from context
is no longer used by ngx_resolve_name_done().  Instead, we now keep
the pointer to resolver node to which this request is linked.
Keeping the original name intact also improves logging.
2016-01-26 16:46:59 +03:00
Roman Arutyunyan 7b5920d9a9 Resolver: changed the ngx_resolver_create_*_query() arguments.
No functional changes.

This is needed by the following change.
2016-01-26 16:46:48 +03:00
Ruslan Ermilov 6c42b28bdd Resolver: fixed CNAME processing for several requests.
When several requests were waiting for a response, then after getting
a CNAME response only the last request was properly processed, while
others were left waiting.
2016-01-26 16:46:38 +03:00
Ruslan Ermilov 92c27f267f Resolver: fixed crashes in timeout handler.
If one or more requests were waiting for a response, then after
getting a CNAME response, the timeout event on the first request
remained active, pointing to the wrong node with an empty
rn->waiting list, and that could cause either null pointer
dereference or use-after-free memory access if this timeout
expired.

If several requests were waiting for a response, and the first
request terminated (e.g., due to client closing a connection),
other requests were left without a timeout and could potentially
wait indefinitely.

This is fixed by introducing per-request independent timeouts.
This change also reverts 954867a2f0a6 and 5004210e8c78.
2016-01-26 16:46:31 +03:00
Roman Arutyunyan 824eae78fb Resolver: fixed possible segmentation fault on DNS format error. 2016-01-26 16:46:18 +03:00
Maxim Dounin 4bcb833c89 Updated OpenSSL and PCRE used for win32 builds. 2016-01-25 21:58:21 +03:00
Valentin Bartenev 144aa35280 SSL: only select SPDY using NPN if "spdy" is enabled.
OpenSSL doesn't check if the negotiated protocol has been announced.
As a result, the client might force using SPDY even if it wasn't
enabled in configuration.
2015-11-05 15:01:09 +03:00
Maxim Dounin f38b4d5a56 Fixed ngx_parse_time() out of bounds access (ticket #821).
The code failed to ensure that "s" is within the buffer passed for
parsing when checking for "ms", and this resulted in unexpected errors when
parsing non-null-terminated strings with trailing "m".  The bug manifested
itself when the expires directive was used with variables.

Found by Roman Arutyunyan.
2015-10-30 21:43:30 +03:00
Maxim Dounin fe6e13e579 SSL: preserve default server context in connection (ticket #235).
This context is needed for shared sessions cache to work in configurations
with multiple virtual servers sharing the same port.  Unfortunately, OpenSSL
does not provide an API to access the session context, thus storing it
separately.

In collaboration with Vladimir Homutov.
2015-10-19 21:22:38 +03:00
Roman Arutyunyan 238a4d5ea9 Upstream: fixed cache send error handling.
The value of NGX_ERROR, returned from filter handlers, was treated as a generic
upstream error and changed to NGX_HTTP_INTERNAL_SERVER_ERROR before calling
ngx_http_finalize_request().  This resulted in "header already sent" alert
if header was already sent in filter handlers.

The problem appeared in 54e9b83d00f0 (1.7.5).
2015-09-03 15:09:21 +03:00
Maxim Dounin 7bb45d91cf Fixed wrong URI after try_files in nested location (ticket #97).
The following configuration with alias, nested location and try_files
resulted in wrong file being used.  Request "/foo/test.gif" tried to
use "/tmp//foo/test.gif" instead of "/tmp/test.gif":

    location /foo/ {
        alias /tmp/;
        location ~ gif {
            try_files $uri =405;
        }
    }

Additionally, rev. c985d90a8d1f introduced a regression if
the "/tmp//foo/test.gif" file was found (ticket #768).  Resulting URI
was set to "gif?/foo/test.gif", as the code used clcf->name of current
location ("location ~ gif") instead of parent one ("location /foo/").

Fix is to use r->uri instead of clcf->name in all cases in the
ngx_http_core_try_files_phase() function.  It is expected to be
already matched and identical to the clcf->name of the right
location.
2015-08-16 10:51:34 +03:00
Maxim Dounin 3f6c0e604a Fixed segfault with try_files introduced by c985d90a8d1f.
If alias was used in a location given by a regular expression,
nginx used to do wrong thing in try_files if a location name (i.e.,
regular expression) was an exact prefix of URI.  The following
configuration triggered a segmentation fault on a request to "/mail":

    location ~ /mail {
        alias /path/to/directory;
        try_files $uri =404;
    }

Reported by Per Hansson.
2015-08-16 10:51:16 +03:00
Ruslan Ermilov 774bd67fc5 Events: made a failure to create a notification channel non-fatal.
This may happen if eventfd() returns ENOSYS, notably seen on CentOS 5.4.
Such a failure will now just disable the notification mechanism and let
the callers cope with it, instead of failing to start worker processes.
If thread pools are not configured, this can safely be ignored.
2015-05-06 17:04:00 +03:00
Roman Arutyunyan e084afb726 Merge proxy_protocol setting of listen directives.
It's now enough to specify proxy_protocol option in one listen directive to
enable it in all servers listening on the same address/port.  Previously,
the setting from the first directive was always used.
2015-04-24 10:54:06 +03:00
Maxim Dounin dcdd591615 Version bump. 2016-01-25 19:32:58 +03:00
Maxim Dounin 736f30b216 release-1.8.0 tag 2015-04-21 17:11:58 +03:00
Maxim Dounin 7097e2a683 nginx-1.8.0-RELEASE 2015-04-21 17:11:58 +03:00
Sergey Kandaurov b6c7cb0523 Core: ensure that ngx_config.h is always included first.
This fixes compilation of various 3rd party modules when nginx is
configured with threads.
2015-04-16 18:18:37 +03:00
Maxim Dounin 7e42c2cd3e Stable branch. 2015-04-16 17:00:52 +03:00
14 changed files with 373 additions and 148 deletions

View File

@ -5,6 +5,179 @@
<change_log title="nginx">
<changes ver="1.8.1" date="26.01.2016">
<change type="security">
<para lang="ru">
при использовании директивы resolver
во время обработки ответов DNS-сервера
могло происходить разыменование некорректного адреса,
что позволяло атакующему,
имеющему возможность подделывать UDP-пакеты от DNS-сервера,
вызвать segmentation fault в рабочем процессе (CVE-2016-0742).
</para>
<para lang="en">
invalid pointer dereference might occur
during DNS server response processing
if the "resolver" directive was used,
allowing an attacker who is able to forge UDP packets from the DNS server
to cause segmentation fault in a worker process (CVE-2016-0742).
</para>
</change>
<change type="security">
<para lang="ru">
при использовании директивы resolver
во время обработки CNAME-записей
могло произойти обращение к ранее освобождённой памяти,
что позволяло атакующему,
имеющему возможность инициировать преобразование произвольных имён в адреса,
вызвать segmentation fault в рабочем процессе,
а также потенциально могло иметь другие последствия (CVE-2016-0746).
</para>
<para lang="en">
use-after-free condition might occur
during CNAME response processing
if the "resolver" directive was used,
allowing an attacker who is able to trigger name resolution
to cause segmentation fault in a worker process,
or might have potential other impact (CVE-2016-0746).
</para>
</change>
<change type="security">
<para lang="ru">
при использовании директивы resolver
во время обработки CNAME-записей
не во всех случаях проверялось ограничение
на максимальное количество записей в цепочке,
что позволяло атакующему,
имеющему возможность инициировать преобразование произвольных имён в адреса,
вызвать чрезмерное потребление ресурсов рабочими процессами (CVE-2016-0747).
</para>
<para lang="en">
CNAME resolution was insufficiently limited
if the "resolver" directive was used,
allowing an attacker who is able to trigger arbitrary name resolution
to cause excessive resource consumption in worker processes (CVE-2016-0747).
</para>
</change>
<change type="bugfix">
<para lang="ru">
параметр proxy_protocol директивы listen не работал,
если не был указан в первой директиве listen для данного listen-сокета.
</para>
<para lang="en">
the "proxy_protocol" parameter of the "listen" directive did not work
if not specified in the first "listen" directive for a listen socket.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx мог не запускаться на некоторых старых версиях Linux;
ошибка появилась в 1.7.11.
</para>
<para lang="en">
nginx might fail to start on some old Linux variants;
the bug had appeared in 1.7.11.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при совместном использовании директив try_files и alias
внутри location'а, заданного регулярным выражением,
в рабочем процессе мог произойти segmentation fault;
ошибка появилась в 1.7.1.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if the "try_files" and "alias" directives were used
inside a location given by a regular expression;
the bug had appeared in 1.7.1.
</para>
</change>
<change type="bugfix">
<para lang="ru">
директива try_files внутри вложенного location'а, заданного регулярным
выражением, работала неправильно, если во внешнем location'е использовалась
директива alias.
</para>
<para lang="en">
the "try_files" directive inside a nested location
given by a regular expression worked incorrectly
if the "alias" directive was used in the outer location.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании кэша
в логах могли появляться сообщения "header already sent";
ошибка появилась в 1.7.5.
</para>
<para lang="en">
"header already sent" alerts might appear in logs
when using cache;
the bug had appeared in 1.7.5.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании различных настроек ssl_session_cache
в разных виртуальных серверах
в рабочем процессе мог произойти segmentation fault.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if different ssl_session_cache settings were used
in different virtual servers.
</para>
</change>
<change type="bugfix">
<para lang="ru">
директива expires могла не срабатывать при использовании переменных.
</para>
<para lang="en">
the "expires" directive might not work when using variables.
</para>
</change>
<change type="bugfix">
<para lang="ru">
если nginx был собран с модулем ngx_http_spdy_module,
протокол SPDY мог быть использован клиентом,
даже если не был указан параметр spdy директивы listen.
</para>
<para lang="en">
if nginx was built with the ngx_http_spdy_module
it was possible to use the SPDY protocol
even if the "spdy" parameter of the "listen" directive was not specified.
</para>
</change>
</changes>
<changes ver="1.8.0" date="21.04.2015">
<change>
<para lang="ru">
Стабильная ветка 1.8.x.
</para>
<para lang="en">
1.8.x stable branch.
</para>
</change>
</changes>
<changes ver="1.7.12" date="07.04.2015">
<change type="feature">

View File

@ -5,9 +5,9 @@ NGINX = nginx-$(VER)
TEMP = tmp
OBJS = objs.msvc8
OPENSSL = openssl-1.0.1m
OPENSSL = openssl-1.0.1q
ZLIB = zlib-1.2.8
PCRE = pcre-8.35
PCRE = pcre-8.38
release: export

View File

@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
#define nginx_version 1007013
#define NGINX_VERSION "1.7.13"
#define nginx_version 1008001
#define NGINX_VERSION "1.8.1"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD

View File

@ -9,6 +9,9 @@
#define _NGX_CORE_H_INCLUDED_
#include <ngx_config.h>
typedef struct ngx_module_s ngx_module_t;
typedef struct ngx_conf_s ngx_conf_t;
typedef struct ngx_cycle_s ngx_cycle_t;

View File

@ -188,7 +188,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
break;
case 'm':
if (*p == 's') {
if (p < last && *p == 's') {
if (is_sec || step >= st_msec) {
return NGX_ERROR;
}

View File

@ -59,15 +59,15 @@ ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
static void ngx_resolver_cleanup(void *data);
static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx);
ngx_resolver_ctx_t *ctx, ngx_str_t *name);
static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
ngx_queue_t *queue);
static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
ngx_resolver_node_t *rn);
static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
ngx_resolver_ctx_t *ctx);
static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
ngx_resolver_ctx_t *ctx);
static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
ngx_resolver_node_t *rn, ngx_str_t *name);
static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
ngx_resolver_node_t *rn, ngx_addr_t *addr);
static void ngx_resolver_resend_handler(ngx_event_t *ev);
static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
ngx_queue_t *queue);
@ -375,7 +375,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx)
/* lock name mutex */
rc = ngx_resolve_name_locked(r, ctx);
rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
if (rc == NGX_OK) {
return NGX_OK;
@ -402,7 +402,6 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx)
void
ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
{
uint32_t hash;
ngx_resolver_t *r;
ngx_resolver_ctx_t *w, **p;
ngx_resolver_node_t *rn;
@ -422,11 +421,9 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
/* lock name mutex */
if (ctx->state == NGX_AGAIN) {
if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
rn = ctx->node;
if (rn) {
p = &rn->waiting;
@ -467,23 +464,28 @@ done:
static ngx_int_t
ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
ngx_str_t *name)
{
uint32_t hash;
ngx_int_t rc;
ngx_str_t cname;
ngx_uint_t naddrs;
ngx_addr_t *addrs;
ngx_resolver_ctx_t *next;
ngx_resolver_ctx_t *next, *last;
ngx_resolver_node_t *rn;
ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len);
ngx_strlow(name->data, name->data, name->len);
hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
hash = ngx_crc32_short(name->data, name->len);
rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
rn = ngx_resolver_lookup_name(r, name, hash);
if (rn) {
/* ctx can be a list after NGX_RESOLVE_CNAME */
for (last = ctx; last->next; last = last->next);
if (rn->valid >= ngx_time()) {
ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
@ -511,7 +513,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
}
}
ctx->next = rn->waiting;
last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@ -551,13 +553,13 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
ctx->name.len = rn->cnlen;
ctx->name.data = rn->u.cname;
cname.len = rn->cnlen;
cname.data = rn->u.cname;
return ngx_resolve_name_locked(r, ctx);
return ngx_resolve_name_locked(r, ctx, &cname);
}
ctx->next = rn->waiting;
last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@ -576,10 +578,29 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
if (rn->waiting) {
ctx->next = rn->waiting;
if (ctx->event == NULL) {
ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
if (ctx->event == NULL) {
return NGX_ERROR;
}
ctx->event->handler = ngx_resolver_timeout_handler;
ctx->event->data = ctx;
ctx->event->log = r->log;
ctx->ident = -1;
ngx_add_timer(ctx->event, ctx->timeout);
}
last->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
do {
ctx->node = rn;
ctx = ctx->next;
} while (ctx);
return NGX_AGAIN;
}
@ -618,14 +639,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
return NGX_ERROR;
}
rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
rn->name = ngx_resolver_dup(r, name->data, name->len);
if (rn->name == NULL) {
ngx_resolver_free(r, rn);
return NGX_ERROR;
}
rn->node.key = hash;
rn->nlen = (u_short) ctx->name.len;
rn->nlen = (u_short) name->len;
rn->query = NULL;
#if (NGX_HAVE_INET6)
rn->query6 = NULL;
@ -634,7 +655,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
rc = ngx_resolver_create_name_query(rn, ctx);
rc = ngx_resolver_create_name_query(r, rn, name);
if (rc == NGX_ERROR) {
goto failed;
@ -647,8 +668,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_resolver_free(r, rn->name);
ngx_resolver_free(r, rn);
ctx->state = NGX_RESOLVE_NXDOMAIN;
ctx->handler(ctx);
do {
ctx->state = NGX_RESOLVE_NXDOMAIN;
next = ctx->next;
ctx->handler(ctx);
ctx = next;
} while (ctx);
return NGX_OK;
}
@ -669,9 +696,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
}
ctx->event->handler = ngx_resolver_timeout_handler;
ctx->event->data = rn;
ctx->event->data = ctx;
ctx->event->log = r->log;
rn->ident = -1;
ctx->ident = -1;
ngx_add_timer(ctx->event, ctx->timeout);
}
@ -692,6 +719,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ctx->state = NGX_AGAIN;
do {
ctx->node = rn;
ctx = ctx->next;
} while (ctx);
return NGX_AGAIN;
failed:
@ -799,9 +831,22 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
if (rn->waiting) {
ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
if (ctx->event == NULL) {
return NGX_ERROR;
}
ctx->event->handler = ngx_resolver_timeout_handler;
ctx->event->data = ctx;
ctx->event->log = r->log;
ctx->ident = -1;
ngx_add_timer(ctx->event, ctx->timeout);
ctx->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
ctx->node = rn;
/* unlock addr mutex */
@ -843,7 +888,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_rbtree_insert(tree, &rn->node);
}
if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
goto failed;
}
@ -862,9 +907,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
}
ctx->event->handler = ngx_resolver_timeout_handler;
ctx->event->data = rn;
ctx->event->data = ctx;
ctx->event->log = r->log;
rn->ident = -1;
ctx->ident = -1;
ngx_add_timer(ctx->event, ctx->timeout);
@ -887,6 +932,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
/* unlock addr mutex */
ctx->state = NGX_AGAIN;
ctx->node = rn;
return NGX_OK;
@ -917,17 +963,11 @@ failed:
void
ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
{
in_addr_t addr;
ngx_queue_t *expire_queue;
ngx_rbtree_t *tree;
ngx_resolver_t *r;
ngx_resolver_ctx_t *w, **p;
struct sockaddr_in *sin;
ngx_resolver_node_t *rn;
#if (NGX_HAVE_INET6)
uint32_t hash;
struct sockaddr_in6 *sin6;
#endif
r = ctx->resolver;
@ -954,23 +994,9 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
/* lock addr mutex */
if (ctx->state == NGX_AGAIN) {
if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
switch (ctx->addr.sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
break;
#endif
default: /* AF_INET */
sin = (struct sockaddr_in *) ctx->addr.sockaddr;
addr = ntohl(sin->sin_addr.s_addr);
rn = ngx_resolver_lookup_addr(r, addr);
}
rn = ctx->node;
if (rn) {
p = &rn->waiting;
@ -1292,7 +1318,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
times = 0;
for (q = ngx_queue_head(&r->name_resend_queue);
q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100;
q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
q = ngx_queue_next(q))
{
rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
@ -1955,21 +1981,40 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
ctx = rn->waiting;
rn->waiting = NULL;
if (ctx) {
ctx->name = name;
(void) ngx_resolve_name_locked(r, ctx);
}
ngx_resolver_free(r, rn->query);
rn->query = NULL;
#if (NGX_HAVE_INET6)
rn->query6 = NULL;
#endif
ctx = rn->waiting;
rn->waiting = NULL;
if (ctx) {
if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
/* unlock name mutex */
do {
ctx->state = NGX_RESOLVE_NXDOMAIN;
next = ctx->next;
ctx->handler(ctx);
ctx = next;
} while (ctx);
return;
}
for (next = ctx; next; next = next->next) {
next->node = NULL;
}
(void) ngx_resolve_name_locked(r, ctx, &name);
}
/* unlock name mutex */
return;
@ -2476,27 +2521,23 @@ ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
static ngx_int_t
ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
ngx_str_t *name)
{
u_char *p, *s;
size_t len, nlen;
ngx_uint_t ident;
#if (NGX_HAVE_INET6)
ngx_resolver_t *r;
#endif
ngx_resolver_qs_t *qs;
ngx_resolver_hdr_t *query;
nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
nlen = name->len ? (1 + name->len + 1) : 1;
len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
#if (NGX_HAVE_INET6)
r = ctx->resolver;
p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len);
p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
#else
p = ngx_resolver_alloc(ctx->resolver, len);
p = ngx_resolver_alloc(r, len);
#endif
if (p == NULL) {
return NGX_ERROR;
@ -2515,8 +2556,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
ident = ngx_random();
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
"resolve: \"%V\" A %i", &ctx->name, ident & 0xffff);
ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve: \"%V\" A %i", name, ident & 0xffff);
query->ident_hi = (u_char) ((ident >> 8) & 0xff);
query->ident_lo = (u_char) (ident & 0xff);
@ -2546,11 +2587,11 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
p--;
*p-- = '\0';
if (ctx->name.len == 0) {
if (name->len == 0) {
return NGX_DECLINED;
}
for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
for (s = name->data + name->len - 1; s >= name->data; s--) {
if (*s != '.') {
*p = *s;
len++;
@ -2586,8 +2627,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
ident = ngx_random();
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
"resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff);
ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve: \"%V\" AAAA %i", name, ident & 0xffff);
query->ident_hi = (u_char) ((ident >> 8) & 0xff);
query->ident_lo = (u_char) (ident & 0xff);
@ -2604,11 +2645,12 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
static ngx_int_t
ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
ngx_addr_t *addr)
{
u_char *p, *d;
size_t len;
in_addr_t addr;
in_addr_t inaddr;
ngx_int_t n;
ngx_uint_t ident;
ngx_resolver_hdr_t *query;
@ -2617,7 +2659,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
struct sockaddr_in6 *sin6;
#endif
switch (ctx->addr.sockaddr->sa_family) {
switch (addr->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
@ -2634,7 +2676,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
+ sizeof(ngx_resolver_qs_t);
}
p = ngx_resolver_alloc(ctx->resolver, len);
p = ngx_resolver_alloc(r, len);
if (p == NULL) {
return NGX_ERROR;
}
@ -2658,11 +2700,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
p += sizeof(ngx_resolver_hdr_t);
switch (ctx->addr.sockaddr->sa_family) {
switch (addr->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
sin6 = (struct sockaddr_in6 *) addr->sockaddr;
for (n = 15; n >= 0; n--) {
p = ngx_sprintf(p, "\1%xd\1%xd",
@ -2677,11 +2719,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
default: /* AF_INET */
sin = (struct sockaddr_in *) ctx->addr.sockaddr;
addr = ntohl(sin->sin_addr.s_addr);
sin = (struct sockaddr_in *) addr->sockaddr;
inaddr = ntohl(sin->sin_addr.s_addr);
for (n = 0; n < 32; n += 8) {
d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
*p = (u_char) (d - &p[1]);
p = d;
}
@ -2795,21 +2837,13 @@ done:
static void
ngx_resolver_timeout_handler(ngx_event_t *ev)
{
ngx_resolver_ctx_t *ctx, *next;
ngx_resolver_node_t *rn;
ngx_resolver_ctx_t *ctx;
rn = ev->data;
ctx = rn->waiting;
rn->waiting = NULL;
ctx = ev->data;
do {
ctx->state = NGX_RESOLVE_TIMEDOUT;
next = ctx->next;
ctx->state = NGX_RESOLVE_TIMEDOUT;
ctx->handler(ctx);
ctx = next;
} while (ctx);
ctx->handler(ctx);
}

View File

@ -51,15 +51,11 @@ typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx);
typedef struct {
/* PTR: resolved name, A: name to resolve */
u_char *name;
ngx_rbtree_node_t node;
ngx_queue_t queue;
/* event ident must be after 3 pointers as in ngx_connection_t */
ngx_int_t ident;
ngx_rbtree_node_t node;
/* PTR: resolved name, A: name to resolve */
u_char *name;
#if (NGX_HAVE_INET6)
/* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */
@ -147,6 +143,9 @@ struct ngx_resolver_ctx_s {
ngx_resolver_t *resolver;
ngx_udp_connection_t *udp_connection;
/* event ident must be after 3 pointers as in ngx_connection_t */
ngx_int_t ident;
ngx_int_t state;
ngx_str_t name;
@ -162,6 +161,8 @@ struct ngx_resolver_ctx_s {
ngx_uint_t quick; /* unsigned quick:1; */
ngx_uint_t recursion;
ngx_event_t *event;
ngx_resolver_node_t *node;
};

View File

@ -329,7 +329,7 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
#if (NGX_HAVE_EVENTFD)
if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
return NGX_ERROR;
ngx_epoll_module_ctx.actions.notify = NULL;
}
#endif

View File

@ -1038,6 +1038,8 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
sc->buffer_size = ssl->buffer_size;
sc->session_ctx = ssl->ctx;
sc->connection = SSL_new(ssl->ctx);
if (sc->connection == NULL) {
@ -2303,7 +2305,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
c = ngx_ssl_get_connection(ssl_conn);
ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
ssl_ctx = c->ssl->session_ctx;
shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
cache = shm_zone->data;
@ -2441,21 +2443,17 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,
ngx_ssl_sess_id_t *sess_id;
ngx_ssl_session_cache_t *cache;
u_char buf[NGX_SSL_MAX_SESSION_SIZE];
#if (NGX_DEBUG)
ngx_connection_t *c;
#endif
hash = ngx_crc32_short(id, (size_t) len);
*copy = 0;
#if (NGX_DEBUG)
c = ngx_ssl_get_connection(ssl_conn);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl get session: %08XD:%d", hash, len);
#endif
shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
shm_zone = SSL_CTX_get_ex_data(c->ssl->session_ctx,
ngx_ssl_session_cache_index);
cache = shm_zone->data;
@ -2834,13 +2832,14 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
SSL_CTX *ssl_ctx;
ngx_uint_t i;
ngx_array_t *keys;
ngx_connection_t *c;
ngx_ssl_session_ticket_key_t *key;
#if (NGX_DEBUG)
u_char buf[32];
ngx_connection_t *c;
#endif
ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
c = ngx_ssl_get_connection(ssl_conn);
ssl_ctx = c->ssl->session_ctx;
keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index);
if (keys == NULL) {
@ -2849,10 +2848,6 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
key = keys->elts;
#if (NGX_DEBUG)
c = ngx_ssl_get_connection(ssl_conn);
#endif
if (enc == 1) {
/* encrypt session ticket */

View File

@ -46,6 +46,7 @@ typedef struct {
typedef struct {
ngx_ssl_conn_t *connection;
SSL_CTX *session_ctx;
ngx_int_t last;
ngx_buf_t *buf;

View File

@ -1220,7 +1220,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
{
u_char *p;
size_t len, off;
ngx_uint_t i, default_server;
ngx_uint_t i, default_server, proxy_protocol;
struct sockaddr *sa;
ngx_http_conf_addr_t *addr;
#if (NGX_HAVE_UNIX_DOMAIN)
@ -1281,6 +1281,8 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
/* preserve default_server bit during listen options overwriting */
default_server = addr[i].opt.default_server;
proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol;
#if (NGX_HTTP_SSL)
ssl = lsopt->ssl || addr[i].opt.ssl;
#endif
@ -1314,6 +1316,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
}
addr[i].opt.default_server = default_server;
addr[i].opt.proxy_protocol = proxy_protocol;
#if (NGX_HTTP_SSL)
addr[i].opt.ssl = ssl;
#endif

View File

@ -1272,7 +1272,9 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
*e.pos = '\0';
if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) {
if (alias && alias != NGX_MAX_SIZE_T_VALUE
&& ngx_strncmp(name, r->uri.data, alias) == 0)
{
ngx_memmove(name, name + alias, len - alias);
path.len -= alias;
}
@ -1355,6 +1357,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
}
} else {
name = r->uri.data;
r->uri.len = alias + path.len;
r->uri.data = ngx_pnalloc(r->pool, r->uri.len);
if (r->uri.data == NULL) {
@ -1362,8 +1366,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
return NGX_OK;
}
p = ngx_copy(r->uri.data, clcf->name.data, alias);
ngx_memcpy(p, name, path.len);
p = ngx_copy(r->uri.data, name, alias);
ngx_memcpy(p, path.data, path.len);
}
ngx_http_set_exten(r);

View File

@ -770,24 +770,32 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
{
unsigned int len;
const unsigned char *data;
ngx_http_connection_t *hc;
static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED);
hc = c->data;
if (hc->addr_conf->spdy) {
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
#ifdef TLSEXT_TYPE_next_proto_neg
if (len == 0) {
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
}
if (len == 0) {
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
}
#endif
#else /* TLSEXT_TYPE_next_proto_neg */
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
#endif
if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) {
ngx_http_spdy_init(c->read);
return;
if (len == spdy.len
&& ngx_strncmp(data, spdy.data, spdy.len) == 0)
{
ngx_http_spdy_init(c->read);
return;
}
}
}
#endif

View File

@ -530,15 +530,24 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
r->write_event_handler = ngx_http_request_empty_handler;
if (rc == NGX_DONE) {
return;
}
if (rc == NGX_ERROR) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
if (rc == NGX_OK) {
rc = ngx_http_upstream_cache_send(r, u);
if (rc == NGX_DONE) {
return;
}
if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
rc = NGX_DECLINED;
r->cached = 0;
}
}
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return;
@ -833,13 +842,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
case NGX_OK:
rc = ngx_http_upstream_cache_send(r, u);
if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
return rc;
}
break;
return NGX_OK;
case NGX_HTTP_CACHE_STALE: