Klaus Demo nginx / 9207cc8
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). Vladimir Homutov 4 years ago
1 changed file(s) with 192 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
66
77 #include <ngx_config.h>
88 #include <ngx_core.h>
9
10
11 #define NGX_PP_V2_SIGLEN 12
12 #define NGX_PP_V2_CMD_PROXY 1
13 #define NGX_PP_V2_STREAM 1
14
15 #define NGX_PP_V2_AF_UNSPEC 0
16 #define NGX_PP_V2_AF_INET 1
17 #define NGX_PP_V2_AF_INET6 2
18
19
20 #define ngx_pp_v2_get_u16(p) \
21 ( ((uint16_t) ((u_char *) (p))[0] << 8) \
22 + ( ((u_char *) (p))[1]) )
23
24
25 typedef struct {
26 u_char signature[NGX_PP_V2_SIGLEN];
27 u_char ver_cmd;
28 u_char fam_transp;
29 u_char len[2];
30 } ngx_pp_v2_header_t;
31
32
33 typedef struct {
34 u_char src[4];
35 u_char dst[4];
36 u_char sport[2];
37 u_char dport[2];
38 } ngx_pp_v2_inet_addrs_t;
39
40
41 typedef struct {
42 u_char src[16];
43 u_char dst[16];
44 u_char sport[2];
45 u_char dport[2];
46 } ngx_pp_v2_inet6_addrs_t;
47
48
49 typedef union {
50 ngx_pp_v2_inet_addrs_t inet;
51 ngx_pp_v2_inet6_addrs_t inet6;
52 } ngx_pp_v2_addrs_t;
53
54
55 static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
56 u_char *last);
57
58 static const u_char ngx_pp_v2_signature[NGX_PP_V2_SIGLEN] =
59 { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
960
1061
1162 u_char *
1869 p = buf;
1970 len = last - buf;
2071
72 if (len >= sizeof(ngx_pp_v2_header_t)
73 && memcmp(p, ngx_pp_v2_signature, NGX_PP_V2_SIGLEN) == 0)
74 {
75 return ngx_proxy_protocol_v2_read(c, buf, last);
76 }
77
2178 if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
2279 goto invalid;
2380 }
165222
166223 return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
167224 }
225
226
227 static u_char *
228 ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
229 {
230 u_char *end;
231 size_t len;
232 socklen_t socklen;
233 ngx_str_t *name;
234 ngx_uint_t ver, cmd, family, transport;
235 ngx_sockaddr_t sockaddr;
236 ngx_pp_v2_addrs_t *addrs;
237 ngx_pp_v2_header_t *hdr;
238
239 hdr = (ngx_pp_v2_header_t *) buf;
240
241 buf += sizeof(ngx_pp_v2_header_t);
242
243 ver = hdr->ver_cmd >> 4;
244
245 if (ver != 2) {
246 ngx_log_error(NGX_LOG_ERR, c->log, 0,
247 "unsupported PROXY protocol version: %ui", ver);
248 return NULL;
249 }
250
251 len = ngx_pp_v2_get_u16(hdr->len);
252
253 if ((size_t) (last - buf) < len) {
254 ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large");
255 return NULL;
256 }
257
258 end = buf + len;
259
260 cmd = hdr->ver_cmd & 0x0F;
261
262 if (cmd != NGX_PP_V2_CMD_PROXY) {
263 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
264 "PROXY protocol v2 unsupported cmd 0x%xi", cmd);
265 return end;
266 }
267
268 transport = hdr->fam_transp & 0x0F;
269
270 if (transport != NGX_PP_V2_STREAM) {
271 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
272 "PROXY protocol v2 unsupported transport 0x%xi",
273 transport);
274 return end;
275 }
276
277 family = hdr->fam_transp >> 4;
278
279 addrs = (ngx_pp_v2_addrs_t *) buf;
280
281 switch (family) {
282
283 case NGX_PP_V2_AF_UNSPEC:
284 ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
285 "PROXY protocol v2 AF_UNSPEC ignored");
286 return end;
287
288 case NGX_PP_V2_AF_INET:
289
290 if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet_addrs_t)) {
291 return NULL;
292 }
293
294 sockaddr.sockaddr_in.sin_family = AF_INET;
295 sockaddr.sockaddr_in.sin_port = 0;
296 memcpy(&sockaddr.sockaddr_in.sin_addr, addrs->inet.src, 4);
297
298 c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet.sport);
299
300 socklen = sizeof(struct sockaddr_in);
301
302 buf += sizeof(ngx_pp_v2_inet_addrs_t);
303
304 break;
305
306 #if (NGX_HAVE_INET6)
307
308 case NGX_PP_V2_AF_INET6:
309
310 if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet6_addrs_t)) {
311 return NULL;
312 }
313
314 sockaddr.sockaddr_in6.sin6_family = AF_INET6;
315 sockaddr.sockaddr_in6.sin6_port = 0;
316 memcpy(&sockaddr.sockaddr_in6.sin6_addr, addrs->inet6.src, 16);
317
318 c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet6.sport);
319
320 socklen = sizeof(struct sockaddr_in6);
321
322 buf += sizeof(ngx_pp_v2_inet6_addrs_t);
323
324 break;
325
326 #endif
327
328 default:
329
330 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
331 "PROXY_protocol v2 unsupported address family "
332 "0x%xi", family);
333 return end;
334 }
335
336 name = &c->proxy_protocol_addr;
337
338 name->data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
339 if (name->data == NULL) {
340 return NULL;
341 }
342
343 name->len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, name->data,
344 NGX_SOCKADDR_STRLEN, 0);
345 if (name->len == 0) {
346 return NULL;
347 }
348
349 ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
350 "PROXY protocol v2 address: %V %i", name,
351 (ngx_int_t) c->proxy_protocol_port);
352
353 if (buf < end) {
354 ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
355 "PROXY protocol v2 %z bytes tlv ignored", end - buf);
356 }
357
358 return end;
359 }