1/*++ 2/* NAME 3/* smtpd_haproxy 3 4/* SUMMARY 5/* Postfix SMTP server haproxy adapter 6/* SYNOPSIS 7/* #include "smtpd.h" 8/* 9/* int smtpd_peer_from_haproxy(state) 10/* SMTPD_STATE *state; 11/* DESCRIPTION 12/* smtpd_peer_from_haproxy() receives endpoint address and 13/* port information via the haproxy protocol. 14/* 15/* The following summarizes what the Postfix SMTP server expects 16/* from an up-stream proxy adapter. 17/* .IP \(bu 18/* Validate protocol, address and port syntax. Permit only 19/* protocols that are configured with the main.cf:inet_protocols 20/* setting. 21/* .IP \(bu 22/* Convert IPv4-in-IPv6 address syntax to IPv4 syntax when 23/* both IPv6 and IPv4 support are enabled with main.cf:inet_protocols. 24/* .IP \(bu 25/* Update the following session context fields: addr, port, 26/* rfc_addr, addr_family, dest_addr. The addr_family field 27/* applies to the client address. 28/* .IP \(bu 29/* Dynamically allocate storage for string information with 30/* mystrdup(). In case of error, leave unassigned string fields 31/* at their initial zero value. 32/* .IP \(bu 33/* Log a clear warning message that explains why a request 34/* fails. 35/* .IP \(bu 36/* Never talk to the remote SMTP client. 37/* .PP 38/* Arguments: 39/* .IP state 40/* Session context. 41/* DIAGNOSTICS 42/* Warnings: I/O errors, malformed haproxy line. 43/* 44/* The result value is 0 in case of success, -1 in case of 45/* error. 46/* LICENSE 47/* .ad 48/* .fi 49/* The Secure Mailer license must be distributed with this software. 50/* AUTHOR(S) 51/* Wietse Venema 52/* IBM T.J. Watson Research 53/* P.O. Box 704 54/* Yorktown Heights, NY 10598, USA 55/*--*/ 56 57/* System library. */ 58 59#include <sys_defs.h> 60#include <sys/socket.h> 61 62/* Utility library. */ 63 64#include <msg.h> 65#include <myaddrinfo.h> 66#include <mymalloc.h> 67#include <stringops.h> 68 69/* Global library. */ 70 71#include <smtp_stream.h> 72#include <mail_params.h> 73#include <valid_mailhost_addr.h> 74#include <haproxy_srvr.h> 75 76/* Application-specific. */ 77 78#include <smtpd.h> 79 80/* SLMs. */ 81 82#define STR(x) vstring_str(x) 83#define LEN(x) VSTRING_LEN(x) 84 85/* smtpd_peer_from_haproxy - initialize peer information from haproxy */ 86 87int smtpd_peer_from_haproxy(SMTPD_STATE *state) 88{ 89 const char *myname = "smtpd_peer_from_haproxy"; 90 MAI_HOSTADDR_STR smtp_client_addr; 91 MAI_SERVPORT_STR smtp_client_port; 92 MAI_HOSTADDR_STR smtp_server_addr; 93 MAI_SERVPORT_STR smtp_server_port; 94 const char *proxy_err; 95 int io_err; 96 VSTRING *escape_buf; 97 98 /* 99 * Note: the haproxy_srvr_parse() routine performs address protocol 100 * checks, address and port syntax checks, and converts IPv4-in-IPv6 101 * address string syntax (:ffff::1.2.3.4) to IPv4 syntax where permitted 102 * by the main.cf:inet_protocols setting, but logs no warnings. 103 */ 104#define ENABLE_DEADLINE 1 105 106 smtp_stream_setup(state->client, var_smtpd_uproxy_tmout, ENABLE_DEADLINE); 107 switch (io_err = vstream_setjmp(state->client)) { 108 default: 109 msg_panic("%s: unhandled I/O error %d", myname, io_err); 110 case SMTP_ERR_EOF: 111 msg_warn("haproxy read: unexpected EOF"); 112 return (-1); 113 case SMTP_ERR_TIME: 114 msg_warn("haproxy read: timeout error"); 115 return (-1); 116 case 0: 117 if (smtp_get(state->buffer, state->client, HAPROXY_MAX_LEN, 118 SMTP_GET_FLAG_NONE) != '\n') { 119 msg_warn("haproxy read: line > %d characters", HAPROXY_MAX_LEN); 120 return (-1); 121 } 122 if ((proxy_err = haproxy_srvr_parse(STR(state->buffer), 123 &smtp_client_addr, &smtp_client_port, 124 &smtp_server_addr, &smtp_server_port)) != 0) { 125 escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2); 126 escape(escape_buf, STR(state->buffer), LEN(state->buffer)); 127 msg_warn("haproxy read: %s: %s", proxy_err, STR(escape_buf)); 128 vstring_free(escape_buf); 129 return (-1); 130 } 131 state->addr = mystrdup(smtp_client_addr.buf); 132 if (strrchr(state->addr, ':') != 0) { 133 state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0); 134 state->addr_family = AF_INET6; 135 } else { 136 state->rfc_addr = mystrdup(state->addr); 137 state->addr_family = AF_INET; 138 } 139 state->port = mystrdup(smtp_client_port.buf); 140 141 /* 142 * Avoid surprises in the Dovecot authentication server. 143 */ 144 state->dest_addr = mystrdup(smtp_server_addr.buf); 145 return (0); 146 } 147} 148