Core: revised the PROXY protocol v2 code.
- use normal prefixes for types and macros
- removed some macros and types
- revised debug messages
- removed useless check of ngx_sock_ntop() returning 0
- removed special processing of AF_UNSPEC
Ruslan Ermilov
4 years ago
8 | 8 | #include <ngx_core.h> |
9 | 9 | |
10 | 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) ((p)[0] << 8 | (p)[1]) | |
11 | #define NGX_PROXY_PROTOCOL_AF_INET 1 | |
12 | #define NGX_PROXY_PROTOCOL_AF_INET6 2 | |
13 | ||
14 | ||
15 | #define ngx_proxy_protocol_parse_uint16(p) ((p)[0] << 8 | (p)[1]) | |
21 | 16 | |
22 | 17 | |
23 | 18 | typedef struct { |
24 | u_char signature[NGX_PP_V2_SIGLEN]; | |
25 | u_char ver_cmd; | |
26 | u_char family_transport; | |
27 | u_char len[2]; | |
28 | } ngx_pp_v2_header_t; | |
19 | u_char signature[12]; | |
20 | u_char version_command; | |
21 | u_char family_transport; | |
22 | u_char len[2]; | |
23 | } ngx_proxy_protocol_header_t; | |
29 | 24 | |
30 | 25 | |
31 | 26 | typedef struct { |
32 | u_char src[4]; | |
33 | u_char dst[4]; | |
34 | u_char sport[2]; | |
35 | u_char dport[2]; | |
36 | } ngx_pp_v2_inet_addrs_t; | |
27 | u_char s_addr[4]; | |
28 | u_char d_addr[4]; | |
29 | u_char s_port[2]; | |
30 | u_char d_port[2]; | |
31 | } ngx_proxy_protocol_inet_addrs_t; | |
37 | 32 | |
38 | 33 | |
39 | 34 | typedef struct { |
40 | u_char src[16]; | |
41 | u_char dst[16]; | |
42 | u_char sport[2]; | |
43 | u_char dport[2]; | |
44 | } ngx_pp_v2_inet6_addrs_t; | |
45 | ||
46 | ||
47 | typedef union { | |
48 | ngx_pp_v2_inet_addrs_t inet; | |
49 | ngx_pp_v2_inet6_addrs_t inet6; | |
50 | } ngx_pp_v2_addrs_t; | |
35 | u_char s_addr[16]; | |
36 | u_char d_addr[16]; | |
37 | u_char s_port[2]; | |
38 | u_char d_port[2]; | |
39 | } ngx_proxy_protocol_inet6_addrs_t; | |
51 | 40 | |
52 | 41 | |
53 | 42 | static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, |
54 | 43 | u_char *last); |
55 | ||
56 | static const u_char ngx_pp_v2_signature[NGX_PP_V2_SIGLEN] = | |
57 | { 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a }; | |
58 | 44 | |
59 | 45 | |
60 | 46 | u_char * |
64 | 50 | u_char ch, *p, *addr, *port; |
65 | 51 | ngx_int_t n; |
66 | 52 | |
53 | static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n"; | |
54 | ||
67 | 55 | p = buf; |
68 | 56 | len = last - buf; |
69 | 57 | |
70 | if (len >= sizeof(ngx_pp_v2_header_t) | |
71 | && memcmp(p, ngx_pp_v2_signature, NGX_PP_V2_SIGLEN) == 0) | |
58 | if (len >= sizeof(ngx_proxy_protocol_header_t) | |
59 | && memcmp(p, signature, sizeof(signature) - 1) == 0) | |
72 | 60 | { |
73 | 61 | return ngx_proxy_protocol_v2_read(c, buf, last); |
74 | 62 | } |
226 | 214 | static u_char * |
227 | 215 | ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last) |
228 | 216 | { |
229 | u_char *end; | |
230 | size_t len; | |
231 | socklen_t socklen; | |
232 | ngx_str_t *name; | |
233 | ngx_uint_t ver, cmd, family, transport; | |
234 | ngx_sockaddr_t sockaddr; | |
235 | ngx_pp_v2_addrs_t *addrs; | |
236 | ngx_pp_v2_header_t *hdr; | |
237 | ||
238 | hdr = (ngx_pp_v2_header_t *) buf; | |
239 | ||
240 | buf += sizeof(ngx_pp_v2_header_t); | |
241 | ||
242 | ver = hdr->ver_cmd >> 4; | |
243 | ||
244 | if (ver != 2) { | |
217 | u_char *end; | |
218 | size_t len; | |
219 | socklen_t socklen; | |
220 | ngx_uint_t version, command, family, transport; | |
221 | ngx_sockaddr_t sockaddr; | |
222 | ngx_proxy_protocol_header_t *header; | |
223 | ngx_proxy_protocol_inet_addrs_t *inet; | |
224 | #if (NGX_HAVE_INET6) | |
225 | ngx_proxy_protocol_inet6_addrs_t *inet6; | |
226 | #endif | |
227 | ||
228 | header = (ngx_proxy_protocol_header_t *) buf; | |
229 | ||
230 | buf += sizeof(ngx_proxy_protocol_header_t); | |
231 | ||
232 | version = header->version_command >> 4; | |
233 | ||
234 | if (version != 2) { | |
245 | 235 | ngx_log_error(NGX_LOG_ERR, c->log, 0, |
246 | "unsupported PROXY protocol version: %ui", ver); | |
247 | return NULL; | |
248 | } | |
249 | ||
250 | len = ngx_pp_v2_get_u16(hdr->len); | |
236 | "unknown PROXY protocol version: %ui", version); | |
237 | return NULL; | |
238 | } | |
239 | ||
240 | len = ngx_proxy_protocol_parse_uint16(header->len); | |
251 | 241 | |
252 | 242 | if ((size_t) (last - buf) < len) { |
253 | 243 | ngx_log_error(NGX_LOG_ERR, c->log, 0, "header is too large"); |
256 | 246 | |
257 | 247 | end = buf + len; |
258 | 248 | |
259 | cmd = hdr->ver_cmd & 0x0f; | |
260 | ||
261 | if (cmd != NGX_PP_V2_CMD_PROXY) { | |
249 | command = header->version_command & 0x0f; | |
250 | ||
251 | /* only PROXY is supported */ | |
252 | if (command != 1) { | |
262 | 253 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, |
263 | "PROXY protocol v2 unsupported command 0x%xi", cmd); | |
254 | "PROXY protocol v2 unsupported command %ui", command); | |
264 | 255 | return end; |
265 | 256 | } |
266 | 257 | |
267 | transport = hdr->family_transport & 0x0f; | |
268 | ||
269 | if (transport != NGX_PP_V2_STREAM) { | |
258 | transport = header->family_transport & 0x0f; | |
259 | ||
260 | /* only STREAM is supported */ | |
261 | if (transport != 1) { | |
270 | 262 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, |
271 | "PROXY protocol v2 unsupported transport 0x%xi", | |
263 | "PROXY protocol v2 unsupported transport %ui", | |
272 | 264 | transport); |
273 | 265 | return end; |
274 | 266 | } |
275 | 267 | |
276 | family = hdr->family_transport >> 4; | |
277 | ||
278 | addrs = (ngx_pp_v2_addrs_t *) buf; | |
268 | family = header->family_transport >> 4; | |
279 | 269 | |
280 | 270 | switch (family) { |
281 | 271 | |
282 | case NGX_PP_V2_AF_UNSPEC: | |
283 | ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, | |
284 | "PROXY protocol v2 AF_UNSPEC ignored"); | |
285 | return end; | |
286 | ||
287 | case NGX_PP_V2_AF_INET: | |
288 | ||
289 | if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet_addrs_t)) { | |
272 | case NGX_PROXY_PROTOCOL_AF_INET: | |
273 | ||
274 | if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet_addrs_t)) { | |
290 | 275 | return NULL; |
291 | 276 | } |
277 | ||
278 | inet = (ngx_proxy_protocol_inet_addrs_t *) buf; | |
292 | 279 | |
293 | 280 | sockaddr.sockaddr_in.sin_family = AF_INET; |
294 | 281 | sockaddr.sockaddr_in.sin_port = 0; |
295 | memcpy(&sockaddr.sockaddr_in.sin_addr, addrs->inet.src, 4); | |
296 | ||
297 | c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet.sport); | |
282 | memcpy(&sockaddr.sockaddr_in.sin_addr, inet->s_addr, 4); | |
283 | ||
284 | c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(inet->s_port); | |
298 | 285 | |
299 | 286 | socklen = sizeof(struct sockaddr_in); |
300 | 287 | |
301 | buf += sizeof(ngx_pp_v2_inet_addrs_t); | |
288 | buf += sizeof(ngx_proxy_protocol_inet_addrs_t); | |
302 | 289 | |
303 | 290 | break; |
304 | 291 | |
305 | 292 | #if (NGX_HAVE_INET6) |
306 | 293 | |
307 | case NGX_PP_V2_AF_INET6: | |
308 | ||
309 | if ((size_t) (end - buf) < sizeof(ngx_pp_v2_inet6_addrs_t)) { | |
294 | case NGX_PROXY_PROTOCOL_AF_INET6: | |
295 | ||
296 | if ((size_t) (end - buf) < sizeof(ngx_proxy_protocol_inet6_addrs_t)) { | |
310 | 297 | return NULL; |
311 | 298 | } |
299 | ||
300 | inet6 = (ngx_proxy_protocol_inet6_addrs_t *) buf; | |
312 | 301 | |
313 | 302 | sockaddr.sockaddr_in6.sin6_family = AF_INET6; |
314 | 303 | sockaddr.sockaddr_in6.sin6_port = 0; |
315 | memcpy(&sockaddr.sockaddr_in6.sin6_addr, addrs->inet6.src, 16); | |
316 | ||
317 | c->proxy_protocol_port = ngx_pp_v2_get_u16(addrs->inet6.sport); | |
304 | memcpy(&sockaddr.sockaddr_in6.sin6_addr, inet6->s_addr, 16); | |
305 | ||
306 | c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(inet6->s_port); | |
318 | 307 | |
319 | 308 | socklen = sizeof(struct sockaddr_in6); |
320 | 309 | |
321 | buf += sizeof(ngx_pp_v2_inet6_addrs_t); | |
310 | buf += sizeof(ngx_proxy_protocol_inet6_addrs_t); | |
322 | 311 | |
323 | 312 | break; |
324 | 313 | |
325 | 314 | #endif |
326 | 315 | |
327 | 316 | default: |
328 | ||
329 | 317 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, |
330 | "PROXY protocol v2 unsupported address family 0x%xi", | |
318 | "PROXY protocol v2 unsupported address family %ui", | |
331 | 319 | family); |
332 | 320 | return end; |
333 | 321 | } |
334 | 322 | |
335 | name = &c->proxy_protocol_addr; | |
336 | ||
337 | name->data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); | |
338 | if (name->data == NULL) { | |
339 | return NULL; | |
340 | } | |
341 | ||
342 | name->len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, name->data, | |
343 | NGX_SOCKADDR_STRLEN, 0); | |
344 | if (name->len == 0) { | |
345 | return NULL; | |
346 | } | |
323 | c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); | |
324 | if (c->proxy_protocol_addr.data == NULL) { | |
325 | return NULL; | |
326 | } | |
327 | ||
328 | c->proxy_protocol_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, | |
329 | c->proxy_protocol_addr.data, | |
330 | NGX_SOCKADDR_STRLEN, 0); | |
347 | 331 | |
348 | 332 | ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, |
349 | "PROXY protocol v2 address: %V %d", name, | |
333 | "PROXY protocol v2 address: %V %d", &c->proxy_protocol_addr, | |
350 | 334 | c->proxy_protocol_port); |
351 | 335 | |
352 | 336 | if (buf < end) { |
353 | 337 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, |
354 | "PROXY protocol v2 %z bytes tlv ignored", end - buf); | |
338 | "PROXY protocol v2 %z bytes of tlv ignored", end - buf); | |
355 | 339 | } |
356 | 340 | |
357 | 341 | return end; |