#include "relayd.h"
#define PROXY_V2_CMD_PROXY 0x01
#define PROXY_V2_FAM_UNSPEC 0x00
#define PROXY_V2_FAM_TCP4 0x11
#define PROXY_V2_FAM_UDP4 0x12
#define PROXY_V2_FAM_TCP6 0x21
#define PROXY_V2_FAM_UDP6 0x22
static const u_int8_t PROXY_V2_SIG[12] = {
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A
};
struct proxy_v2_hdr {
u_int8_t sig[12];
u_int8_t ver_cmd;
u_int8_t fam;
u_int16_t len;
};
union proxy_v2_addr {
struct {
u_int32_t src_addr;
u_int32_t dst_addr;
in_port_t src_port;
in_port_t dst_port;
} ipv4_addr;
struct {
u_int8_t src_addr[16];
u_int8_t dst_addr[16];
in_port_t src_port;
in_port_t dst_port;
} ipv6_addr;
};
int
proxy_protocol_v1(struct rsession *con, struct evbuffer *dstout)
{
char ibuf[128], obuf[128];
const char *proxyproto;
int ret;
bzero(&ibuf, sizeof(ibuf));
bzero(&obuf, sizeof(obuf));
if (print_host(&con->se_in.ss, ibuf, sizeof(ibuf)) == NULL ||
print_host(&con->se_sockname, obuf, sizeof(obuf)) == NULL)
return -1;
if (con->se_relay->rl_conf.flags & F_UDP)
proxyproto = "UNKNOWN";
else {
switch (con->se_in.ss.ss_family) {
case AF_INET:
proxyproto = "TCP4";
break;
case AF_INET6:
proxyproto = "TCP6";
break;
default:
proxyproto = "UNKNOWN";
break;
}
}
ret = evbuffer_add_printf(dstout,
"PROXY %s %s %s %d %d\r\n", proxyproto, ibuf, obuf,
ntohs(con->se_in.port), ntohs(con->se_relay->rl_conf.port));
return ret == -1 ? -1 : 0;
}
int
proxy_protocol_v2(struct rsession *con, struct evbuffer *dstout)
{
union proxy_v2_addr addr;
struct proxy_v2_hdr hdr;
const struct relay_config *conf = &con->se_relay->rl_conf;
const struct sockaddr_storage *srcss = &con->se_in.ss;
const struct sockaddr_storage *dstss = &con->se_sockname;
int error;
in_port_t srcport = con->se_in.port;
in_port_t dstport = conf->port;
u_int16_t len;
bcopy(PROXY_V2_SIG, hdr.sig, sizeof(hdr.sig));
hdr.ver_cmd = 0x20 | PROXY_V2_CMD_PROXY;
switch (dstss->ss_family) {
case AF_INET:
hdr.fam = (conf->flags & F_UDP) ?
PROXY_V2_FAM_UDP4 : PROXY_V2_FAM_TCP4;
len = sizeof(addr.ipv4_addr);
addr.ipv4_addr.src_addr =
((const struct sockaddr_in *)srcss)->sin_addr.s_addr;
addr.ipv4_addr.dst_addr =
((const struct sockaddr_in *)dstss)->sin_addr.s_addr;
addr.ipv4_addr.src_port = srcport;
addr.ipv4_addr.dst_port = dstport;
break;
case AF_INET6:
hdr.fam = (conf->flags & F_UDP) ?
PROXY_V2_FAM_UDP6 : PROXY_V2_FAM_TCP6;
len = sizeof(addr.ipv6_addr);
bcopy(&((const struct sockaddr_in6 *)srcss)->sin6_addr,
addr.ipv6_addr.src_addr, sizeof(addr.ipv6_addr.src_addr));
bcopy(&((const struct sockaddr_in6 *)dstss)->sin6_addr,
addr.ipv6_addr.dst_addr, sizeof(addr.ipv6_addr.dst_addr));
addr.ipv6_addr.src_port = srcport;
addr.ipv6_addr.dst_port = dstport;
break;
default:
hdr.fam = 0x00;
len = 0;
break;
}
hdr.len = htons(len);
if ((error = evbuffer_add(dstout, &hdr, sizeof(hdr))) != 0)
return error;
if (len > 0 && (error = evbuffer_add(dstout, &addr, len)) != 0)
return error;
return 0;
}