1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2023 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
10 /************************************************
11 * Proxy-Protocol support *
12 ************************************************/
17 /*************************************************
18 * Check if host is required proxy host *
19 *************************************************/
20 /* The function determines if inbound host will be a regular smtp host
21 or if it is configured that it must use Proxy Protocol. A local
25 Returns: boolean for Proxy Protocol needed
29 proxy_protocol_host(void)
33 if ( sender_host_address
34 && (rc = verify_check_this_host(CUSS &hosts_proxy, NULL, NULL,
35 sender_host_address, NULL)) == OK)
38 debug_printf("Detected proxy protocol configured host\n");
45 /*************************************************
46 * Read data until newline or end of buffer *
47 *************************************************/
48 /* While SMTP is server-speaks-first, TLS is client-speaks-first, so we can't
49 read an entire buffer and assume there will be nothing past a proxy protocol
50 header. Our approach normally is to use stdio, but again that relies upon
51 "STARTTLS\r\n" and a server response before the client starts TLS handshake, or
52 reading _nothing_ before client TLS handshake. So we don't want to use the
53 usual buffering reads which may read enough to block TLS starting.
55 So unfortunately we're down to "read one byte at a time, with a syscall each,
56 and expect a little overhead", for all proxy-opened connections which are v1,
57 just to handle the TLS-on-connect case. Since SSL functions wrap the
58 underlying fd, we can't assume that we can feed them any already-read content.
60 We need to know where to read to, the max capacity, and we'll read until we
61 get a CR and one more character. Let the caller scream if it's CR+!LF.
63 Return the amount read.
67 swallow_until_crlf(int fd, uschar *base, int already, int capacity)
69 uschar *to = base + already;
75 /* For "PROXY UNKNOWN\r\n" we, at time of writing, expect to have read
76 up through the \r; for the _normal_ case, we haven't yet seen the \r. */
78 cr = memchr(base, '\r', already);
81 if ((cr - base) < already - 1)
83 /* \r and presumed \n already within what we have; probably not
84 actually proxy protocol, but abort cleanly. */
87 /* \r is last character read, just need one more. */
93 do { ret = read(fd, to, 1); } while (ret == -1 && errno == EINTR && !had_command_timeout);
105 /* reached end without having room for a final newline, abort */
112 proxy_debug(uschar * buf, unsigned start, unsigned end)
114 debug_printf("PROXY<<");
115 while (start < end) debug_printf(" %02x", buf[start++]);
120 /*************************************************
121 * Setup host for proxy protocol *
122 *************************************************/
123 /* The function configures the connection based on a header from the
124 inbound host to use Proxy Protocol. The specification is very exact
125 so exit with an error if do not find the exact required pieces. This
126 includes an incorrect number of spaces separating args.
129 Returns: Boolean success
133 proxy_protocol_setup(void)
145 struct { /* TCP/UDP over IPv4, len = 12 */
151 struct { /* TCP/UDP over IPv6, len = 36 */
152 uint8_t src_addr[16];
153 uint8_t dst_addr[16];
157 struct { /* AF_UNIX sockets, len = 216 */
158 uschar src_addr[108];
159 uschar dst_addr[108];
165 /* Temp variables used in PPv2 address:port parsing */
167 char tmpip[INET_ADDRSTRLEN];
168 struct sockaddr_in tmpaddr;
169 char tmpip6[INET6_ADDRSTRLEN];
170 struct sockaddr_in6 tmpaddr6;
172 /* We can't read "all data until end" because while SMTP is
173 server-speaks-first, the TLS handshake is client-speaks-first, so for
174 TLS-on-connect ports the proxy protocol header will usually be immediately
175 followed by a TLS handshake, and with N TLS libraries, we can't reliably
176 reinject data for reading by those. So instead we first read "enough to be
177 safely read within the header, and figure out how much more to read".
178 For v1 we will later read to the end-of-line, for v2 we will read based upon
181 The v2 sig is 12 octets, and another 4 gets us the length, so we know how much
182 data is needed total. For v1, where the line looks like:
183 PROXY TCPn L3src L3dest SrcPort DestPort \r\n
185 However, for v1 there's also `PROXY UNKNOWN\r\n` which is only 15 octets.
186 We seem to support that. So, if we read 14 octets then we can tell if we're
187 v2 or v1. If we're v1, we can continue reading as normal.
189 If we're v2, we can't slurp up the entire header. We need the length in the
190 15th & 16th octets, then to read everything after that.
192 So to safely handle v1 and v2, with client-sent-first supported correctly,
193 we have to do a minimum of 3 read calls, not 1. Eww.
196 # define PROXY_INITIAL_READ 14
197 # define PROXY_V2_HEADER_SIZE 16
198 # if PROXY_INITIAL_READ > PROXY_V2_HEADER_SIZE
199 # error Code bug in sizes of data to read for proxy usage
204 int fd = fileno(smtp_in);
205 const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
206 uschar * iptype; /* To display debug info */
207 socklen_t vslen = sizeof(struct timeval);
210 ALARM(proxy_protocol_timeout);
214 /* The inbound host was declared to be a Proxy Protocol host, so
215 don't do a PEEK into the data, actually slurp up enough to be
216 "safe". Can't take it all because TLS-on-connect clients follow
217 immediately with TLS handshake. */
218 ret = read(fd, &hdr, PROXY_INITIAL_READ);
219 } while (ret == -1 && errno == EINTR && !had_command_timeout);
223 DEBUG(D_receive) proxy_debug(US &hdr, 0, ret);
225 /* For v2, handle reading the length, and then the rest. */
226 if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0))
231 DEBUG(D_receive) debug_printf("v2\n");
233 /* First get the length fields. */
236 retmore = read(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ);
237 } while (retmore == -1 && errno == EINTR && !had_command_timeout);
240 DEBUG(D_receive) proxy_debug(US &hdr, ret, ret + retmore);
244 ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
246 /* May 2014: haproxy combined the version and command into one byte to
247 allow two full bytes for the length field in order to proxy SSL
248 connections. SSL Proxy is not supported in this version of Exim, but
249 must still separate values here. */
253 DEBUG(D_receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver);
257 /* The v2 header will always be 16 bytes per the spec. */
258 size = 16 + ntohs(hdr.v2.len);
259 DEBUG(D_receive) debug_printf("Detected PROXYv2 header, size %d (limit %d)\n",
260 size, (int)sizeof(hdr));
262 /* We should now have 16 octets (PROXY_V2_HEADER_SIZE), and we know the total
263 amount that we need. Double-check that the size is not unreasonable, then
265 if (size > sizeof(hdr))
267 DEBUG(D_receive) debug_printf("PROXYv2 header size unreasonably large; security attack?\n");
275 retmore = read(fd, (uschar*)&hdr + ret, size-ret);
276 } while (retmore == -1 && errno == EINTR && !had_command_timeout);
279 DEBUG(D_receive) proxy_debug(US &hdr, ret, ret + retmore);
281 DEBUG(D_receive) debug_printf("PROXYv2: have %d/%d required octets\n", ret, size);
282 } while (ret < size);
284 } /* end scope for getting rest of data for v2 */
286 /* At this point: if PROXYv2, we've read the exact size required for all data;
287 if PROXYv1 then we've read "less than required for any valid line" and should
290 if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0)
292 uint8_t cmd = (hdr.v2.ver_cmd & 0x0f);
296 case 0x01: /* PROXY command */
299 case 0x11: /* TCPv4 address type */
301 tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.src_addr;
302 inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip));
303 if (!string_is_ip_address(US tmpip, NULL))
305 DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype);
308 proxy_local_address = sender_host_address;
309 sender_host_address = string_copy(US tmpip);
310 tmpport = ntohs(hdr.v2.addr.ip4.src_port);
311 proxy_local_port = sender_host_port;
312 sender_host_port = tmpport;
313 /* Save dest ip/port */
314 tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.dst_addr;
315 inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip));
316 if (!string_is_ip_address(US tmpip, NULL))
318 DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype);
321 proxy_external_address = string_copy(US tmpip);
322 tmpport = ntohs(hdr.v2.addr.ip4.dst_port);
323 proxy_external_port = tmpport;
325 case 0x21: /* TCPv6 address type */
327 memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.src_addr, 16);
328 inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6));
329 if (!string_is_ip_address(US tmpip6, NULL))
331 DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype);
334 proxy_local_address = sender_host_address;
335 sender_host_address = string_copy(US tmpip6);
336 tmpport = ntohs(hdr.v2.addr.ip6.src_port);
337 proxy_local_port = sender_host_port;
338 sender_host_port = tmpport;
339 /* Save dest ip/port */
340 memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.dst_addr, 16);
341 inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6));
342 if (!string_is_ip_address(US tmpip6, NULL))
344 DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype);
347 proxy_external_address = string_copy(US tmpip6);
348 tmpport = ntohs(hdr.v2.addr.ip6.dst_port);
349 proxy_external_port = tmpport;
353 debug_printf("Unsupported PROXYv2 connection type: 0x%02x\n",
357 /* Unsupported protocol, keep local connection address */
359 case 0x00: /* LOCAL command */
360 /* Keep local connection address for LOCAL */
365 debug_printf("Unsupported PROXYv2 command: 0x%x\n", cmd);
369 else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0)
373 uschar *sp; /* Utility variables follow */
378 /* get the rest of the line */
379 r2 = swallow_until_crlf(fd, (uschar*)&hdr, ret, sizeof(hdr)-ret);
384 p = string_copy(hdr.v1.line);
385 end = memchr(p, '\r', ret - 1);
387 if (!end || (end == (uschar*)&hdr + ret) || end[1] != '\n')
389 DEBUG(D_receive) debug_printf("Partial or invalid PROXY header\n");
392 *end = '\0'; /* Terminate the string */
393 size = end + 2 - p; /* Skip header + CRLF */
394 DEBUG(D_receive) debug_printf("Detected PROXYv1 header\n");
395 DEBUG(D_receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size);
396 /* Step through the string looking for the required fields. Ensure
397 strict adherence to required formatting, exit for any error. */
399 if (!isspace(*(p++)))
401 DEBUG(D_receive) debug_printf("Missing space after PROXY command\n");
404 if (!Ustrncmp(p, CCS"TCP4", 4))
406 else if (!Ustrncmp(p,CCS"TCP6", 4))
408 else if (!Ustrncmp(p,CCS"UNKNOWN", 7))
410 iptype = US"Unknown";
415 DEBUG(D_receive) debug_printf("Invalid TCP type\n");
419 p += Ustrlen(iptype);
420 if (!isspace(*(p++)))
422 DEBUG(D_receive) debug_printf("Missing space after TCP4/6 command\n");
425 /* Find the end of the arg */
426 if ((sp = Ustrchr(p, ' ')) == NULL)
429 debug_printf("Did not find proxied src %s\n", iptype);
433 if(!string_is_ip_address(p, NULL))
436 debug_printf("Proxied src arg is not an %s address\n", iptype);
439 proxy_local_address = sender_host_address;
440 sender_host_address = p;
442 if ((sp = Ustrchr(p, ' ')) == NULL)
445 debug_printf("Did not find proxy dest %s\n", iptype);
449 if(!string_is_ip_address(p, NULL))
452 debug_printf("Proxy dest arg is not an %s address\n", iptype);
455 proxy_external_address = p;
457 if ((sp = Ustrchr(p, ' ')) == NULL)
459 DEBUG(D_receive) debug_printf("Did not find proxied src port\n");
463 tmp_port = strtol(CCS p, &endc, 10);
464 if (*endc || tmp_port == 0)
467 debug_printf("Proxied src port '%s' not an integer\n", p);
470 proxy_local_port = sender_host_port;
471 sender_host_port = tmp_port;
473 if ((sp = Ustrchr(p, '\0')) == NULL)
475 DEBUG(D_receive) debug_printf("Did not find proxy dest port\n");
478 tmp_port = strtol(CCS p, &endc, 10);
479 if (*endc || tmp_port == 0)
482 debug_printf("Proxy dest port '%s' not an integer\n", p);
485 proxy_external_port = tmp_port;
486 /* Already checked for /r /n above. Good V1 header received. */
491 DEBUG(D_receive) debug_printf("Invalid proxy protocol version negotiation\n");
492 (void) swallow_until_crlf(fd, (uschar*)&hdr, ret, sizeof(hdr)-ret);
498 debug_printf("Valid %s sender from Proxy Protocol header\n", iptype);
499 yield = proxy_session;
501 /* Don't flush any potential buffer contents. Any input on proxyfail
502 should cause a synchronization failure */
505 DEBUG(D_receive) if (had_command_timeout)
506 debug_printf("Timeout while reading proxy header\n");
511 sender_host_name = NULL;
512 (void) host_name_lookup();
513 host_build_sender_fullhost();
517 f.proxy_session_failed = TRUE;
519 debug_printf("Failure to extract proxied host, only QUIT allowed\n");
525 #endif /*SUPPORT_PROXY*/