diff options
Diffstat (limited to 'app/nginx/src/stream/ngx_stream_proxy_module.c')
-rw-r--r-- | app/nginx/src/stream/ngx_stream_proxy_module.c | 2170 |
1 files changed, 0 insertions, 2170 deletions
diff --git a/app/nginx/src/stream/ngx_stream_proxy_module.c b/app/nginx/src/stream/ngx_stream_proxy_module.c deleted file mode 100644 index 81a0891..0000000 --- a/app/nginx/src/stream/ngx_stream_proxy_module.c +++ /dev/null @@ -1,2170 +0,0 @@ - -/* - * Copyright (C) Roman Arutyunyan - * Copyright (C) Nginx, Inc. - */ - - -#include <ngx_config.h> -#include <ngx_core.h> -#include <ngx_stream.h> - - -typedef struct { - ngx_addr_t *addr; - ngx_stream_complex_value_t *value; -#if (NGX_HAVE_TRANSPARENT_PROXY) - ngx_uint_t transparent; /* unsigned transparent:1; */ -#endif -} ngx_stream_upstream_local_t; - - -typedef struct { - ngx_msec_t connect_timeout; - ngx_msec_t timeout; - ngx_msec_t next_upstream_timeout; - size_t buffer_size; - size_t upload_rate; - size_t download_rate; - ngx_uint_t responses; - ngx_uint_t next_upstream_tries; - ngx_flag_t next_upstream; - ngx_flag_t proxy_protocol; - ngx_stream_upstream_local_t *local; - -#if (NGX_STREAM_SSL) - ngx_flag_t ssl_enable; - ngx_flag_t ssl_session_reuse; - ngx_uint_t ssl_protocols; - ngx_str_t ssl_ciphers; - ngx_stream_complex_value_t *ssl_name; - ngx_flag_t ssl_server_name; - - ngx_flag_t ssl_verify; - ngx_uint_t ssl_verify_depth; - ngx_str_t ssl_trusted_certificate; - ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; - - ngx_ssl_t *ssl; -#endif - - ngx_stream_upstream_srv_conf_t *upstream; - ngx_stream_complex_value_t *upstream_value; -} ngx_stream_proxy_srv_conf_t; - - -static void ngx_stream_proxy_handler(ngx_stream_session_t *s); -static ngx_int_t ngx_stream_proxy_eval(ngx_stream_session_t *s, - ngx_stream_proxy_srv_conf_t *pscf); -static ngx_int_t ngx_stream_proxy_set_local(ngx_stream_session_t *s, - ngx_stream_upstream_t *u, ngx_stream_upstream_local_t *local); -static void ngx_stream_proxy_connect(ngx_stream_session_t *s); -static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s); -static void ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx); -static void ngx_stream_proxy_upstream_handler(ngx_event_t *ev); -static void ngx_stream_proxy_downstream_handler(ngx_event_t *ev); -static void ngx_stream_proxy_process_connection(ngx_event_t *ev, - ngx_uint_t from_upstream); -static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); -static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); -static void ngx_stream_proxy_process(ngx_stream_session_t *s, - ngx_uint_t from_upstream, ngx_uint_t do_write); -static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); -static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc); -static u_char *ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, - size_t len); - -static void *ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf); -static char *ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, - void *child); -static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -#if (NGX_STREAM_SSL) - -static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); -static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); -static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); -static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); -static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, - ngx_stream_proxy_srv_conf_t *pscf); - - -static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - -#endif - - -static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_downstream_buffer = { - ngx_conf_deprecated, "proxy_downstream_buffer", "proxy_buffer_size" -}; - -static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_upstream_buffer = { - ngx_conf_deprecated, "proxy_upstream_buffer", "proxy_buffer_size" -}; - - -static ngx_command_t ngx_stream_proxy_commands[] = { - - { ngx_string("proxy_pass"), - NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_stream_proxy_pass, - NGX_STREAM_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("proxy_bind"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE12, - ngx_stream_proxy_bind, - NGX_STREAM_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("proxy_connect_timeout"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, connect_timeout), - NULL }, - - { ngx_string("proxy_timeout"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, timeout), - NULL }, - - { ngx_string("proxy_buffer_size"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), - NULL }, - - { ngx_string("proxy_downstream_buffer"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), - &ngx_conf_deprecated_proxy_downstream_buffer }, - - { ngx_string("proxy_upstream_buffer"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, buffer_size), - &ngx_conf_deprecated_proxy_upstream_buffer }, - - { ngx_string("proxy_upload_rate"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, upload_rate), - NULL }, - - { ngx_string("proxy_download_rate"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, download_rate), - NULL }, - - { ngx_string("proxy_responses"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, responses), - NULL }, - - { ngx_string("proxy_next_upstream"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, next_upstream), - NULL }, - - { ngx_string("proxy_next_upstream_tries"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_tries), - NULL }, - - { ngx_string("proxy_next_upstream_timeout"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout), - NULL }, - - { ngx_string("proxy_protocol"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol), - NULL }, - -#if (NGX_STREAM_SSL) - - { ngx_string("proxy_ssl"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_enable), - NULL }, - - { ngx_string("proxy_ssl_session_reuse"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_session_reuse), - NULL }, - - { ngx_string("proxy_ssl_protocols"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, - ngx_conf_set_bitmask_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_protocols), - &ngx_stream_proxy_ssl_protocols }, - - { ngx_string("proxy_ssl_ciphers"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_ciphers), - NULL }, - - { ngx_string("proxy_ssl_name"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_stream_set_complex_value_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_name), - NULL }, - - { ngx_string("proxy_ssl_server_name"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_server_name), - NULL }, - - { ngx_string("proxy_ssl_verify"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_verify), - NULL }, - - { ngx_string("proxy_ssl_verify_depth"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_verify_depth), - NULL }, - - { ngx_string("proxy_ssl_trusted_certificate"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_trusted_certificate), - NULL }, - - { ngx_string("proxy_ssl_crl"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_crl), - NULL }, - - { ngx_string("proxy_ssl_certificate"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate), - NULL }, - - { ngx_string("proxy_ssl_certificate_key"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), - NULL }, - - { ngx_string("proxy_ssl_password_file"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_stream_proxy_ssl_password_file, - NGX_STREAM_SRV_CONF_OFFSET, - 0, - NULL }, - -#endif - - ngx_null_command -}; - - -static ngx_stream_module_t ngx_stream_proxy_module_ctx = { - NULL, /* preconfiguration */ - NULL, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - ngx_stream_proxy_create_srv_conf, /* create server configuration */ - ngx_stream_proxy_merge_srv_conf /* merge server configuration */ -}; - - -ngx_module_t ngx_stream_proxy_module = { - NGX_MODULE_V1, - &ngx_stream_proxy_module_ctx, /* module context */ - ngx_stream_proxy_commands, /* module directives */ - NGX_STREAM_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING -}; - - -static void -ngx_stream_proxy_handler(ngx_stream_session_t *s) -{ - u_char *p; - ngx_str_t *host; - ngx_uint_t i; - ngx_connection_t *c; - ngx_resolver_ctx_t *ctx, temp; - ngx_stream_upstream_t *u; - ngx_stream_core_srv_conf_t *cscf; - ngx_stream_proxy_srv_conf_t *pscf; - ngx_stream_upstream_srv_conf_t *uscf, **uscfp; - ngx_stream_upstream_main_conf_t *umcf; - - c = s->connection; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "proxy connection handler"); - - u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t)); - if (u == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - s->upstream = u; - - s->log_handler = ngx_stream_proxy_log_error; - - u->peer.log = c->log; - u->peer.log_error = NGX_ERROR_ERR; - - if (ngx_stream_proxy_set_local(s, u, pscf->local) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->peer.type = c->type; - u->start_sec = ngx_time(); - - c->write->handler = ngx_stream_proxy_downstream_handler; - c->read->handler = ngx_stream_proxy_downstream_handler; - - s->upstream_states = ngx_array_create(c->pool, 1, - sizeof(ngx_stream_upstream_state_t)); - if (s->upstream_states == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (c->type == SOCK_STREAM) { - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->downstream_buf.start = p; - u->downstream_buf.end = p + pscf->buffer_size; - u->downstream_buf.pos = p; - u->downstream_buf.last = p; - - if (c->read->ready) { - ngx_post_event(c->read, &ngx_posted_events); - } - } - - if (pscf->upstream_value) { - if (ngx_stream_proxy_eval(s, pscf) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - } - - if (u->resolved == NULL) { - - uscf = pscf->upstream; - - } else { - -#if (NGX_STREAM_SSL) - u->ssl_name = u->resolved->host; -#endif - - host = &u->resolved->host; - - umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module); - - uscfp = umcf->upstreams.elts; - - for (i = 0; i < umcf->upstreams.nelts; i++) { - - uscf = uscfp[i]; - - if (uscf->host.len == host->len - && ((uscf->port == 0 && u->resolved->no_port) - || uscf->port == u->resolved->port) - && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) - { - goto found; - } - } - - if (u->resolved->sockaddr) { - - if (u->resolved->port == 0 - && u->resolved->sockaddr->sa_family != AF_UNIX) - { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no port in upstream \"%V\"", host); - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (ngx_stream_upstream_create_round_robin_peer(s, u->resolved) - != NGX_OK) - { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ngx_stream_proxy_connect(s); - - return; - } - - if (u->resolved->port == 0) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no port in upstream \"%V\"", host); - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - temp.name = *host; - - cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - - ctx = ngx_resolve_start(cscf->resolver, &temp); - if (ctx == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (ctx == NGX_NO_RESOLVER) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no resolver defined to resolve %V", host); - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ctx->name = *host; - ctx->handler = ngx_stream_proxy_resolve_handler; - ctx->data = s; - ctx->timeout = cscf->resolver_timeout; - - u->resolved->ctx = ctx; - - if (ngx_resolve_name(ctx) != NGX_OK) { - u->resolved->ctx = NULL; - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - return; - } - -found: - - if (uscf == NULL) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, "no upstream configuration"); - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->upstream = uscf; - -#if (NGX_STREAM_SSL) - u->ssl_name = uscf->host; -#endif - - if (uscf->peer.init(s, uscf) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->peer.start_time = ngx_current_msec; - - if (pscf->next_upstream_tries - && u->peer.tries > pscf->next_upstream_tries) - { - u->peer.tries = pscf->next_upstream_tries; - } - - ngx_stream_proxy_connect(s); -} - - -static ngx_int_t -ngx_stream_proxy_eval(ngx_stream_session_t *s, - ngx_stream_proxy_srv_conf_t *pscf) -{ - ngx_str_t host; - ngx_url_t url; - ngx_stream_upstream_t *u; - - if (ngx_stream_complex_value(s, pscf->upstream_value, &host) != NGX_OK) { - return NGX_ERROR; - } - - ngx_memzero(&url, sizeof(ngx_url_t)); - - url.url = host; - url.no_resolve = 1; - - if (ngx_parse_url(s->connection->pool, &url) != NGX_OK) { - if (url.err) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "%s in upstream \"%V\"", url.err, &url.url); - } - - return NGX_ERROR; - } - - u = s->upstream; - - u->resolved = ngx_pcalloc(s->connection->pool, - sizeof(ngx_stream_upstream_resolved_t)); - if (u->resolved == NULL) { - return NGX_ERROR; - } - - if (url.addrs) { - u->resolved->sockaddr = url.addrs[0].sockaddr; - u->resolved->socklen = url.addrs[0].socklen; - u->resolved->name = url.addrs[0].name; - u->resolved->naddrs = 1; - } - - u->resolved->host = url.host; - u->resolved->port = url.port; - u->resolved->no_port = url.no_port; - - return NGX_OK; -} - - -static ngx_int_t -ngx_stream_proxy_set_local(ngx_stream_session_t *s, ngx_stream_upstream_t *u, - ngx_stream_upstream_local_t *local) -{ - ngx_int_t rc; - ngx_str_t val; - ngx_addr_t *addr; - - if (local == NULL) { - u->peer.local = NULL; - return NGX_OK; - } - -#if (NGX_HAVE_TRANSPARENT_PROXY) - u->peer.transparent = local->transparent; -#endif - - if (local->value == NULL) { - u->peer.local = local->addr; - return NGX_OK; - } - - if (ngx_stream_complex_value(s, local->value, &val) != NGX_OK) { - return NGX_ERROR; - } - - if (val.len == 0) { - return NGX_OK; - } - - addr = ngx_palloc(s->connection->pool, sizeof(ngx_addr_t)); - if (addr == NULL) { - return NGX_ERROR; - } - - rc = ngx_parse_addr_port(s->connection->pool, addr, val.data, val.len); - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "invalid local address \"%V\"", &val); - return NGX_OK; - } - - addr->name = val; - u->peer.local = addr; - - return NGX_OK; -} - - -static void -ngx_stream_proxy_connect(ngx_stream_session_t *s) -{ - ngx_int_t rc; - ngx_connection_t *c, *pc; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - c = s->connection; - - c->log->action = "connecting to upstream"; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - u = s->upstream; - - u->connected = 0; - u->proxy_protocol = pscf->proxy_protocol; - - if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; - } - - u->state = ngx_array_push(s->upstream_states); - if (u->state == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ngx_memzero(u->state, sizeof(ngx_stream_upstream_state_t)); - - u->state->connect_time = (ngx_msec_t) -1; - u->state->first_byte_time = (ngx_msec_t) -1; - u->state->response_time = ngx_current_msec; - - rc = ngx_event_connect_peer(&u->peer); - - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc); - - if (rc == NGX_ERROR) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->state->peer = u->peer.name; - - if (rc == NGX_BUSY) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams"); - ngx_stream_proxy_finalize(s, NGX_STREAM_BAD_GATEWAY); - return; - } - - if (rc == NGX_DECLINED) { - ngx_stream_proxy_next_upstream(s); - return; - } - - /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ - - pc = u->peer.connection; - - pc->data = s; - pc->log = c->log; - pc->pool = c->pool; - pc->read->log = c->log; - pc->write->log = c->log; - - if (rc != NGX_AGAIN) { - ngx_stream_proxy_init_upstream(s); - return; - } - - pc->read->handler = ngx_stream_proxy_connect_handler; - pc->write->handler = ngx_stream_proxy_connect_handler; - - ngx_add_timer(pc->write, pscf->connect_timeout); -} - - -static void -ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) -{ - int tcp_nodelay; - u_char *p; - ngx_chain_t *cl; - ngx_connection_t *c, *pc; - ngx_log_handler_pt handler; - ngx_stream_upstream_t *u; - ngx_stream_core_srv_conf_t *cscf; - ngx_stream_proxy_srv_conf_t *pscf; - - u = s->upstream; - pc = u->peer.connection; - - cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - - if (pc->type == SOCK_STREAM - && cscf->tcp_nodelay - && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(pc->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(pc, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_stream_proxy_next_upstream(s); - return; - } - - pc->tcp_nodelay = NGX_TCP_NODELAY_SET; - } - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - -#if (NGX_STREAM_SSL) - - if (pc->type == SOCK_STREAM && pscf->ssl) { - - if (u->proxy_protocol) { - if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) { - return; - } - - u->proxy_protocol = 0; - } - - if (pc->ssl == NULL) { - ngx_stream_proxy_ssl_init_connection(s); - return; - } - } - -#endif - - c = s->connection; - - if (c->log->log_level >= NGX_LOG_INFO) { - ngx_str_t str; - u_char addr[NGX_SOCKADDR_STRLEN]; - - str.len = NGX_SOCKADDR_STRLEN; - str.data = addr; - - if (ngx_connection_local_sockaddr(pc, &str, 1) == NGX_OK) { - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%sproxy %V connected to %V", - pc->type == SOCK_DGRAM ? "udp " : "", - &str, u->peer.name); - - c->log->handler = handler; - } - } - - u->state->connect_time = ngx_current_msec - u->state->response_time; - - if (u->peer.notify) { - u->peer.notify(&u->peer, u->peer.data, - NGX_STREAM_UPSTREAM_NOTIFY_CONNECT); - } - - c->log->action = "proxying connection"; - - if (u->upstream_buf.start == NULL) { - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - u->upstream_buf.start = p; - u->upstream_buf.end = p + pscf->buffer_size; - u->upstream_buf.pos = p; - u->upstream_buf.last = p; - } - - if (c->buffer && c->buffer->pos < c->buffer->last) { - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy add preread buffer: %uz", - c->buffer->last - c->buffer->pos); - - cl = ngx_chain_get_free_buf(c->pool, &u->free); - if (cl == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - *cl->buf = *c->buffer; - - cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; - cl->buf->flush = 1; - cl->buf->last_buf = (c->type == SOCK_DGRAM); - - cl->next = u->upstream_out; - u->upstream_out = cl; - } - - if (u->proxy_protocol) { - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy add PROXY protocol header"); - - cl = ngx_chain_get_free_buf(c->pool, &u->free); - if (cl == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - p = ngx_pnalloc(c->pool, NGX_PROXY_PROTOCOL_MAX_HEADER); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - cl->buf->pos = p; - - p = ngx_proxy_protocol_write(c, p, p + NGX_PROXY_PROTOCOL_MAX_HEADER); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - cl->buf->last = p; - cl->buf->temporary = 1; - cl->buf->flush = 0; - cl->buf->last_buf = 0; - cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; - - cl->next = u->upstream_out; - u->upstream_out = cl; - - u->proxy_protocol = 0; - } - - if (c->type == SOCK_DGRAM && pscf->responses == 0) { - pc->read->ready = 0; - pc->read->eof = 1; - } - - u->connected = 1; - - pc->read->handler = ngx_stream_proxy_upstream_handler; - pc->write->handler = ngx_stream_proxy_upstream_handler; - - if (pc->read->ready || pc->read->eof) { - ngx_post_event(pc->read, &ngx_posted_events); - } - - ngx_stream_proxy_process(s, 0, 1); -} - - -#if (NGX_STREAM_SSL) - -static ngx_int_t -ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) -{ - u_char *p; - ssize_t n, size; - ngx_connection_t *c, *pc; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; - - c = s->connection; - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy send PROXY protocol header"); - - p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - - u = s->upstream; - - pc = u->peer.connection; - - size = p - buf; - - n = pc->send(pc, buf, size); - - if (n == NGX_AGAIN) { - if (ngx_handle_write_event(pc->write, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - ngx_add_timer(pc->write, pscf->timeout); - - pc->write->handler = ngx_stream_proxy_connect_handler; - - return NGX_AGAIN; - } - - if (n == NGX_ERROR) { - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return NGX_ERROR; - } - - if (n != size) { - - /* - * PROXY protocol specification: - * The sender must always ensure that the header - * is sent at once, so that the transport layer - * maintains atomicity along the path to the receiver. - */ - - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "could not send PROXY protocol header at once"); - - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - - return NGX_ERROR; - } - - return NGX_OK; -} - - -static char * -ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_stream_proxy_srv_conf_t *pscf = conf; - - ngx_str_t *value; - - if (pscf->ssl_passwords != NGX_CONF_UNSET_PTR) { - return "is duplicate"; - } - - value = cf->args->elts; - - pscf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - - if (pscf->ssl_passwords == NULL) { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static void -ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) -{ - ngx_int_t rc; - ngx_connection_t *pc; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - u = s->upstream; - - pc = u->peer.connection; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - if (ngx_ssl_create_connection(pscf->ssl, pc, NGX_SSL_BUFFER|NGX_SSL_CLIENT) - != NGX_OK) - { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (pscf->ssl_server_name || pscf->ssl_verify) { - if (ngx_stream_proxy_ssl_name(s) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - } - - if (pscf->ssl_session_reuse) { - if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - } - - s->connection->log->action = "SSL handshaking to upstream"; - - rc = ngx_ssl_handshake(pc); - - if (rc == NGX_AGAIN) { - - if (!pc->write->timer_set) { - ngx_add_timer(pc->write, pscf->connect_timeout); - } - - pc->ssl->handler = ngx_stream_proxy_ssl_handshake; - return; - } - - ngx_stream_proxy_ssl_handshake(pc); -} - - -static void -ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) -{ - long rc; - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - s = pc->data; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - if (pc->ssl->handshaked) { - - if (pscf->ssl_verify) { - rc = SSL_get_verify_result(pc->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_ERR, pc->log, 0, - "upstream SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - goto failed; - } - - u = s->upstream; - - if (ngx_ssl_check_host(pc, &u->ssl_name) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, pc->log, 0, - "upstream SSL certificate does not match \"%V\"", - &u->ssl_name); - goto failed; - } - } - - if (pscf->ssl_session_reuse) { - u = s->upstream; - u->peer.save_session(&u->peer, u->peer.data); - } - - if (pc->write->timer_set) { - ngx_del_timer(pc->write); - } - - ngx_stream_proxy_init_upstream(s); - - return; - } - -failed: - - ngx_stream_proxy_next_upstream(s); -} - - -static ngx_int_t -ngx_stream_proxy_ssl_name(ngx_stream_session_t *s) -{ - u_char *p, *last; - ngx_str_t name; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - u = s->upstream; - - if (pscf->ssl_name) { - if (ngx_stream_complex_value(s, pscf->ssl_name, &name) != NGX_OK) { - return NGX_ERROR; - } - - } else { - name = u->ssl_name; - } - - if (name.len == 0) { - goto done; - } - - /* - * ssl name here may contain port, strip it for compatibility - * with the http module - */ - - p = name.data; - last = name.data + name.len; - - if (*p == '[') { - p = ngx_strlchr(p, last, ']'); - - if (p == NULL) { - p = name.data; - } - } - - p = ngx_strlchr(p, last, ':'); - - if (p != NULL) { - name.len = p - name.data; - } - - if (!pscf->ssl_server_name) { - goto done; - } - -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - - /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */ - - if (name.len == 0 || *name.data == '[') { - goto done; - } - - if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) { - goto done; - } - - /* - * SSL_set_tlsext_host_name() needs a null-terminated string, - * hence we explicitly null-terminate name here - */ - - p = ngx_pnalloc(s->connection->pool, name.len + 1); - if (p == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(p, name.data, name.len + 1); - - name.data = p; - - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "upstream SSL server name: \"%s\"", name.data); - - if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection, - (char *) name.data) - == 0) - { - ngx_ssl_error(NGX_LOG_ERR, s->connection->log, 0, - "SSL_set_tlsext_host_name(\"%s\") failed", name.data); - return NGX_ERROR; - } - -#endif - -done: - - u->ssl_name = name; - - return NGX_OK; -} - -#endif - - -static void -ngx_stream_proxy_downstream_handler(ngx_event_t *ev) -{ - ngx_stream_proxy_process_connection(ev, ev->write); -} - - -static void -ngx_stream_proxy_resolve_handler(ngx_resolver_ctx_t *ctx) -{ - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - ngx_stream_upstream_resolved_t *ur; - - s = ctx->data; - - u = s->upstream; - ur = u->resolved; - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "stream upstream resolve"); - - if (ctx->state) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "%V could not be resolved (%i: %s)", - &ctx->name, ctx->state, - ngx_resolver_strerror(ctx->state)); - - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ur->naddrs = ctx->naddrs; - ur->addrs = ctx->addrs; - -#if (NGX_DEBUG) - { - u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; - ngx_uint_t i; - - addr.data = text; - - for (i = 0; i < ctx->naddrs; i++) { - addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, - text, NGX_SOCKADDR_STRLEN, 0); - - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "name was resolved to %V", &addr); - } - } -#endif - - if (ngx_stream_upstream_create_round_robin_peer(s, ur) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - ngx_resolve_name_done(ctx); - ur->ctx = NULL; - - u->peer.start_time = ngx_current_msec; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - if (pscf->next_upstream_tries - && u->peer.tries > pscf->next_upstream_tries) - { - u->peer.tries = pscf->next_upstream_tries; - } - - ngx_stream_proxy_connect(s); -} - - -static void -ngx_stream_proxy_upstream_handler(ngx_event_t *ev) -{ - ngx_stream_proxy_process_connection(ev, !ev->write); -} - - -static void -ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) -{ - ngx_connection_t *c, *pc; - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - c = ev->data; - s = c->data; - u = s->upstream; - - c = s->connection; - pc = u->peer.connection; - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - if (ev->timedout) { - ev->timedout = 0; - - if (ev->delayed) { - ev->delayed = 0; - - if (!ev->ready) { - if (ngx_handle_read_event(ev, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, - NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (u->connected && !c->read->delayed && !pc->read->delayed) { - ngx_add_timer(c->write, pscf->timeout); - } - - return; - } - - } else { - if (s->connection->type == SOCK_DGRAM) { - if (pscf->responses == NGX_MAX_INT32_VALUE) { - - /* - * successfully terminate timed out UDP session - * with unspecified number of responses - */ - - pc->read->ready = 0; - pc->read->eof = 1; - - ngx_stream_proxy_process(s, 1, 0); - return; - } - - if (u->received == 0) { - ngx_stream_proxy_next_upstream(s); - return; - } - } - - ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return; - } - - } else if (ev->delayed) { - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream connection delayed"); - - if (ngx_handle_read_event(ev, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - } - - return; - } - - if (from_upstream && !u->connected) { - return; - } - - ngx_stream_proxy_process(s, from_upstream, ev->write); -} - - -static void -ngx_stream_proxy_connect_handler(ngx_event_t *ev) -{ - ngx_connection_t *c; - ngx_stream_session_t *s; - - c = ev->data; - s = c->data; - - if (ev->timedout) { - ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "upstream timed out"); - ngx_stream_proxy_next_upstream(s); - return; - } - - ngx_del_timer(c->write); - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, - "stream proxy connect upstream"); - - if (ngx_stream_proxy_test_connect(c) != NGX_OK) { - ngx_stream_proxy_next_upstream(s); - return; - } - - ngx_stream_proxy_init_upstream(s); -} - - -static ngx_int_t -ngx_stream_proxy_test_connect(ngx_connection_t *c) -{ - int err; - socklen_t len; - -#if (NGX_HAVE_KQUEUE) - - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - err = c->write->kq_errno ? c->write->kq_errno : c->read->kq_errno; - - if (err) { - (void) ngx_connection_error(c, err, - "kevent() reported that connect() failed"); - return NGX_ERROR; - } - - } else -#endif - { - err = 0; - len = sizeof(int); - - /* - * BSDs and Linux return 0 and set a pending error in err - * Solaris returns -1 and sets errno - */ - - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) - == -1) - { - err = ngx_socket_errno; - } - - if (err) { - (void) ngx_connection_error(c, err, "connect() failed"); - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static void -ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, - ngx_uint_t do_write) -{ - off_t *received, limit; - size_t size, limit_rate; - ssize_t n; - ngx_buf_t *b; - ngx_int_t rc; - ngx_uint_t flags; - ngx_msec_t delay; - ngx_chain_t *cl, **ll, **out, **busy; - ngx_connection_t *c, *pc, *src, *dst; - ngx_log_handler_pt handler; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - u = s->upstream; - - c = s->connection; - pc = u->connected ? u->peer.connection : NULL; - - if (c->type == SOCK_DGRAM && (ngx_terminate || ngx_exiting)) { - - /* socket is already closed on worker shutdown */ - - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, "disconnected on shutdown"); - - c->log->handler = handler; - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return; - } - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - if (from_upstream) { - src = pc; - dst = c; - b = &u->upstream_buf; - limit_rate = pscf->download_rate; - received = &u->received; - out = &u->downstream_out; - busy = &u->downstream_busy; - - } else { - src = c; - dst = pc; - b = &u->downstream_buf; - limit_rate = pscf->upload_rate; - received = &s->received; - out = &u->upstream_out; - busy = &u->upstream_busy; - } - - for ( ;; ) { - - if (do_write && dst) { - - if (*out || *busy || dst->buffered) { - rc = ngx_stream_top_filter(s, *out, from_upstream); - - if (rc == NGX_ERROR) { - if (c->type == SOCK_DGRAM && !from_upstream) { - ngx_stream_proxy_next_upstream(s); - return; - } - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return; - } - - ngx_chain_update_chains(c->pool, &u->free, busy, out, - (ngx_buf_tag_t) &ngx_stream_proxy_module); - - if (*busy == NULL) { - b->pos = b->start; - b->last = b->start; - } - } - } - - size = b->end - b->last; - - if (size && src->read->ready && !src->read->delayed - && !src->read->error) - { - if (limit_rate) { - limit = (off_t) limit_rate * (ngx_time() - u->start_sec + 1) - - *received; - - if (limit <= 0) { - src->read->delayed = 1; - delay = (ngx_msec_t) (- limit * 1000 / limit_rate + 1); - ngx_add_timer(src->read, delay); - break; - } - - if ((off_t) size > limit) { - size = (size_t) limit; - } - } - - n = src->recv(src, b->last, size); - - if (n == NGX_AGAIN) { - break; - } - - if (n == NGX_ERROR) { - if (c->type == SOCK_DGRAM && u->received == 0) { - ngx_stream_proxy_next_upstream(s); - return; - } - - src->read->eof = 1; - n = 0; - } - - if (n >= 0) { - if (limit_rate) { - delay = (ngx_msec_t) (n * 1000 / limit_rate); - - if (delay > 0) { - src->read->delayed = 1; - ngx_add_timer(src->read, delay); - } - } - - if (from_upstream) { - if (u->state->first_byte_time == (ngx_msec_t) -1) { - u->state->first_byte_time = ngx_current_msec - - u->state->response_time; - } - } - - if (c->type == SOCK_DGRAM && ++u->responses == pscf->responses) - { - src->read->ready = 0; - src->read->eof = 1; - } - - for (ll = out; *ll; ll = &(*ll)->next) { /* void */ } - - cl = ngx_chain_get_free_buf(c->pool, &u->free); - if (cl == NULL) { - ngx_stream_proxy_finalize(s, - NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - *ll = cl; - - cl->buf->pos = b->last; - cl->buf->last = b->last + n; - cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; - - cl->buf->temporary = (n ? 1 : 0); - cl->buf->last_buf = src->read->eof; - cl->buf->flush = 1; - - *received += n; - b->last += n; - do_write = 1; - - continue; - } - } - - break; - } - - if (src->read->eof && dst && (dst->read->eof || !dst->buffered)) { - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%s%s disconnected" - ", bytes from/to client:%O/%O" - ", bytes from/to upstream:%O/%O", - src->type == SOCK_DGRAM ? "udp " : "", - from_upstream ? "upstream" : "client", - s->received, c->sent, u->received, pc ? pc->sent : 0); - - c->log->handler = handler; - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return; - } - - flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - - if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (dst) { - if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (!c->read->delayed && !pc->read->delayed) { - ngx_add_timer(c->write, pscf->timeout); - - } else if (c->write->timer_set) { - ngx_del_timer(c->write); - } - } -} - - -static void -ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) -{ - ngx_msec_t timeout; - ngx_connection_t *pc; - ngx_stream_upstream_t *u; - ngx_stream_proxy_srv_conf_t *pscf; - - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "stream proxy next upstream"); - - u = s->upstream; - pc = u->peer.connection; - - if (u->upstream_out || u->upstream_busy || (pc && pc->buffered)) { - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "pending buffers on next upstream"); - ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return; - } - - if (u->peer.sockaddr) { - u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED); - u->peer.sockaddr = NULL; - } - - pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); - - timeout = pscf->next_upstream_timeout; - - if (u->peer.tries == 0 - || !pscf->next_upstream - || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) - { - ngx_stream_proxy_finalize(s, NGX_STREAM_BAD_GATEWAY); - return; - } - - if (pc) { - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "close proxy upstream connection: %d", pc->fd); - -#if (NGX_STREAM_SSL) - if (pc->ssl) { - pc->ssl->no_wait_shutdown = 1; - pc->ssl->no_send_shutdown = 1; - - (void) ngx_ssl_shutdown(pc); - } -#endif - - u->state->bytes_received = u->received; - u->state->bytes_sent = pc->sent; - - ngx_close_connection(pc); - u->peer.connection = NULL; - } - - ngx_stream_proxy_connect(s); -} - - -static void -ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) -{ - ngx_connection_t *pc; - ngx_stream_upstream_t *u; - - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "finalize stream proxy: %i", rc); - - u = s->upstream; - - if (u == NULL) { - goto noupstream; - } - - if (u->resolved && u->resolved->ctx) { - ngx_resolve_name_done(u->resolved->ctx); - u->resolved->ctx = NULL; - } - - pc = u->peer.connection; - - if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; - - if (pc) { - u->state->bytes_received = u->received; - u->state->bytes_sent = pc->sent; - } - } - - if (u->peer.free && u->peer.sockaddr) { - u->peer.free(&u->peer, u->peer.data, 0); - u->peer.sockaddr = NULL; - } - - if (pc) { - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "close stream proxy upstream connection: %d", pc->fd); - -#if (NGX_STREAM_SSL) - if (pc->ssl) { - pc->ssl->no_wait_shutdown = 1; - (void) ngx_ssl_shutdown(pc); - } -#endif - - ngx_close_connection(pc); - u->peer.connection = NULL; - } - -noupstream: - - ngx_stream_finalize_session(s, rc); -} - - -static u_char * -ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len) -{ - u_char *p; - ngx_connection_t *pc; - ngx_stream_session_t *s; - ngx_stream_upstream_t *u; - - s = log->data; - - u = s->upstream; - - p = buf; - - if (u->peer.name) { - p = ngx_snprintf(p, len, ", upstream: \"%V\"", u->peer.name); - len -= p - buf; - } - - pc = u->peer.connection; - - p = ngx_snprintf(p, len, - ", bytes from/to client:%O/%O" - ", bytes from/to upstream:%O/%O", - s->received, s->connection->sent, - u->received, pc ? pc->sent : 0); - - return p; -} - - -static void * -ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) -{ - ngx_stream_proxy_srv_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_proxy_srv_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->ssl_protocols = 0; - * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = NULL; - * conf->ssl_trusted_certificate = { 0, NULL }; - * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; - * - * conf->ssl = NULL; - * conf->upstream = NULL; - * conf->upstream_value = NULL; - */ - - conf->connect_timeout = NGX_CONF_UNSET_MSEC; - conf->timeout = NGX_CONF_UNSET_MSEC; - conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; - conf->buffer_size = NGX_CONF_UNSET_SIZE; - conf->upload_rate = NGX_CONF_UNSET_SIZE; - conf->download_rate = NGX_CONF_UNSET_SIZE; - conf->responses = NGX_CONF_UNSET_UINT; - conf->next_upstream_tries = NGX_CONF_UNSET_UINT; - conf->next_upstream = NGX_CONF_UNSET; - conf->proxy_protocol = NGX_CONF_UNSET; - conf->local = NGX_CONF_UNSET_PTR; - -#if (NGX_STREAM_SSL) - conf->ssl_enable = NGX_CONF_UNSET; - conf->ssl_session_reuse = NGX_CONF_UNSET; - conf->ssl_server_name = NGX_CONF_UNSET; - conf->ssl_verify = NGX_CONF_UNSET; - conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; -#endif - - return conf; -} - - -static char * -ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_stream_proxy_srv_conf_t *prev = parent; - ngx_stream_proxy_srv_conf_t *conf = child; - - ngx_conf_merge_msec_value(conf->connect_timeout, - prev->connect_timeout, 60000); - - ngx_conf_merge_msec_value(conf->timeout, - prev->timeout, 10 * 60000); - - ngx_conf_merge_msec_value(conf->next_upstream_timeout, - prev->next_upstream_timeout, 0); - - ngx_conf_merge_size_value(conf->buffer_size, - prev->buffer_size, 16384); - - ngx_conf_merge_size_value(conf->upload_rate, - prev->upload_rate, 0); - - ngx_conf_merge_size_value(conf->download_rate, - prev->download_rate, 0); - - ngx_conf_merge_uint_value(conf->responses, - prev->responses, NGX_MAX_INT32_VALUE); - - ngx_conf_merge_uint_value(conf->next_upstream_tries, - prev->next_upstream_tries, 0); - - ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1); - - ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0); - - ngx_conf_merge_ptr_value(conf->local, prev->local, NULL); - -#if (NGX_STREAM_SSL) - - ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); - - ngx_conf_merge_value(conf->ssl_session_reuse, - prev->ssl_session_reuse, 1); - - ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); - - ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - - if (conf->ssl_name == NULL) { - conf->ssl_name = prev->ssl_name; - } - - ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); - - ngx_conf_merge_value(conf->ssl_verify, prev->ssl_verify, 0); - - ngx_conf_merge_uint_value(conf->ssl_verify_depth, - prev->ssl_verify_depth, 1); - - ngx_conf_merge_str_value(conf->ssl_trusted_certificate, - prev->ssl_trusted_certificate, ""); - - ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); - - if (conf->ssl_enable && ngx_stream_proxy_set_ssl(cf, conf) != NGX_OK) { - return NGX_CONF_ERROR; - } - -#endif - - return NGX_CONF_OK; -} - - -#if (NGX_STREAM_SSL) - -static ngx_int_t -ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) -{ - ngx_pool_cleanup_t *cln; - - pscf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); - if (pscf->ssl == NULL) { - return NGX_ERROR; - } - - pscf->ssl->log = cf->log; - - if (ngx_ssl_create(pscf->ssl, pscf->ssl_protocols, NULL) != NGX_OK) { - return NGX_ERROR; - } - - cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_ssl_cleanup_ctx; - cln->data = pscf->ssl; - - if (pscf->ssl_certificate.len) { - - if (pscf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &pscf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate, - &pscf->ssl_certificate_key, pscf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - - if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { - return NGX_ERROR; - } - - if (pscf->ssl_verify) { - if (pscf->ssl_trusted_certificate.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no proxy_ssl_trusted_certificate for proxy_ssl_verify"); - return NGX_ERROR; - } - - if (ngx_ssl_trusted_certificate(cf, pscf->ssl, - &pscf->ssl_trusted_certificate, - pscf->ssl_verify_depth) - != NGX_OK) - { - return NGX_ERROR; - } - - if (ngx_ssl_crl(cf, pscf->ssl, &pscf->ssl_crl) != NGX_OK) { - return NGX_ERROR; - } - } - - return NGX_OK; -} - -#endif - - -static char * -ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_stream_proxy_srv_conf_t *pscf = conf; - - ngx_url_t u; - ngx_str_t *value, *url; - ngx_stream_complex_value_t cv; - ngx_stream_core_srv_conf_t *cscf; - ngx_stream_compile_complex_value_t ccv; - - if (pscf->upstream || pscf->upstream_value) { - return "is duplicate"; - } - - cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module); - - cscf->handler = ngx_stream_proxy_handler; - - value = cf->args->elts; - - url = &value[1]; - - ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = url; - ccv.complex_value = &cv; - - if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - if (cv.lengths) { - pscf->upstream_value = ngx_palloc(cf->pool, - sizeof(ngx_stream_complex_value_t)); - if (pscf->upstream_value == NULL) { - return NGX_CONF_ERROR; - } - - *pscf->upstream_value = cv; - - return NGX_CONF_OK; - } - - ngx_memzero(&u, sizeof(ngx_url_t)); - - u.url = *url; - u.no_resolve = 1; - - pscf->upstream = ngx_stream_upstream_add(cf, &u, 0); - if (pscf->upstream == NULL) { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_stream_proxy_srv_conf_t *pscf = conf; - - ngx_int_t rc; - ngx_str_t *value; - ngx_stream_complex_value_t cv; - ngx_stream_upstream_local_t *local; - ngx_stream_compile_complex_value_t ccv; - - if (pscf->local != NGX_CONF_UNSET_PTR) { - return "is duplicate"; - } - - value = cf->args->elts; - - if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) { - pscf->local = NULL; - return NGX_CONF_OK; - } - - ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); - - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &cv; - - if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { - return NGX_CONF_ERROR; - } - - local = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_local_t)); - if (local == NULL) { - return NGX_CONF_ERROR; - } - - pscf->local = local; - - if (cv.lengths) { - local->value = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); - if (local->value == NULL) { - return NGX_CONF_ERROR; - } - - *local->value = cv; - - } else { - local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); - if (local->addr == NULL) { - return NGX_CONF_ERROR; - } - - rc = ngx_parse_addr_port(cf->pool, local->addr, value[1].data, - value[1].len); - - switch (rc) { - case NGX_OK: - local->addr->name = value[1]; - break; - - case NGX_DECLINED: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid address \"%V\"", &value[1]); - /* fall through */ - - default: - return NGX_CONF_ERROR; - } - } - - if (cf->args->nelts > 2) { - if (ngx_strcmp(value[2].data, "transparent") == 0) { -#if (NGX_HAVE_TRANSPARENT_PROXY) - local->transparent = 1; -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "transparent proxying is not supported " - "on this platform, ignored"); -#endif - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[2]); - return NGX_CONF_ERROR; - } - } - - return NGX_CONF_OK; -} |