Mercurial > hg > nginx
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 } |