/src/opensips/net/proxy_protocol.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2025 OpenSIPS Solutions |
3 | | * |
4 | | * This file is part of opensips, a free SIP server. |
5 | | * |
6 | | * opensips is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * opensips is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | #include <stdio.h> |
25 | | #include "proxy_protocol.h" |
26 | | #include "../socket_info.h" |
27 | | #include "tcp_conn_defs.h" |
28 | | #include "tcp_common.h" |
29 | | #include "../ut.h" |
30 | | #include "../tsend.h" |
31 | | |
32 | 0 | #define PROXY_PROTOCOL_V1_HDR "PROXY " |
33 | 0 | #define PROXY_PROTOCOL_V1_HDR_LEN (sizeof(PROXY_PROTOCOL_V1_HDR) - 1) |
34 | 0 | #define PROXY_PROTOCOL_V1_UNKN "PROXY UNKNOWN\r\n" |
35 | 0 | #define PROXY_PROTOCOL_V1_UNKN_LEN (sizeof(PROXY_PROTOCOL_V1_UNKN) - 1) |
36 | 0 | #define PROXY_PROTOCOL_TCP4 "TCP4 " |
37 | 0 | #define PROXY_PROTOCOL_TCP4_LEN (sizeof(PROXY_PROTOCOL_TCP4) - 1) |
38 | 0 | #define PROXY_PROTOCOL_TCP6 "TCP6 " |
39 | 0 | #define PROXY_PROTOCOL_TCP6_LEN (sizeof(PROXY_PROTOCOL_TCP6) - 1) |
40 | 0 | #define PROXY_PROTOCOL_UNKN "UNKNOWN" |
41 | 0 | #define PROXY_PROTOCOL_UNKN_LEN (sizeof(PROXY_PROTOCOL_UNKN) - 1) |
42 | 0 | #define PROXY_PROTOCOL_END "\r\n" |
43 | 0 | #define PROXY_PROTOCOL_END_LEN (sizeof(PROXY_PROTOCOL_END) - 1) |
44 | 0 | #define PROXY_PROTOCOL_SEP ' ' |
45 | | /* |
46 | | * these are defined in the specs: |
47 | | * https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt |
48 | | */ |
49 | 0 | #define PROXY_PROTOCOL_TCP4_MAX 56 |
50 | | #define PROXY_PROTOCOL_TCP4_PAYLOAD_MAX \ |
51 | 0 | (PROXY_PROTOCOL_TCP4_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_TCP4_LEN) |
52 | 0 | #define PROXY_PROTOCOL_TCP6_MAX 104 |
53 | | #define PROXY_PROTOCOL_TCP6_PAYLOAD_MAX \ |
54 | 0 | (PROXY_PROTOCOL_TCP6_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_TCP6_LEN) |
55 | 0 | #define PROXY_PROTOCOL_UNKN_MAX PROXY_PROTOCOL_BUF_MAX |
56 | | #define PROXY_PROTOCOL_UNKN_PAYLOAD_MAX \ |
57 | 0 | (PROXY_PROTOCOL_UNKN_MAX - PROXY_PROTOCOL_V1_HDR_LEN - PROXY_PROTOCOL_UNKN_LEN) |
58 | | |
59 | | enum proxy_tok_match { |
60 | | PP_TOK_MISMATCH = -1, |
61 | | PP_TOK_PARTIAL = 0, |
62 | | PP_TOK_MATCH = 1, |
63 | | }; |
64 | | |
65 | | static inline enum proxy_tok_match match_proxy_token(const str *buf, |
66 | | const char *tok, int tok_len) |
67 | 0 | { |
68 | 0 | int cmp_len; |
69 | |
|
70 | 0 | cmp_len = (buf->len < tok_len) ? buf->len : tok_len; |
71 | 0 | if (strncasecmp(buf->s, tok, cmp_len) != 0) |
72 | 0 | return PP_TOK_MISMATCH; |
73 | 0 | if (buf->len < tok_len) |
74 | 0 | return PP_TOK_PARTIAL; |
75 | 0 | return PP_TOK_MATCH; |
76 | 0 | } |
77 | | |
78 | | int is_net_proxy_protocol(char *buf, int size) |
79 | 0 | { |
80 | 0 | if (size < PROXY_PROTOCOL_V1_HDR_LEN) |
81 | 0 | return -1; /* don't know yet */ |
82 | 0 | if (memcmp(buf, PROXY_PROTOCOL_V1_HDR, PROXY_PROTOCOL_V1_HDR_LEN)) |
83 | 0 | return 0; |
84 | | /* TODO: support v2 as well? */ |
85 | 0 | return 1; |
86 | 0 | } |
87 | | |
88 | | static int build_proxy_protocol_v1_hdr(const struct ip_addr *src_ip, |
89 | | unsigned short src_port, const struct ip_addr *dst_ip, |
90 | | unsigned short dst_port, char *buf, int size) |
91 | 0 | { |
92 | 0 | const char *src_s, *dst_s, *proto; |
93 | 0 | int len; |
94 | |
|
95 | 0 | if (!src_ip || !dst_ip || !buf || size <= 0) |
96 | 0 | return -1; |
97 | | |
98 | 0 | if (src_ip->af != dst_ip->af || |
99 | 0 | (src_ip->af != AF_INET && src_ip->af != AF_INET6)) { |
100 | 0 | if (size < PROXY_PROTOCOL_V1_UNKN_LEN + 1) |
101 | 0 | return -1; |
102 | 0 | memcpy(buf, PROXY_PROTOCOL_V1_UNKN, PROXY_PROTOCOL_V1_UNKN_LEN + 1); |
103 | 0 | return PROXY_PROTOCOL_V1_UNKN_LEN; |
104 | 0 | } |
105 | | |
106 | 0 | src_s = ip_addr2a((struct ip_addr *)src_ip); |
107 | 0 | dst_s = ip_addr2a((struct ip_addr *)dst_ip); |
108 | 0 | proto = (src_ip->af == AF_INET) ? "TCP4" : "TCP6"; |
109 | 0 | len = snprintf(buf, size, "PROXY %s %s %s %hu %hu\r\n", |
110 | 0 | proto, src_s, dst_s, src_port, dst_port); |
111 | 0 | if (len <= 0 || len >= size) |
112 | 0 | return -1; |
113 | | |
114 | 0 | return len; |
115 | 0 | } |
116 | | |
117 | | int build_outbound_proxy_protocol_v1_hdr(const struct receive_info *ri, |
118 | | const struct ip_addr *fallback_src_ip, |
119 | | unsigned short fallback_src_port, |
120 | | const struct ip_addr *fallback_dst_ip, |
121 | | unsigned short fallback_dst_port, |
122 | | char *buf, int size) |
123 | 0 | { |
124 | 0 | const struct ip_addr *src_ip = fallback_src_ip; |
125 | 0 | const struct ip_addr *dst_ip = fallback_dst_ip; |
126 | 0 | unsigned short src_port = fallback_src_port; |
127 | 0 | unsigned short dst_port = fallback_dst_port; |
128 | |
|
129 | 0 | if (ri) { |
130 | 0 | if (ri->real_ep.flags == PP_OK) { |
131 | 0 | src_ip = &ri->real_ep.src_ip; |
132 | 0 | src_port = ri->real_ep.src_port; |
133 | 0 | dst_ip = &ri->real_ep.dst_ip; |
134 | 0 | dst_port = ri->real_ep.dst_port; |
135 | 0 | } else { |
136 | 0 | src_ip = &ri->src_ip; |
137 | 0 | src_port = ri->src_port; |
138 | 0 | dst_ip = &ri->dst_ip; |
139 | 0 | dst_port = ri->dst_port; |
140 | 0 | } |
141 | 0 | } |
142 | |
|
143 | 0 | return build_proxy_protocol_v1_hdr(src_ip, src_port, dst_ip, dst_port, |
144 | 0 | buf, size); |
145 | 0 | } |
146 | | |
147 | | static inline int should_send_stream_proxy_protocol(const struct tcp_connection *c) |
148 | 0 | { |
149 | 0 | return c && c->rcv.bind_address && |
150 | 0 | (c->flags & F_CONN_ACCEPTED) == 0 && |
151 | 0 | (c->rcv.bind_address->flags & SI_PROXY_OUT) && |
152 | 0 | (c->flags & F_CONN_PROXY_OUT_SENT) == 0; |
153 | 0 | } |
154 | | |
155 | | int send_stream_proxy_protocol_v1(struct tcp_connection *c, int fd, |
156 | | int write_timeout, int lock, const struct receive_info *ri, |
157 | | const char *proto_name) |
158 | 0 | { |
159 | 0 | char pp_hdr[PROXY_PROTOCOL_BUF_MAX]; |
160 | 0 | int pp_len, rc, dbg_len; |
161 | 0 | const char *action; |
162 | |
|
163 | 0 | if (!should_send_stream_proxy_protocol(c)) |
164 | 0 | return 0; |
165 | | |
166 | 0 | if (fd < 0 && ((c->flags & F_CONN_INIT) == 0 || c->fd < 0)) |
167 | 0 | return 0; |
168 | | |
169 | 0 | pp_len = build_outbound_proxy_protocol_v1_hdr(ri, |
170 | 0 | &c->rcv.dst_ip, c->rcv.dst_port, |
171 | 0 | &c->rcv.src_ip, c->rcv.src_port, |
172 | 0 | pp_hdr, sizeof(pp_hdr)); |
173 | 0 | if (pp_len < 0) { |
174 | 0 | LM_ERR("failed to build outbound PROXY header\n"); |
175 | 0 | return -1; |
176 | 0 | } |
177 | | |
178 | 0 | dbg_len = pp_len; |
179 | 0 | if (dbg_len >= 2 && pp_hdr[dbg_len - 2] == '\r' && |
180 | 0 | pp_hdr[dbg_len - 1] == '\n') |
181 | 0 | dbg_len -= 2; |
182 | |
|
183 | 0 | action = (fd < 0) ? "queueing" : "sending"; |
184 | 0 | LM_DBG("%s outbound PROXY header on %s conn %u: %.*s\n", |
185 | 0 | action, proto_name ? proto_name : "stream", c->id, |
186 | 0 | dbg_len, pp_hdr); |
187 | |
|
188 | 0 | if (fd < 0) { |
189 | 0 | rc = tcp_async_add_chunk(c, pp_hdr, pp_len, lock); |
190 | 0 | } else { |
191 | 0 | if (lock) |
192 | 0 | lock_get(&c->write_lock); |
193 | 0 | rc = tsend_stream(fd, pp_hdr, pp_len, write_timeout); |
194 | 0 | if (lock) |
195 | 0 | lock_release(&c->write_lock); |
196 | 0 | if (rc != pp_len) { |
197 | 0 | LM_ERR("failed to send outbound PROXY header on %s\n", |
198 | 0 | proto_name ? proto_name : "stream"); |
199 | 0 | return -1; |
200 | 0 | } |
201 | 0 | tcp_conn_reset_lifetime(c); |
202 | 0 | rc = 0; |
203 | 0 | } |
204 | | |
205 | 0 | if (rc < 0) { |
206 | 0 | LM_ERR("failed to send outbound PROXY header on %s\n", |
207 | 0 | proto_name ? proto_name : "stream"); |
208 | 0 | return -1; |
209 | 0 | } |
210 | | |
211 | 0 | c->flags |= F_CONN_PROXY_OUT_SENT; |
212 | 0 | return 0; |
213 | 0 | } |
214 | | |
215 | | char *parse_net_proxy_protocol(char *buf, int size, struct proxy_protocol *proxy) |
216 | 0 | { |
217 | 0 | int af, max; |
218 | 0 | char *p, *end; |
219 | 0 | str _buf, tmp; |
220 | 0 | struct ip_addr *ip; |
221 | 0 | unsigned int port; |
222 | 0 | enum proxy_tok_match m; |
223 | |
|
224 | 0 | if (size < PROXY_PROTOCOL_V1_HDR_LEN || |
225 | 0 | memcmp(buf, PROXY_PROTOCOL_V1_HDR, PROXY_PROTOCOL_V1_HDR_LEN) != 0) |
226 | 0 | goto error; |
227 | | |
228 | 0 | _buf.s = buf + PROXY_PROTOCOL_V1_HDR_LEN; |
229 | 0 | _buf.len = size - PROXY_PROTOCOL_V1_HDR_LEN; |
230 | |
|
231 | 0 | m = match_proxy_token(&_buf, PROXY_PROTOCOL_TCP4, PROXY_PROTOCOL_TCP4_LEN); |
232 | 0 | if (m == PP_TOK_MATCH) { |
233 | 0 | af = AF_INET; |
234 | 0 | _buf.s += PROXY_PROTOCOL_TCP4_LEN; |
235 | 0 | _buf.len -= PROXY_PROTOCOL_TCP4_LEN; |
236 | 0 | if (_buf.len > PROXY_PROTOCOL_TCP4_PAYLOAD_MAX) |
237 | 0 | _buf.len = PROXY_PROTOCOL_TCP4_PAYLOAD_MAX; |
238 | 0 | max = PROXY_PROTOCOL_TCP4_MAX; |
239 | 0 | } else if (m == PP_TOK_PARTIAL) { |
240 | 0 | return NULL; |
241 | 0 | } else { |
242 | 0 | m = match_proxy_token(&_buf, PROXY_PROTOCOL_TCP6, PROXY_PROTOCOL_TCP6_LEN); |
243 | 0 | if (m == PP_TOK_MATCH) { |
244 | 0 | af = AF_INET6; |
245 | 0 | _buf.s += PROXY_PROTOCOL_TCP6_LEN; |
246 | 0 | _buf.len -= PROXY_PROTOCOL_TCP6_LEN; |
247 | 0 | if (_buf.len > PROXY_PROTOCOL_TCP6_PAYLOAD_MAX) |
248 | 0 | _buf.len = PROXY_PROTOCOL_TCP6_PAYLOAD_MAX; |
249 | 0 | max = PROXY_PROTOCOL_TCP6_MAX; |
250 | 0 | } else if (m == PP_TOK_PARTIAL) { |
251 | 0 | return NULL; |
252 | 0 | } else { |
253 | 0 | m = match_proxy_token(&_buf, PROXY_PROTOCOL_UNKN, PROXY_PROTOCOL_UNKN_LEN); |
254 | 0 | if (m == PP_TOK_MATCH) { |
255 | 0 | _buf.s += PROXY_PROTOCOL_UNKN_LEN; |
256 | 0 | _buf.len -= PROXY_PROTOCOL_UNKN_LEN; |
257 | 0 | if (_buf.len == 0) |
258 | 0 | return NULL; |
259 | 0 | if (_buf.s[0] != PROXY_PROTOCOL_SEP && |
260 | 0 | _buf.s[0] != PROXY_PROTOCOL_END[0]) { |
261 | 0 | LM_DBG("bad separator after proxy_protocol UNKNOWN: 0x%x\n", |
262 | 0 | (unsigned char)_buf.s[0]); |
263 | 0 | goto error; |
264 | 0 | } |
265 | 0 | if (_buf.len > PROXY_PROTOCOL_UNKN_PAYLOAD_MAX) |
266 | 0 | _buf.len = PROXY_PROTOCOL_UNKN_PAYLOAD_MAX; |
267 | 0 | af = AF_UNSPEC; |
268 | 0 | max = PROXY_PROTOCOL_UNKN_MAX; |
269 | 0 | } else if (m == PP_TOK_PARTIAL) { |
270 | 0 | return NULL; |
271 | 0 | } else { |
272 | 0 | LM_DBG("unknown proxy_protocol proto [%.*s]\n", _buf.len, _buf.s); |
273 | 0 | goto error; |
274 | 0 | } |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | | /* search for the end within the maximum payload */ |
279 | 0 | end = str_strstr(&_buf, _str(PROXY_PROTOCOL_END)); |
280 | 0 | if (!end) { |
281 | 0 | if (size < max) /* we still don't have enough data to find the end */ |
282 | 0 | return NULL; |
283 | 0 | LM_DBG("could not find proxy_protocol end in [%.*s]\n", |
284 | 0 | _buf.len, _buf.s); |
285 | 0 | goto error; |
286 | 0 | } |
287 | 0 | if (af == AF_UNSPEC) { |
288 | | /* we have an unknown protocol - stop it here */ |
289 | 0 | proxy->flags = PP_UNKNOWN; |
290 | 0 | return end + PROXY_PROTOCOL_END_LEN; |
291 | 0 | } |
292 | 0 | _buf.len = end - _buf.s; |
293 | | /* src ip */ |
294 | 0 | p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len); |
295 | 0 | if (!p) |
296 | 0 | goto error; |
297 | 0 | tmp.s = _buf.s; |
298 | 0 | tmp.len = p - _buf.s; |
299 | 0 | ip = (af == AF_INET?str2ip(&tmp):str2ip6(&tmp)); |
300 | 0 | if (!ip) { |
301 | 0 | LM_DBG("could not parse proxy_protocol src ip %.*s for af %d\n", |
302 | 0 | tmp.len, tmp.s, af); |
303 | 0 | goto error; |
304 | 0 | } |
305 | 0 | memcpy(&proxy->src_ip, ip, sizeof *ip); |
306 | 0 | _buf.len -= tmp.len + 1; |
307 | 0 | _buf.s = p + 1; |
308 | | |
309 | | /* dst ip */ |
310 | 0 | p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len); |
311 | 0 | if (!p) |
312 | 0 | goto error; |
313 | 0 | tmp.s = _buf.s; |
314 | 0 | tmp.len = p - _buf.s; |
315 | 0 | ip = (af == AF_INET?str2ip(&tmp):str2ip6(&tmp)); |
316 | 0 | if (!ip) { |
317 | 0 | LM_DBG("could not parse proxy_protocol dst ip %.*s for af %d\n", |
318 | 0 | tmp.len, tmp.s, af); |
319 | 0 | goto error; |
320 | 0 | } |
321 | 0 | memcpy(&proxy->dst_ip, ip, sizeof *ip); |
322 | 0 | _buf.len -= tmp.len + 1; |
323 | 0 | _buf.s = p + 1; |
324 | | |
325 | | /* src port */ |
326 | 0 | p = q_memchr(_buf.s, PROXY_PROTOCOL_SEP, _buf.len); |
327 | 0 | if (!p) |
328 | 0 | goto error; |
329 | 0 | tmp.s = _buf.s; |
330 | 0 | tmp.len = p - _buf.s; |
331 | 0 | if (str2int(&tmp, &port) < 0) { |
332 | 0 | LM_DBG("could not parse proxy_protocol src port %.*s\n", tmp.len, tmp.s); |
333 | 0 | goto error; |
334 | 0 | } |
335 | 0 | if (port > 65535) { |
336 | 0 | LM_DBG("bad proxy_protocol src port %d\n", port); |
337 | 0 | goto error; |
338 | 0 | } |
339 | 0 | proxy->src_port = port; |
340 | 0 | _buf.len -= tmp.len + 1; |
341 | 0 | _buf.s = p + 1; |
342 | | |
343 | | /* dst port */ |
344 | | /* remaining should be just the dst port */ |
345 | 0 | if (str2int(&_buf, &port) < 0) { |
346 | 0 | LM_DBG("could not parse proxy_protocol dst port %.*s\n", _buf.len, _buf.s); |
347 | 0 | goto error; |
348 | 0 | } |
349 | 0 | if (port > 65535) { |
350 | 0 | LM_DBG("bad proxy_protocol dst port %d\n", port); |
351 | 0 | goto error; |
352 | 0 | } |
353 | 0 | proxy->dst_port = port; |
354 | 0 | proxy->flags = PP_OK; |
355 | 0 | return end + PROXY_PROTOCOL_END_LEN; |
356 | 0 | error: |
357 | 0 | proxy->flags = PP_ERROR; |
358 | 0 | return NULL; |
359 | 0 | } |
360 | | |
361 | | static int tcp_peek(struct tcp_connection *c, char *buf, int len) |
362 | 0 | { |
363 | 0 | int bytes_read; |
364 | 0 | int fd; |
365 | |
|
366 | 0 | fd=c->fd; |
367 | 0 | again: |
368 | 0 | bytes_read=recv(fd, buf, len, MSG_PEEK); |
369 | |
|
370 | 0 | if(bytes_read==-1){ |
371 | 0 | if (errno == EWOULDBLOCK || errno == EAGAIN){ |
372 | 0 | return 0; /* nothing has been read */ |
373 | 0 | } else if (errno == EINTR) { |
374 | 0 | goto again; |
375 | 0 | } else if (errno == ECONNRESET) { |
376 | 0 | c->state=S_CONN_EOF; |
377 | 0 | LM_DBG("CONN RESET on %p, FD %d\n", c, fd); |
378 | 0 | return -1; |
379 | 0 | } else { |
380 | 0 | LM_ERR("error reading: %s\n",strerror(errno)); |
381 | 0 | return -1; |
382 | 0 | } |
383 | 0 | }else if (bytes_read==0){ |
384 | 0 | c->state=S_CONN_EOF; |
385 | 0 | LM_DBG("EOF on %p, FD %d\n", c, fd); |
386 | 0 | return -1; |
387 | 0 | } |
388 | | #ifdef EXTRA_DEBUG |
389 | | LM_DBG("peek %d bytes:\n%.*s\n", bytes_read, bytes_read, buf); |
390 | | #endif |
391 | 0 | return bytes_read; |
392 | 0 | } |
393 | | |
394 | | static int tcp_drain(struct tcp_connection *c, char *buf, int len) |
395 | 0 | { |
396 | 0 | int bytes_read, total = 0; |
397 | 0 | int retries = 0; |
398 | 0 | int fd = c->fd; |
399 | 0 | again: |
400 | 0 | bytes_read = read(fd, buf + total, len - total); |
401 | 0 | if (bytes_read < 0) { |
402 | 0 | if (errno == EINTR) { |
403 | 0 | goto again; |
404 | 0 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { |
405 | 0 | if (++retries > 100) { |
406 | 0 | LM_ERR("failed consuming proxy_protocol header due to repeated EAGAIN\n"); |
407 | 0 | return -1; |
408 | 0 | } |
409 | 0 | goto again; |
410 | 0 | } else { |
411 | 0 | LM_ERR("error consuming proxy_protocol header: %s\n", strerror(errno)); |
412 | 0 | return -1; |
413 | 0 | } |
414 | 0 | } else if (bytes_read == 0) { |
415 | 0 | c->state = S_CONN_EOF; |
416 | 0 | LM_DBG("EOF on %p, FD %d while consuming proxy_protocol header\n", c, fd); |
417 | 0 | return -1; |
418 | 0 | } |
419 | 0 | total += bytes_read; |
420 | 0 | retries = 0; |
421 | 0 | if (total < len) |
422 | 0 | goto again; |
423 | | |
424 | 0 | return total; |
425 | 0 | } |
426 | | |
427 | | int check_tcp_proxy_protocol(struct tcp_connection *c) |
428 | 0 | { |
429 | 0 | static char pp_buf[PROXY_PROTOCOL_BUF_MAX]; |
430 | 0 | char *p; |
431 | 0 | int len; |
432 | |
|
433 | 0 | if (c->flags & F_CONN_DATA_READY) |
434 | 0 | return 1; |
435 | | |
436 | 0 | if (!c->rcv.bind_address || |
437 | 0 | (c->rcv.bind_address->flags & SI_PROXY_IN) == 0) { |
438 | 0 | c->flags |= F_CONN_DATA_READY; |
439 | 0 | return 1; |
440 | 0 | } |
441 | | |
442 | 0 | len = tcp_peek(c, pp_buf, PROXY_PROTOCOL_BUF_MAX); |
443 | 0 | if (len < 0) |
444 | 0 | return -1; |
445 | | |
446 | 0 | switch (is_net_proxy_protocol(pp_buf, len)) { |
447 | 0 | case -1: |
448 | 0 | return 0; |
449 | 0 | case 0: |
450 | 0 | c->flags |= F_CONN_DATA_READY; |
451 | 0 | return 1; |
452 | 0 | default: |
453 | | /* parse proxy_protocol fields */ |
454 | 0 | break; |
455 | 0 | } |
456 | | |
457 | 0 | p = parse_net_proxy_protocol(pp_buf, len, &c->rcv.real_ep); |
458 | 0 | if (!p) { |
459 | 0 | if (c->rcv.real_ep.flags == PP_ERROR) { |
460 | 0 | LM_ERR("could not parse proxy_protocol header\n"); |
461 | 0 | return -1; |
462 | 0 | } |
463 | 0 | return 0; |
464 | 0 | } |
465 | 0 | if (c->rcv.real_ep.flags == PP_OK) { |
466 | 0 | LM_DBG("message proxy_protocol %s:%hu -> %s:%hu\n", |
467 | 0 | ip_addr2a(&c->rcv.real_ep.src_ip), c->rcv.real_ep.src_port, |
468 | 0 | ip_addr2a(&c->rcv.real_ep.dst_ip), c->rcv.real_ep.dst_port); |
469 | 0 | } else { |
470 | 0 | LM_DBG("message proxy_protocol UNKNOWN\n"); |
471 | 0 | } |
472 | |
|
473 | 0 | if (tcp_drain(c, pp_buf, p - pp_buf) < 0) { |
474 | 0 | LM_ERR("could not consume PROXY header\n"); |
475 | 0 | return -1; |
476 | 0 | } |
477 | | |
478 | 0 | c->flags |= F_CONN_DATA_READY; |
479 | 0 | return 1; |
480 | 0 | } |
481 | | |
482 | | int check_udp_proxy_protocol(char **buf, int *size, struct receive_info *ri) |
483 | 0 | { |
484 | 0 | char *p, *msg; |
485 | 0 | int len; |
486 | |
|
487 | 0 | if (!buf || !*buf || !size || !ri) |
488 | 0 | return -1; |
489 | | |
490 | 0 | ri->real_ep.flags = PP_INIT; |
491 | |
|
492 | 0 | if (!ri->bind_address || (ri->bind_address->flags & SI_PROXY_IN) == 0) |
493 | 0 | return 1; |
494 | | |
495 | 0 | msg = *buf; |
496 | 0 | len = *size; |
497 | |
|
498 | 0 | switch (is_net_proxy_protocol(msg, len)) { |
499 | 0 | case -1: |
500 | 0 | case 0: |
501 | 0 | return 1; |
502 | 0 | default: |
503 | 0 | break; |
504 | 0 | } |
505 | | |
506 | 0 | p = parse_net_proxy_protocol(msg, len, &ri->real_ep); |
507 | 0 | if (!p) { |
508 | 0 | if (ri->real_ep.flags == PP_ERROR) { |
509 | 0 | LM_ERR("could not parse proxy_protocol header\n"); |
510 | 0 | } else { |
511 | 0 | LM_ERR("incomplete proxy_protocol header in UDP packet\n"); |
512 | 0 | } |
513 | 0 | return -1; |
514 | 0 | } |
515 | | |
516 | 0 | if (ri->real_ep.flags == PP_OK) { |
517 | 0 | LM_DBG("message proxy_protocol %s:%hu -> %s:%hu\n", |
518 | 0 | ip_addr2a(&ri->real_ep.src_ip), ri->real_ep.src_port, |
519 | 0 | ip_addr2a(&ri->real_ep.dst_ip), ri->real_ep.dst_port); |
520 | 0 | } else { |
521 | 0 | LM_DBG("message proxy_protocol UNKNOWN\n"); |
522 | 0 | } |
523 | |
|
524 | 0 | *size -= p - msg; |
525 | 0 | *buf = p; |
526 | 0 | return 1; |
527 | 0 | } |