diff options
author | Roman Arutyunyan <arut@nginx.com> | 2014-03-17 17:41:24 +0400 |
---|---|---|
committer | Roman Arutyunyan <arut@nginx.com> | 2014-03-17 17:41:24 +0400 |
commit | 0b5f3297849c6061cf07b359e8b42768889e28cd (patch) | |
tree | 5ae00cb3fd666a763e76baef6598a2edc577734e /src/http | |
parent | 2f917b6d0636bd62ab0dfce0cad28148b0e9b002 (diff) |
Added server-side support for PROXY protocol v1 (ticket #355).
Client address specified in the PROXY protocol header is now
saved in the $proxy_protocol_addr variable and can be used in
the realip module.
This is currently not implemented for mail.
Diffstat (limited to 'src/http')
-rw-r--r-- | src/http/modules/ngx_http_realip_module.c | 18 | ||||
-rw-r--r-- | src/http/ngx_http.c | 1 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 5 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.h | 2 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 64 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 3 | ||||
-rw-r--r-- | src/http/ngx_http_spdy.c | 23 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 19 |
8 files changed, 131 insertions, 4 deletions
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index b15954759..7a6211803 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -13,6 +13,7 @@ #define NGX_HTTP_REALIP_XREALIP 0 #define NGX_HTTP_REALIP_XFWD 1 #define NGX_HTTP_REALIP_HEADER 2 +#define NGX_HTTP_REALIP_PROXY 3 typedef struct { @@ -156,6 +157,18 @@ ngx_http_realip_handler(ngx_http_request_t *r) break; + case NGX_HTTP_REALIP_PROXY: + + value = &r->connection->proxy_protocol_addr; + + if (value->len == 0) { + return NGX_DECLINED; + } + + xfwd = NULL; + + break; + default: /* NGX_HTTP_REALIP_HEADER */ part = &r->headers_in.headers.part; @@ -343,6 +356,11 @@ ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } + if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) { + rlcf->type = NGX_HTTP_REALIP_PROXY; + return NGX_CONF_OK; + } + rlcf->type = NGX_HTTP_REALIP_HEADER; rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len); rlcf->header = value[1]; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index c3ac7266c..ce5adb737 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1849,6 +1849,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, #if (NGX_HTTP_SPDY) addrs[i].conf.spdy = addr[i].opt.spdy; #endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; if (addr[i].hash.buckets == NULL && (addr[i].wc_head == NULL diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 74a448a88..b023bdbc8 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4287,6 +4287,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[n].data, "proxy_protocol") == 0) { + lsopt.proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[n]); return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 220c94ee4..799d2fe0d 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -82,6 +82,7 @@ typedef struct { unsigned ipv6only:1; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; int backlog; int rcvbuf; @@ -243,6 +244,7 @@ struct ngx_http_addr_conf_s { #if (NGX_HTTP_SPDY) unsigned spdy:1; #endif + unsigned proxy_protocol:1; }; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 5f2cf7d39..4bf9d1fcf 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -343,6 +343,11 @@ ngx_http_init_connection(ngx_connection_t *c) } #endif + if (hc->addr_conf->proxy_protocol) { + hc->proxy_protocol = 1; + c->log->action = "reading PROXY protocol"; + } + if (rev->ready) { /* the deferred accept(), rtsig, aio, iocp */ @@ -368,6 +373,7 @@ ngx_http_init_connection(ngx_connection_t *c) static void ngx_http_wait_request_handler(ngx_event_t *rev) { + u_char *p; size_t size; ssize_t n; ngx_buf_t *b; @@ -458,6 +464,27 @@ ngx_http_wait_request_handler(ngx_event_t *rev) b->last += n; + if (hc->proxy_protocol) { + hc->proxy_protocol = 0; + + p = ngx_proxy_protocol_parse(c, b->pos, b->last); + + if (p == NULL) { + ngx_http_close_connection(c); + return; + } + + b->pos = p; + + if (b->pos == b->last) { + c->log->action = "waiting for request"; + b->pos = b->start; + b->last = b->start; + ngx_post_event(rev, &ngx_posted_events); + return; + } + } + c->log->action = "reading client request line"; ngx_reusable_connection(c, 0); @@ -589,7 +616,8 @@ ngx_http_create_request(ngx_connection_t *c) static void ngx_http_ssl_handshake(ngx_event_t *rev) { - u_char buf[1]; + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; + size_t size; ssize_t n; ngx_err_t err; ngx_int_t rc; @@ -598,6 +626,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_http_ssl_srv_conf_t *sscf; c = rev->data; + hc = c->data; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http check ssl handshake"); @@ -613,7 +642,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } - n = recv(c->fd, (char *) buf, 1, MSG_PEEK); + size = hc->proxy_protocol ? sizeof(buf) : 1; + + n = recv(c->fd, (char *) buf, size, MSG_PEEK); err = ngx_socket_errno; @@ -640,12 +671,39 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } + if (hc->proxy_protocol) { + hc->proxy_protocol = 0; + + p = ngx_proxy_protocol_parse(c, buf, buf + n); + + if (p == NULL) { + ngx_http_close_connection(c); + return; + } + + size = p - buf; + + if (c->recv(c, buf, size) != (ssize_t) size) { + ngx_http_close_connection(c); + return; + } + + c->log->action = "SSL handshaking"; + + if (n == (ssize_t) size) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + n = 1; + buf[0] = *p; + } + if (n == 1) { if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "https ssl handshake: 0x%02Xd", buf[0]); - hc = c->data; sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 3b0858ace..a1295e799 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -309,8 +309,9 @@ typedef struct { ngx_int_t nfree; #if (NGX_HTTP_SSL) - ngx_uint_t ssl; /* unsigned ssl:1; */ + unsigned ssl:1; #endif + unsigned proxy_protocol:1; } ngx_http_connection_t; diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c index 4005bfbe7..e9bad9444 100644 --- a/src/http/ngx_http_spdy.c +++ b/src/http/ngx_http_spdy.c @@ -95,6 +95,8 @@ static void ngx_http_spdy_read_handler(ngx_event_t *rev); static void ngx_http_spdy_write_handler(ngx_event_t *wev); static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc); +static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, + u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end); static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, @@ -421,6 +423,11 @@ ngx_http_spdy_init(ngx_event_t *rev) sc->handler = ngx_http_spdy_state_head; + if (hc->proxy_protocol) { + c->log->action = "reading PROXY protocol"; + sc->handler = ngx_http_spdy_proxy_protocol; + } + sc->zstream_in.zalloc = ngx_http_spdy_zalloc; sc->zstream_in.zfree = ngx_http_spdy_zfree; sc->zstream_in.opaque = sc; @@ -810,6 +817,22 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc) static u_char * +ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos, + u_char *end) +{ + pos = ngx_proxy_protocol_parse(sc->connection, pos, end); + + if (pos == NULL) { + return ngx_http_spdy_state_protocol_error(sc); + } + + sc->connection->log->action = "processing SPDY"; + + return ngx_http_spdy_state_complete(sc, pos, end); +} + + +static u_char * ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end) { diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 8b86d5a9a..f61862297 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -54,6 +54,8 @@ static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, @@ -183,6 +185,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 }, + { ngx_string("proxy_protocol_addr"), NULL, + ngx_http_variable_proxy_protocol_addr, 0, 0, 0 }, + { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 }, { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 }, @@ -1206,6 +1211,20 @@ ngx_http_variable_remote_port(ngx_http_request_t *r, static ngx_int_t +ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + v->len = r->connection->proxy_protocol_addr.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->connection->proxy_protocol_addr.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { |