comparison src/core/ngx_proxy_protocol.c @ 7251:416953ef0428

Core: added processing of version 2 of the PROXY protocol. The protocol used on inbound connection is auto-detected and corresponding parser is used to extract passed addresses. TLV parameters are ignored. The maximum supported size of PROXY protocol header is 107 bytes (similar to version 1).
author Vladimir Homutov <vl@nginx.com>
date Thu, 22 Mar 2018 15:55:28 +0300
parents b3b7e33083ac
children 7bdab16c55f1
comparison
equal deleted inserted replaced
7250:ec4d95eed062 7251:416953ef0428
5 */ 5 */
6 6
7 7
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10
11
12 #define NGX_PP_V2_SIGLEN 12
13 #define NGX_PP_V2_CMD_PROXY 1
14 #define NGX_PP_V2_STREAM 1
15
16 #define NGX_PP_V2_AF_UNSPEC 0
17 #define NGX_PP_V2_AF_INET 1
18 #define NGX_PP_V2_AF_INET6 2
19
20
21 #define ngx_pp_v2_get_u16(p) \
22 ( ((uint16_t) ((u_char *) (p))[0] << 8) \
23 + ( ((u_char *) (p))[1]) )
24
25
26 typedef struct {
27 u_char signature[NGX_PP_V2_SIGLEN];
28 u_char ver_cmd;
29 u_char fam_transp;
30 u_char len[2];
31 } ngx_pp_v2_header_t;
32
33
34 typedef struct {
35 u_char src[4];
36 u_char dst[4];
37 u_char sport[2];
38 u_char dport[2];
39 } ngx_pp_v2_inet_addrs_t;
40
41
42 typedef struct {
43 u_char src[16];
44 u_char dst[16];
45 u_char sport[2];
46 u_char dport[2];
47 } ngx_pp_v2_inet6_addrs_t;
48
49
50 typedef union {
51 ngx_pp_v2_inet_addrs_t inet;
52 ngx_pp_v2_inet6_addrs_t inet6;
53 } ngx_pp_v2_addrs_t;
54
55
56 static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
57 u_char *last);
58
59 static const u_char ngx_pp_v2_signature[NGX_PP_V2_SIGLEN] =
60 { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
10 61
11 62
12 u_char * 63 u_char *
13 ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) 64 ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
14 { 65 {
17 ngx_int_t n; 68 ngx_int_t n;
18 69
19 p = buf; 70 p = buf;
20 len = last - buf; 71 len = last - buf;
21 72
73 if (len >= sizeof(ngx_pp_v2_header_t)
74 && memcmp(p, ngx_pp_v2_signature, NGX_PP_V2_SIGLEN) == 0)
75 {
76 return ngx_proxy_protocol_v2_read(c, buf, last);
77 }
78
22 if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) { 79 if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
23 goto invalid; 80 goto invalid;
24 } 81 }
25 82
26 p += 6; 83 p += 6;
164 port = ngx_inet_get_port(c->sockaddr); 221 port = ngx_inet_get_port(c->sockaddr);
165 lport = ngx_inet_get_port(c->local_sockaddr); 222 lport = ngx_inet_get_port(c->local_sockaddr);
166 223
167 return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport); 224 return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
168 } 225 }
226
227
228 static u_char *
229 ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
230 {
231 u_char *end;
232 size_t len;
233 socklen_t socklen;
234 ngx_str_t *name;
235 ngx_uint_t ver, cmd, family, transport;
236 ngx_sockaddr_t sockaddr;
237 ngx_pp_v2_addrs_t *addrs;
238 ngx_pp_v2_header_t *hdr;
239
240 hdr = (ngx_pp_v2_header_t *) buf;
241
242 buf += sizeof(ngx_pp_v2_header_t);
243
244 ver = hdr->ver_cmd >> 4;
245
246 if (ver != 2) {
247 ngx_log_error(NGX_LOG_ERR, c->log, 0,
248 "unsupported PROXY protocol version: %ui", ver);
249 return NULL;
250 }
251
252 len = ngx_pp_v2_get_u16(hdr->len);
253
254 if ((size_t) (last - buf) < len) {
255 ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
256 return NULL;
257 }
258
259 end = buf + len;
260
261 cmd = hdr->ver_cmd & 0x0F;
262
263 if (cmd != NGX_PP_V2_CMD_PROXY) {
264 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
265 "PROXY protocol v2 unsupported cmd 0x%xi", cmd);
266 return end;
267 }
268
269 transport = hdr->fam_transp & 0x0F;
270
271 if (transport != NGX_PP_V2_STREAM) {
272 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
273 "PROXY protocol v2 unsupported transport 0x%xi",
274 transport);
275 return end;
276 }
277
278 family = hdr->fam_transp >> 4;
279
280 addrs = (ngx_pp_v2_addrs_t *) buf;
281
282 switch (family) {
283
284 case NGX_PP_V2_AF_UNSPEC:
285 ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
286 "PROXY protocol v2 AF_UNSPEC ignored");
287 return end;
288
289 case NGX_PP_V2_AF_INET:
290
291 if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet_addrs_t)) {
292 return NULL;
293 }
294
295 sockaddr.sockaddr_in.sin_family = AF_INET;
296 sockaddr.sockaddr_in.sin_port = 0;
297 memcpy(&sockaddr.sockaddr_in.sin_addr, addrs->inet.src, 4);
298
299 c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet.sport);
300
301 socklen = sizeof(struct sockaddr_in);
302
303 buf += sizeof(ngx_pp_v2_inet_addrs_t);
304
305 break;
306
307 #if (NGX_HAVE_INET6)
308
309 case NGX_PP_V2_AF_INET6:
310
311 if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet6_addrs_t)) {
312 return NULL;
313 }
314
315 sockaddr.sockaddr_in6.sin6_family = AF_INET6;
316 sockaddr.sockaddr_in6.sin6_port = 0;
317 memcpy(&sockaddr.sockaddr_in6.sin6_addr, addrs->inet6.src, 16);
318
319 c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet6.sport);
320
321 socklen = sizeof(struct sockaddr_in6);
322
323 buf += sizeof(ngx_pp_v2_inet6_addrs_t);
324
325 break;
326
327 #endif
328
329 default:
330
331 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
332 "PROXY_protocol v2 unsupported address family "
333 "0x%xi", family);
334 return end;
335 }
336
337 name = &c->proxy_protocol_addr;
338
339 name->data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
340 if (name->data == NULL) {
341 return NULL;
342 }
343
344 name->len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, name->data,
345 NGX_SOCKADDR_STRLEN, 0);
346 if (name->len == 0) {
347 return NULL;
348 }
349
350 ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
351 "PROXY protocol v2 address: %V %i", name,
352 (ngx_int_t) c->proxy_protocol_port);
353
354 if (buf < end) {
355 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
356 "PROXY protocol v2 %z bytes tlv ignored", end - buf);
357 }
358
359 return end;
360 }