1 /* $NetBSD: haproxy_srvr.c,v 1.1.1.1 2013/09/25 19:06:30 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* haproxy_srvr 3 6 /* SUMMARY 7 /* server-side haproxy protocol support 8 /* SYNOPSIS 9 /* #include <haproxy_srvr.h> 10 /* 11 /* const char *haproxy_srvr_parse(str, 12 /* smtp_client_addr, smtp_client_port, 13 /* smtp_server_addr, smtp_server_port) 14 /* const char *str; 15 /* MAI_HOSTADDR_STR *smtp_client_addr, 16 /* MAI_SERVPORT_STR *smtp_client_port, 17 /* MAI_HOSTADDR_STR *smtp_server_addr, 18 /* MAI_SERVPORT_STR *smtp_server_port; 19 /* DESCRIPTION 20 /* haproxy_srvr_parse() parses a haproxy line. The result is 21 /* null in case of success, a pointer to text (with the error 22 /* type) in case of error. If both IPv6 and IPv4 support are 23 /* enabled, IPV4_IN_IPV6 address syntax (::ffff:1.2.3.4) is 24 /* converted to IPV4 syntax. 25 /* LICENSE 26 /* .ad 27 /* .fi 28 /* The Secure Mailer license must be distributed with this software. 29 /* AUTHOR(S) 30 /* Wietse Venema 31 /* IBM T.J. Watson Research 32 /* P.O. Box 704 33 /* Yorktown Heights, NY 10598, USA 34 /*--*/ 35 36 /* System library. */ 37 38 #include <sys_defs.h> 39 #include <stdarg.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #ifdef STRCASECMP_IN_STRINGS_H 44 #include <strings.h> 45 #endif 46 47 /* Utility library. */ 48 49 #include <msg.h> 50 #include <myaddrinfo.h> 51 #include <valid_hostname.h> 52 #include <stringops.h> 53 #include <mymalloc.h> 54 #include <inet_proto.h> 55 56 /* Global library. */ 57 58 #include <haproxy_srvr.h> 59 60 /* Application-specific. */ 61 62 static INET_PROTO_INFO *proto_info; 63 64 /* haproxy_srvr_parse_lit - extract and validate string literal */ 65 66 static int haproxy_srvr_parse_lit(const char *str,...) 67 { 68 va_list ap; 69 const char *cp; 70 int result = -1; 71 72 if (msg_verbose) 73 msg_info("haproxy_srvr_parse: %s", str); 74 75 if (str != 0) { 76 va_start(ap, str); 77 while (result < 0 && (cp = va_arg(ap, const char *)) != 0) 78 if (strcmp(str, cp) == 0) 79 result = 0; 80 va_end(ap); 81 } 82 return (result); 83 } 84 85 /* haproxy_srvr_parse_proto - parse and validate the protocol type */ 86 87 static int haproxy_srvr_parse_proto(const char *str, int *addr_family) 88 { 89 if (msg_verbose) 90 msg_info("haproxy_srvr_parse: proto=%s", str); 91 92 #ifdef AF_INET6 93 if (strcasecmp(str, "TCP6") == 0) { 94 if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) { 95 *addr_family = AF_INET6; 96 return (0); 97 } 98 } else 99 #endif 100 if (strcasecmp(str, "TCP4") == 0) { 101 if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0) { 102 *addr_family = AF_INET; 103 return (0); 104 } 105 } 106 return (-1); 107 } 108 109 /* haproxy_srvr_parse_addr - extract and validate IP address */ 110 111 static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr, 112 int addr_family) 113 { 114 if (msg_verbose) 115 msg_info("haproxy_srvr_parse: addr=%s proto=%d", str, addr_family); 116 117 if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR)) 118 return (-1); 119 120 switch (addr_family) { 121 #ifdef AF_INET6 122 case AF_INET6: 123 if (!valid_ipv6_hostaddr(str, DONT_GRIPE)) 124 return (-1); 125 if (strncasecmp("::ffff:", str, 7) == 0 126 && strchr((char *) proto_info->sa_family_list, AF_INET) != 0) { 127 memcpy(addr->buf, str + 7, strlen(str) + 1 - 7); 128 return (0); 129 } else { 130 memcpy(addr->buf, str, strlen(str) + 1); 131 return (0); 132 } 133 #endif 134 case AF_INET: 135 if (!valid_ipv4_hostaddr(str, DONT_GRIPE)) 136 return (-1); 137 memcpy(addr->buf, str, strlen(str) + 1); 138 return (0); 139 default: 140 msg_panic("haproxy_srvr_parse: unexpected address family: %d", 141 addr_family); 142 } 143 } 144 145 /* haproxy_srvr_parse_port - extract and validate TCP port */ 146 147 static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port) 148 { 149 if (msg_verbose) 150 msg_info("haproxy_srvr_parse: port=%s", str); 151 if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR) 152 || !valid_hostport(str, DONT_GRIPE)) { 153 return (-1); 154 } else { 155 memcpy(port->buf, str, strlen(str) + 1); 156 return (0); 157 } 158 } 159 160 /* haproxy_srvr_parse - parse haproxy line */ 161 162 const char *haproxy_srvr_parse(const char *str, 163 MAI_HOSTADDR_STR *smtp_client_addr, 164 MAI_SERVPORT_STR *smtp_client_port, 165 MAI_HOSTADDR_STR *smtp_server_addr, 166 MAI_SERVPORT_STR *smtp_server_port) 167 { 168 char *saved_str = mystrdup(str); 169 char *cp = saved_str; 170 const char *err; 171 int addr_family; 172 173 if (proto_info == 0) 174 proto_info = inet_proto_info(); 175 176 /* 177 * XXX We don't accept connections with the "UNKNOWN" protocol type, 178 * because those would sidestep address-based access control mechanisms. 179 */ 180 #define NEXT_TOKEN mystrtok(&cp, " \r\n") 181 if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0) 182 err = "unexpected protocol header"; 183 else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0) 184 err = "unsupported protocol type"; 185 else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr, 186 addr_family) < 0) 187 err = "unexpected client address syntax"; 188 else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr, 189 addr_family) < 0) 190 err = "unexpected server address syntax"; 191 else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0) 192 err = "unexpected client port syntax"; 193 else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0) 194 err = "unexpected server port syntax"; 195 else 196 err = 0; 197 myfree(saved_str); 198 return (err); 199 } 200