mirror of
https://github.com/nginx/nginx.git
synced 2024-11-24 04:49:01 +08:00
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.
This commit is contained in:
parent
2f917b6d06
commit
0b5f329784
@ -36,7 +36,8 @@ CORE_DEPS="src/core/nginx.h \
|
||||
src/core/ngx_conf_file.h \
|
||||
src/core/ngx_resolver.h \
|
||||
src/core/ngx_open_file_cache.h \
|
||||
src/core/ngx_crypt.h"
|
||||
src/core/ngx_crypt.h \
|
||||
src/core/ngx_proxy_protocol.h"
|
||||
|
||||
|
||||
CORE_SRCS="src/core/nginx.c \
|
||||
@ -67,7 +68,8 @@ CORE_SRCS="src/core/nginx.c \
|
||||
src/core/ngx_conf_file.c \
|
||||
src/core/ngx_resolver.c \
|
||||
src/core/ngx_open_file_cache.c \
|
||||
src/core/ngx_crypt.c"
|
||||
src/core/ngx_crypt.c \
|
||||
src/core/ngx_proxy_protocol.c"
|
||||
|
||||
|
||||
REGEX_MODULE=ngx_regex_module
|
||||
|
@ -139,6 +139,8 @@ 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
|
||||
|
@ -77,6 +77,7 @@ 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_proxy_protocol.h>
|
||||
|
||||
|
||||
#define LF (u_char) 10
|
||||
|
91
src/core/ngx_proxy_protocol.c
Normal file
91
src/core/ngx_proxy_protocol.c
Normal file
@ -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;
|
||||
}
|
23
src/core/ngx_proxy_protocol.h
Normal file
23
src/core/ngx_proxy_protocol.h
Normal file
@ -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_ */
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
@ -809,6 +816,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)
|
||||
|
@ -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 },
|
||||
@ -1205,6 +1210,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)
|
||||
|
Loading…
Reference in New Issue
Block a user