ngx_proxy_protocol.c revision e18a033b
1
2/*
3 * Copyright (C) Roman Arutyunyan
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10
11
12u_char *
13ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
14{
15    size_t     len;
16    u_char     ch, *p, *addr, *port;
17    ngx_int_t  n;
18
19    p = buf;
20    len = last - buf;
21
22    if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
23        goto invalid;
24    }
25
26    p += 6;
27    len -= 6;
28
29    if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
30        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
31                       "PROXY protocol unknown protocol");
32        p += 7;
33        goto skip;
34    }
35
36    if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
37        || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
38    {
39        goto invalid;
40    }
41
42    p += 5;
43    addr = p;
44
45    for ( ;; ) {
46        if (p == last) {
47            goto invalid;
48        }
49
50        ch = *p++;
51
52        if (ch == ' ') {
53            break;
54        }
55
56        if (ch != ':' && ch != '.'
57            && (ch < 'a' || ch > 'f')
58            && (ch < 'A' || ch > 'F')
59            && (ch < '0' || ch > '9'))
60        {
61            goto invalid;
62        }
63    }
64
65    len = p - addr - 1;
66    c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
67
68    if (c->proxy_protocol_addr.data == NULL) {
69        return NULL;
70    }
71
72    ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
73    c->proxy_protocol_addr.len = len;
74
75    for ( ;; ) {
76        if (p == last) {
77            goto invalid;
78        }
79
80        if (*p++ == ' ') {
81            break;
82        }
83    }
84
85    port = p;
86
87    for ( ;; ) {
88        if (p == last) {
89            goto invalid;
90        }
91
92        if (*p++ == ' ') {
93            break;
94        }
95    }
96
97    len = p - port - 1;
98
99    n = ngx_atoi(port, len);
100
101    if (n < 0 || n > 65535) {
102        goto invalid;
103    }
104
105    c->proxy_protocol_port = (in_port_t) n;
106
107    ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
108                   "PROXY protocol address: %V %i", &c->proxy_protocol_addr, n);
109
110skip:
111
112    for ( /* void */ ; p < last - 1; p++) {
113        if (p[0] == CR && p[1] == LF) {
114            return p + 2;
115        }
116    }
117
118invalid:
119
120    ngx_log_error(NGX_LOG_ERR, c->log, 0,
121                  "broken header: \"%*s\"", (size_t) (last - buf), buf);
122
123    return NULL;
124}
125
126
127u_char *
128ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
129{
130    ngx_uint_t  port, lport;
131
132    if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
133        return NULL;
134    }
135
136    if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
137        return NULL;
138    }
139
140    switch (c->sockaddr->sa_family) {
141
142    case AF_INET:
143        buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
144        break;
145
146#if (NGX_HAVE_INET6)
147    case AF_INET6:
148        buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
149        break;
150#endif
151
152    default:
153        return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
154                          sizeof("PROXY UNKNOWN" CRLF) - 1);
155    }
156
157    buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
158
159    *buf++ = ' ';
160
161    buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
162                         0);
163
164    port = ngx_inet_get_port(c->sockaddr);
165    lport = ngx_inet_get_port(c->local_sockaddr);
166
167    return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
168}
169