bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 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
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_ALPN 0x01
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_AUTHORITY 0x02
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_CRC32C 0x03
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_NOOP 0x04
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_SSL 0x20
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_SUBTYPE_SSL_VERSION 0x21
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_SUBTYPE_SSL_CN 0x22
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_SUBTYPE_SSL_CIPHER 0x23
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_SUBTYPE_SSL_SIG_ALG 0x24
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_SUBTYPE_SSL_KEY_ALG 0x25
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_TYPE_NETNS 0x30
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_CLIENT_SSL 0x01
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_CLIENT_CERT_CONN 0x02
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define PP2_CLIENT_CERT_SESS 0x04
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomienum haproxy_version_t {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi HAPROXY_VERSION_1,
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi HAPROXY_VERSION_2,
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi};
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
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
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define SIZEOF_PP2_TLV (1U+2U)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistruct haproxy_pp2_tlv {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint8_t type;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint16_t len;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const unsigned char *data;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi};
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi#define SIZEOF_PP2_TLV_SSL (1U+4U)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistruct haproxy_pp2_tlv_ssl {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint8_t client;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint32_t verify;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi size_t len;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const unsigned char *data;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi};
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstruct master_service_haproxy_conn {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen struct master_service_connection conn;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi pool_t pool;
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi
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
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&hpconn->io);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&hpconn->to);
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi pool_unref(&hpconn->pool);
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
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic int
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomimaster_service_haproxy_recv(int fd, void *buf, size_t len, int flags)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi{
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi ssize_t ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi do {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi ret = recv(fd, buf, len, flags);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } while (ret < 0 && errno == EINTR);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret < 0 && errno == EAGAIN)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return 0;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret <= 0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret == 0)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi errno = ECONNRESET;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return -1;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi }
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi}
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic int get_ssl_tlv(const unsigned char *kvdata, size_t dlen,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct haproxy_pp2_tlv_ssl *kv)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (dlen < SIZEOF_PP2_TLV_SSL)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->client = kvdata[0];
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* spec does not specify the endianess of this field */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->verify = cpu32_to_cpu_unaligned(kvdata+1);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->data = kvdata+SIZEOF_PP2_TLV_SSL;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->len = dlen - SIZEOF_PP2_TLV_SSL;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return 0;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi}
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic int get_tlv(const unsigned char *kvdata, size_t dlen,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct haproxy_pp2_tlv *kv)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (dlen < SIZEOF_PP2_TLV)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* spec says
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint8_t type
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint8_t len_hi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi uint8_t len_lo
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi so we combine the hi and lo here. */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->type = kvdata[0];
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->len = (kvdata[1]<<8)+kvdata[2];
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi kv->data = kvdata + SIZEOF_PP2_TLV;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (kv->len + SIZEOF_PP2_TLV > dlen)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return 0;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi}
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic int
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomimaster_service_haproxy_parse_ssl_tlv(struct master_service_haproxy_conn *hpconn,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const struct haproxy_pp2_tlv_ssl *ssl_kv,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const char **error_r)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxy.ssl = (ssl_kv->client & (PP2_CLIENT_SSL)) != 0;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* try parse some more */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi for(size_t i = 0; i < ssl_kv->len;) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct haproxy_pp2_tlv kv;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (get_tlv(ssl_kv->data + i, ssl_kv->len - i, &kv) < 0) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi *error_r = t_strdup_printf("get_tlv(%"PRIuSIZE_T") failed:"
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "Truncated data", i);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i += SIZEOF_PP2_TLV + kv.len;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi switch(kv.type) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* we don't care about these */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_SUBTYPE_SSL_CIPHER:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_SUBTYPE_SSL_SIG_ALG:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_SUBTYPE_SSL_KEY_ALG:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi break;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_SUBTYPE_SSL_CN:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxy.cert_common_name =
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi p_strndup(hpconn->pool, kv.data, kv.len);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi break;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return 0;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi}
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic int
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomimaster_service_haproxy_parse_tlv(struct master_service_haproxy_conn *hpconn,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const unsigned char *buf, size_t blen,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const char **error_r)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi for(size_t i = 0; i < blen;) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct haproxy_pp2_tlv kv;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi struct haproxy_pp2_tlv_ssl ssl_kv;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (get_tlv(buf + i, blen - i, &kv) < 0) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi *error_r = t_strdup_printf("get_tlv(%"PRIuSIZE_T") failed:"
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "Truncated data", i);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* skip unsupported values */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi switch(kv.type) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_TYPE_ALPN:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxy.alpn_size = kv.len;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxy.alpn =
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi p_memdup(hpconn->pool, kv.data, kv.len);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi break;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_TYPE_AUTHORITY:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* store hostname somewhere */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxy.hostname =
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi p_strndup(hpconn->pool, kv.data, kv.len);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi break;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi case PP2_TYPE_SSL:
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (get_ssl_tlv(kv.data, kv.len, &ssl_kv) < 0) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi *error_r = t_strdup_printf("get_ssl_tlv(%"PRIuSIZE_T") failed:"
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "Truncated data", i);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (master_service_haproxy_parse_ssl_tlv(hpconn, &ssl_kv, error_r)<0)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi break;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i += SIZEOF_PP2_TLV + kv.len;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return 0;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi}
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenstatic int
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainenmaster_service_haproxy_read(struct master_service_haproxy_conn *hpconn)
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen{
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi /* reasonable max size for haproxy data */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi unsigned char rbuf[1500];
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi const char *error;
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;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t local_port, remote_port;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi size_t size,i,want;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen ssize_t ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi enum haproxy_version_t version;
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 */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_zero(&buf);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_zero(rbuf);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi /* see if there is a HAPROXY protocol command waiting */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if ((ret = master_service_haproxy_recv(fd, &buf, sizeof(buf), MSG_PEEK))<=0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret < 0)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_info("haproxy: Client disconnected (rip=%s): %m",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi /* see if there is a haproxy command, 8 is used later on as well */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } else if (ret >= 8 && memcmp(buf.v1_data, "PROXY", 5) == 0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi /* fine */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi version = HAPROXY_VERSION_1;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } else if ((size_t)ret >= sizeof(buf.v2.hdr) &&
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi memcmp(buf.v2.hdr.sig, haproxy_v2sig, sizeof(haproxy_v2sig)) == 0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi want = ntohs(buf.v2.hdr.len) + sizeof(buf.v2.hdr);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (want > sizeof(rbuf)) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_error("haproxy: Client disconnected: Too long header (rip=%s)",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return -1;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if ((ret = master_service_haproxy_recv(fd, rbuf, want, MSG_WAITALL))<=0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret < 0)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_info("haproxy: Client disconnected (rip=%s): %m",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi }
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret != (ssize_t)want) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_info("haproxy: Client disconnected: Failed to read full header (rip=%s)",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return -1;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi }
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi memcpy(&buf, rbuf, sizeof(buf));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi version = HAPROXY_VERSION_2;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } else {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi /* it wasn't haproxy data */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_error("haproxy: Client disconnected: "
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi "Failed to read valid HAproxy data (rip=%s)",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi 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 */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (version == HAPROXY_VERSION_2) {
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
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_assert(ret >= (ssize_t)sizeof(buf.v2.hdr));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
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;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi /* keep tab of how much address data there really is because
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi because TLVs begin after that. */
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i = 0;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
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
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i += sizeof(*hdr);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
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);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i += sizeof(data->addr.ip4);
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);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i += sizeof(data->addr.ip6);
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
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi if (master_service_haproxy_parse_tlv(hpconn, rbuf+i, size-i, &error) < 0) {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi i_error("haproxy(v2): Client disconnected: "
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "Invalid TLV: %s (cmd=%02x, rip=%s)",
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi error,
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi (hdr->ver_cmd & 0x0f),
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi net_ip2addr(real_remote_ip));
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi return -1;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* protocol version 1 (soon obsolete) */
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } else if (version == HAPROXY_VERSION_1) {
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned char *data = buf.v1_data, *end;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen const char *const *fields;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen unsigned int family = 0;
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_assert(ret >= 8);
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
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 }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(*fields, &remote_port) < 0) {
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 }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(*fields, &local_port) < 0) {
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 }
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_assert(size <= sizeof(buf));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if ((ret = master_service_haproxy_recv(fd, &buf, size, 0))<=0) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi if (ret < 0)
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_info("haproxy: Client disconnected (rip=%s): %m",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return ret;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi } else if (ret != (ssize_t)size) {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_error("haproxy: Client disconnected: "
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi "Failed to read full header (rip=%s)",
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi net_ip2addr(real_remote_ip));
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi return -1;
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen /* invalid protocol */
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else {
f43567aab398e7ecc0cede120b442affc8f29807Aki Tuomi i_unreached();
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;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi hpconn->conn.proxied = TRUE;
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
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;
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi pool_t pool;
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
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi pool = pool_alloconly_create("haproxy connection", 128);
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi hpconn = p_new(pool, struct master_service_haproxy_conn, 1);
894610212596c35aade07a4d0af9d5e7fd6245c7Aki Tuomi hpconn->pool = pool;
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 master_service_haproxy_conn_free(service->haproxy_conns);
a8f11f9d8c391577b84a8b42f18f5b4ec0d2adeaTimo Sirainen i_close_fd(&fd);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen }
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen}
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen