master-service-haproxy.c revision 8761992b5aa05862e7ec3a460cdc17af41a4a0f5
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen/* Copyright (c) 2013-2015 Dovecot authors, see the included COPYING file */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "lib.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "llist.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "ioloop.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "str-sanitize.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "master-service-private.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#include "master-service-settings.h"
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen#define HAPROXY_V1_MAX_HEADER_SIZE (108)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenenum {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_CMD_LOCAL = 0x00,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_CMD_PROXY = 0x01
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenenum {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_AF_UNSPEC = 0x00,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_AF_INET = 0x01,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_AF_INET6 = 0x02,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_AF_UNIX = 0x03
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenenum {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_SOCK_UNSPEC = 0x00,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_SOCK_STREAM = 0x01,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen HAPROXY_SOCK_DGRAM = 0x02
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic const char haproxy_v2sig[12] =
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstruct haproxy_header_v2 {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t sig[12];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t ver_cmd;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t fam;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint16_t len;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstruct haproxy_data_v2 {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen union {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct { /* for TCP/UDP over IPv4, len = 12 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint32_t src_addr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint32_t dst_addr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint16_t src_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint16_t dst_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } ip4;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct { /* for TCP/UDP over IPv6, len = 36 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t src_addr[16];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t dst_addr[16];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint16_t src_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint16_t dst_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } ip6;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct { /* for AF_UNIX sockets, len = 216 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t src_addr[108];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen uint8_t dst_addr[108];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } unx;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } addr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstruct master_service_haproxy_conn {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection conn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_haproxy_conn *prev, *next;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service *service;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct io *io;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct timeout *to;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen};
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic void
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_conn_free(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service *service = hpconn->service;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen DLLIST_REMOVE(&service->haproxy_conns, hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (hpconn->io != NULL)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen io_remove(&hpconn->io);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (hpconn->to != NULL)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen timeout_remove(&hpconn->to);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_free(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic void
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_conn_failure(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service *service = hpconn->service;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection conn = hpconn->conn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_free(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_client_connection_handled(service, &conn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic void
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_conn_success(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service *service = hpconn->service;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection conn = hpconn->conn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_free(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_client_connection_callback(service, &conn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic void
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_timeout(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy: Client timed out (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(&hpconn->conn.remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_failure(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic int
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_read(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen static union {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned char v1_data[HAPROXY_V1_MAX_HEADER_SIZE];
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const struct haproxy_header_v2 hdr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const struct haproxy_data_v2 data;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } v2;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } buf;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct ip_addr *real_remote_ip = &hpconn->conn.remote_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen int fd = hpconn->conn.fd;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct ip_addr local_ip, remote_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned int local_port, remote_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen size_t size;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen ssize_t ret;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* the protocol specification explicitly states that the protocol header
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen must be sent as one TCP frame, meaning that we will get it in full
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen with the first recv() call.
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen FIXME: still, it would be cleaner to allow reading it incrementally.
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen do {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen ret = recv(fd, &buf, sizeof(buf), MSG_PEEK);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } while (ret < 0 && errno == EINTR);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret < 0 && errno == EAGAIN)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return 0;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret <= 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_info("haproxy: Client disconnected (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* don't update true connection data until we succeed */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_ip = hpconn->conn.local_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_ip = hpconn->conn.remote_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_port = hpconn->conn.local_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_port = hpconn->conn.remote_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* protocol version 2 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret >= (ssize_t)sizeof(buf.v2.hdr) &&
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen memcmp(buf.v2.hdr.sig, haproxy_v2sig,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen sizeof(buf.v2.hdr.sig)) == 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const struct haproxy_header_v2 *hdr = &buf.v2.hdr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const struct haproxy_data_v2 *data = &buf.v2.data;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen size_t hdr_len;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if ((hdr->ver_cmd & 0xf0) != 0x20) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy: Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Unsupported protocol version (version=%02x, rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen (hdr->ver_cmd & 0xf0) >> 4,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hdr_len = ntohs(hdr->len);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen size = sizeof(*hdr) + hdr_len;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret < (ssize_t)size) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Protocol payload length does not match header "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(got=%"PRIuSIZE_T", expect=%"PRIuSIZE_T", rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen (size_t)ret, size, net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen switch (hdr->ver_cmd & 0x0f) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_CMD_LOCAL:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* keep local connection address for LOCAL */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /*i_debug("haproxy(v2): Local connection (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));*/
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_CMD_PROXY:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if ((hdr->fam & 0x0f) != HAPROXY_SOCK_STREAM) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* UDP makes no sense currently */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Not using TCP (type=%02x, rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen (hdr->fam & 0x0f), net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen switch ((hdr->fam & 0xf0) >> 4) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_AF_INET:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* IPv4 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (hdr_len < sizeof(data->addr.ip4)) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "IPv4 data is incomplete (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_ip.family = AF_INET;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_ip.u.ip4.s_addr = data->addr.ip4.dst_addr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_port = ntohs(data->addr.ip4.dst_port);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_ip.family = AF_INET;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_ip.u.ip4.s_addr = data->addr.ip4.src_addr;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_port = ntohs(data->addr.ip4.src_port);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_AF_INET6:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* IPv6 */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (hdr_len < sizeof(data->addr.ip6)) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "IPv6 data is incomplete (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_ip.family = AF_INET6;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen memcpy(&local_ip.u.ip6.s6_addr, data->addr.ip6.dst_addr, 16);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_port = ntohs(data->addr.ip6.dst_port);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_ip.family = AF_INET6;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen memcpy(&remote_ip.u.ip6.s6_addr, data->addr.ip6.src_addr, 16);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_port = ntohs(data->addr.ip6.src_port);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_AF_UNSPEC:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen case HAPROXY_AF_UNIX:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* unsupported; ignored */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Unsupported address family "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(family=%02x, rip=%s)", (hdr->fam & 0xf0) >> 4,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen default:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* unsupported; error */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Unknown address family "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(family=%02x, rip=%s)", (hdr->fam & 0xf0) >> 4,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen default:
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v2): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Invalid command (cmd=%02x, rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen (hdr->ver_cmd & 0x0f),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1; /* not a supported command */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen // FIXME: TLV vectors are ignored
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen // (useful to see whether proxied client is using SSL)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* protocol version 1 (soon obsolete) */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else if (ret >= 8 && memcmp(buf.v1_data, "PROXY", 5) == 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned char *data = buf.v1_data, *end;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const char *const *fields;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned int family = 0;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* find end of header line */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen end = memchr(data, '\r', ret - 1);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (end == NULL || end[1] != '\n')
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen *end = '\0';
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen size = end + 2 - data;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* magic */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields = t_strsplit((char *)data, " ");
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_assert(strcmp(*fields, "PROXY") == 0);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* protocol */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields == NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Field for proxied protocol is missing "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(rip=%s)", net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (strcmp(*fields, "TCP4") == 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen family = AF_INET;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else if (strcmp(*fields, "TCP6") == 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen family = AF_INET6;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else if (strcmp(*fields, "UNKNOWN") == 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen family = 0;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Unknown proxied protocol "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(protocol=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (family != 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* remote address */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields == NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Field for proxied remote address is missing "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(rip=%s)", net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (net_addr2ip(*fields, &remote_ip) < 0 ||
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_ip.family != family) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Proxied remote address is invalid "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(address=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* local address */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields == NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Field for proxied local address is missing "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(rip=%s)", net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (net_addr2ip(*fields, &local_ip) < 0 ||
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_ip.family != family) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Proxied local address is invalid "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(address=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* remote port */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields == NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Field for proxied local port is missing "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(rip=%s)", net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (str_to_uint(*fields, &remote_port) < 0 ||
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen remote_port > 65535) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Proxied remote port is invalid "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(port=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* local port */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields == NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Field for proxied local port is missing "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(rip=%s)", net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (str_to_uint(*fields, &local_port) < 0 ||
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen local_port > 65535) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Proxied local port is invalid "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(port=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen fields++;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (*fields != NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy(v1): Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Header line has spurius extra field "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "(field=`%s', rip=%s)", str_sanitize(*fields, 64),
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* invalid protocol */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy: Client disconnected: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "No valid proxy header found (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* remove proxy protocol header from socket buffer */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_assert(size <= sizeof(buf));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen do {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen ret = recv(fd, &buf, size, 0);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } while (ret == -1 && errno == EINTR);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret <= 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_info("haproxy: Client disconnected (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret != (ssize_t)size) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* not supposed to happen */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy: Client disconencted: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Failed to read full header (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return -1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* assign data from proxy */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->conn.local_ip = local_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->conn.remote_ip = remote_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->conn.local_port = local_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->conn.remote_port = remote_port;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return 1;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic void
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_input(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen int ret;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if ((ret = master_service_haproxy_read(hpconn)) <= 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (ret < 0)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_failure(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_success(hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic bool
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_conn_is_trusted(struct master_service *service,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection *conn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const char *const *net;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct ip_addr net_ip;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned int bits;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (service->set->haproxy_trusted_networks == NULL)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return FALSE;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net = t_strsplit_spaces(service->set->haproxy_trusted_networks, ", ");
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen for (; *net != NULL; net++) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (net_parse_range(*net, &net_ip, &bits) < 0) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy_trusted_networks: "
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen "Invalid network '%s'", *net);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen break;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (net_is_in_network(&conn->real_remote_ip, &net_ip, bits))
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return TRUE;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return FALSE;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenvoid master_service_haproxy_new(struct master_service *service,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection *conn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_haproxy_conn *hpconn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (!master_service_haproxy_conn_is_trusted(service, conn)) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_warning("haproxy: Client not trusted (rip=%s)",
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen net_ip2addr(&conn->real_remote_ip));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_client_connection_handled(service, conn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen return;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn = i_new(struct master_service_haproxy_conn, 1);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->conn = *conn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->service = service;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen DLLIST_PREPEND(&service->haproxy_conns, hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->io = io_add(conn->fd, IO_READ,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_input, hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen hpconn->to = timeout_add(service->set->haproxy_timeout*1000,
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_timeout, hpconn);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenvoid master_service_haproxy_abort(struct master_service *service)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen while (service->haproxy_conns != NULL) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen int fd = service->haproxy_conns->conn.fd;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen if (close(fd) < 0)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen i_error("haproxy: close(service connection) failed: %m");
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_haproxy_conn_free(service->haproxy_conns);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen