-int get_ok = 0;
-int size, ret;
-int fd = fileno(smtp_in);
-const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
-uschar * iptype; /* To display debug info */
-socklen_t vslen = sizeof(struct timeval);
-BOOL yield = FALSE;
-
-os_non_restarting_signal(SIGALRM, command_timeout_handler);
-ALARM(proxy_protocol_timeout);
-
-do
- {
- /* The inbound host was declared to be a Proxy Protocol host, so
- don't do a PEEK into the data, actually slurp up enough to be
- "safe". Can't take it all because TLS-on-connect clients follow
- immediately with TLS handshake. */
- ret = read(fd, &hdr, PROXY_INITIAL_READ);
- }
- while (ret == -1 && errno == EINTR && !had_command_timeout);
-
-if (ret == -1)
- goto proxyfail;
-
-/* For v2, handle reading the length, and then the rest. */
-if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0))
- {
- int retmore;
- uint8_t ver;
-
- /* First get the length fields. */
- do
- {
- retmore = read(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ);
- } while (retmore == -1 && errno == EINTR && !had_command_timeout);
- if (retmore == -1)
- goto proxyfail;
- ret += retmore;
-
- ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
-
- /* May 2014: haproxy combined the version and command into one byte to
- allow two full bytes for the length field in order to proxy SSL
- connections. SSL Proxy is not supported in this version of Exim, but
- must still separate values here. */
-
- if (ver != 0x02)
- {
- DEBUG(D_receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver);
- goto proxyfail;
- }
-
- /* The v2 header will always be 16 bytes per the spec. */
- size = 16 + ntohs(hdr.v2.len);
- DEBUG(D_receive) debug_printf("Detected PROXYv2 header, size %d (limit %d)\n",
- size, (int)sizeof(hdr));
-
- /* We should now have 16 octets (PROXY_V2_HEADER_SIZE), and we know the total
- amount that we need. Double-check that the size is not unreasonable, then
- get the rest. */
- if (size > sizeof(hdr))
- {
- DEBUG(D_receive) debug_printf("PROXYv2 header size unreasonably large; security attack?\n");
- goto proxyfail;
- }
-
- do
- {
- do
- {
- retmore = read(fd, (uschar*)&hdr + ret, size-ret);
- } while (retmore == -1 && errno == EINTR && !had_command_timeout);
- if (retmore == -1)
- goto proxyfail;
- ret += retmore;
- DEBUG(D_receive) debug_printf("PROXYv2: have %d/%d required octets\n", ret, size);
- } while (ret < size);
-
- } /* end scope for getting rest of data for v2 */
-
-/* At this point: if PROXYv2, we've read the exact size required for all data;
-if PROXYv1 then we've read "less than required for any valid line" and should
-read the rest". */
-
-if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0)
- {
- uint8_t cmd = (hdr.v2.ver_cmd & 0x0f);
-
- switch (cmd)
- {
- case 0x01: /* PROXY command */
- switch (hdr.v2.fam)
- {
- case 0x11: /* TCPv4 address type */
- iptype = US"IPv4";
- tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.src_addr;
- inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip));
- if (!string_is_ip_address(US tmpip, NULL))
- {
- DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype);
- goto proxyfail;
- }
- proxy_local_address = sender_host_address;
- sender_host_address = string_copy(US tmpip);
- tmpport = ntohs(hdr.v2.addr.ip4.src_port);
- proxy_local_port = sender_host_port;
- sender_host_port = tmpport;
- /* Save dest ip/port */
- tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.dst_addr;
- inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip));
- if (!string_is_ip_address(US tmpip, NULL))
- {
- DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype);
- goto proxyfail;
- }
- proxy_external_address = string_copy(US tmpip);
- tmpport = ntohs(hdr.v2.addr.ip4.dst_port);
- proxy_external_port = tmpport;
- goto done;
- case 0x21: /* TCPv6 address type */
- iptype = US"IPv6";
- memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.src_addr, 16);
- inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6));
- if (!string_is_ip_address(US tmpip6, NULL))
- {
- DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype);
- goto proxyfail;
- }
- proxy_local_address = sender_host_address;
- sender_host_address = string_copy(US tmpip6);
- tmpport = ntohs(hdr.v2.addr.ip6.src_port);
- proxy_local_port = sender_host_port;
- sender_host_port = tmpport;
- /* Save dest ip/port */
- memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.dst_addr, 16);
- inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6));
- if (!string_is_ip_address(US tmpip6, NULL))
- {
- DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype);
- goto proxyfail;
- }
- proxy_external_address = string_copy(US tmpip6);
- tmpport = ntohs(hdr.v2.addr.ip6.dst_port);
- proxy_external_port = tmpport;
- goto done;
- default:
- DEBUG(D_receive)
- debug_printf("Unsupported PROXYv2 connection type: 0x%02x\n",
- hdr.v2.fam);
- goto proxyfail;
- }
- /* Unsupported protocol, keep local connection address */
- break;
- case 0x00: /* LOCAL command */
- /* Keep local connection address for LOCAL */
- iptype = US"local";
- break;
- default:
- DEBUG(D_receive)
- debug_printf("Unsupported PROXYv2 command: 0x%x\n", cmd);
- goto proxyfail;
- }
- }
-else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0)
- {
- uschar *p;
- uschar *end;
- uschar *sp; /* Utility variables follow */
- int tmp_port;
- int r2;
- char *endc;
-
- /* get the rest of the line */
- r2 = swallow_until_crlf(fd, (uschar*)&hdr, ret, sizeof(hdr)-ret);
- if (r2 == -1)
- goto proxyfail;
- ret += r2;
-
- p = string_copy(hdr.v1.line);
- end = memchr(p, '\r', ret - 1);
-
- if (!end || (end == (uschar*)&hdr + ret) || end[1] != '\n')
- {
- DEBUG(D_receive) debug_printf("Partial or invalid PROXY header\n");
- goto proxyfail;
- }
- *end = '\0'; /* Terminate the string */
- size = end + 2 - p; /* Skip header + CRLF */
- DEBUG(D_receive) debug_printf("Detected PROXYv1 header\n");
- DEBUG(D_receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size);
- /* Step through the string looking for the required fields. Ensure
- strict adherence to required formatting, exit for any error. */
- p += 5;
- if (!isspace(*(p++)))
- {
- DEBUG(D_receive) debug_printf("Missing space after PROXY command\n");
- goto proxyfail;
- }
- if (!Ustrncmp(p, CCS"TCP4", 4))
- iptype = US"IPv4";
- else if (!Ustrncmp(p,CCS"TCP6", 4))
- iptype = US"IPv6";
- else if (!Ustrncmp(p,CCS"UNKNOWN", 7))
- {
- iptype = US"Unknown";
- goto done;
- }
- else
- {
- DEBUG(D_receive) debug_printf("Invalid TCP type\n");
- goto proxyfail;
- }
-
- p += Ustrlen(iptype);
- if (!isspace(*(p++)))
- {
- DEBUG(D_receive) debug_printf("Missing space after TCP4/6 command\n");
- goto proxyfail;
- }
- /* Find the end of the arg */
- if ((sp = Ustrchr(p, ' ')) == NULL)
- {
- DEBUG(D_receive)
- debug_printf("Did not find proxied src %s\n", iptype);
- goto proxyfail;
- }
- *sp = '\0';
- if(!string_is_ip_address(p, NULL))
- {
- DEBUG(D_receive)
- debug_printf("Proxied src arg is not an %s address\n", iptype);
- goto proxyfail;
- }
- proxy_local_address = sender_host_address;
- sender_host_address = p;
- p = sp + 1;
- if ((sp = Ustrchr(p, ' ')) == NULL)
- {
- DEBUG(D_receive)
- debug_printf("Did not find proxy dest %s\n", iptype);
- goto proxyfail;
- }
- *sp = '\0';
- if(!string_is_ip_address(p, NULL))
- {
- DEBUG(D_receive)
- debug_printf("Proxy dest arg is not an %s address\n", iptype);
- goto proxyfail;
- }
- proxy_external_address = p;
- p = sp + 1;
- if ((sp = Ustrchr(p, ' ')) == NULL)
- {
- DEBUG(D_receive) debug_printf("Did not find proxied src port\n");
- goto proxyfail;
- }
- *sp = '\0';
- tmp_port = strtol(CCS p, &endc, 10);
- if (*endc || tmp_port == 0)
- {
- DEBUG(D_receive)
- debug_printf("Proxied src port '%s' not an integer\n", p);
- goto proxyfail;
- }
- proxy_local_port = sender_host_port;
- sender_host_port = tmp_port;
- p = sp + 1;
- if ((sp = Ustrchr(p, '\0')) == NULL)
- {
- DEBUG(D_receive) debug_printf("Did not find proxy dest port\n");
- goto proxyfail;
- }
- tmp_port = strtol(CCS p, &endc, 10);
- if (*endc || tmp_port == 0)
- {
- DEBUG(D_receive)
- debug_printf("Proxy dest port '%s' not an integer\n", p);
- goto proxyfail;
- }
- proxy_external_port = tmp_port;
- /* Already checked for /r /n above. Good V1 header received. */
- }
-else
- {
- /* Wrong protocol */
- DEBUG(D_receive) debug_printf("Invalid proxy protocol version negotiation\n");
- (void) swallow_until_crlf(fd, (uschar*)&hdr, ret, sizeof(hdr)-ret);
- goto proxyfail;
- }