#include <sys_defs.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include <msg.h>
#include <myaddrinfo.h>
#include <valid_hostname.h>
#include <stringops.h>
#include <mymalloc.h>
#include <inet_proto.h>
#include <haproxy_srvr.h>
static INET_PROTO_INFO *proto_info;
static int haproxy_srvr_parse_lit(const char *str,...)
{
va_list ap;
const char *cp;
int result = -1;
if (msg_verbose)
msg_info("haproxy_srvr_parse: %s", str);
if (str != 0) {
va_start(ap, str);
while (result < 0 && (cp = va_arg(ap, const char *)) != 0)
if (strcmp(str, cp) == 0)
result = 0;
va_end(ap);
}
return (result);
}
static int haproxy_srvr_parse_proto(const char *str, int *addr_family)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: proto=%s", str);
#ifdef AF_INET6
if (strcasecmp(str, "TCP6") == 0) {
if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) {
*addr_family = AF_INET6;
return (0);
}
} else
#endif
if (strcasecmp(str, "TCP4") == 0) {
if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
*addr_family = AF_INET;
return (0);
}
}
return (-1);
}
static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr,
int addr_family)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: addr=%s proto=%d", str, addr_family);
if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR))
return (-1);
switch (addr_family) {
#ifdef AF_INET6
case AF_INET6:
if (!valid_ipv6_hostaddr(str, DONT_GRIPE))
return (-1);
if (strncasecmp("::ffff:", str, 7) == 0
&& strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
memcpy(addr->buf, str + 7, strlen(str) + 1 - 7);
return (0);
} else {
memcpy(addr->buf, str, strlen(str) + 1);
return (0);
}
#endif
case AF_INET:
if (!valid_ipv4_hostaddr(str, DONT_GRIPE))
return (-1);
memcpy(addr->buf, str, strlen(str) + 1);
return (0);
default:
msg_panic("haproxy_srvr_parse: unexpected address family: %d",
addr_family);
}
}
static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: port=%s", str);
if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR)
|| !valid_hostport(str, DONT_GRIPE)) {
return (-1);
} else {
memcpy(port->buf, str, strlen(str) + 1);
return (0);
}
}
const char *haproxy_srvr_parse(const char *str,
MAI_HOSTADDR_STR *smtp_client_addr,
MAI_SERVPORT_STR *smtp_client_port,
MAI_HOSTADDR_STR *smtp_server_addr,
MAI_SERVPORT_STR *smtp_server_port)
{
char *saved_str = mystrdup(str);
char *cp = saved_str;
const char *err;
int addr_family;
if (proto_info == 0)
proto_info = inet_proto_info();
#define NEXT_TOKEN mystrtok(&cp, " \r\n")
if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0)
err = "unexpected protocol header";
else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0)
err = "unsupported protocol type";
else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr,
addr_family) < 0)
err = "unexpected client address syntax";
else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr,
addr_family) < 0)
err = "unexpected server address syntax";
else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0)
err = "unexpected client port syntax";
else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0)
err = "unexpected server port syntax";
else
err = 0;
myfree(saved_str);
return (err);
}