/* SYNOPSIS
/* #include <haproxy_srvr.h>
/*
-/* const char *haproxy_srvr_parse(str,
+/* const char *haproxy_srvr_parse(str, str_len, non_proxy,
/* smtp_client_addr, smtp_client_port,
/* smtp_server_addr, smtp_server_port)
/* const char *str;
+/* ssize_t *str_len;
+/* int *non_proxy;
+/* MAI_HOSTADDR_STR *smtp_client_addr,
+/* MAI_SERVPORT_STR *smtp_client_port,
+/* MAI_HOSTADDR_STR *smtp_server_addr,
+/* MAI_SERVPORT_STR *smtp_server_port;
+/*
+/* const char *haproxy_srvr_receive(fd, non_proxy,
+/* smtp_client_addr, smtp_client_port,
+/* smtp_server_addr, smtp_server_port)
+/* int fd;
+/* int *non_proxy;
/* MAI_HOSTADDR_STR *smtp_client_addr,
/* MAI_SERVPORT_STR *smtp_client_port,
/* MAI_HOSTADDR_STR *smtp_server_addr,
/* MAI_SERVPORT_STR *smtp_server_port;
/* DESCRIPTION
-/* haproxy_srvr_parse() parses a haproxy line. The result is
-/* null in case of success, a pointer to text (with the error
-/* type) in case of error. If both IPv6 and IPv4 support are
-/* enabled, IPV4_IN_IPV6 address syntax (::ffff:1.2.3.4) is
-/* converted to IPV4 syntax, provided that IPv4 support is
-/* enabled.
+/* haproxy_srvr_parse() parses a haproxy v1 or v2 protocol
+/* message. The result is null in case of success, a pointer
+/* to text (with the error type) in case of error. If both
+/* IPv6 and IPv4 support are enabled, IPV4_IN_IPV6 address
+/* syntax (::ffff:1.2.3.4) is converted to IPV4 syntax, provided
+/* that IPv4 support is enabled. In case of success, the
+/* str_len argument is updated with the number of bytes parsed,
+/* and the non_proxy argument is true or false if the
+/* haproxy message specifies a non-proxied connection.
+/*
+/* haproxy_srvr_receive() receives and parses a haproxy protocol
+/* handshake. This must be called before any I/O is done on
+/* the specified file descriptor. The result is 0 in case of
+/* success, -1 in case of error. All errors are logged.
/* LICENSE
/* .ad
/* .fi
#include <stringops.h>
#include <mymalloc.h>
#include <inet_proto.h>
+#include <split_at.h>
/* Global library. */
static INET_PROTO_INFO *proto_info;
+#define STR_OR_NULL(str) ((str) ? (str) : "(null)")
+
/* haproxy_srvr_parse_lit - extract and validate string literal */
static int haproxy_srvr_parse_lit(const char *str,...)
int result = -1;
if (msg_verbose)
- msg_info("haproxy_srvr_parse: %s", str);
+ msg_info("haproxy_srvr_parse: %s", STR_OR_NULL(str));
if (str != 0) {
va_start(ap, str);
static int haproxy_srvr_parse_proto(const char *str, int *addr_family)
{
if (msg_verbose)
- msg_info("haproxy_srvr_parse: proto=%s", str);
+ msg_info("haproxy_srvr_parse: proto=%s", STR_OR_NULL(str));
#ifdef AF_INET6
if (strcasecmp(str, "TCP6") == 0) {
int err;
if (msg_verbose)
- msg_info("haproxy_srvr_parse: addr=%s proto=%d", str, addr_family);
+ msg_info("haproxy_srvr_parse: addr=%s proto=%d",
+ STR_OR_NULL(str), addr_family);
if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR))
return (-1);
static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port)
{
if (msg_verbose)
- msg_info("haproxy_srvr_parse: port=%s", str);
+ msg_info("haproxy_srvr_parse: port=%s", STR_OR_NULL(str));
if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR)
|| !valid_hostport(str, DONT_GRIPE)) {
return (-1);
/* haproxy_srvr_parse - parse haproxy line */
-const char *haproxy_srvr_parse(const char *str,
+const char *haproxy_srvr_parse(const char *str, ssize_t *str_len,
+ int *non_proxy,
MAI_HOSTADDR_STR *smtp_client_addr,
MAI_SERVPORT_STR *smtp_client_port,
MAI_HOSTADDR_STR *smtp_server_addr,
MAI_SERVPORT_STR *smtp_server_port)
{
- char *saved_str = mystrdup(str);
- char *cp = saved_str;
const char *err;
int addr_family;
if (proto_info == 0)
proto_info = inet_proto_info();
+ *non_proxy = 0;
+
/*
* XXX We don't accept connections with the "UNKNOWN" protocol type,
* because those would sidestep address-based access control mechanisms.
*/
-#define NEXT_TOKEN mystrtok(&cp, " \r\n")
- if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0)
- err = "unexpected protocol header";
- else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0)
- err = "unsupported protocol type";
- else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr,
- addr_family) < 0)
- err = "unexpected client address syntax";
- else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr,
- addr_family) < 0)
- err = "unexpected server address syntax";
- else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0)
- err = "unexpected client port syntax";
- else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0)
- err = "unexpected server port syntax";
- else
- err = 0;
- myfree(saved_str);
- return (err);
+
+ /*
+ * Try version 1 protocol.
+ */
+ if (strncmp(str, "PROXY ", 6) == 0) {
+ char *saved_str = mystrdup(str);
+ char *cp = saved_str;
+ char *beyond_header = split_at(saved_str, '\n');
+
+#define NEXT_TOKEN mystrtok(&cp, " \r")
+ if (beyond_header == 0)
+ err = "missing protocol header terminator";
+ else if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0)
+ err = "unexpected protocol header";
+ else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0)
+ err = "unsupported protocol type";
+ else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr,
+ addr_family) < 0)
+ err = "unexpected client address syntax";
+ else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr,
+ addr_family) < 0)
+ err = "unexpected server address syntax";
+ else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0)
+ err = "unexpected client port syntax";
+ else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0)
+ err = "unexpected server port syntax";
+ else {
+ err = 0;
+ *str_len = beyond_header - saved_str;
+ }
+ myfree(saved_str);
+ return (err);
+ }
+
+ /*
+ * Assume version 2 protocol.
+ */
+ else {
+ return ("v2 protocol is not implemented");
+ }
+}
+
+/* haproxy_srvr_receive - redceive and parse haproxy protocol handshake */
+
+int haproxy_srvr_receive(int fd, int *non_proxy,
+ MAI_HOSTADDR_STR *smtp_client_addr,
+ MAI_SERVPORT_STR *smtp_client_port,
+ MAI_HOSTADDR_STR *smtp_server_addr,
+ MAI_SERVPORT_STR *smtp_server_port)
+{
+ const char *err;
+ VSTRING *escape_buf;
+ char read_buf[HAPROXY_MAX_LEN];
+ ssize_t read_len;
+
+ /*
+ * We must not read(2) past the end of the HaProxy handshake. The v2
+ * protocol assumes that the handshake will never be fragmented,
+ * therefore we peek, parse the entire input, then read(2) only the
+ * number of bytes parsed.
+ */
+ if ((read_len = recv(fd, read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
+ msg_warn("haproxy read: EOF");
+ return (-1);
+ }
+
+ /*
+ * Parse the haproxy handshake, and determine the handshake length.
+ */
+ read_buf[read_len] = 0;
+ if ((err = haproxy_srvr_parse(read_buf, &read_len, non_proxy,
+ smtp_client_addr, smtp_client_port,
+ smtp_server_addr, smtp_server_port)) != 0) {
+ escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
+ escape(escape_buf, read_buf, read_len);
+ msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
+ vstring_free(escape_buf);
+ return (-1);
+ }
+
+ /*
+ * Try to pop the haproxy handshake off the input queue.
+ */
+ if (recv(fd, read_buf, read_len, 0) <= 0) {
+ msg_warn("haproxy read: %m");
+ return (-1);
+ }
+ return (0);
}
/*
/* Test cases with inputs and expected outputs. */
typedef struct TEST_CASE {
const char *haproxy_request;
+ ssize_t exp_str_len;
+ int exp_non_proxy;
const char *exp_return;
const char *exp_client_addr;
const char *exp_server_addr;
} TEST_CASE;
static TEST_CASE test_cases[] = {
/* IPv6. */
- {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1 123 321", 0, "fc::1:2:3:4", "fc::4:3:2:1", "123", "321"},
- {"PROXY TCP6 FC:00:00:00:1:2:3:4 FC:00:00:00:4:3:2:1 123 321", 0, "fc::1:2:3:4", "fc::4:3:2:1", "123", "321"},
- {"PROXY TCP6 1.2.3.4 4.3.2.1 123 321", "unexpected client address syntax"},
- {"PROXY TCP6 fc:00:00:00:1:2:3:4 4.3.2.1 123 321", "unexpected server address syntax"},
+ {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1 123 321", 0, 0, 0, "fc::1:2:3:4", "fc::4:3:2:1", "123", "321"},
+ {"PROXY TCP6 FC:00:00:00:1:2:3:4 FC:00:00:00:4:3:2:1 123 321", 0, 0, 0, "fc::1:2:3:4", "fc::4:3:2:1", "123", "321"},
+ {"PROXY TCP6 1.2.3.4 4.3.2.1 123 321", 0, 0, "unexpected client address syntax"},
+ {"PROXY TCP6 fc:00:00:00:1:2:3:4 4.3.2.1 123 321", 0, 0, "unexpected server address syntax"},
/* IPv4 in IPv6. */
- {"PROXY TCP6 ::ffff:1.2.3.4 ::ffff:4.3.2.1 123 321", 0, "1.2.3.4", "4.3.2.1", "123", "321"},
- {"PROXY TCP6 ::FFFF:1.2.3.4 ::FFFF:4.3.2.1 123 321", 0, "1.2.3.4", "4.3.2.1", "123", "321"},
- {"PROXY TCP4 ::ffff:1.2.3.4 ::ffff:4.3.2.1 123 321", "unexpected client address syntax"},
- {"PROXY TCP4 1.2.3.4 ::ffff:4.3.2.1 123 321", "unexpected server address syntax"},
+ {"PROXY TCP6 ::ffff:1.2.3.4 ::ffff:4.3.2.1 123 321", 0, 0, 0, "1.2.3.4", "4.3.2.1", "123", "321"},
+ {"PROXY TCP6 ::FFFF:1.2.3.4 ::FFFF:4.3.2.1 123 321", 0, 0, 0, "1.2.3.4", "4.3.2.1", "123", "321"},
+ {"PROXY TCP4 ::ffff:1.2.3.4 ::ffff:4.3.2.1 123 321", 0, 0, "unexpected client address syntax"},
+ {"PROXY TCP4 1.2.3.4 ::ffff:4.3.2.1 123 321", 0, 0, "unexpected server address syntax"},
/* IPv4. */
- {"PROXY TCP4 1.2.3.4 4.3.2.1 123 321", 0, "1.2.3.4", "4.3.2.1", "123", "321"},
- {"PROXY TCP4 01.02.03.04 04.03.02.01 123 321", 0, "1.2.3.4", "4.3.2.1", "123", "321"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1 123456 321", "unexpected client port syntax"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1 123 654321", "unexpected server port syntax"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1 0123 321", "unexpected client port syntax"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1 123 0321", "unexpected server port syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 123 321", 0, 0, 0, "1.2.3.4", "4.3.2.1", "123", "321"},
+ {"PROXY TCP4 01.02.03.04 04.03.02.01 123 321", 0, 0, 0, "1.2.3.4", "4.3.2.1", "123", "321"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 123456 321", 0, 0, "unexpected client port syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 123 654321", 0, 0, "unexpected server port syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 0123 321", 0, 0, "unexpected client port syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 123 0321", 0, 0, "unexpected server port syntax"},
/* Missing fields. */
- {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1 123", "unexpected server port syntax"},
- {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1", "unexpected client port syntax"},
- {"PROXY TCP6 fc:00:00:00:1:2:3:4", "unexpected server address syntax"},
- {"PROXY TCP6", "unexpected client address syntax"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1 123", "unexpected server port syntax"},
- {"PROXY TCP4 1.2.3.4 4.3.2.1", "unexpected client port syntax"},
- {"PROXY TCP4 1.2.3.4", "unexpected server address syntax"},
- {"PROXY TCP4", "unexpected client address syntax"},
+ {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1 123", 0, 0, "unexpected server port syntax"},
+ {"PROXY TCP6 fc:00:00:00:1:2:3:4 fc:00:00:00:4:3:2:1", 0, 0, "unexpected client port syntax"},
+ {"PROXY TCP6 fc:00:00:00:1:2:3:4", 0, 0, "unexpected server address syntax"},
+ {"PROXY TCP6", 0, 0, "unexpected client address syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1 123", 0, 0, "unexpected server port syntax"},
+ {"PROXY TCP4 1.2.3.4 4.3.2.1", 0, 0, "unexpected client port syntax"},
+ {"PROXY TCP4 1.2.3.4", 0, 0, "unexpected server address syntax"},
+ {"PROXY TCP4", 0, 0, "unexpected client address syntax"},
/* Other. */
- {"PROXY BLAH", "unsupported protocol type"},
- {"BLAH", "unexpected protocol header"},
+ {"PROXY BLAH", 0, 0, "unsupported protocol type"},
+ {"BLAH", 0, 0, "v2 protocol is not implemented"},
0,
};
TEST_CASE *test_case;
/* Actual results. */
const char *act_return;
+ ssize_t act_str_len;
+ int act_non_proxy;
MAI_HOSTADDR_STR act_smtp_client_addr;
MAI_HOSTADDR_STR act_smtp_server_addr;
MAI_SERVPORT_STR act_smtp_client_port;
for (tests_failed = 0, test_case = test_cases; test_case->haproxy_request;
tests_failed += test_failed, test_case++) {
test_failed = 0;
+ act_str_len = strlen(test_case->haproxy_request);
+ if (test_case->exp_str_len == 0)
+ test_case->exp_str_len = act_str_len;
act_return =
- haproxy_srvr_parse(test_case->haproxy_request,
+ haproxy_srvr_parse(test_case->haproxy_request, &act_str_len,
+ &act_non_proxy,
&act_smtp_client_addr, &act_smtp_client_port,
&act_smtp_server_addr, &act_smtp_server_port);
if (act_return != test_case->exp_return) {
test_failed = 1;
continue;
}
+ if (act_str_len != test_case->exp_str_len) {
+ msg_warn("test case %d str_len expected=%ld actual=%ld",
+ (int) (test_case - test_cases),
+ (long) test_case->exp_str_len, (long) act_str_len);
+ test_failed = 1;
+ continue;
+ }
+ if (act_non_proxy != test_case->exp_non_proxy) {
+ msg_warn("test case %d non_proxy expected=%d actual=%d",
+ (int) (test_case - test_cases),
+ test_case->exp_non_proxy, act_non_proxy);
+ test_failed = 1;
+ continue;
+ }
if (test_case->exp_return != 0)
continue;
if (strcmp(test_case->exp_client_addr, act_smtp_client_addr.buf)) {
typedef struct {
VSTREAM *stream;
PSC_ENDPT_LOOKUP_FN notify;
- VSTRING *buffer;
} PSC_HAPROXY_STATE;
/* psc_endpt_haproxy_event - read or time event */
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
- int last_char = 0;
- const char *err;
- VSTRING *escape_buf;
- char read_buf[HAPROXY_MAX_LEN];
- ssize_t read_len;
- char *cp;
+ int non_proxy = 0;
- /*
- * We must not read(2) past the <CR><LF> that terminates the haproxy
- * line. For efficiency reasons we read the entire haproxy line in one
- * read(2) call when we know that the line is unfragmented. In the rare
- * case that the line is fragmented, we fall back and read(2) it one
- * character at a time.
- */
switch (event) {
case EVENT_TIME:
msg_warn("haproxy read: time limit exceeded");
status = -1;
break;
case EVENT_READ:
- /* Determine the initial VSTREAM read(2) buffer size. */
- if (VSTRING_LEN(state->buffer) == 0) {
- if ((read_len = recv(vstream_fileno(state->stream),
- read_buf, sizeof(read_buf) - 1, MSG_PEEK)) > 0
- && ((cp = memchr(read_buf, '\n', read_len)) != 0)) {
- read_len = cp - read_buf + 1;
- } else {
- read_len = 1;
- }
- vstream_control(state->stream, CA_VSTREAM_CTL_BUFSIZE(read_len),
- CA_VSTREAM_CTL_END);
- }
- /* Drain the VSTREAM buffer, otherwise this pseudo-thread will hang. */
- do {
- if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) {
- if (vstream_ferror(state->stream))
- msg_warn("haproxy read: %m");
- else
- msg_warn("haproxy read: lost connection");
- status = -1;
- break;
- }
- if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) {
- msg_warn("haproxy read: line too long");
- status = -1;
- break;
- }
- VSTRING_ADDCH(state->buffer, last_char);
- } while (vstream_peek(state->stream) > 0);
- break;
- }
-
- /*
- * Parse the haproxy line. Note: the haproxy_srvr_parse() routine
- * performs address protocol checks, address and port syntax checks, and
- * converts IPv4-in-IPv6 address string syntax (::ffff:1.2.3.4) to IPv4
- * syntax where permitted by the main.cf:inet_protocols setting.
- */
- if (status == 0 && last_char == '\n') {
- VSTRING_TERMINATE(state->buffer);
- if ((err = haproxy_srvr_parse(vstring_str(state->buffer),
+ status = haproxy_srvr_receive(vstream_fileno(state->stream), &non_proxy,
&smtp_client_addr, &smtp_client_port,
- &smtp_server_addr, &smtp_server_port)) != 0) {
- escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
- escape(escape_buf, vstring_str(state->buffer),
- VSTRING_LEN(state->buffer));
- msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
- status = -1;
- vstring_free(escape_buf);
- }
+ &smtp_server_addr, &smtp_server_port);
}
/*
- * Are we done yet?
+ * Terminate this pseudo thread, and notify the caller.
*/
- if (status < 0 || last_char == '\n') {
- PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream),
- psc_endpt_haproxy_event, context);
- vstream_control(state->stream,
- CA_VSTREAM_CTL_BUFSIZE(VSTREAM_BUFSIZE),
- CA_VSTREAM_CTL_END);
+ PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream),
+ psc_endpt_haproxy_event, context);
+ if (non_proxy)
+ psc_endpt_local_lookup(state->stream, state->notify);
+ else
state->notify(status, state->stream,
&smtp_client_addr, &smtp_client_port,
&smtp_server_addr, &smtp_server_port);
- /* Note: the stream may be closed at this point. */
- vstring_free(state->buffer);
- myfree((void *) state);
- }
+ /* Note: the stream may be closed at this point. */
+ myfree((void *) state);
}
/* psc_endpt_haproxy_lookup - event-driven haproxy client */
state = (PSC_HAPROXY_STATE *) mymalloc(sizeof(*state));
state->stream = stream;
state->notify = notify;
- state->buffer = vstring_alloc(100);
/*
* Read the haproxy line.
/* SYNOPSIS
/* #include "smtpd.h"
/*
-/* int smtpd_peer_from_haproxy(state)
+/* int smtpd_peer_from_haproxy(state, default_lookup)
/* SMTPD_STATE *state;
+/* void (*default_lookup) (SMTPD_STATE *);
/* DESCRIPTION
/* smtpd_peer_from_haproxy() receives endpoint address and
/* port information via the haproxy protocol.
/* The following summarizes what the Postfix SMTP server expects
/* from an up-stream proxy adapter.
/* .IP \(bu
+/* Call the default_lookup function if the up-stream proxy
+/* indicates that the connection is not proxied. In that case,
+/* a proxy adapter MUST NOT update the connection info: the
+/* default_lookup function will do that instead.
+/* .IP \(bu
/* Validate protocol, address and port syntax. Permit only
/* protocols that are configured with the main.cf:inet_protocols
/* setting.
#include <myaddrinfo.h>
#include <mymalloc.h>
#include <stringops.h>
+#include <iostuff.h>
/* Global library. */
/* smtpd_peer_from_haproxy - initialize peer information from haproxy */
-int smtpd_peer_from_haproxy(SMTPD_STATE *state)
+int smtpd_peer_from_haproxy(SMTPD_STATE *state,
+ void (*default_lookup) (SMTPD_STATE *))
{
- const char *myname = "smtpd_peer_from_haproxy";
MAI_HOSTADDR_STR smtp_client_addr;
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
- const char *proxy_err;
- int io_err;
- VSTRING *escape_buf;
+ int non_proxy = 0;
- /*
- * While reading HAProxy handshake information, don't buffer input beyond
- * the end-of-line. That would break the TLS wrappermode handshake.
- */
- vstream_control(state->client,
- VSTREAM_CTL_BUFSIZE, 1,
- VSTREAM_CTL_END);
-
- /*
- * Note: the haproxy_srvr_parse() routine performs address protocol
- * checks, address and port syntax checks, and converts IPv4-in-IPv6
- * address string syntax (::ffff:1.2.3.4) to IPv4 syntax where permitted
- * by the main.cf:inet_protocols setting, but logs no warnings.
- */
-#define ENABLE_DEADLINE 1
-
- smtp_stream_setup(state->client, var_smtpd_uproxy_tmout, ENABLE_DEADLINE);
- switch (io_err = vstream_setjmp(state->client)) {
- default:
- msg_panic("%s: unhandled I/O error %d", myname, io_err);
- case SMTP_ERR_EOF:
- msg_warn("haproxy read: unexpected EOF");
- return (-1);
- case SMTP_ERR_TIME:
+ if (read_wait(vstream_fileno(state->client), var_smtpd_uproxy_tmout) < 0) {
msg_warn("haproxy read: timeout error");
return (-1);
- case 0:
- if (smtp_get(state->buffer, state->client, HAPROXY_MAX_LEN,
- SMTP_GET_FLAG_NONE) != '\n') {
- msg_warn("haproxy read: line > %d characters", HAPROXY_MAX_LEN);
- return (-1);
- }
- if ((proxy_err = haproxy_srvr_parse(STR(state->buffer),
- &smtp_client_addr, &smtp_client_port,
- &smtp_server_addr, &smtp_server_port)) != 0) {
- escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
- escape(escape_buf, STR(state->buffer), LEN(state->buffer));
- msg_warn("haproxy read: %s: %s", proxy_err, STR(escape_buf));
- vstring_free(escape_buf);
- return (-1);
- }
- state->addr = mystrdup(smtp_client_addr.buf);
- if (strrchr(state->addr, ':') != 0) {
- state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0);
- state->addr_family = AF_INET6;
- } else {
- state->rfc_addr = mystrdup(state->addr);
- state->addr_family = AF_INET;
- }
- state->port = mystrdup(smtp_client_port.buf);
-
- /*
- * The Dovecot authentication server needs the server IP address.
- */
- state->dest_addr = mystrdup(smtp_server_addr.buf);
- state->dest_port = mystrdup(smtp_server_port.buf);
-
- /*
- * Enable normal buffering.
- */
- vstream_control(state->client,
- VSTREAM_CTL_BUFSIZE, VSTREAM_BUFSIZE,
- VSTREAM_CTL_END);
+ }
+ if (haproxy_srvr_receive(vstream_fileno(state->client), &non_proxy,
+ &smtp_client_addr, &smtp_client_port,
+ &smtp_server_addr, &smtp_server_port) < 0) {
+ return (-1);
+ }
+ if (non_proxy) {
+ default_lookup(state);
return (0);
}
+ state->addr = mystrdup(smtp_client_addr.buf);
+ if (strrchr(state->addr, ':') != 0) {
+ state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0);
+ state->addr_family = AF_INET6;
+ } else {
+ state->rfc_addr = mystrdup(state->addr);
+ state->addr_family = AF_INET;
+ }
+ state->port = mystrdup(smtp_client_port.buf);
+
+ /*
+ * The Dovecot authentication server needs the server IP address.
+ */
+ state->dest_addr = mystrdup(smtp_server_addr.buf);
+ state->dest_port = mystrdup(smtp_server_port.buf);
+ return (0);
}