mirror of
https://github.com/nginx/nginx.git
synced 2025-07-25 22:56:59 +08:00
PROXY protocol v2 TLV variables.
The variables have prefix $proxy_protocol_tlv_ and are accessible by name and by type. Examples are: $proxy_protocol_tlv_0x01, $proxy_protocol_tlv_alpn.
This commit is contained in:
parent
68119b4362
commit
50e3ff8a00
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
#define ngx_proxy_protocol_parse_uint16(p) ((p)[0] << 8 | (p)[1])
|
#define ngx_proxy_protocol_parse_uint16(p) ((p)[0] << 8 | (p)[1])
|
||||||
|
|
||||||
|
#define ngx_proxy_protocol_parse_uint32(p) \
|
||||||
|
( ((uint32_t) (p)[0] << 24) \
|
||||||
|
+ ( (p)[1] << 16) \
|
||||||
|
+ ( (p)[2] << 8) \
|
||||||
|
+ ( (p)[3]) )
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_char signature[12];
|
u_char signature[12];
|
||||||
@ -40,12 +46,52 @@ typedef struct {
|
|||||||
} ngx_proxy_protocol_inet6_addrs_t;
|
} ngx_proxy_protocol_inet6_addrs_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u_char type;
|
||||||
|
u_char len[2];
|
||||||
|
} ngx_proxy_protocol_tlv_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u_char client;
|
||||||
|
u_char verify[4];
|
||||||
|
} ngx_proxy_protocol_tlv_ssl_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ngx_str_t name;
|
||||||
|
ngx_uint_t type;
|
||||||
|
} ngx_proxy_protocol_tlv_entry_t;
|
||||||
|
|
||||||
|
|
||||||
static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
|
static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
|
||||||
u_char *last, ngx_str_t *addr);
|
u_char *last, ngx_str_t *addr);
|
||||||
static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
|
static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
|
||||||
in_port_t *port, u_char sep);
|
in_port_t *port, u_char sep);
|
||||||
static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
|
static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
|
||||||
u_char *last);
|
u_char *last);
|
||||||
|
static ngx_int_t ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c,
|
||||||
|
ngx_str_t *tlvs, ngx_uint_t type, ngx_str_t *value);
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_entries[] = {
|
||||||
|
{ ngx_string("alpn"), 0x01 },
|
||||||
|
{ ngx_string("authority"), 0x02 },
|
||||||
|
{ ngx_string("unique_id"), 0x05 },
|
||||||
|
{ ngx_string("ssl"), 0x20 },
|
||||||
|
{ ngx_string("netns"), 0x30 },
|
||||||
|
{ ngx_null_string, 0x00 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_proxy_protocol_tlv_entry_t ngx_proxy_protocol_tlv_ssl_entries[] = {
|
||||||
|
{ ngx_string("version"), 0x21 },
|
||||||
|
{ ngx_string("cn"), 0x22 },
|
||||||
|
{ ngx_string("cipher"), 0x23 },
|
||||||
|
{ ngx_string("sig_alg"), 0x24 },
|
||||||
|
{ ngx_string("key_alg"), 0x25 },
|
||||||
|
{ ngx_null_string, 0x00 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
u_char *
|
u_char *
|
||||||
@ -418,11 +464,147 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
|
|||||||
&pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
|
&pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
|
||||||
|
|
||||||
if (buf < end) {
|
if (buf < end) {
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
pp->tlvs.data = ngx_pnalloc(c->pool, end - buf);
|
||||||
"PROXY protocol v2 %z bytes of tlv ignored", end - buf);
|
if (pp->tlvs.data == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_memcpy(pp->tlvs.data, buf, end - buf);
|
||||||
|
pp->tlvs.len = end - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->proxy_protocol = pp;
|
c->proxy_protocol = pp;
|
||||||
|
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name,
|
||||||
|
ngx_str_t *value)
|
||||||
|
{
|
||||||
|
u_char *p;
|
||||||
|
size_t n;
|
||||||
|
uint32_t verify;
|
||||||
|
ngx_str_t ssl, *tlvs;
|
||||||
|
ngx_int_t rc, type;
|
||||||
|
ngx_proxy_protocol_tlv_ssl_t *tlv_ssl;
|
||||||
|
ngx_proxy_protocol_tlv_entry_t *te;
|
||||||
|
|
||||||
|
if (c->proxy_protocol == NULL) {
|
||||||
|
return NGX_DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||||
|
"PROXY protocol v2 get tlv \"%V\"", name);
|
||||||
|
|
||||||
|
te = ngx_proxy_protocol_tlv_entries;
|
||||||
|
tlvs = &c->proxy_protocol->tlvs;
|
||||||
|
|
||||||
|
p = name->data;
|
||||||
|
n = name->len;
|
||||||
|
|
||||||
|
if (n >= 4 && p[0] == 's' && p[1] == 's' && p[2] == 'l' && p[3] == '_') {
|
||||||
|
|
||||||
|
rc = ngx_proxy_protocol_lookup_tlv(c, tlvs, 0x20, &ssl);
|
||||||
|
if (rc != NGX_OK) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssl.len < sizeof(ngx_proxy_protocol_tlv_ssl_t)) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += 4;
|
||||||
|
n -= 4;
|
||||||
|
|
||||||
|
if (n == 6 && ngx_strncmp(p, "verify", 6) == 0) {
|
||||||
|
|
||||||
|
tlv_ssl = (ngx_proxy_protocol_tlv_ssl_t *) ssl.data;
|
||||||
|
verify = ngx_proxy_protocol_parse_uint32(tlv_ssl->verify);
|
||||||
|
|
||||||
|
value->data = ngx_pnalloc(c->pool, NGX_INT32_LEN);
|
||||||
|
if (value->data == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
value->len = ngx_sprintf(value->data, "%uD", verify)
|
||||||
|
- value->data;
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl.data += sizeof(ngx_proxy_protocol_tlv_ssl_t);
|
||||||
|
ssl.len -= sizeof(ngx_proxy_protocol_tlv_ssl_t);
|
||||||
|
|
||||||
|
te = ngx_proxy_protocol_tlv_ssl_entries;
|
||||||
|
tlvs = &ssl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n >= 2 && p[0] == '0' && p[1] == 'x') {
|
||||||
|
|
||||||
|
type = ngx_hextoi(p + 2, n - 2);
|
||||||
|
if (type == NGX_ERROR) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||||
|
"invalid PROXY protocol TLV \"%V\"", name);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ngx_proxy_protocol_lookup_tlv(c, tlvs, type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( /* void */ ; te->type; te++) {
|
||||||
|
if (te->name.len == n && ngx_strncmp(te->name.data, p, n) == 0) {
|
||||||
|
return ngx_proxy_protocol_lookup_tlv(c, tlvs, te->type, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||||
|
"unknown PROXY protocol TLV \"%V\"", name);
|
||||||
|
|
||||||
|
return NGX_DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_proxy_protocol_lookup_tlv(ngx_connection_t *c, ngx_str_t *tlvs,
|
||||||
|
ngx_uint_t type, ngx_str_t *value)
|
||||||
|
{
|
||||||
|
u_char *p;
|
||||||
|
size_t n, len;
|
||||||
|
ngx_proxy_protocol_tlv_t *tlv;
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||||
|
"PROXY protocol v2 lookup tlv:%02xi", type);
|
||||||
|
|
||||||
|
p = tlvs->data;
|
||||||
|
n = tlvs->len;
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
if (n < sizeof(ngx_proxy_protocol_tlv_t)) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlv = (ngx_proxy_protocol_tlv_t *) p;
|
||||||
|
len = ngx_proxy_protocol_parse_uint16(tlv->len);
|
||||||
|
|
||||||
|
p += sizeof(ngx_proxy_protocol_tlv_t);
|
||||||
|
n -= sizeof(ngx_proxy_protocol_tlv_t);
|
||||||
|
|
||||||
|
if (n < len) {
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0, "broken PROXY protocol TLV");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tlv->type == type) {
|
||||||
|
value->data = p;
|
||||||
|
value->len = len;
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += len;
|
||||||
|
n -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_DECLINED;
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ struct ngx_proxy_protocol_s {
|
|||||||
ngx_str_t dst_addr;
|
ngx_str_t dst_addr;
|
||||||
in_port_t src_port;
|
in_port_t src_port;
|
||||||
in_port_t dst_port;
|
in_port_t dst_port;
|
||||||
|
ngx_str_t tlvs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +29,8 @@ u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
|
|||||||
u_char *last);
|
u_char *last);
|
||||||
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
|
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
|
||||||
u_char *last);
|
u_char *last);
|
||||||
|
ngx_int_t ngx_proxy_protocol_get_tlv(ngx_connection_t *c, ngx_str_t *name,
|
||||||
|
ngx_str_t *value);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
||||||
|
@ -61,6 +61,8 @@ static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r,
|
|||||||
ngx_http_variable_value_t *v, uintptr_t data);
|
ngx_http_variable_value_t *v, uintptr_t data);
|
||||||
static ngx_int_t ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
|
static ngx_int_t ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
|
||||||
ngx_http_variable_value_t *v, uintptr_t data);
|
ngx_http_variable_value_t *v, uintptr_t data);
|
||||||
|
static ngx_int_t ngx_http_variable_proxy_protocol_tlv(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,
|
static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
|
||||||
ngx_http_variable_value_t *v, uintptr_t data);
|
ngx_http_variable_value_t *v, uintptr_t data);
|
||||||
static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
|
static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
|
||||||
@ -214,6 +216,10 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
|
|||||||
ngx_http_variable_proxy_protocol_port,
|
ngx_http_variable_proxy_protocol_port,
|
||||||
offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
|
offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("proxy_protocol_tlv_"), NULL,
|
||||||
|
ngx_http_variable_proxy_protocol_tlv,
|
||||||
|
0, NGX_HTTP_VAR_PREFIX, 0 },
|
||||||
|
|
||||||
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_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 },
|
{ ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
|
||||||
@ -1386,6 +1392,39 @@ ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_http_variable_proxy_protocol_tlv(ngx_http_request_t *r,
|
||||||
|
ngx_http_variable_value_t *v, uintptr_t data)
|
||||||
|
{
|
||||||
|
ngx_str_t *name = (ngx_str_t *) data;
|
||||||
|
|
||||||
|
ngx_int_t rc;
|
||||||
|
ngx_str_t tlv, value;
|
||||||
|
|
||||||
|
tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1);
|
||||||
|
tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1;
|
||||||
|
|
||||||
|
rc = ngx_proxy_protocol_get_tlv(r->connection, &tlv, &value);
|
||||||
|
|
||||||
|
if (rc == NGX_ERROR) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == NGX_DECLINED) {
|
||||||
|
v->not_found = 1;
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->len = value.len;
|
||||||
|
v->valid = 1;
|
||||||
|
v->no_cacheable = 0;
|
||||||
|
v->not_found = 0;
|
||||||
|
v->data = value.data;
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_http_variable_server_addr(ngx_http_request_t *r,
|
ngx_http_variable_server_addr(ngx_http_request_t *r,
|
||||||
ngx_http_variable_value_t *v, uintptr_t data)
|
ngx_http_variable_value_t *v, uintptr_t data)
|
||||||
|
@ -23,6 +23,8 @@ static ngx_int_t ngx_stream_variable_proxy_protocol_addr(
|
|||||||
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
|
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
|
||||||
static ngx_int_t ngx_stream_variable_proxy_protocol_port(
|
static ngx_int_t ngx_stream_variable_proxy_protocol_port(
|
||||||
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
|
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
|
||||||
|
static ngx_int_t ngx_stream_variable_proxy_protocol_tlv(
|
||||||
|
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
|
||||||
static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
|
static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
|
||||||
ngx_stream_variable_value_t *v, uintptr_t data);
|
ngx_stream_variable_value_t *v, uintptr_t data);
|
||||||
static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
|
static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
|
||||||
@ -79,6 +81,10 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = {
|
|||||||
ngx_stream_variable_proxy_protocol_port,
|
ngx_stream_variable_proxy_protocol_port,
|
||||||
offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
|
offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
|
||||||
|
|
||||||
|
{ ngx_string("proxy_protocol_tlv_"), NULL,
|
||||||
|
ngx_stream_variable_proxy_protocol_tlv,
|
||||||
|
0, NGX_STREAM_VAR_PREFIX, 0 },
|
||||||
|
|
||||||
{ ngx_string("server_addr"), NULL,
|
{ ngx_string("server_addr"), NULL,
|
||||||
ngx_stream_variable_server_addr, 0, 0, 0 },
|
ngx_stream_variable_server_addr, 0, 0, 0 },
|
||||||
|
|
||||||
@ -621,6 +627,39 @@ ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_stream_variable_proxy_protocol_tlv(ngx_stream_session_t *s,
|
||||||
|
ngx_stream_variable_value_t *v, uintptr_t data)
|
||||||
|
{
|
||||||
|
ngx_str_t *name = (ngx_str_t *) data;
|
||||||
|
|
||||||
|
ngx_int_t rc;
|
||||||
|
ngx_str_t tlv, value;
|
||||||
|
|
||||||
|
tlv.len = name->len - (sizeof("proxy_protocol_tlv_") - 1);
|
||||||
|
tlv.data = name->data + sizeof("proxy_protocol_tlv_") - 1;
|
||||||
|
|
||||||
|
rc = ngx_proxy_protocol_get_tlv(s->connection, &tlv, &value);
|
||||||
|
|
||||||
|
if (rc == NGX_ERROR) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == NGX_DECLINED) {
|
||||||
|
v->not_found = 1;
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->len = value.len;
|
||||||
|
v->valid = 1;
|
||||||
|
v->no_cacheable = 0;
|
||||||
|
v->not_found = 0;
|
||||||
|
v->data = value.data;
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_stream_variable_server_addr(ngx_stream_session_t *s,
|
ngx_stream_variable_server_addr(ngx_stream_session_t *s,
|
||||||
ngx_stream_variable_value_t *v, uintptr_t data)
|
ngx_stream_variable_value_t *v, uintptr_t data)
|
||||||
|
Loading…
Reference in New Issue
Block a user