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