/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "ioloop.h"
#include "str-sanitize.h"
#include "master-service-private.h"
#include "master-service-settings.h"
enum haproxy_version_t {
};
enum {
};
enum {
};
enum {
};
"\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
struct haproxy_header_v2 {
};
struct haproxy_data_v2 {
union {
} ip4;
} ip6;
struct { /* for AF_UNIX sockets, len = 216 */
} unx;
} addr;
};
struct haproxy_pp2_tlv {
const unsigned char *data;
};
struct haproxy_pp2_tlv_ssl {
const unsigned char *data;
};
struct master_service_haproxy_conn {
};
static void
{
}
static void
{
}
static void
{
}
static void
{
i_error("haproxy: Client timed out (rip=%s)",
}
static int
{
do {
return 0;
if (ret <= 0) {
if (ret == 0)
errno = ECONNRESET;
return -1;
}
return ret;
}
struct haproxy_pp2_tlv_ssl *kv)
{
if (dlen < SIZEOF_PP2_TLV_SSL)
return -1;
/* spec does not specify the endianess of this field */
return 0;
}
struct haproxy_pp2_tlv *kv)
{
if (dlen < SIZEOF_PP2_TLV)
return -1;
/* spec says
uint8_t type
uint8_t len_hi
uint8_t len_lo
so we combine the hi and lo here. */
return -1;
return 0;
}
static int
const struct haproxy_pp2_tlv_ssl *ssl_kv,
const char **error_r)
{
/* try parse some more */
"Truncated data", i);
return -1;
}
/* we don't care about these */
case PP2_SUBTYPE_SSL_CIPHER:
case PP2_SUBTYPE_SSL_SIG_ALG:
case PP2_SUBTYPE_SSL_KEY_ALG:
break;
case PP2_SUBTYPE_SSL_CN:
break;
}
}
return 0;
}
static int
const char **error_r)
{
"Truncated data", i);
return -1;
}
/* skip unsupported values */
case PP2_TYPE_ALPN:
break;
case PP2_TYPE_AUTHORITY:
/* store hostname somewhere */
break;
case PP2_TYPE_SSL:
"Truncated data", i);
return -1;
}
return -1;
break;
}
}
return 0;
}
static int
{
/* reasonable max size for haproxy data */
const char *error;
static union {
struct {
} v2;
} buf;
/* the protocol specification explicitly states that the protocol header
must be sent as one TCP frame, meaning that we will get it in full
with the first recv() call.
*/
/* see if there is a HAPROXY protocol command waiting */
if (ret < 0)
i_info("haproxy: Client disconnected (rip=%s): %m",
return ret;
/* see if there is a haproxy command, 8 is used later on as well */
/* fine */
i_error("haproxy: Client disconnected: Too long header (rip=%s)",
return -1;
}
if (ret < 0)
i_info("haproxy: Client disconnected (rip=%s): %m",
return ret;
}
i_info("haproxy: Client disconnected: Failed to read full header (rip=%s)",
return -1;
}
} else {
/* it wasn't haproxy data */
i_error("haproxy: Client disconnected: "
"Failed to read valid HAproxy data (rip=%s)",
return -1;
}
/* don't update true connection data until we succeed */
/* protocol version 2 */
if (version == HAPROXY_VERSION_2) {
i_error("haproxy: Client disconnected: "
"Unsupported protocol version (version=%02x, rip=%s)",
return -1;
}
/* keep tab of how much address data there really is because
because TLVs begin after that. */
i = 0;
i_error("haproxy(v2): Client disconnected: "
"Protocol payload length does not match header "
return -1;
}
i += sizeof(*hdr);
case HAPROXY_CMD_LOCAL:
/* keep local connection address for LOCAL */
/*i_debug("haproxy(v2): Local connection (rip=%s)",
net_ip2addr(real_remote_ip));*/
break;
case HAPROXY_CMD_PROXY:
/* UDP makes no sense currently */
i_error("haproxy(v2): Client disconnected: "
"Not using TCP (type=%02x, rip=%s)",
return -1;
}
case HAPROXY_AF_INET:
/* IPv4 */
i_error("haproxy(v2): Client disconnected: "
"IPv4 data is incomplete (rip=%s)",
return -1;
}
break;
case HAPROXY_AF_INET6:
/* IPv6 */
i_error("haproxy(v2): Client disconnected: "
"IPv6 data is incomplete (rip=%s)",
return -1;
}
break;
case HAPROXY_AF_UNSPEC:
case HAPROXY_AF_UNIX:
/* unsupported; ignored */
i_error("haproxy(v2): Unsupported address family "
break;
default:
/* unsupported; error */
i_error("haproxy(v2): Client disconnected: "
"Unknown address family "
return -1;
}
break;
default:
i_error("haproxy(v2): Client disconnected: "
"Invalid command (cmd=%02x, rip=%s)",
return -1; /* not a supported command */
}
i_error("haproxy(v2): Client disconnected: "
"Invalid TLV: %s (cmd=%02x, rip=%s)",
return -1;
}
/* protocol version 1 (soon obsolete) */
} else if (version == HAPROXY_VERSION_1) {
const char *const *fields;
unsigned int family = 0;
/* find end of header line */
return -1;
*end = '\0';
/* magic */
fields++;
/* protocol */
i_error("haproxy(v1): Client disconnected: "
"Field for proxied protocol is missing "
return -1;
}
family = 0;
} else {
i_error("haproxy(v1): Client disconnected: "
"Unknown proxied protocol "
return -1;
}
fields++;
if (family != 0) {
/* remote address */
i_error("haproxy(v1): Client disconnected: "
"Field for proxied remote address is missing "
return -1;
}
i_error("haproxy(v1): Client disconnected: "
"Proxied remote address is invalid "
return -1;
}
fields++;
/* local address */
i_error("haproxy(v1): Client disconnected: "
"Field for proxied local address is missing "
return -1;
}
i_error("haproxy(v1): Client disconnected: "
"Proxied local address is invalid "
return -1;
}
fields++;
/* remote port */
i_error("haproxy(v1): Client disconnected: "
"Field for proxied local port is missing "
return -1;
}
i_error("haproxy(v1): Client disconnected: "
"Proxied remote port is invalid "
return -1;
}
fields++;
/* local port */
i_error("haproxy(v1): Client disconnected: "
"Field for proxied local port is missing "
return -1;
}
i_error("haproxy(v1): Client disconnected: "
"Proxied local port is invalid "
return -1;
}
fields++;
i_error("haproxy(v1): Client disconnected: "
"Header line has spurius extra field "
return -1;
}
}
if (ret < 0)
i_info("haproxy: Client disconnected (rip=%s): %m",
return ret;
i_error("haproxy: Client disconnected: "
"Failed to read full header (rip=%s)",
return -1;
}
/* invalid protocol */
} else {
i_unreached();
}
/* assign data from proxy */
return 1;
}
static void
{
int ret;
if (ret < 0)
} else {
}
}
static bool
struct master_service_connection *conn)
{
const char *const *net;
unsigned int bits;
return FALSE;
i_error("haproxy_trusted_networks: "
"Invalid network '%s'", *net);
break;
}
return TRUE;
}
return FALSE;
}
struct master_service_connection *conn)
{
i_warning("haproxy: Client not trusted (rip=%s)",
return;
}
}
{
i_close_fd(&fd);
}
}