/*++
/* NAME
/*	smtpd_haproxy 3
/* SUMMARY
/*	Postfix SMTP server haproxy adapter
/* SYNOPSIS
/*	#include "smtpd.h"
/*
/*	int	smtpd_peer_from_haproxy(state)
/*	SMTPD_STATE *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
/*	Return -1 in case of error, zero otherwise. In case of error,
/*	the caller will clean up any incomplete endpoint info.
/* .IP \(bu
/*	Call smtpd_peer_from_default() if the up-stream proxy
/*	indicates that the connection is not proxied. In that case,
/*	a proxy adapter MUST NOT update dynamically-allocated STATE
/*	text fields: the smtpd_peer_from_default() 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.
/* .IP \(bu
/*	Convert IPv4-in-IPv6 address syntax to IPv4 syntax when
/*	both IPv6 and IPv4 support are enabled with main.cf:inet_protocols.
/* .IP \(bu
/*	Update the following STATE fields: addr, port, rfc_addr,
/*	addr_family, dest_addr, dest_port. The addr_family field applies
/*	to the client address.
/* .IP \(bu
/*	Either update the STATE binary fields sockaddr and dest_sockaddr,
/*	or call smtpd_peer_hostaddr_to_sockaddr() after updating the
/*	STATE text fields addr, port, dest_addr, and dest_port.
/* .IP \(bu
/*	Dynamically allocate storage for string information with
/*	mystrdup(). In case of error, leave unassigned string fields
/*	at their initial zero value. The caller will clean up.
/* .IP \(bu
/*	Log a clear warning message that explains why a request
/*	fails.
/* .IP \(bu
/*	Never talk to the remote SMTP client.
/* .PP
/*	Arguments:
/* .IP state
/*	Session context.
/* DIAGNOSTICS
/*	Warnings: I/O errors, malformed haproxy line.
/*
/*	The result value is 0 in case of success, -1 in case of
/*	error.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*
/*	Wietse Venema
/*	porcupine.org
/*--*/

/* System library. */

#include <sys_defs.h>
#include <sys/socket.h>

/* Utility library. */

#include <msg.h>
#include <myaddrinfo.h>
#include <mymalloc.h>
#include <stringops.h>
#include <iostuff.h>

/* Global library. */

#include <smtp_stream.h>
#include <mail_params.h>
#include <valid_mailhost_addr.h>
#include <haproxy_srvr.h>

/* Application-specific. */

#include <smtpd.h>

/* SLMs. */

#define STR(x)	vstring_str(x)
#define LEN(x)	VSTRING_LEN(x)

/* smtpd_peer_from_haproxy - initialize peer information from haproxy */

int     smtpd_peer_from_haproxy(SMTPD_STATE *state)
{
    MAI_HOSTADDR_STR smtp_client_addr;
    MAI_SERVPORT_STR smtp_client_port;
    MAI_HOSTADDR_STR smtp_server_addr;
    MAI_SERVPORT_STR smtp_server_port;
    int     non_proxy = 0;

    if (read_wait(vstream_fileno(state->client), var_smtpd_uproxy_tmout) < 0) {
	msg_warn("haproxy read: timeout error");
	return (-1);
    }
    state->sockaddr_len = sizeof(state->sockaddr);
    state->dest_sockaddr_len = sizeof(state->dest_sockaddr);
    if (haproxy_srvr_receive_sa(vstream_fileno(state->client), &non_proxy,
				&smtp_client_addr, &smtp_client_port,
				&smtp_server_addr, &smtp_server_port,
				(struct sockaddr *) &state->sockaddr,
				&state->sockaddr_len,
				(struct sockaddr *) &state->dest_sockaddr,
				&state->dest_sockaddr_len) <0) {
	return (-1);
    }
    if (non_proxy) {
	smtpd_peer_from_default(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);
}
