diff options
Diffstat (limited to 'usr.sbin/nginx/src/core')
32 files changed, 2291 insertions, 812 deletions
diff --git a/usr.sbin/nginx/src/core/nginx.c b/usr.sbin/nginx/src/core/nginx.c index 7f0011d879f..5960fa85658 100644 --- a/usr.sbin/nginx/src/core/nginx.c +++ b/usr.sbin/nginx/src/core/nginx.c @@ -389,13 +389,8 @@ main(int argc, char *const *argv) return 1; } - if (cycle->log->file->fd != ngx_stderr) { - - if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - ngx_set_stderr_n " failed"); - return 1; - } + if (ngx_log_redirect_stderr(cycle) != NGX_OK) { + return 1; } if (log->file->fd != ngx_stderr) { diff --git a/usr.sbin/nginx/src/core/nginx.h b/usr.sbin/nginx/src/core/nginx.h index 77c88bf5f94..0ef0f2e110f 100644 --- a/usr.sbin/nginx/src/core/nginx.h +++ b/usr.sbin/nginx/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1004007 -#define NGINX_VERSION "1.4.7" +#define nginx_version 1006000 +#define NGINX_VERSION "1.6.0" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.c b/usr.sbin/nginx/src/core/ngx_conf_file.c index a262672139c..f61bfcabf99 100644 --- a/usr.sbin/nginx/src/core/ngx_conf_file.c +++ b/usr.sbin/nginx/src/core/ngx_conf_file.c @@ -12,7 +12,6 @@ static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); -static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -225,6 +224,11 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) * "types { ... }" directive */ + if (rc == NGX_CONF_BLOCK_START) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); + goto failed; + } + rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; @@ -796,95 +800,11 @@ ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix) { - size_t len; - u_char *p, *n, *prefix; - ngx_int_t rc; - - rc = ngx_conf_test_full_name(name); - - if (rc == NGX_OK) { - return rc; - } - - if (conf_prefix) { - len = cycle->conf_prefix.len; - prefix = cycle->conf_prefix.data; - - } else { - len = cycle->prefix.len; - prefix = cycle->prefix.data; - } - -#if (NGX_WIN32) - - if (rc == 2) { - len = rc; - } - -#endif - - n = ngx_pnalloc(cycle->pool, len + name->len + 1); - if (n == NULL) { - return NGX_ERROR; - } - - p = ngx_cpymem(n, prefix, len); - ngx_cpystrn(p, name->data, name->len + 1); - - name->len += len; - name->data = n; - - return NGX_OK; -} - - -static ngx_int_t -ngx_conf_test_full_name(ngx_str_t *name) -{ -#if (NGX_WIN32) - u_char c0, c1; - - c0 = name->data[0]; - - if (name->len < 2) { - if (c0 == '/') { - return 2; - } + ngx_str_t *prefix; - return NGX_DECLINED; - } - - c1 = name->data[1]; - - if (c1 == ':') { - c0 |= 0x20; + prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix; - if ((c0 >= 'a' && c0 <= 'z')) { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if (c1 == '/') { - return NGX_OK; - } - - if (c0 == '/') { - return 2; - } - - return NGX_DECLINED; - -#else - - if (name->data[0] == '/') { - return NGX_OK; - } - - return NGX_DECLINED; - -#endif + return ngx_get_full_name(cycle->pool, prefix, name); } diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.h b/usr.sbin/nginx/src/core/ngx_conf_file.h index 237e6ecea6e..d73a6c8bf55 100644 --- a/usr.sbin/nginx/src/core/ngx_conf_file.h +++ b/usr.sbin/nginx/src/core/ngx_conf_file.h @@ -5,8 +5,8 @@ */ -#ifndef _NGX_HTTP_CONF_FILE_H_INCLUDED_ -#define _NGX_HTTP_CONF_FILE_H_INCLUDED_ +#ifndef _NGX_CONF_FILE_H_INCLUDED_ +#define _NGX_CONF_FILE_H_INCLUDED_ #include <ngx_config.h> @@ -337,4 +337,4 @@ extern ngx_uint_t ngx_max_module; extern ngx_module_t *ngx_modules[]; -#endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */ +#endif /* _NGX_CONF_FILE_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_config.h b/usr.sbin/nginx/src/core/ngx_config.h index b0cb17fca80..1da71f8d1a1 100644 --- a/usr.sbin/nginx/src/core/ngx_config.h +++ b/usr.sbin/nginx/src/core/ngx_config.h @@ -80,8 +80,8 @@ typedef uintptr_t ngx_uint_t; typedef intptr_t ngx_flag_t; -#define NGX_INT32_LEN sizeof("-2147483648") - 1 -#define NGX_INT64_LEN sizeof("-9223372036854775808") - 1 +#define NGX_INT32_LEN (sizeof("-2147483648") - 1) +#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1) #if (NGX_PTR_SIZE == 4) #define NGX_INT_T_LEN NGX_INT32_LEN diff --git a/usr.sbin/nginx/src/core/ngx_connection.c b/usr.sbin/nginx/src/core/ngx_connection.c index 986bf0d0208..6b6e3b3a512 100644 --- a/usr.sbin/nginx/src/core/ngx_connection.c +++ b/usr.sbin/nginx/src/core/ngx_connection.c @@ -41,7 +41,7 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) ls->sockaddr = sa; ls->socklen = socklen; - len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); + len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1); ls->addr_text.len = len; switch (ls->sockaddr->sa_family) { @@ -82,6 +82,10 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen) ls->setfib = -1; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = -1; +#endif + return ls; } @@ -93,8 +97,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) ngx_uint_t i; ngx_listening_t *ls; socklen_t olen; -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) +#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN) ngx_err_t err; +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) struct accept_filter_arg af; #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) @@ -123,7 +129,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; - len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; break; #endif @@ -152,7 +158,8 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1); + len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen, + ls[i].addr_text.data, len, 1); if (len == 0) { return NGX_ERROR; } @@ -192,7 +199,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_SETFIB) - if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB, + olen = sizeof(int); + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB, (void *) &ls[i].setfib, &olen) == -1) { @@ -206,6 +215,27 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #endif #endif +#if (NGX_HAVE_TCP_FASTOPEN) + + olen = sizeof(int); + + if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN, + (void *) &ls[i].fastopen, &olen) + == -1) + { + err = ngx_socket_errno; + + if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, + "getsockopt(TCP_FASTOPEN) %V failed, ignored", + &ls[i].addr_text); + } + + ls[i].fastopen = -1; + } + +#endif + #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_memzero(&af, sizeof(struct accept_filter_arg)); @@ -214,7 +244,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen) == -1) { - err = ngx_errno; + err = ngx_socket_errno; if (err == NGX_EINVAL) { continue; @@ -247,7 +277,13 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen) == -1) { - ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, + err = ngx_socket_errno; + + if (err == NGX_EOPNOTSUPP) { + continue; + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, err, "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored", &ls[i].addr_text); continue; @@ -296,7 +332,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) continue; } - if (ls[i].fd != -1) { + if (ls[i].fd != (ngx_socket_t) -1) { continue; } @@ -311,7 +347,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_socket_n " %V failed", &ls[i].addr_text); return NGX_ERROR; @@ -463,16 +499,13 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) void ngx_configure_listening_sockets(ngx_cycle_t *cycle) { - int keepalive; + int value; ngx_uint_t i; ngx_listening_t *ls; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) struct accept_filter_arg af; #endif -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - int timeout; -#endif ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -502,39 +535,51 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } if (ls[i].keepalive) { - keepalive = (ls[i].keepalive == 1) ? 1 : 0; + value = (ls[i].keepalive == 1) ? 1 : 0; if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE, - (const void *) &keepalive, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_KEEPALIVE, %d) %V failed, ignored", - keepalive, &ls[i].addr_text); + value, &ls[i].addr_text); } } #if (NGX_HAVE_KEEPALIVE_TUNABLE) if (ls[i].keepidle) { + value = ls[i].keepidle; + +#if (NGX_KEEPALIVE_FACTOR) + value *= NGX_KEEPALIVE_FACTOR; +#endif + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE, - (const void *) &ls[i].keepidle, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored", - ls[i].keepidle, &ls[i].addr_text); + value, &ls[i].addr_text); } } if (ls[i].keepintvl) { + value = ls[i].keepintvl; + +#if (NGX_KEEPALIVE_FACTOR) + value *= NGX_KEEPALIVE_FACTOR; +#endif + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL, - (const void *) &ls[i].keepintvl, sizeof(int)) + (const void *) &value, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored", - ls[i].keepintvl, &ls[i].addr_text); + value, &ls[i].addr_text); } } @@ -564,6 +609,19 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } #endif +#if (NGX_HAVE_TCP_FASTOPEN) + if (ls[i].fastopen != -1) { + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN, + (const void *) &ls[i].fastopen, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(TCP_FASTOPEN, %d) %V failed, ignored", + ls[i].fastopen, &ls[i].addr_text); + } + } +#endif + #if 0 if (1) { int tcp_nodelay = 1; @@ -603,7 +661,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, NULL) " "for %V failed, ignored", &ls[i].addr_text); @@ -630,7 +688,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) &af, sizeof(struct accept_filter_arg)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, \"%s\") " "for %V failed, ignored", ls[i].accept_filter, &ls[i].addr_text); @@ -653,20 +711,20 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) * if syncookies were used), hence we use 1 second timeout * here. */ - timeout = 1; + value = 1; } else { - timeout = 0; + value = 0; } if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, - &timeout, sizeof(int)) + &value, sizeof(int)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, " "ignored", - timeout, &ls[i].addr_text); + value, &ls[i].addr_text); continue; } @@ -859,7 +917,7 @@ ngx_close_connection(ngx_connection_t *c) ngx_uint_t log_error, level; ngx_socket_t fd; - if (c->fd == -1) { + if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } @@ -1034,6 +1092,10 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, struct sockaddr_in6 *sin6; #endif + if (c->local_socklen == 0) { + return NGX_ERROR; + } + switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) @@ -1047,6 +1109,12 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + addr = 1; + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) c->local_sockaddr; addr = sin->sin_addr.s_addr; @@ -1068,13 +1136,16 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, } ngx_memcpy(c->local_sockaddr, &sa, len); + + c->local_socklen = len; } if (s == NULL) { return NGX_OK; } - s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, port); + s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen, + s->data, s->len, port); return NGX_OK; } diff --git a/usr.sbin/nginx/src/core/ngx_connection.h b/usr.sbin/nginx/src/core/ngx_connection.h index 3daf2eee4cb..ed14e6023e7 100644 --- a/usr.sbin/nginx/src/core/ngx_connection.h +++ b/usr.sbin/nginx/src/core/ngx_connection.h @@ -80,6 +80,10 @@ struct ngx_listening_s { int setfib; #endif +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif + }; @@ -108,6 +112,7 @@ typedef enum { #define NGX_LOWLEVEL_BUFFERED 0x0f #define NGX_SSL_BUFFERED 0x01 +#define NGX_SPDY_BUFFERED 0x02 struct ngx_connection_s { @@ -134,11 +139,14 @@ struct ngx_connection_s { socklen_t socklen; ngx_str_t addr_text; + ngx_str_t proxy_protocol_addr; + #if (NGX_SSL) ngx_ssl_connection_t *ssl; #endif struct sockaddr *local_sockaddr; + socklen_t local_socklen; ngx_buf_t *buffer; @@ -166,12 +174,15 @@ struct ngx_connection_s { unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */ + unsigned need_last_buf:1; + #if (NGX_HAVE_IOCP) unsigned accept_context_updated:1; #endif #if (NGX_HAVE_AIO_SENDFILE) unsigned aio_sendfile:1; + unsigned busy_count:2; ngx_buf_t *busy_sendfile; #endif diff --git a/usr.sbin/nginx/src/core/ngx_core.h b/usr.sbin/nginx/src/core/ngx_core.h index dfcf2d56cf8..c479a59546d 100644 --- a/usr.sbin/nginx/src/core/ngx_core.h +++ b/usr.sbin/nginx/src/core/ngx_core.h @@ -77,6 +77,8 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include <ngx_open_file_cache.h> #include <ngx_os.h> #include <ngx_connection.h> +#include <ngx_syslog.h> +#include <ngx_proxy_protocol.h> #define LF (u_char) 10 diff --git a/usr.sbin/nginx/src/core/ngx_cycle.c b/usr.sbin/nginx/src/core/ngx_cycle.c index 0c354c65665..aa42406ffe3 100644 --- a/usr.sbin/nginx/src/core/ngx_cycle.c +++ b/usr.sbin/nginx/src/core/ngx_cycle.c @@ -11,7 +11,6 @@ static void ngx_destroy_cycle_pools(ngx_conf_t *conf); -static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2); static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *shm_zone); static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log); @@ -36,8 +35,6 @@ ngx_tls_key_t ngx_core_tls_key; static ngx_connection_t dumb; /* STUB */ -static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); - ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) @@ -84,13 +81,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->pool = pool; cycle->log = log; - cycle->new_log.log_level = NGX_LOG_ERR; -#if (NGX_ENABLE_SYSLOG) - cycle->new_log.facility = SYSLOG_FACILITY; - cycle->new_log.facility = ERR_SYSLOG_PRIORITY; - cycle->new_log.syslog_on = 0; - cycle->new_log.syslog_set = 0; -#endif cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; @@ -345,11 +335,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } - if (cycle->new_log.file == NULL) { - cycle->new_log.file = ngx_conf_open_file(cycle, &error_log); - if (cycle->new_log.file == NULL) { - goto failed; - } + if (ngx_log_open_default(cycle) != NGX_OK) { + goto failed; } /* open the new files */ @@ -506,13 +493,15 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) continue; } - if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK) + if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, + ls[i].sockaddr, ls[i].socklen, 1) + == NGX_OK) { nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1; - if (ls[n].backlog != nls[i].backlog) { + if (ls[i].backlog != nls[n].backlog) { nls[n].listen = 1; } @@ -543,7 +532,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - if (ls[n].deferred_accept && !nls[n].deferred_accept) { + if (ls[i].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) @@ -555,8 +544,18 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } - if (nls[n].fd == -1) { + if (nls[n].fd == (ngx_socket_t) -1) { nls[n].open = 1; +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + if (nls[n].accept_filter) { + nls[n].add_deferred = 1; + } +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + if (nls[n].deferred_accept) { + nls[n].add_deferred = 1; + } +#endif } } @@ -588,12 +587,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) /* commit the new cycle configuration */ - if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) { - - if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - ngx_set_stderr_n " failed"); - } + if (!ngx_use_stderr) { + (void) ngx_log_redirect_stderr(cycle); } pool->log = cycle->log; @@ -665,7 +660,7 @@ old_shm_zone_done: ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { - if (ls[i].remain || ls[i].fd == -1) { + if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) { continue; } @@ -829,7 +824,7 @@ failed: ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - if (ls[i].fd == -1 || !ls[i].open) { + if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) { continue; } @@ -855,74 +850,6 @@ ngx_destroy_cycle_pools(ngx_conf_t *conf) static ngx_int_t -ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2) -{ - struct sockaddr_in *sin1, *sin2; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin61, *sin62; -#endif -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun1, *saun2; -#endif - - if (sa1->sa_family != sa2->sa_family) { - return NGX_DECLINED; - } - - switch (sa1->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin61 = (struct sockaddr_in6 *) sa1; - sin62 = (struct sockaddr_in6 *) sa2; - - if (sin61->sin6_port != sin62->sin6_port) { - return NGX_DECLINED; - } - - if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { - return NGX_DECLINED; - } - - break; -#endif - -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - saun1 = (struct sockaddr_un *) sa1; - saun2 = (struct sockaddr_un *) sa2; - - if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, - sizeof(saun1->sun_path)) - != 0) - { - return NGX_DECLINED; - } - - break; -#endif - - default: /* AF_INET */ - - sin1 = (struct sockaddr_in *) sa1; - sin2 = (struct sockaddr_in *) sa2; - - if (sin1->sin_port != sin2->sin_port) { - return NGX_DECLINED; - } - - if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { - return NGX_DECLINED; - } - - break; - } - - return NGX_OK; -} - - -static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) { u_char *file; @@ -1238,16 +1165,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) file[i].fd = fd; } -#if !(NGX_WIN32) - - if (cycle->log->file->fd != STDERR_FILENO) { - if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "dup2(STDERR) failed"); - } - } - -#endif + (void) ngx_log_redirect_stderr(cycle); } diff --git a/usr.sbin/nginx/src/core/ngx_cycle.h b/usr.sbin/nginx/src/core/ngx_cycle.h index 2e4bc4ba278..21bf5ca3f25 100644 --- a/usr.sbin/nginx/src/core/ngx_cycle.h +++ b/usr.sbin/nginx/src/core/ngx_cycle.h @@ -41,6 +41,8 @@ struct ngx_cycle_s { ngx_log_t *log; ngx_log_t new_log; + ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */ + ngx_connection_t **files; ngx_connection_t *free_connections; ngx_uint_t free_connection_n; diff --git a/usr.sbin/nginx/src/core/ngx_file.c b/usr.sbin/nginx/src/core/ngx_file.c index ce09bb6021f..4bbdc940211 100644 --- a/usr.sbin/nginx/src/core/ngx_file.c +++ b/usr.sbin/nginx/src/core/ngx_file.c @@ -9,11 +9,102 @@ #include <ngx_core.h> +static ngx_int_t ngx_test_full_name(ngx_str_t *name); + + static ngx_atomic_t temp_number = 0; ngx_atomic_t *ngx_temp_number = &temp_number; ngx_atomic_int_t ngx_random_number = 123456; +ngx_int_t +ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name) +{ + size_t len; + u_char *p, *n; + ngx_int_t rc; + + rc = ngx_test_full_name(name); + + if (rc == NGX_OK) { + return rc; + } + + len = prefix->len; + +#if (NGX_WIN32) + + if (rc == 2) { + len = rc; + } + +#endif + + n = ngx_pnalloc(pool, len + name->len + 1); + if (n == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(n, prefix->data, len); + ngx_cpystrn(p, name->data, name->len + 1); + + name->len += len; + name->data = n; + + return NGX_OK; +} + + +static ngx_int_t +ngx_test_full_name(ngx_str_t *name) +{ +#if (NGX_WIN32) + u_char c0, c1; + + c0 = name->data[0]; + + if (name->len < 2) { + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + } + + c1 = name->data[1]; + + if (c1 == ':') { + c0 |= 0x20; + + if ((c0 >= 'a' && c0 <= 'z')) { + return NGX_OK; + } + + return NGX_DECLINED; + } + + if (c1 == '/') { + return NGX_OK; + } + + if (c0 == '/') { + return 2; + } + + return NGX_DECLINED; + +#else + + if (name->data[0] == '/') { + return NGX_OK; + } + + return NGX_DECLINED; + +#endif +} + + ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) { @@ -268,9 +359,6 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NULL; } - path->len = 0; - path->manager = NULL; - path->loader = NULL; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -311,7 +399,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, return NGX_CONF_OK; } - *path = ngx_palloc(cf->pool, sizeof(ngx_path_t)); + *path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); if (*path == NULL) { return NGX_CONF_ERROR; } @@ -330,10 +418,6 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, + init->level[1] + (init->level[1] ? 1 : 0) + init->level[2] + (init->level[2] ? 1 : 0); - (*path)->manager = NULL; - (*path)->loader = NULL; - (*path)->conf_file = NULL; - if (ngx_add_path(cf, path) != NGX_OK) { return NGX_CONF_ERROR; } @@ -417,6 +501,14 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot) if (p[i]->name.len == path->name.len && ngx_strcmp(p[i]->name.data, path->name.data) == 0) { + if (p[i]->data != path->data) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the same path name \"%V\" " + "used in %s:%ui and", + &p[i]->name, p[i]->conf_file, p[i]->line); + return NGX_ERROR; + } + for (n = 0; n < 3; n++) { if (p[i]->level[n] != path->level[n]) { if (path->conf_file == NULL) { diff --git a/usr.sbin/nginx/src/core/ngx_file.h b/usr.sbin/nginx/src/core/ngx_file.h index 18abf142316..3ea6c28c863 100644 --- a/usr.sbin/nginx/src/core/ngx_file.h +++ b/usr.sbin/nginx/src/core/ngx_file.h @@ -122,6 +122,9 @@ struct ngx_tree_ctx_s { }; +ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, + ngx_str_t *name); + ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain); ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean, diff --git a/usr.sbin/nginx/src/core/ngx_hash.c b/usr.sbin/nginx/src/core/ngx_hash.c index b532945027c..c7bfed70979 100644 --- a/usr.sbin/nginx/src/core/ngx_hash.c +++ b/usr.sbin/nginx/src/core/ngx_hash.c @@ -282,7 +282,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) start = hinit->max_size - 1000; } - for (size = start; size < hinit->max_size; size++) { + for (size = start; size <= hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); @@ -312,15 +312,12 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) continue; } - ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, - "could not build the %s, you should increase " - "either %s_max_size: %i or %s_bucket_size: %i", + ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, + "could not build optimal %s, you should increase " + "either %s_max_size: %i or %s_bucket_size: %i; " + "ignoring %s_bucket_size", hinit->name, hinit->name, hinit->max_size, - hinit->name, hinit->bucket_size); - - ngx_free(test); - - return NGX_ERROR; + hinit->name, hinit->bucket_size, hinit->name); found: diff --git a/usr.sbin/nginx/src/core/ngx_inet.c b/usr.sbin/nginx/src/core/ngx_inet.c index 7757ab7d905..26c5bc4b0bb 100644 --- a/usr.sbin/nginx/src/core/ngx_inet.c +++ b/usr.sbin/nginx/src/core/ngx_inet.c @@ -174,7 +174,8 @@ ngx_inet6_addr(u_char *p, size_t len, u_char *addr) size_t -ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) +ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, + ngx_uint_t port) { u_char *p; struct sockaddr_in *sin; @@ -230,9 +231,18 @@ ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) case AF_UNIX: saun = (struct sockaddr_un *) sa; + /* on Linux sockaddr might not include sun_path at all */ + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { + p = ngx_snprintf(text, len, "unix:%Z"); + + } else { + p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); + } + /* we do not include trailing zero in address length */ - return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1; + return (p - text - 1); #endif @@ -953,6 +963,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) ngx_memzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { u->err = "host not found"; @@ -1020,7 +1033,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) goto failed; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1053,7 +1066,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) goto failed; } - len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p, + len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1138,7 +1152,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) return NGX_ERROR; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + len = ngx_sock_ntop((struct sockaddr *) sin, + sizeof(struct sockaddr_in), p, len, 1); u->addrs[i].name.len = len; u->addrs[i].name.data = p; @@ -1181,3 +1196,76 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) } #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ + + +ngx_int_t +ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, + struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port) +{ + struct sockaddr_in *sin1, *sin2; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin61, *sin62; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun1, *saun2; +#endif + + if (sa1->sa_family != sa2->sa_family) { + return NGX_DECLINED; + } + + switch (sa1->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + + sin61 = (struct sockaddr_in6 *) sa1; + sin62 = (struct sockaddr_in6 *) sa2; + + if (cmp_port && sin61->sin6_port != sin62->sin6_port) { + return NGX_DECLINED; + } + + if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { + return NGX_DECLINED; + } + + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + /* TODO length */ + + saun1 = (struct sockaddr_un *) sa1; + saun2 = (struct sockaddr_un *) sa2; + + if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, + sizeof(saun1->sun_path)) + != 0) + { + return NGX_DECLINED; + } + + break; +#endif + + default: /* AF_INET */ + + sin1 = (struct sockaddr_in *) sa1; + sin2 = (struct sockaddr_in *) sa2; + + if (cmp_port && sin1->sin_port != sin2->sin_port) { + return NGX_DECLINED; + } + + if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { + return NGX_DECLINED; + } + + break; + } + + return NGX_OK; +} diff --git a/usr.sbin/nginx/src/core/ngx_inet.h b/usr.sbin/nginx/src/core/ngx_inet.h index 6a5a3687d8c..05557509d65 100644 --- a/usr.sbin/nginx/src/core/ngx_inet.h +++ b/usr.sbin/nginx/src/core/ngx_inet.h @@ -107,14 +107,16 @@ in_addr_t ngx_inet_addr(u_char *text, size_t len); ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr); size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); #endif -size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, - ngx_uint_t port); +size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, + size_t len, ngx_uint_t port); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); +ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, + struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_list.c b/usr.sbin/nginx/src/core/ngx_list.c index 89ea8235275..d0eb15930a8 100644 --- a/usr.sbin/nginx/src/core/ngx_list.c +++ b/usr.sbin/nginx/src/core/ngx_list.c @@ -19,18 +19,10 @@ ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size) return NULL; } - list->part.elts = ngx_palloc(pool, n * size); - if (list->part.elts == NULL) { + if (ngx_list_init(list, pool, n, size) != NGX_OK) { return NULL; } - list->part.nelts = 0; - list->part.next = NULL; - list->last = &list->part; - list->size = size; - list->nalloc = n; - list->pool = pool; - return list; } diff --git a/usr.sbin/nginx/src/core/ngx_log.c b/usr.sbin/nginx/src/core/ngx_log.c index ddc2bbf6847..375d52f65d4 100644 --- a/usr.sbin/nginx/src/core/ngx_log.c +++ b/usr.sbin/nginx/src/core/ngx_log.c @@ -10,15 +10,8 @@ static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if (NGX_ENABLE_SYSLOG) -static char *ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -void log_exit(ngx_cycle_t *cycle); - -typedef struct{ - ngx_str_t name; - ngx_int_t macro; -} ngx_string_to_macro_t; -#endif +static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); +static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log); static ngx_command_t ngx_errlog_commands[] = { @@ -30,15 +23,6 @@ static ngx_command_t ngx_errlog_commands[] = { 0, NULL}, -#if (NGX_ENABLE_SYSLOG) - {ngx_string("syslog"), - NGX_MAIN_CONF|NGX_CONF_TAKE12, - ngx_set_syslog, - 0, - 0, - NULL}, -#endif - ngx_null_command }; @@ -61,11 +45,7 @@ ngx_module_t ngx_errlog_module = { NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ -#if (NGX_ENABLE_SYSLOG) - log_exit, /* exit master */ -#else - NULL, -#endif + NULL, /* exit master */ NGX_MODULE_V1_PADDING }; @@ -74,48 +54,6 @@ static ngx_log_t ngx_log; static ngx_open_file_t ngx_log_file; ngx_uint_t ngx_use_stderr = 1; -#if (NGX_ENABLE_SYSLOG) -static ngx_string_to_macro_t ngx_syslog_facilities[] = { - {ngx_string("auth"), LOG_AUTH}, -#if !(NGX_SOLARIS) - {ngx_string("authpriv"), LOG_AUTHPRIV}, -#endif - {ngx_string("cron"), LOG_CRON}, - {ngx_string("daemon"), LOG_DAEMON}, -#if !(NGX_SOLARIS) - {ngx_string("ftp"), LOG_FTP}, -#endif - {ngx_string("kern"), LOG_KERN}, - {ngx_string("local0"), LOG_LOCAL0}, - {ngx_string("local1"), LOG_LOCAL1}, - {ngx_string("local2"), LOG_LOCAL2}, - {ngx_string("local3"), LOG_LOCAL3}, - {ngx_string("local4"), LOG_LOCAL4}, - {ngx_string("local5"), LOG_LOCAL5}, - {ngx_string("local6"), LOG_LOCAL6}, - {ngx_string("local7"), LOG_LOCAL7}, - {ngx_string("lpr"), LOG_LPR}, - {ngx_string("mail"), LOG_MAIL}, - {ngx_string("news"), LOG_NEWS}, - {ngx_string("syslog"), LOG_SYSLOG}, - {ngx_string("user"), LOG_USER}, - {ngx_string("uucp"), LOG_UUCP}, - { ngx_null_string, 0} -}; - -static ngx_string_to_macro_t ngx_syslog_priorities[] = { - {ngx_string("emerg"), LOG_EMERG}, - {ngx_string("alert"), LOG_ALERT}, - {ngx_string("crit"), LOG_CRIT}, - {ngx_string("error"), LOG_ERR}, - {ngx_string("err"), LOG_ERR}, - {ngx_string("warn"), LOG_WARNING}, - {ngx_string("notice"),LOG_NOTICE}, - {ngx_string("info"), LOG_INFO}, - {ngx_string("debug"), LOG_DEBUG}, - { ngx_null_string, 0} -}; -#endif static ngx_str_t err_levels[] = { ngx_null_string, @@ -150,19 +88,11 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, #endif { #if (NGX_HAVE_VARIADIC_MACROS) - va_list args; -#endif - u_char *p, *last, *msg; -#if (NGX_ENABLE_SYSLOG) - u_char *errstr_syslog; -#endif - u_char errstr[NGX_MAX_ERROR_STR]; - -#if !(NGX_ENABLE_SYSLOG) - if (log->file->fd == NGX_INVALID_FILE) { - return; - } + va_list args; #endif + u_char *p, *last, *msg; + u_char errstr[NGX_MAX_ERROR_STR]; + ngx_uint_t wrote_stderr, debug_connection; last = errstr + NGX_MAX_ERROR_STR; @@ -171,10 +101,6 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, p = errstr + ngx_cached_err_log_time.len; -#if (NGX_ENABLE_SYSLOG) - errstr_syslog = p; -#endif - p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]); /* pid#tid */ @@ -213,27 +139,33 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, ngx_linefeed(p); -#if (NGX_ENABLE_SYSLOG) - if (log->file != NULL && log->file->name.len != 0) { - (void) ngx_write_fd(log->file->fd, errstr, p - errstr); - } + wrote_stderr = 0; + debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0; + + while (log) { + + if (log->log_level < level && !debug_connection) { + break; + } + + if (log->writer) { + log->writer(log, level, errstr, p - errstr); + log = log->next; + continue; + } + + (void) ngx_write_fd(log->file->fd, errstr, p - errstr); - /* Don't send the debug level info to syslog */ - if (log->syslog_on && level < NGX_LOG_DEBUG) { - /* write to syslog */ - syslog(log->priority, "%.*s", (int)(p - errstr_syslog), errstr_syslog); + if (log->file->fd == ngx_stderr) { + wrote_stderr = 1; + } + + log = log->next; } -#else - (void) ngx_write_fd(log->file->fd, errstr, p - errstr); -#endif if (!ngx_use_stderr || level > NGX_LOG_WARN -#if (NGX_ENABLE_SYSLOG) - || (log->file != NULL && log->file->fd == ngx_stderr)) -#else - || log->file->fd == ngx_stderr) -#endif + || wrote_stderr) { return; } @@ -437,75 +369,93 @@ ngx_log_init(u_char *prefix) } -ngx_log_t * -ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name) +ngx_int_t +ngx_log_open_default(ngx_cycle_t *cycle) { - ngx_log_t *log; + ngx_log_t *log; + static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH); + + if (ngx_log_get_file_log(&cycle->new_log) != NULL) { + return NGX_OK; + } + + if (cycle->new_log.log_level != 0) { + /* there are some error logs, but no files */ - log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); - if (log == NULL) { - return NULL; + log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); + if (log == NULL) { + return NGX_ERROR; + } + + log->log_level = NGX_LOG_ERR; + ngx_log_insert(&cycle->new_log, log); + + } else { + /* no error logs at all */ + log = &cycle->new_log; + log->log_level = NGX_LOG_ERR; } - log->file = ngx_conf_open_file(cycle, name); + log->file = ngx_conf_open_file(cycle, &error_log); if (log->file == NULL) { - return NULL; + return NGX_ERROR; } - return log; + return NGX_OK; } -#if (NGX_ENABLE_SYSLOG) ngx_int_t -ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority) +ngx_log_redirect_stderr(ngx_cycle_t *cycle) { - ngx_int_t p = 0; - ngx_uint_t n, match = 0; - - for (n = 0; ngx_syslog_priorities[n].name.len != 0; n++) { - if (ngx_strncmp(priority->data, ngx_syslog_priorities[n].name.data, - ngx_syslog_priorities[n].name.len) == 0) { - p = ngx_syslog_priorities[n].macro; - match = 1; - } + ngx_fd_t fd; + + if (cycle->log_use_stderr) { + return NGX_OK; } - if (!match) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syslog priority \"%V\"", priority); - return -1; + /* file log always exists when we are called */ + fd = ngx_log_get_file_log(cycle->log)->file->fd; + + if (fd != ngx_stderr) { + if (ngx_set_stderr(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_set_stderr_n " failed"); + + return NGX_ERROR; + } } - return p; + return NGX_OK; } -char * -ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log) +ngx_log_t * +ngx_log_get_file_log(ngx_log_t *head) { - log->priority = ERR_SYSLOG_PRIORITY; - - if (priority->len == 0) { - return NGX_CONF_OK; - } + ngx_log_t *log; - log->priority = ngx_log_get_priority(cf, priority); - if (log->priority == (-1)) { - return NGX_CONF_ERROR; + for (log = head; log; log = log->next) { + if (log->file != NULL) { + return log; + } } - return NGX_CONF_OK; + return NULL; } -#endif -char * +static char * ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) { ngx_uint_t i, n, d, found; ngx_str_t *value; + if (cf->args->nelts == 2) { + log->log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + value = cf->args->elts; for (i = 2; i < cf->args->nelts; i++) { @@ -561,136 +511,109 @@ ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) static char * ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value, name; -#if (NGX_ENABLE_SYSLOG) - u_char *off = NULL; - ngx_str_t priority; + ngx_log_t *dummy; - ngx_str_null(&name); - ngx_str_null(&priority); -#endif + dummy = &cf->cycle->new_log; - if (cf->cycle->new_log.file) { - return "is duplicate"; - } + return ngx_log_set_log(cf, &dummy); +} - value = cf->args->elts; -#if (NGX_ENABLE_SYSLOG) - if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) { - if (!cf->cycle->new_log.syslog_set) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "You must set the syslog directive and enable it first."); +char * +ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head) +{ + ngx_log_t *new_log; + ngx_str_t *value, name; + ngx_syslog_peer_t *peer; + + if (*head != NULL && (*head)->log_level == 0) { + new_log = *head; + + } else { + + new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t)); + if (new_log == NULL) { return NGX_CONF_ERROR; } - cf->cycle->new_log.syslog_on = 1; + if (*head == NULL) { + *head = new_log; + } + } - if (value[1].data[sizeof("syslog") - 1] == ':') { - priority.len = value[1].len - sizeof("syslog"); - priority.data = value[1].data + sizeof("syslog"); + value = cf->args->elts; - off = (u_char *)ngx_strchr(priority.data, (int) '|'); - if (off != NULL) { - priority.len = off - priority.data; + if (ngx_strcmp(value[1].data, "stderr") == 0) { + ngx_str_null(&name); + cf->cycle->log_use_stderr = 1; - off++; - name.len = value[1].data + value[1].len - off; - name.data = off; - } + new_log->file = ngx_conf_open_file(cf->cycle, &name); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; } - else { - if (value[1].len > sizeof("syslog")) { - name.len = value[1].len - sizeof("syslog"); - name.data = value[1].data + sizeof("syslog"); - } + + + } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) { + peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t)); + if (peer == NULL) { + return NGX_CONF_ERROR; } - if (ngx_log_set_priority(cf, &priority, &cf->cycle->new_log) == NGX_CONF_ERROR) { + if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) { return NGX_CONF_ERROR; } - } - else if (ngx_strcmp(value[1].data, "stderr") == 0) { -#else - if (ngx_strcmp(value[1].data, "stderr") == 0) { -#endif - ngx_str_null(&name); + + new_log->writer = ngx_syslog_writer; + new_log->wdata = peer; } else { - name = value[1]; + new_log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (new_log->file == NULL) { + return NGX_CONF_ERROR; + } } - cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name); - if (cf->cycle->new_log.file == NULL) { - return NULL; + if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) { + return NGX_CONF_ERROR; } - if (cf->args->nelts == 2) { - cf->cycle->new_log.log_level = NGX_LOG_ERR; - return NGX_CONF_OK; + if (*head != new_log) { + ngx_log_insert(*head, new_log); } - cf->cycle->new_log.log_level = 0; - - return ngx_log_set_levels(cf, &cf->cycle->new_log); + return NGX_CONF_OK; } -#if (NGX_ENABLE_SYSLOG) - -#define SYSLOG_IDENT_NAME "nginx" - -static char * -ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static void +ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log) { - char *program; - ngx_str_t *value; - ngx_int_t facility = SYSLOG_FACILITY, match = 0; - ngx_uint_t n; + ngx_log_t tmp; - value = cf->args->elts; + if (new_log->log_level > log->log_level) { - if (cf->cycle->new_log.syslog_set) { - return "is duplicate"; - } + /* + * list head address is permanent, insert new log after + * head and swap its contents with head + */ - cf->cycle->new_log.syslog_set = 1; + tmp = *log; + *log = *new_log; + *new_log = tmp; - for (n = 0; ngx_syslog_facilities[n].name.len != 0; n++) { - if (ngx_strncmp(value[1].data, ngx_syslog_facilities[n].name.data, - ngx_syslog_facilities[n].name.len) == 0) { - facility = ngx_syslog_facilities[n].macro; - match = 1; - break; - } + log->next = new_log; + return; } - if (match) { - cf->cycle->new_log.facility = facility; - cf->cycle->new_log.priority = ERR_SYSLOG_PRIORITY; - } - else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid syslog facility \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } + while (log->next) { + if (new_log->log_level > log->next->log_level) { + new_log->next = log->next; + log->next = new_log; + return; + } - program = SYSLOG_IDENT_NAME; - if (cf->args->nelts > 2) { - program = (char *) value[2].data; + log = log->next; } - openlog(program, LOG_ODELAY, facility); - - return NGX_CONF_OK; + log->next = new_log; } - - -void log_exit(ngx_cycle_t *cycle) -{ - if (cycle->new_log.syslog_set) { - closelog(); - } -} -#endif - diff --git a/usr.sbin/nginx/src/core/ngx_log.h b/usr.sbin/nginx/src/core/ngx_log.h index 5e7fdbf4b4e..c1a52c44f0b 100644 --- a/usr.sbin/nginx/src/core/ngx_log.h +++ b/usr.sbin/nginx/src/core/ngx_log.h @@ -12,13 +12,6 @@ #include <ngx_config.h> #include <ngx_core.h> -#if (NGX_ENABLE_SYSLOG) -#include <syslog.h> - -#define SYSLOG_FACILITY LOG_LOCAL5 -#define ERR_SYSLOG_PRIORITY LOG_ERR -#endif - #define NGX_LOG_STDERR 0 #define NGX_LOG_EMERG 1 @@ -50,6 +43,8 @@ typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len); +typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level, + u_char *buf, size_t len); struct ngx_log_s { @@ -61,6 +56,9 @@ struct ngx_log_s { ngx_log_handler_pt handler; void *data; + ngx_log_writer_pt writer; + void *wdata; + /* * we declare "action" as "char *" because the actions are usually * the static strings and in the "u_char *" case we have to override @@ -69,12 +67,7 @@ struct ngx_log_s { char *action; -#if (NGX_ENABLE_SYSLOG) - ngx_int_t priority; - ngx_int_t facility; - unsigned syslog_on:1; /* unsigned :1 syslog_on */ - unsigned syslog_set:1; /*unsigned :1 syslog_set */ -#endif + ngx_log_t *next; }; @@ -234,15 +227,13 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, /*********************************/ ngx_log_t *ngx_log_init(u_char *prefix); -ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name); -#if (NGX_ENABLE_SYSLOG) -ngx_int_t ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority); -char * ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log); -#endif -char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...); void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); +ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle); +ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle); +ngx_log_t *ngx_log_get_file_log(ngx_log_t *head); +char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head); /* diff --git a/usr.sbin/nginx/src/core/ngx_open_file_cache.c b/usr.sbin/nginx/src/core/ngx_open_file_cache.c index c44ac96b8b7..4df2134b2bd 100644 --- a/usr.sbin/nginx/src/core/ngx_open_file_cache.c +++ b/usr.sbin/nginx/src/core/ngx_open_file_cache.c @@ -25,6 +25,10 @@ static void ngx_open_file_cache_cleanup(void *data); #if (NGX_HAVE_OPENAT) static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); +#if (NGX_HAVE_O_PATH) +static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, + ngx_log_t *log); +#endif #endif static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, @@ -124,7 +128,7 @@ ngx_open_file_cache_cleanup(void *data) if (cache->current) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "%d items still leave in open file cache", + "%ui items still leave in open file cache", cache->current); } @@ -517,10 +521,17 @@ ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, goto failed; } +#if (NGX_HAVE_O_PATH) + if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) { + err = ngx_errno; + goto failed; + } +#else if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { err = ngx_errno; goto failed; } +#endif if (fi.st_uid != atfi.st_uid) { err = NGX_ELOOP; @@ -541,8 +552,63 @@ failed: return NGX_INVALID_FILE; } + +#if (NGX_HAVE_O_PATH) + +static ngx_int_t +ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log) +{ + static ngx_uint_t use_fstat = 1; + + /* + * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain + * a descriptor without actually opening file or directory. It requires + * less permissions for path components, but till Linux 3.6 fstat() returns + * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag + * should be used instead. + * + * Three scenarios are handled in this function: + * + * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was + * backported by vendor. Then fstat() is used. + * + * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case + * the first call of fstat() returns EBADF and we fallback to fstatat() + * with AT_EMPTY_PATH which was introduced at the same time as O_PATH. + * + * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH + * support. Since descriptors are opened with O_PATH|O_RDONLY flags + * and O_PATH is ignored by the kernel then the O_RDONLY flag is + * actually used. In this case fstat() just works. + */ + + if (use_fstat) { + if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) { + return NGX_OK; + } + + if (ngx_errno != NGX_EBADF) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "fstat(O_PATH) failed with EBADF, " + "switching to fstatat(AT_EMPTY_PATH)"); + + use_fstat = 0; + } + + if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) { + return NGX_OK; + } + + return NGX_ERROR; +} + #endif +#endif /* NGX_HAVE_OPENAT */ + static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, diff --git a/usr.sbin/nginx/src/core/ngx_palloc.c b/usr.sbin/nginx/src/core/ngx_palloc.c index efbc24452bd..1f70f9eee29 100644 --- a/usr.sbin/nginx/src/core/ngx_palloc.c +++ b/usr.sbin/nginx/src/core/ngx_palloc.c @@ -105,11 +105,14 @@ ngx_reset_pool(ngx_pool_t *pool) } } - pool->large = NULL; - for (p = pool; p; p = p->d.next) { p->d.last = (u_char *) p + sizeof(ngx_pool_t); + p->d.failed = 0; } + + pool->current = pool; + pool->chain = NULL; + pool->large = NULL; } diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.c b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c new file mode 100644 index 00000000000..59ef010fc06 --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c @@ -0,0 +1,91 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +u_char * +ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, u_char *last) +{ + size_t len; + u_char ch, *p, *addr; + + p = buf; + len = last - buf; + + if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) { + goto invalid; + } + + p += 6; + len -= 6; + + if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol unknown protocol"); + p += 7; + goto skip; + } + + if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0 + || (p[3] != '4' && p[3] != '6') || p[4] != ' ') + { + goto invalid; + } + + p += 5; + addr = p; + + for ( ;; ) { + if (p == last) { + goto invalid; + } + + ch = *p++; + + if (ch == ' ') { + break; + } + + if (ch != ':' && ch != '.' + && (ch < 'a' || ch > 'f') + && (ch < 'A' || ch > 'F') + && (ch < '0' || ch > '9')) + { + goto invalid; + } + } + + len = p - addr - 1; + c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len); + + if (c->proxy_protocol_addr.data == NULL) { + return NULL; + } + + ngx_memcpy(c->proxy_protocol_addr.data, addr, len); + c->proxy_protocol_addr.len = len; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, + "PROXY protocol address: \"%V\"", &c->proxy_protocol_addr); + +skip: + + for ( /* void */ ; p < last - 1; p++) { + if (p[0] == CR && p[1] == LF) { + return p + 2; + } + } + +invalid: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "broken header: \"%*s\"", (size_t) (last - buf), buf); + + return NULL; +} diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.h b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h new file mode 100644 index 00000000000..4f3912512f1 --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h @@ -0,0 +1,23 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_ +#define _NGX_PROXY_PROTOCOL_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_PROXY_PROTOCOL_MAX_HEADER 107 + + +u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, + u_char *last); + + +#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_resolver.c b/usr.sbin/nginx/src/core/ngx_resolver.c index d59d0c47162..645738ce531 100644 --- a/usr.sbin/nginx/src/core/ngx_resolver.c +++ b/usr.sbin/nginx/src/core/ngx_resolver.c @@ -26,7 +26,7 @@ typedef struct { u_char nns_lo; u_char nar_hi; u_char nar_lo; -} ngx_resolver_query_t; +} ngx_resolver_hdr_t; typedef struct { @@ -70,7 +70,8 @@ static void ngx_resolver_read_response(ngx_event_t *rev); static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n); static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, - ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans); + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, + ngx_uint_t nan, ngx_uint_t ans); static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, @@ -88,10 +89,17 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); -static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, - ngx_uint_t n); +static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_uint_t rotate); static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len); +#if (NGX_HAVE_INET6) +static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r, + struct in6_addr *addr, uint32_t hash); +#endif + ngx_resolver_t * ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) @@ -134,6 +142,17 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) ngx_queue_init(&r->name_expire_queue); ngx_queue_init(&r->addr_expire_queue); +#if (NGX_HAVE_INET6) + r->ipv6 = 1; + + ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel, + ngx_resolver_rbtree_insert_addr6_value); + + ngx_queue_init(&r->addr6_resend_queue); + + ngx_queue_init(&r->addr6_expire_queue); +#endif + r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; @@ -171,6 +190,25 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) continue; } +#if (NGX_HAVE_INET6) + if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) { + + if (ngx_strcmp(&names[i].data[5], "on") == 0) { + r->ipv6 = 1; + + } else if (ngx_strcmp(&names[i].data[5], "off") == 0) { + r->ipv6 = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter: %V", &names[i]); + return NULL; + } + + continue; + } +#endif + ngx_memzero(&u, sizeof(ngx_url_t)); u.url = names[i]; @@ -220,6 +258,10 @@ ngx_resolver_cleanup(void *data) ngx_resolver_cleanup_tree(r, &r->addr_rbtree); +#if (NGX_HAVE_INET6) + ngx_resolver_cleanup_tree(r, &r->addr6_rbtree); +#endif + if (r->event) { ngx_free(r->event); } @@ -281,7 +323,11 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) temp->state = NGX_OK; temp->naddrs = 1; temp->addrs = &temp->addr; - temp->addr = addr; + temp->addr.sockaddr = (struct sockaddr *) &temp->sin; + temp->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&temp->sin, sizeof(struct sockaddr_in)); + temp->sin.sin_family = AF_INET; + temp->sin.sin_addr.s_addr = addr; temp->quick = 1; return temp; @@ -310,6 +356,10 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) r = ctx->resolver; + if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') { + ctx->name.len--; + } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve: \"%V\"", &ctx->name); @@ -411,18 +461,18 @@ done: } -/* NGX_RESOLVE_A only */ - static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) { uint32_t hash; - in_addr_t addr, *addrs; ngx_int_t rc; ngx_uint_t naddrs; + ngx_addr_t *addrs; ngx_resolver_ctx_t *next; ngx_resolver_node_t *rn; + ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); + hash = ngx_crc32_short(ctx->name.data, ctx->name.len); rn = ngx_resolver_lookup_name(r, &ctx->name, hash); @@ -439,22 +489,21 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); - naddrs = rn->naddrs; + naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs; +#if (NGX_HAVE_INET6) + naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6; +#endif if (naddrs) { - /* NGX_RESOLVE_A answer */ + if (naddrs == 1 && rn->naddrs == 1) { + addrs = NULL; - if (naddrs != 1) { - addr = 0; - addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs); + } else { + addrs = ngx_resolver_export(r, rn, 1); if (addrs == NULL) { return NGX_ERROR; } - - } else { - addr = rn->u.addr; - addrs = NULL; } ctx->next = rn->waiting; @@ -465,8 +514,19 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) do { ctx->state = NGX_OK; ctx->naddrs = naddrs; - ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; - ctx->addr = addr; + + if (addrs == NULL) { + ctx->addrs = &ctx->addr; + ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin; + ctx->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in)); + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_addr.s_addr = rn->u.addr; + + } else { + ctx->addrs = addrs; + } + next = ctx->next; ctx->handler(ctx); @@ -474,7 +534,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ctx = next; } while (ctx); - if (addrs) { + if (addrs != NULL) { + ngx_resolver_free(r, addrs->sockaddr); ngx_resolver_free(r, addrs); } @@ -524,16 +585,25 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) if (rn->query) { ngx_resolver_free_locked(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif } if (rn->cnlen) { ngx_resolver_free_locked(r, rn->u.cname); } - if (rn->naddrs > 1) { + if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) { ngx_resolver_free_locked(r, rn->u.addrs); } +#if (NGX_HAVE_INET6) + if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) { + ngx_resolver_free_locked(r, rn->u6.addrs6); + } +#endif + /* unlock alloc mutex */ } else { @@ -552,6 +622,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) rn->node.key = hash; rn->nlen = (u_short) ctx->name.len; rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif ngx_rbtree_insert(&r->name_rbtree, &rn->node); } @@ -575,6 +648,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return NGX_OK; } + rn->naddrs = (u_short) -1; +#if (NGX_HAVE_INET6) + rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; +#endif + if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } @@ -601,9 +679,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + rn->code = 0; rn->cnlen = 0; - rn->naddrs = 0; rn->valid = 0; + rn->ttl = NGX_MAX_UINT32_VALUE; rn->waiting = ctx; ctx->state = NGX_AGAIN; @@ -630,16 +709,57 @@ ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx) { u_char *name; + in_addr_t addr; + ngx_queue_t *resend_queue, *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_t *r; + struct sockaddr_in *sin; ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + struct sockaddr_in6 *sin6; +#endif + +#if (NGX_SUPPRESS_WARN) + addr = 0; +#if (NGX_HAVE_INET6) + hash = 0; + sin6 = NULL; +#endif +#endif r = ctx->resolver; - ctx->addr = ntohl(ctx->addr); + switch (ctx->addr.sockaddr->sa_family) { - /* lock addr mutex */ +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); + + tree = &r->addr6_rbtree; + resend_queue = &r->addr6_resend_queue; + expire_queue = &r->addr6_expire_queue; + + 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, ctx->addr); + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + tree = &r->addr_rbtree; + resend_queue = &r->addr_resend_queue; + expire_queue = &r->addr_expire_queue; + } if (rn) { @@ -651,7 +771,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); name = ngx_resolver_dup(r, rn->name, rn->nlen); if (name == NULL) { @@ -687,6 +807,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif } else { rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); @@ -694,16 +817,36 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } - rn->node.key = ctx->addr; + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + rn->addr6 = sin6->sin6_addr; + rn->node.key = hash; + break; +#endif + + default: /* AF_INET */ + rn->node.key = addr; + } + rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif - ngx_rbtree_insert(&r->addr_rbtree, &rn->node); + ngx_rbtree_insert(tree, &rn->node); } if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { goto failed; } + rn->naddrs = (u_short) -1; +#if (NGX_HAVE_INET6) + rn->naddrs6 = (u_short) -1; +#endif + if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } @@ -720,19 +863,20 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ngx_add_timer(ctx->event, ctx->timeout); - if (ngx_queue_empty(&r->addr_resend_queue)) { + if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); } rn->expire = ngx_time() + r->resend_timeout; - ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue); + ngx_queue_insert_head(resend_queue, &rn->queue); + rn->code = 0; rn->cnlen = 0; - rn->naddrs = 0; rn->name = NULL; rn->nlen = 0; rn->valid = 0; + rn->ttl = NGX_MAX_UINT32_VALUE; rn->waiting = ctx; /* unlock addr mutex */ @@ -744,7 +888,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) failed: if (rn) { - ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); if (rn->query) { ngx_resolver_free(r, rn->query); @@ -769,12 +913,33 @@ 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; + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + tree = &r->addr6_rbtree; + expire_queue = &r->addr6_expire_queue; + break; +#endif + + default: /* AF_INET */ + tree = &r->addr_rbtree; + expire_queue = &r->addr_expire_queue; + } + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve addr done: %i", ctx->state); @@ -786,7 +951,21 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { - rn = ngx_resolver_lookup_addr(r, ctx->addr); + 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); + } if (rn) { p = &rn->waiting; @@ -804,17 +983,22 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) } } - addr = ntohl(ctx->addr); + { + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addrtext; - ngx_log_error(NGX_LOG_ALERT, r->log, 0, - "could not cancel %ud.%ud.%ud.%ud resolving", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + addrtext.data = text; + addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen, + text, NGX_SOCKADDR_STRLEN, 0); + + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %V resolving", &addrtext); + } } done: - ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue); + ngx_resolver_expire(r, tree, expire_queue); /* unlock addr mutex */ @@ -896,16 +1080,33 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) uc->connection->read->resolver = 1; } - n = ngx_send(uc->connection, rn->query, rn->qlen); + if (rn->naddrs == (u_short) -1) { + n = ngx_send(uc->connection, rn->query, rn->qlen); - if (n == -1) { - return NGX_ERROR; + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) rn->qlen) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); + return NGX_ERROR; + } } - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); - return NGX_ERROR; +#if (NGX_HAVE_INET6) + if (rn->query6 && rn->naddrs6 == (u_short) -1) { + n = ngx_send(uc->connection, rn->query6, rn->qlen); + + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) rn->qlen) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete"); + return NGX_ERROR; + } } +#endif return NGX_OK; } @@ -915,6 +1116,9 @@ static void ngx_resolver_resend_handler(ngx_event_t *ev) { time_t timer, atimer, ntimer; +#if (NGX_HAVE_INET6) + time_t a6timer; +#endif ngx_resolver_t *r; r = ev->data; @@ -934,16 +1138,36 @@ ngx_resolver_resend_handler(ngx_event_t *ev) /* unlock addr mutex */ - if (ntimer == 0) { +#if (NGX_HAVE_INET6) + + /* lock addr6 mutex */ + + a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue); + + /* unlock addr6 mutex */ + +#endif + + timer = ntimer; + + if (timer == 0) { timer = atimer; - } else if (atimer == 0) { - timer = ntimer; + } else if (atimer) { + timer = ngx_min(timer, atimer); + } - } else { - timer = (atimer < ntimer) ? atimer : ntimer; +#if (NGX_HAVE_INET6) + + if (timer == 0) { + timer = a6timer; + + } else if (a6timer) { + timer = ngx_min(timer, a6timer); } +#endif + if (timer) { ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000)); } @@ -1021,39 +1245,42 @@ ngx_resolver_read_response(ngx_event_t *rev) static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) { - char *err; - size_t len; - ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, - qtype, qclass; - ngx_queue_t *q; - ngx_resolver_qs_t *qs; - ngx_resolver_node_t *rn; - ngx_resolver_query_t *query; - - if ((size_t) n < sizeof(ngx_resolver_query_t)) { + char *err; + ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, + qtype, qclass; +#if (NGX_HAVE_INET6) + ngx_uint_t qident6; +#endif + ngx_queue_t *q; + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *response; + ngx_resolver_node_t *rn; + + if (n < sizeof(ngx_resolver_hdr_t)) { goto short_response; } - query = (ngx_resolver_query_t *) buf; + response = (ngx_resolver_hdr_t *) buf; - ident = (query->ident_hi << 8) + query->ident_lo; - flags = (query->flags_hi << 8) + query->flags_lo; - nqs = (query->nqs_hi << 8) + query->nqs_lo; - nan = (query->nan_hi << 8) + query->nan_lo; + ident = (response->ident_hi << 8) + response->ident_lo; + flags = (response->flags_hi << 8) + response->flags_lo; + nqs = (response->nqs_hi << 8) + response->nqs_lo; + nan = (response->nan_hi << 8) + response->nan_lo; ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", ident, flags, nqs, nan, - (query->nns_hi << 8) + query->nns_lo, - (query->nar_hi << 8) + query->nar_lo); + (response->nns_hi << 8) + response->nns_lo, + (response->nar_hi << 8) + response->nar_lo); - if (!(flags & 0x8000)) { + /* response to a standard query */ + if ((flags & 0xf870) != 0x8000) { ngx_log_error(r->log_level, r->log, 0, "invalid DNS response %ui fl:%04Xui", ident, flags); return; } - code = flags & 0x7f; + code = flags & 0xf; if (code == NGX_RESOLVE_FORMERR) { @@ -1067,12 +1294,18 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) qident = (rn->query[0] << 8) + rn->query[1]; if (qident == ident) { - ngx_log_error(r->log_level, r->log, 0, - "DNS error (%ui: %s), query id:%ui, name:\"%*s\"", - code, ngx_resolver_strerror(code), ident, - rn->nlen, rn->name); - return; + goto dns_error_name; + } + +#if (NGX_HAVE_INET6) + if (rn->query6) { + qident6 = (rn->query6[0] << 8) + rn->query6[1]; + + if (qident6 == ident) { + goto dns_error_name; + } } +#endif } goto dns_error; @@ -1087,22 +1320,21 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) goto done; } - i = sizeof(ngx_resolver_query_t); + i = sizeof(ngx_resolver_hdr_t); while (i < (ngx_uint_t) n) { if (buf[i] == '\0') { goto found; } - len = buf[i]; - i += 1 + len; + i += 1 + buf[i]; } goto short_response; found: - if (i++ == 0) { + if (i++ == sizeof(ngx_resolver_hdr_t)) { err = "zero-length domain name in DNS response"; goto done; } @@ -1130,8 +1362,11 @@ found: switch (qtype) { case NGX_RESOLVE_A: +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: +#endif - ngx_resolver_process_a(r, buf, n, ident, code, nan, + ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, i + sizeof(ngx_resolver_qs_t)); break; @@ -1152,7 +1387,7 @@ found: short_response: - err = "short dns response"; + err = "short DNS response"; done: @@ -1160,6 +1395,14 @@ done: return; +dns_error_name: + + ngx_log_error(r->log_level, r->log, 0, + "DNS error (%ui: %s), query id:%ui, name:\"%*s\"", + code, ngx_resolver_strerror(code), ident, + rn->nlen, rn->name); + return; + dns_error: ngx_log_error(r->log_level, r->log, 0, @@ -1171,21 +1414,29 @@ dns_error: static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, - ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans) + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, + ngx_uint_t nan, ngx_uint_t ans) { char *err; u_char *cname; size_t len; int32_t ttl; uint32_t hash; - in_addr_t addr, *addrs; + in_addr_t *addr; ngx_str_t name; - ngx_uint_t qtype, qident, naddrs, a, i, n, start; + ngx_addr_t *addrs; + ngx_uint_t type, class, qident, naddrs, a, i, n, start; +#if (NGX_HAVE_INET6) + struct in6_addr *addr6; +#endif ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; - if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) { + if (ngx_resolver_copy(r, &name, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + last) + != NGX_OK) + { return; } @@ -1197,28 +1448,113 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, rn = ngx_resolver_lookup_name(r, &name, hash); - if (rn == NULL || rn->query == NULL) { + if (rn == NULL) { ngx_log_error(r->log_level, r->log, 0, "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); goto failed; } - qident = (rn->query[0] << 8) + rn->query[1]; + switch (qtype) { + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + rn->naddrs6 = 0; + qident = (rn->query6[0] << 8) + rn->query6[1]; + + break; +#endif + + default: /* NGX_RESOLVE_A */ + + if (rn->query == NULL || rn->naddrs != (u_short) -1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + rn->naddrs = 0; + qident = (rn->query[0] << 8) + rn->query[1]; + } if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, "wrong ident %ui response for %V, expect %ui", ident, &name, qident); + ngx_resolver_free(r, name.data); goto failed; } ngx_resolver_free(r, name.data); + if (code == 0 && rn->code) { + code = rn->code; + } + if (code == 0 && nan == 0) { - code = 3; /* NXDOMAIN */ + +#if (NGX_HAVE_INET6) + switch (qtype) { + + case NGX_RESOLVE_AAAA: + + if (rn->naddrs == (u_short) -1) { + goto next; + } + + if (rn->naddrs) { + goto export; + } + + break; + + default: /* NGX_RESOLVE_A */ + + if (rn->naddrs6 == (u_short) -1) { + goto next; + } + + if (rn->naddrs6) { + goto export; + } + } +#endif + + code = NGX_RESOLVE_NXDOMAIN; } if (code) { + +#if (NGX_HAVE_INET6) + switch (qtype) { + + case NGX_RESOLVE_AAAA: + + if (rn->naddrs == (u_short) -1) { + rn->code = (u_char) code; + goto next; + } + + break; + + default: /* NGX_RESOLVE_A */ + + if (rn->naddrs6 == (u_short) -1) { + rn->code = (u_char) code; + goto next; + } + } +#endif + next = rn->waiting; rn->waiting = NULL; @@ -1231,11 +1567,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, /* unlock name mutex */ while (next) { - ctx = next; - ctx->state = code; - next = ctx->next; + ctx = next; + ctx->state = code; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } return; @@ -1243,11 +1579,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, i = ans; naddrs = 0; - addr = 0; - addrs = NULL; cname = NULL; - qtype = 0; - ttl = 0; for (a = 0; a < nan; a++) { @@ -1273,7 +1605,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, test_length: if (i - start < 2) { - err = "invalid name in dns response"; + err = "invalid name in DNS response"; goto invalid; } @@ -1285,115 +1617,239 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, an = (ngx_resolver_an_t *) &buf[i]; - qtype = (an->type_hi << 8) + an->type_lo; + type = (an->type_hi << 8) + an->type_lo; + class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + if (ttl < 0) { ttl = 0; } - if (qtype == NGX_RESOLVE_A) { + rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl); - i += sizeof(ngx_resolver_an_t); + i += sizeof(ngx_resolver_an_t); + + switch (type) { + + case NGX_RESOLVE_A: + + if (qtype != NGX_RESOLVE_A) { + err = "unexpected A record in DNS response"; + goto invalid; + } - if (i + len > last) { + if (len != 4) { + err = "invalid A record in DNS response"; + goto invalid; + } + + if (i + 4 > last) { goto short_response; } - addr = htonl((buf[i] << 24) + (buf[i + 1] << 16) - + (buf[i + 2] << 8) + (buf[i + 3])); + naddrs++; + + break; + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + if (qtype != NGX_RESOLVE_AAAA) { + err = "unexpected AAAA record in DNS response"; + goto invalid; + } + + if (len != 16) { + err = "invalid AAAA record in DNS response"; + goto invalid; + } + + if (i + 16 > last) { + goto short_response; + } naddrs++; - i += len; + break; +#endif - } else if (qtype == NGX_RESOLVE_CNAME) { - cname = &buf[i] + sizeof(ngx_resolver_an_t); - i += sizeof(ngx_resolver_an_t) + len; + case NGX_RESOLVE_CNAME: - } else if (qtype == NGX_RESOLVE_DNAME) { - i += sizeof(ngx_resolver_an_t) + len; + cname = &buf[i]; + + break; + + case NGX_RESOLVE_DNAME: + + break; + + default: - } else { ngx_log_error(r->log_level, r->log, 0, - "unexpected qtype %ui", qtype); + "unexpected RR type %ui", type); } + + i += len; } ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver naddrs:%ui cname:%p ttl:%d", - naddrs, cname, ttl); + "resolver naddrs:%ui cname:%p ttl:%uD", + naddrs, cname, rn->ttl); if (naddrs) { - if (naddrs == 1) { - rn->u.addr = addr; + switch (qtype) { - } else { +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: - addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t)); - if (addrs == NULL) { - return; + if (naddrs == 1) { + addr6 = &rn->u6.addr6; + rn->naddrs6 = 1; + + } else { + addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr)); + if (addr6 == NULL) { + goto failed; + } + + rn->u6.addrs6 = addr6; + rn->naddrs6 = (u_short) naddrs; } - n = 0; - i = ans; +#if (NGX_SUPPRESS_WARN) + addr = NULL; +#endif - for (a = 0; a < nan; a++) { + break; +#endif - for ( ;; ) { + default: /* NGX_RESOLVE_A */ - if (buf[i] & 0xc0) { - i += 2; - goto ok; - } + if (naddrs == 1) { + addr = &rn->u.addr; + rn->naddrs = 1; - if (buf[i] == 0) { - i++; - goto ok; - } + } else { + addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t)); + if (addr == NULL) { + goto failed; + } + + rn->u.addrs = addr; + rn->naddrs = (u_short) naddrs; + } + +#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN) + addr6 = NULL; +#endif + } - i += 1 + buf[i]; + n = 0; + i = ans; + + for (a = 0; a < nan; a++) { + + for ( ;; ) { + + if (buf[i] & 0xc0) { + i += 2; + break; + } + + if (buf[i] == 0) { + i++; + break; } - ok: + i += 1 + buf[i]; + } + + an = (ngx_resolver_an_t *) &buf[i]; - an = (ngx_resolver_an_t *) &buf[i]; + type = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; - qtype = (an->type_hi << 8) + an->type_lo; - len = (an->len_hi << 8) + an->len_lo; + i += sizeof(ngx_resolver_an_t); - i += sizeof(ngx_resolver_an_t); + if (type == NGX_RESOLVE_A) { - if (qtype == NGX_RESOLVE_A) { + addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + + (buf[i + 2] << 8) + (buf[i + 3])); - addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16) - + (buf[i + 2] << 8) + (buf[i + 3])); + if (++n == naddrs) { - if (n == naddrs) { - break; +#if (NGX_HAVE_INET6) + if (rn->naddrs6 == (u_short) -1) { + goto next; } +#endif + + break; } + } + +#if (NGX_HAVE_INET6) + else if (type == NGX_RESOLVE_AAAA) { + + ngx_memcpy(addr6[n].s6_addr, &buf[i], 16); + + if (++n == naddrs) { + + if (rn->naddrs == (u_short) -1) { + goto next; + } - i += len; + break; + } } +#endif - rn->u.addrs = addrs; + i += len; + } + } - addrs = ngx_resolver_dup(r, rn->u.addrs, - naddrs * sizeof(in_addr_t)); + if (rn->naddrs != (u_short) -1 +#if (NGX_HAVE_INET6) + && rn->naddrs6 != (u_short) -1 +#endif + && rn->naddrs +#if (NGX_HAVE_INET6) + + rn->naddrs6 +#endif + > 0) + { + +#if (NGX_HAVE_INET6) + export: +#endif + + naddrs = rn->naddrs; +#if (NGX_HAVE_INET6) + naddrs += rn->naddrs6; +#endif + + if (naddrs == 1 && rn->naddrs == 1) { + addrs = NULL; + + } else { + addrs = ngx_resolver_export(r, rn, 0); if (addrs == NULL) { - return; + goto failed; } } - rn->naddrs = (u_short) naddrs; - ngx_queue_remove(&rn->queue); - rn->valid = ngx_time() + (r->valid ? r->valid : ttl); + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); rn->expire = ngx_time() + r->expire; ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); @@ -1404,31 +1860,56 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, /* unlock name mutex */ while (next) { - ctx = next; - ctx->state = NGX_OK; - ctx->naddrs = naddrs; - ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; - ctx->addr = addr; - next = ctx->next; + ctx = next; + ctx->state = NGX_OK; + ctx->naddrs = naddrs; + + if (addrs == NULL) { + ctx->addrs = &ctx->addr; + ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin; + ctx->addr.socklen = sizeof(struct sockaddr_in); + ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in)); + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_addr.s_addr = rn->u.addr; + + } else { + ctx->addrs = addrs; + } - ctx->handler(ctx); + next = ctx->next; + + ctx->handler(ctx); } - if (naddrs > 1) { + if (addrs != NULL) { + ngx_resolver_free(r, addrs->sockaddr); ngx_resolver_free(r, addrs); } ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif return; + } - } else if (cname) { + if (cname) { /* CNAME only */ - if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) { - return; + if (rn->naddrs == (u_short) -1 +#if (NGX_HAVE_INET6) + || rn->naddrs6 == (u_short) -1 +#endif + ) + { + goto next; + } + + if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) { + goto failed; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, @@ -1439,7 +1920,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, rn->cnlen = (u_short) name.len; rn->u.cname = name.data; - rn->valid = ngx_time() + (r->valid ? r->valid : ttl); + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); rn->expire = ngx_time() + r->expire; ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); @@ -1455,18 +1936,22 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_resolver_free(r, rn->query); rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif + + /* unlock name mutex */ return; } ngx_log_error(r->log_level, r->log, 0, - "no A or CNAME types in DNS responses, unknown query type: %ui", - qtype); + "no A or CNAME types in DNS response"); return; short_response: - err = "short dns response"; + err = "short DNS response"; invalid: @@ -1478,9 +1963,9 @@ invalid: failed: - /* unlock name mutex */ +next: - ngx_resolver_free(r, name.data); + /* unlock name mutex */ return; } @@ -1492,47 +1977,123 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, { char *err; size_t len; + u_char text[NGX_SOCKADDR_STRLEN]; in_addr_t addr; int32_t ttl; - ngx_int_t digit; + ngx_int_t octet; ngx_str_t name; - ngx_uint_t i, mask, qident; + ngx_uint_t i, mask, qident, class; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + ngx_int_t digit; + struct in6_addr addr6; +#endif - if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) { - goto invalid_in_addr_arpa; + if (ngx_resolver_copy(r, NULL, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + n) + != NGX_OK) + { + return; } + /* AF_INET */ + addr = 0; - i = 12; + i = sizeof(ngx_resolver_hdr_t); for (mask = 0; mask < 32; mask += 8) { len = buf[i++]; - digit = ngx_atoi(&buf[i], len); - if (digit == NGX_ERROR || digit > 255) { + octet = ngx_atoi(&buf[i], len); + if (octet == NGX_ERROR || octet > 255) { goto invalid_in_addr_arpa; } - addr += digit << mask; + addr += octet << mask; i += len; } - if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) { - goto invalid_in_addr_arpa; + if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) { + i += sizeof("\7in-addr\4arpa"); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + tree = &r->addr_rbtree; + expire_queue = &r->addr_expire_queue; + + addr = htonl(addr); + name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN); + name.data = text; + + goto valid; } - /* lock addr mutex */ +invalid_in_addr_arpa: + +#if (NGX_HAVE_INET6) + + i = sizeof(ngx_resolver_hdr_t); + + for (octet = 15; octet >= 0; octet--) { + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] = (u_char) digit; + + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] += (u_char) (digit * 16); + } + + if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) { + i += sizeof("\3ip6\4arpa"); + + /* lock addr mutex */ + + hash = ngx_crc32_short(addr6.s6_addr, 16); + rn = ngx_resolver_lookup_addr6(r, &addr6, hash); + + tree = &r->addr6_rbtree; + expire_queue = &r->addr6_expire_queue; + + name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN); + name.data = text; + + goto valid; + } - rn = ngx_resolver_lookup_addr(r, addr); +invalid_ip6_arpa: +#endif + + ngx_log_error(r->log_level, r->log, 0, + "invalid in-addr.arpa or ip6.arpa name in DNS response"); + return; + +valid: if (rn == NULL || rn->query == NULL) { ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + "unexpected response for %V", &name); goto failed; } @@ -1540,14 +2101,13 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui", - ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff, qident); + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); goto failed; } if (code == 0 && nan == 0) { - code = 3; /* NXDOMAIN */ + code = NGX_RESOLVE_NXDOMAIN; } if (code) { @@ -1556,42 +2116,49 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_queue_remove(&rn->queue); - ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); ngx_resolver_free_node(r, rn); /* unlock addr mutex */ while (next) { - ctx = next; - ctx->state = code; - next = ctx->next; + ctx = next; + ctx->state = code; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } return; } - i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t); + i += sizeof(ngx_resolver_qs_t); - if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) { + if (i + 2 + sizeof(ngx_resolver_an_t) >= n) { goto short_response; } - /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */ + /* compression pointer to *.arpa */ - if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) { - err = "invalid in-addr.arpa name in DNS response"; + if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) { + err = "invalid in-addr.arpa or ip6.arpa name in DNS response"; goto invalid; } an = (ngx_resolver_an_t *) &buf[i + 2]; + class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + if (ttl < 0) { ttl = 0; } @@ -1599,16 +2166,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qt:%ui cl:%ui len:%uz", (an->type_hi << 8) + an->type_lo, - (an->class_hi << 8) + an->class_lo, len); + class, len); i += 2 + sizeof(ngx_resolver_an_t); - if (i + len > (ngx_uint_t) n) { + if (i + len > n) { goto short_response; } - if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) { - return; + if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) { + goto failed; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name); @@ -1634,7 +2201,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, rn->valid = ngx_time() + (r->valid ? r->valid : ttl); rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); next = rn->waiting; rn->waiting = NULL; @@ -1642,24 +2209,18 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, /* unlock addr mutex */ while (next) { - ctx = next; - ctx->state = NGX_OK; - ctx->name = name; - next = ctx->next; + ctx = next; + ctx->state = NGX_OK; + ctx->name = name; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); } ngx_resolver_free(r, name.data); return; -invalid_in_addr_arpa: - - ngx_log_error(r->log_level, r->log, 0, - "invalid in-addr.arpa name in DNS response"); - return; - short_response: err = "short DNS response"; @@ -1752,6 +2313,52 @@ ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) } +#if (NGX_HAVE_INET6) + +static ngx_resolver_node_t * +ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_resolver_node_t *rn; + + node = r->addr6_rbtree.root; + sentinel = r->addr6_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + rn = (ngx_resolver_node_t *) node; + + rc = ngx_memcmp(addr, &rn->addr6, 16); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; + } + + /* not found */ + + return NULL; +} + +#endif + + static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) @@ -1793,20 +2400,74 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, } +#if (NGX_HAVE_INET6) + +static void +ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_resolver_node_t *rn, *rn_temp; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + rn = (ngx_resolver_node_t *) node; + rn_temp = (ngx_resolver_node_t *) temp; + + p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16) + < 0) ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + +#endif + + static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) { - u_char *p, *s; - size_t len, nlen; - ngx_uint_t ident; - ngx_resolver_qs_t *qs; - ngx_resolver_query_t *query; + 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; - len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t); + 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); +#else p = ngx_resolver_alloc(ctx->resolver, len); +#endif if (p == NULL) { return NGX_ERROR; } @@ -1814,12 +2475,18 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) rn->qlen = (u_short) len; rn->query = p; - query = (ngx_resolver_query_t *) p; +#if (NGX_HAVE_INET6) + if (r->ipv6) { + rn->query6 = p + len; + } +#endif + + query = (ngx_resolver_hdr_t *) p; ident = ngx_random(); ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, - "resolve: \"%V\" %i", &ctx->name, ident & 0xffff); + "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff); query->ident_hi = (u_char) ((ident >> 8) & 0xff); query->ident_lo = (u_char) (ident & 0xff); @@ -1833,14 +2500,14 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) query->nns_hi = 0; query->nns_lo = 0; query->nar_hi = 0; query->nar_lo = 0; - p += sizeof(ngx_resolver_query_t) + nlen; + p += sizeof(ngx_resolver_hdr_t) + nlen; qs = (ngx_resolver_qs_t *) p; /* query type */ - qs->type_hi = 0; qs->type_lo = (u_char) ctx->type; + qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A; - /* IP query class */ + /* IN query class */ qs->class_hi = 0; qs->class_lo = 1; /* convert "www.example.com" to "\3www\7example\3com\0" */ @@ -1876,24 +2543,66 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) *p = (u_char) len; +#if (NGX_HAVE_INET6) + if (!r->ipv6) { + return NGX_OK; + } + + p = rn->query6; + + ngx_memcpy(p, rn->query, rn->qlen); + + query = (ngx_resolver_hdr_t *) p; + + ident = ngx_random(); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, + "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + p += sizeof(ngx_resolver_hdr_t) + nlen; + + qs = (ngx_resolver_qs_t *) p; + + qs->type_lo = NGX_RESOLVE_AAAA; +#endif + return NGX_OK; } -/* AF_INET only */ - static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) { - u_char *p, *d; - size_t len; - ngx_int_t n; - ngx_uint_t ident; - ngx_resolver_query_t *query; + u_char *p, *d; + size_t len; + in_addr_t addr; + ngx_int_t n; + ngx_uint_t ident; + ngx_resolver_hdr_t *query; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (ctx->addr.sockaddr->sa_family) { - len = sizeof(ngx_resolver_query_t) - + sizeof(".255.255.255.255.in-addr.arpa.") - 1 - + sizeof(ngx_resolver_qs_t); +#if (NGX_HAVE_INET6) + case AF_INET6: + len = sizeof(ngx_resolver_hdr_t) + + 64 + sizeof(".ip6.arpa.") - 1 + + sizeof(ngx_resolver_qs_t); + + break; +#endif + + default: /* AF_INET */ + len = sizeof(ngx_resolver_hdr_t) + + sizeof(".255.255.255.255.in-addr.arpa.") - 1 + + sizeof(ngx_resolver_qs_t); + } p = ngx_resolver_alloc(ctx->resolver, len); if (p == NULL) { @@ -1901,7 +2610,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) } rn->query = p; - query = (ngx_resolver_query_t *) p; + query = (ngx_resolver_hdr_t *) p; ident = ngx_random(); @@ -1917,20 +2626,43 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) query->nns_hi = 0; query->nns_lo = 0; query->nar_hi = 0; query->nar_lo = 0; - p += sizeof(ngx_resolver_query_t); + p += sizeof(ngx_resolver_hdr_t); + + switch (ctx->addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; + + for (n = 15; n >= 0; n--) { + p = ngx_sprintf(p, "\1%xd\1%xd", + sin6->sin6_addr.s6_addr[n] & 0xf, + (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf); + } + + p = ngx_cpymem(p, "\3ip6\4arpa\0", 10); - for (n = 0; n < 32; n += 8) { - d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff); - *p = (u_char) (d - &p[1]); - p = d; + break; +#endif + + default: /* AF_INET */ + + sin = (struct sockaddr_in *) ctx->addr.sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + for (n = 0; n < 32; n += 8) { + d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff); + *p = (u_char) (d - &p[1]); + p = d; + } + + p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14); } - /* query type "PTR", IP query class */ - ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18); + /* query type "PTR", IN query class */ + p = ngx_cpymem(p, "\0\14\0\1", 4); - rn->qlen = (u_short) - (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t) - - rn->query); + rn->qlen = (u_short) (p - rn->query); return NGX_OK; } @@ -2012,7 +2744,7 @@ done: n = *src++; } else { - ngx_memcpy(dst, src, n); + ngx_strlow(dst, src, n); dst += n; src += n; @@ -2061,10 +2793,16 @@ ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) ngx_resolver_free_locked(r, rn->u.cname); } - if (rn->naddrs > 1) { + if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) { ngx_resolver_free_locked(r, rn->u.addrs); } +#if (NGX_HAVE_INET6) + if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) { + ngx_resolver_free_locked(r, rn->u6.addrs6); + } +#endif + ngx_resolver_free_locked(r, rn); /* unlock alloc mutex */ @@ -2136,27 +2874,84 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size) } -static in_addr_t * -ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n) +static ngx_addr_t * +ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_uint_t rotate) { - void *dst, *p; - ngx_uint_t j; + ngx_addr_t *dst; + ngx_uint_t d, i, j, n; + u_char (*sockaddr)[NGX_SOCKADDRLEN]; + in_addr_t *addr; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr *addr6; + struct sockaddr_in6 *sin6; +#endif - dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t)); + n = rn->naddrs; +#if (NGX_HAVE_INET6) + n += rn->naddrs6; +#endif + dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t)); if (dst == NULL) { - return dst; + return NULL; } - j = ngx_random() % n; + sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN); + if (sockaddr == NULL) { + ngx_resolver_free(r, dst); + return NULL; + } - if (j == 0) { - ngx_memcpy(dst, src, n * sizeof(in_addr_t)); - return dst; + i = 0; + d = rotate ? ngx_random() % n : 0; + + if (rn->naddrs) { + j = rotate ? ngx_random() % rn->naddrs : 0; + + addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs; + + do { + sin = (struct sockaddr_in *) sockaddr[d]; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr[j++]; + dst[d].sockaddr = (struct sockaddr *) sin; + dst[d++].socklen = sizeof(struct sockaddr_in); + + if (d == n) { + d = 0; + } + + if (j == rn->naddrs) { + j = 0; + } + } while (++i < rn->naddrs); } - p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t)); - ngx_memcpy(p, src, j * sizeof(in_addr_t)); +#if (NGX_HAVE_INET6) + if (rn->naddrs6) { + j = rotate ? ngx_random() % rn->naddrs6 : 0; + + addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6; + + do { + sin6 = (struct sockaddr_in6 *) sockaddr[d]; + sin6->sin6_family = AF_INET6; + ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16); + dst[d].sockaddr = (struct sockaddr *) sin6; + dst[d++].socklen = sizeof(struct sockaddr_in6); + + if (d == n) { + d = 0; + } + + if (j == rn->naddrs6) { + j = 0; + } + } while (++i < n); + } +#endif return dst; } @@ -2221,7 +3016,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s); - if (s == -1) { + if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; @@ -2242,14 +3037,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - ngx_free_connection(c); - - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - - return NGX_ERROR; + goto failed; } rev = c->read; @@ -2274,7 +3062,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) #endif ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, - "connect to %V, fd:%d #%d", &uc->server, s, c->number); + "connect to %V, fd:%d #%uA", &uc->server, s, c->number); rc = connect(s, uc->sockaddr, uc->socklen); @@ -2284,7 +3072,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "connect() failed"); - return NGX_ERROR; + goto failed; } /* UDP sockets are always ready to write */ @@ -2298,16 +3086,23 @@ ngx_udp_connect(ngx_udp_connection_t *uc) /* eventport event type has no meaning: oneshot only */ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } } else { /* rtsig */ if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; + goto failed; } } return NGX_OK; + +failed: + + ngx_close_connection(c); + uc->connection = NULL; + + return NGX_ERROR; } diff --git a/usr.sbin/nginx/src/core/ngx_resolver.h b/usr.sbin/nginx/src/core/ngx_resolver.h index ae34ca56d3a..264c8c42b98 100644 --- a/usr.sbin/nginx/src/core/ngx_resolver.h +++ b/usr.sbin/nginx/src/core/ngx_resolver.h @@ -18,6 +18,9 @@ #define NGX_RESOLVE_PTR 12 #define NGX_RESOLVE_MX 15 #define NGX_RESOLVE_TXT 16 +#if (NGX_HAVE_INET6) +#define NGX_RESOLVE_AAAA 28 +#endif #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 @@ -54,10 +57,18 @@ typedef struct { /* 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) */ + struct in6_addr addr6; +#endif + u_short nlen; u_short qlen; u_char *query; +#if (NGX_HAVE_INET6) + u_char *query6; +#endif union { in_addr_t addr; @@ -65,11 +76,22 @@ typedef struct { u_char *cname; } u; + u_char code; u_short naddrs; u_short cnlen; +#if (NGX_HAVE_INET6) + union { + struct in6_addr addr6; + struct in6_addr *addrs6; + } u6; + + u_short naddrs6; +#endif + time_t expire; time_t valid; + uint32_t ttl; ngx_resolver_ctx_t *waiting; } ngx_resolver_node_t; @@ -100,6 +122,14 @@ typedef struct { ngx_queue_t name_expire_queue; ngx_queue_t addr_expire_queue; +#if (NGX_HAVE_INET6) + ngx_uint_t ipv6; /* unsigned ipv6:1; */ + ngx_rbtree_t addr6_rbtree; + ngx_rbtree_node_t addr6_sentinel; + ngx_queue_t addr6_resend_queue; + ngx_queue_t addr6_expire_queue; +#endif + time_t resend_timeout; time_t expire; time_t valid; @@ -117,12 +147,12 @@ struct ngx_resolver_ctx_s { ngx_int_t ident; ngx_int_t state; - ngx_int_t type; ngx_str_t name; ngx_uint_t naddrs; - in_addr_t *addrs; - in_addr_t addr; + ngx_addr_t *addrs; + ngx_addr_t addr; + struct sockaddr_in sin; ngx_resolver_handler_pt handler; void *data; diff --git a/usr.sbin/nginx/src/core/ngx_slab.c b/usr.sbin/nginx/src/core/ngx_slab.c index ae9d6f3fc0e..be7927ce067 100644 --- a/usr.sbin/nginx/src/core/ngx_slab.c +++ b/usr.sbin/nginx/src/core/ngx_slab.c @@ -129,6 +129,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } + pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; } @@ -440,7 +441,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); n /= (sizeof(uintptr_t) * 8); - bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1)); + bitmap = (uintptr_t *) + ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); if (bitmap[n] & m) { @@ -657,7 +659,10 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages) } } - ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory"); + if (pool->log_nomem) { + ngx_slab_error(pool, NGX_LOG_CRIT, + "ngx_slab_alloc() failed: no memory"); + } return NULL; } diff --git a/usr.sbin/nginx/src/core/ngx_slab.h b/usr.sbin/nginx/src/core/ngx_slab.h index c5e420bfa8e..5735e3bb3b9 100644 --- a/usr.sbin/nginx/src/core/ngx_slab.h +++ b/usr.sbin/nginx/src/core/ngx_slab.h @@ -39,6 +39,8 @@ typedef struct { u_char *log_ctx; u_char zero; + unsigned log_nomem:1; + void *data; void *addr; } ngx_slab_pool_t; diff --git a/usr.sbin/nginx/src/core/ngx_string.c b/usr.sbin/nginx/src/core/ngx_string.c index 1d1989da24d..a4cfcdc7a5e 100644 --- a/usr.sbin/nginx/src/core/ngx_string.c +++ b/usr.sbin/nginx/src/core/ngx_string.c @@ -11,6 +11,8 @@ static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); +static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, + const u_char *basis, ngx_uint_t padding); static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis); @@ -486,7 +488,7 @@ ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, if (hexadecimal == 0) { - if (ui64 <= NGX_MAX_UINT32_VALUE) { + if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) { /* * To divide 64-bit numbers and to find remainders @@ -853,6 +855,46 @@ ngx_dns_strcmp(u_char *s1, u_char *s2) ngx_int_t +ngx_filename_cmp(u_char *s1, u_char *s2, size_t n) +{ + ngx_uint_t c1, c2; + + while (n) { + c1 = (ngx_uint_t) *s1++; + c2 = (ngx_uint_t) *s2++; + +#if (NGX_HAVE_CASELESS_FILESYSTEM) + c1 = tolower(c1); + c2 = tolower(c2); +#endif + + if (c1 == c2) { + + if (c1) { + n--; + continue; + } + + return 0; + } + + /* we need '/' to be the lowest character */ + + if (c1 == 0 || c2 == 0) { + return c1 - c2; + } + + c1 = (c1 == '/') ? 0 : c1; + c2 = (c2 == '/') ? 0 : c2; + + return c1 - c2; + } + + return 0; +} + + +ngx_int_t ngx_atoi(u_char *line, size_t n) { ngx_int_t value; @@ -1060,38 +1102,61 @@ ngx_hex_dump(u_char *dst, u_char *src, size_t len) void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src) { - u_char *d, *s; - size_t len; static u_char basis64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + ngx_encode_base64_internal(dst, src, basis64, 1); +} + + +void +ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src) +{ + static u_char basis64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + ngx_encode_base64_internal(dst, src, basis64, 0); +} + + +static void +ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis, + ngx_uint_t padding) +{ + u_char *d, *s; + size_t len; + len = src->len; s = src->data; d = dst->data; while (len > 2) { - *d++ = basis64[(s[0] >> 2) & 0x3f]; - *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)]; - *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; - *d++ = basis64[s[2] & 0x3f]; + *d++ = basis[(s[0] >> 2) & 0x3f]; + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; + *d++ = basis[s[2] & 0x3f]; s += 3; len -= 3; } if (len) { - *d++ = basis64[(s[0] >> 2) & 0x3f]; + *d++ = basis[(s[0] >> 2) & 0x3f]; if (len == 1) { - *d++ = basis64[(s[0] & 3) << 4]; - *d++ = '='; + *d++ = basis[(s[0] & 3) << 4]; + if (padding) { + *d++ = '='; + } } else { - *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)]; - *d++ = basis64[(s[1] & 0x0f) << 2]; + *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; + *d++ = basis[(s[1] & 0x0f) << 2]; } - *d++ = '='; + if (padding) { + *d++ = '='; + } } dst->len = d - dst->data; diff --git a/usr.sbin/nginx/src/core/ngx_string.h b/usr.sbin/nginx/src/core/ngx_string.h index 52c6f338d89..dc0be5b5532 100644 --- a/usr.sbin/nginx/src/core/ngx_string.h +++ b/usr.sbin/nginx/src/core/ngx_string.h @@ -167,6 +167,7 @@ ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2); ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2); +ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_atoi(u_char *line, size_t n); ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point); @@ -182,6 +183,7 @@ u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len); #define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3) void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src); +void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); diff --git a/usr.sbin/nginx/src/core/ngx_syslog.c b/usr.sbin/nginx/src/core/ngx_syslog.c new file mode 100644 index 00000000000..7c5de38b6cb --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_syslog.c @@ -0,0 +1,342 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#define NGX_SYSLOG_MAX_STR \ + NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \ + + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \ + + 32 /* tag */ + 2 /* colon, space */ + + +static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer); +static void ngx_syslog_cleanup(void *data); + + +static char *facilities[] = { + "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp", + "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7", + NULL +}; + +/* note 'error/warn' like in nginx.conf, not 'err/warning' */ +static char *severities[] = { + "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL +}; + +static ngx_log_t ngx_syslog_dummy_log; +static ngx_event_t ngx_syslog_dummy_event; + + +char * +ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + peer->pool = cf->pool; + peer->facility = NGX_CONF_UNSET_UINT; + peer->severity = NGX_CONF_UNSET_UINT; + + if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if (peer->server.sockaddr == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no syslog server specified"); + return NGX_CONF_ERROR; + } + + if (peer->facility == NGX_CONF_UNSET_UINT) { + peer->facility = 23; /* local7 */ + } + + if (peer->severity == NGX_CONF_UNSET_UINT) { + peer->severity = 6; /* info */ + } + + if (peer->tag.data == NULL) { + ngx_str_set(&peer->tag, "nginx"); + } + + peer->conn.fd = (ngx_socket_t) -1; + + return NGX_CONF_OK; +} + + +static char * +ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer) +{ + u_char *p, *comma, c; + size_t len; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t i; + + value = cf->args->elts; + + p = value[1].data + sizeof("syslog:") - 1; + + for ( ;; ) { + comma = (u_char *) ngx_strchr(p, ','); + + if (comma != NULL) { + len = comma - p; + *comma = '\0'; + + } else { + len = value[1].data + value[1].len - p; + } + + if (ngx_strncmp(p, "server=", 7) == 0) { + + if (peer->server.sockaddr != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"server\""); + return NGX_CONF_ERROR; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url.data = p + 7; + u.url.len = len - 7; + u.default_port = 514; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in syslog server \"%V\"", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + peer->server = u.addrs[0]; + + } else if (ngx_strncmp(p, "facility=", 9) == 0) { + + if (peer->facility != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"facility\""); + return NGX_CONF_ERROR; + } + + for (i = 0; facilities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, facilities[i]) == 0) { + peer->facility = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog facility \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "severity=", 9) == 0) { + + if (peer->severity != NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"severity\""); + return NGX_CONF_ERROR; + } + + for (i = 0; severities[i] != NULL; i++) { + + if (ngx_strcmp(p + 9, severities[i]) == 0) { + peer->severity = i; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog severity \"%s\"", p + 9); + return NGX_CONF_ERROR; + + } else if (ngx_strncmp(p, "tag=", 4) == 0) { + + if (peer->tag.data != NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate syslog \"tag\""); + return NGX_CONF_ERROR; + } + + /* + * RFC 3164: the TAG is a string of ABNF alphanumeric characters + * that MUST NOT exceed 32 characters. + */ + if (len - 4 > 32) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog tag length exceeds 32"); + return NGX_CONF_ERROR; + } + + for (i = 4; i < len; i++) { + c = ngx_tolower(p[i]); + + if (c < '0' || (c > '9' && c < 'a') || c > 'z') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "syslog \"tag\" only allows " + "alphanumeric characters"); + return NGX_CONF_ERROR; + } + } + + peer->tag.data = p + 4; + peer->tag.len = len - 4; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown syslog parameter \"%s\"", p); + return NGX_CONF_ERROR; + } + + next: + + if (comma == NULL) { + break; + } + + p = comma + 1; + } + + return NGX_CONF_OK; +} + + +u_char * +ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf) +{ + ngx_uint_t pri; + + pri = peer->facility * 8 + peer->severity; + + return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time, + &ngx_cycle->hostname, &peer->tag); +} + + +void +ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len) +{ + u_char *p, msg[NGX_SYSLOG_MAX_STR]; + ngx_uint_t head_len; + ngx_syslog_peer_t *peer; + + peer = log->wdata; + + if (peer->processing) { + return; + } + + peer->processing = 1; + peer->severity = level - 1; + + p = ngx_syslog_add_header(peer, msg); + head_len = p - msg; + + len -= NGX_LINEFEED_SIZE; + + if (len > NGX_SYSLOG_MAX_STR - head_len) { + len = NGX_SYSLOG_MAX_STR - head_len; + } + + p = ngx_snprintf(p, len, "%s", buf); + + (void) ngx_syslog_send(peer, msg, p - msg); + + peer->processing = 0; +} + + +ssize_t +ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len) +{ + if (peer->conn.fd == (ngx_socket_t) -1) { + if (ngx_syslog_init_peer(peer) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_send) { + return ngx_send(&peer->conn, buf, len); + + } else { + /* event module has not yet set ngx_io */ + return ngx_os_io.send(&peer->conn, buf, len); + } +} + + +static ngx_int_t +ngx_syslog_init_peer(ngx_syslog_peer_t *peer) +{ + ngx_socket_t fd; + ngx_pool_cleanup_t *cln; + + peer->conn.read = &ngx_syslog_dummy_event; + peer->conn.write = &ngx_syslog_dummy_event; + peer->conn.log = &ngx_syslog_dummy_log; + + ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log; + + fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0); + if (fd == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + if (ngx_nonblocking(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + goto failed; + } + + if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + "connect() failed"); + goto failed; + } + + cln = ngx_pool_cleanup_add(peer->pool, 0); + if (cln == NULL) { + goto failed; + } + + cln->data = peer; + cln->handler = ngx_syslog_cleanup; + + peer->conn.fd = fd; + return NGX_OK; + +failed: + + if (ngx_close_socket(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; +} + + +static void +ngx_syslog_cleanup(void *data) +{ + ngx_syslog_peer_t *peer = data; + + if (ngx_close_socket(peer->conn.fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } +} diff --git a/usr.sbin/nginx/src/core/ngx_syslog.h b/usr.sbin/nginx/src/core/ngx_syslog.h new file mode 100644 index 00000000000..92d47d5f5fd --- /dev/null +++ b/usr.sbin/nginx/src/core/ngx_syslog.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SYSLOG_H_INCLUDED_ +#define _NGX_SYSLOG_H_INCLUDED_ + + +typedef struct { + ngx_pool_t *pool; + ngx_uint_t facility; + ngx_uint_t severity; + ngx_str_t tag; + + ngx_addr_t server; + ngx_connection_t conn; + ngx_uint_t processing; /* unsigned processing:1; */ +} ngx_syslog_peer_t; + + +char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer); +u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf); +void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf, + size_t len); +ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len); + + +#endif /* _NGX_SYSLOG_H_INCLUDED_ */ diff --git a/usr.sbin/nginx/src/core/ngx_times.c b/usr.sbin/nginx/src/core/ngx_times.c index 77490faf045..595c1224d0e 100644 --- a/usr.sbin/nginx/src/core/ngx_times.c +++ b/usr.sbin/nginx/src/core/ngx_times.c @@ -29,6 +29,7 @@ volatile ngx_str_t ngx_cached_err_log_time; volatile ngx_str_t ngx_cached_http_time; volatile ngx_str_t ngx_cached_http_log_time; volatile ngx_str_t ngx_cached_http_log_iso8601; +volatile ngx_str_t ngx_cached_syslog_time; #if !(NGX_WIN32) @@ -50,6 +51,8 @@ static u_char cached_http_log_time[NGX_TIME_SLOTS] [sizeof("28/Sep/1970:12:00:00 +0600")]; static u_char cached_http_log_iso8601[NGX_TIME_SLOTS] [sizeof("1970-09-28T12:00:00+06:00")]; +static u_char cached_syslog_time[NGX_TIME_SLOTS] + [sizeof("Sep 28 12:00:00")]; static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @@ -63,6 +66,7 @@ ngx_time_init(void) ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1; ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1; + ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1; ngx_cached_time = &cached_time[0]; @@ -73,7 +77,7 @@ ngx_time_init(void) void ngx_time_update(void) { - u_char *p0, *p1, *p2, *p3; + u_char *p0, *p1, *p2, *p3, *p4; ngx_tm_t tm, gmt; time_t sec; ngx_uint_t msec; @@ -166,6 +170,11 @@ ngx_time_update(void) tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); + p4 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); ngx_memory_barrier(); @@ -174,6 +183,7 @@ ngx_time_update(void) ngx_cached_err_log_time.data = p1; ngx_cached_http_log_time.data = p2; ngx_cached_http_log_iso8601.data = p3; + ngx_cached_syslog_time.data = p4; ngx_unlock(&ngx_time_lock); } @@ -184,7 +194,7 @@ ngx_time_update(void) void ngx_time_sigsafe_update(void) { - u_char *p; + u_char *p, *p2; ngx_tm_t tm; time_t sec; ngx_time_t *tp; @@ -224,9 +234,16 @@ ngx_time_sigsafe_update(void) tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + p2 = &cached_syslog_time[slot][0]; + + (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d", + months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday, + tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec); + ngx_memory_barrier(); ngx_cached_err_log_time.data = p; + ngx_cached_syslog_time.data = p2; ngx_unlock(&ngx_time_lock); } diff --git a/usr.sbin/nginx/src/core/ngx_times.h b/usr.sbin/nginx/src/core/ngx_times.h index c4b26a2ed0b..94aedcdc94c 100644 --- a/usr.sbin/nginx/src/core/ngx_times.h +++ b/usr.sbin/nginx/src/core/ngx_times.h @@ -40,6 +40,7 @@ extern volatile ngx_str_t ngx_cached_err_log_time; extern volatile ngx_str_t ngx_cached_http_time; extern volatile ngx_str_t ngx_cached_http_log_time; extern volatile ngx_str_t ngx_cached_http_log_iso8601; +extern volatile ngx_str_t ngx_cached_syslog_time; /* * milliseconds elapsed since epoch and truncated to ngx_msec_t, |
