1 /* $NetBSD: haproxy_srvr.c,v 1.5 2026/05/09 18:49:16 christos 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_sa( 12 /* const char *str, 13 /* ssize_t *str_len, 14 /* int *non_proxy, 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 /* struct sockaddr *client_sa, 20 /* SOCKADDR_SIZE *client_sa_len, 21 /* struct sockaddr *server_sa, 22 /* SOCKADDR_SIZE *server_sa_len) 23 /* 24 /* const char *haproxy_srvr_receive_sa( 25 /* int fd, 26 /* int *non_proxy, 27 /* MAI_HOSTADDR_STR *smtp_client_addr, 28 /* MAI_SERVPORT_STR *smtp_client_port, 29 /* MAI_HOSTADDR_STR *smtp_server_addr, 30 /* MAI_SERVPORT_STR *smtp_server_port, 31 /* struct sockaddr *client_sa, 32 /* SOCKADDR_SIZE *client_sa_len, 33 /* struct sockaddr *server_sa, 34 /* SOCKADDR_SIZE *server_sa_len) 35 /* ABI COMPATIBILITY 36 /* const char *haproxy_srvr_parse(str, str_len, non_proxy, 37 /* smtp_client_addr, smtp_client_port, 38 /* smtp_server_addr, smtp_server_port) 39 /* const char *str; 40 /* ssize_t *str_len; 41 /* int *non_proxy; 42 /* MAI_HOSTADDR_STR *smtp_client_addr, 43 /* MAI_SERVPORT_STR *smtp_client_port, 44 /* MAI_HOSTADDR_STR *smtp_server_addr, 45 /* MAI_SERVPORT_STR *smtp_server_port; 46 /* 47 /* const char *haproxy_srvr_receive(fd, non_proxy, 48 /* smtp_client_addr, smtp_client_port, 49 /* smtp_server_addr, smtp_server_port) 50 /* int fd; 51 /* int *non_proxy; 52 /* MAI_HOSTADDR_STR *smtp_client_addr, 53 /* MAI_SERVPORT_STR *smtp_client_port, 54 /* MAI_HOSTADDR_STR *smtp_server_addr, 55 /* MAI_SERVPORT_STR *smtp_server_port; 56 /* DESCRIPTION 57 /* haproxy_srvr_parse_sa() parses a haproxy v1 or v2 protocol 58 /* message. The result is null in case of success, a pointer 59 /* to text (with the error type) in case of error. If both 60 /* IPv6 and IPv4 support are enabled, IPV4_IN_IPV6 address 61 /* form (::ffff:1.2.3.4) is converted to IPV4 form. In case 62 /* of success, the str_len argument is updated with the number 63 /* of bytes parsed, and the non_proxy argument is true or false 64 /* if the haproxy message specifies a non-proxied connection. 65 /* 66 /* haproxy_srvr_receive_sa() receives and parses a haproxy protocol 67 /* handshake. This must be called before any I/O is done on 68 /* the specified file descriptor. The result is 0 in case of 69 /* success, -1 in case of error. All errors are logged. 70 /* 71 /* The haproxy v2 protocol support is limited to TCP over IPv4, 72 /* TCP over IPv6, and non-proxied connections. In the latter 73 /* case, the caller is responsible for any local or remote 74 /* address/port lookup. 75 /* 76 /* The client or server sockaddr and length storage are updated 77 /* when their pointers are non-null. 78 /* 79 /* haproxy_srvr_parse() and haproxy_srvr_receive() provide ABI 80 /* backwards compatibility, passing null pointers for the sockaddr 81 /* and length storage arguments. 82 /* LICENSE 83 /* .ad 84 /* .fi 85 /* The Secure Mailer license must be distributed with this software. 86 /* AUTHOR(S) 87 /* Wietse Venema 88 /* IBM T.J. Watson Research 89 /* P.O. Box 704 90 /* Yorktown Heights, NY 10598, USA 91 /* 92 /* Wietse Venema 93 /* Google, Inc. 94 /* 111 8th Avenue 95 /* New York, NY 10011, USA 96 /* 97 /* Wietse Venema 98 /* porcupine.org 99 /*--*/ 100 101 /* System library. */ 102 103 #include <sys_defs.h> 104 #include <stdarg.h> 105 #include <stdlib.h> 106 #include <string.h> 107 108 #ifdef STRCASECMP_IN_STRINGS_H 109 #include <strings.h> 110 #endif 111 112 /* Utility library. */ 113 114 #include <msg.h> 115 #include <myaddrinfo.h> 116 #include <valid_hostname.h> 117 #include <stringops.h> 118 #include <mymalloc.h> 119 #include <inet_proto.h> 120 #include <split_at.h> 121 #include <sock_addr.h> 122 #include <normalize_v4mapped_addr.h> 123 124 /* Global library. */ 125 126 #define _HAPROXY_SRVR_INTERNAL_ 127 #include <haproxy_srvr.h> 128 129 static const INET_PROTO_INFO *proto_info; 130 131 #define STR_OR_NULL(str) ((str) ? (str) : "(null)") 132 133 /* haproxy_srvr_parse_lit - extract and validate string literal */ 134 135 static int haproxy_srvr_parse_lit(const char *str,...) 136 { 137 va_list ap; 138 const char *cp; 139 int result = -1; 140 int count; 141 142 if (msg_verbose) 143 msg_info("haproxy_srvr_parse: %s", STR_OR_NULL(str)); 144 145 if (str != 0) { 146 va_start(ap, str); 147 for (count = 0; (cp = va_arg(ap, const char *)) != 0; count++) { 148 if (strcmp(str, cp) == 0) { 149 result = count; 150 break; 151 } 152 } 153 va_end(ap); 154 } 155 return (result); 156 } 157 158 /* haproxy_srvr_parse_proto - parse and validate the protocol type */ 159 160 static int haproxy_srvr_parse_proto(const char *str, int *addr_family) 161 { 162 if (msg_verbose) 163 msg_info("haproxy_srvr_parse: proto=%s", STR_OR_NULL(str)); 164 165 if (str == 0) 166 return (-1); 167 #ifdef HAS_IPV6 168 if (strcasecmp(str, "TCP6") == 0) { 169 if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) { 170 *addr_family = AF_INET6; 171 return (0); 172 } 173 } else 174 #endif 175 if (strcasecmp(str, "TCP4") == 0) { 176 if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0) { 177 *addr_family = AF_INET; 178 return (0); 179 } 180 } 181 return (-1); 182 } 183 184 /* haproxy_srvr_parse_addr - extract and validate IP address */ 185 186 static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr, 187 int addr_family, 188 struct sockaddr *sa, 189 SOCKADDR_SIZE *sa_len) 190 { 191 struct addrinfo *res; 192 int err; 193 struct sockaddr_storage ss; 194 SOCKADDR_SIZE ss_len; 195 196 if (msg_verbose) 197 msg_info("haproxy_srvr_parse: addr=%s proto=%d", 198 STR_OR_NULL(str), addr_family); 199 200 if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR)) 201 return (-1); 202 203 switch (addr_family) { 204 #ifdef HAS_IPV6 205 case AF_INET6: 206 if (!valid_ipv6_hostaddr(str, DONT_GRIPE)) 207 return (-1); 208 break; 209 #endif 210 case AF_INET: 211 if (!valid_ipv4_hostaddr(str, DONT_GRIPE)) 212 return (-1); 213 break; 214 default: 215 msg_panic("haproxy_srvr_parse: unexpected address family: %d", 216 addr_family); 217 } 218 219 /* 220 * Convert the printable address to canonical form. Don't rely on the 221 * proxy. This requires a conversion to binary form and back, even if a 222 * caller such as postscreen does not need the binary form. 223 */ 224 if ((err = hostaddr_to_sockaddr(str, (char *) 0, 0, &res)) != 0) { 225 msg_warn("haproxy_srvr_parse: hostaddr_to_sockaddr(\"%s\") failed: %s", 226 str, MAI_STRERROR(err)); 227 return (-1); 228 } 229 if (sa == 0) { 230 sa = (struct sockaddr *) &ss; 231 ss_len = sizeof(ss); 232 sa_len = &ss_len; 233 } else { 234 if (sa_len == 0) 235 msg_panic("haproxy_srvr_parse: sockaddr length not specified"); 236 } 237 if (*sa_len < res->ai_addrlen) 238 msg_panic("haproxy_srvr_parse: sockaddr size %d too small", 239 (int) *sa_len); 240 *sa_len = res->ai_addrlen; 241 memcpy((void *) sa, res->ai_addr, res->ai_addrlen); 242 freeaddrinfo(res); 243 #ifdef HAS_IPV6 244 if (sa->sa_family == AF_INET6) 245 normalize_v4mapped_sockaddr(sa, sa_len); 246 #endif 247 if ((err = sockaddr_to_hostaddr(sa, *sa_len, 248 addr, (MAI_SERVPORT_STR *) 0, 0)) != 0) { 249 msg_warn("haproxy_srvr_parse: sockaddr_to_hostaddr() failed: %s", 250 MAI_STRERROR(err)); 251 return (-1); 252 } 253 return (0); 254 } 255 256 /* haproxy_srvr_parse_port - extract and validate TCP port */ 257 258 static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port, 259 struct sockaddr *sa) 260 { 261 if (msg_verbose) 262 msg_info("haproxy_srvr_parse: port=%s", STR_OR_NULL(str)); 263 if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR) 264 || !valid_hostport(str, DONT_GRIPE)) { 265 return (-1); 266 } else { 267 memcpy(port->buf, str, strlen(str) + 1); 268 if (sa != 0) { 269 switch (sa->sa_family) { 270 #ifdef HAS_IPV6 271 case AF_INET6: 272 SOCK_ADDR_IN6_PORT(sa) = htons(atoi(str)); 273 break; 274 #endif 275 case AF_INET: 276 SOCK_ADDR_IN_PORT(sa) = htons(atoi(str)); 277 break; 278 default: 279 msg_panic("haproxy_srvr_parse: unexpected address family: %d", 280 sa->sa_family); 281 } 282 } 283 return (0); 284 } 285 } 286 287 /* haproxy_srvr_parse_v2_addr_v4 - parse IPv4 info from v2 header */ 288 289 static int haproxy_srvr_parse_v2_addr_v4(uint32_t sin_addr, 290 unsigned sin_port, 291 MAI_HOSTADDR_STR *addr, 292 MAI_SERVPORT_STR *port, 293 struct sockaddr *sa, 294 SOCKADDR_SIZE *sa_len) 295 { 296 struct sockaddr_in sin; 297 SOCKADDR_SIZE sin_len; 298 299 /* 300 * Convert the binary address and port to printable form. 301 */ 302 if (sa == 0) { 303 sa = (struct sockaddr *) &sin; 304 sin_len = sizeof(sin); 305 sa_len = &sin_len; 306 } else { 307 if (sa_len == 0) 308 msg_panic("haproxy_srvr_parse: sockaddr length not specified"); 309 if (*sa_len < sizeof(sin)) 310 msg_panic("haproxy_srvr_parse: sockaddr size %d too small", 311 (int) *sa_len); 312 *sa_len = sizeof(sin); 313 } 314 memset((void *) sa, 0, *sa_len); 315 SOCK_ADDR_IN_FAMILY(sa) = AF_INET; 316 SOCK_ADDR_IN_ADDR(sa).s_addr = sin_addr; 317 SOCK_ADDR_IN_PORT(sa) = sin_port; 318 if (sockaddr_to_hostaddr(sa, *sa_len, addr, port, 0) < 0) 319 return (-1); 320 return (0); 321 } 322 323 #ifdef HAS_IPV6 324 325 /* haproxy_srvr_parse_v2_addr_v6 - parse IPv6 info from v2 header */ 326 327 static int haproxy_srvr_parse_v2_addr_v6(uint8_t *sin6_addr, 328 unsigned sin6_port, 329 MAI_HOSTADDR_STR *addr, 330 MAI_SERVPORT_STR *port, 331 struct sockaddr *sa, 332 SOCKADDR_SIZE *sa_len) 333 { 334 struct sockaddr_in6 sin6; 335 SOCKADDR_SIZE sin6_len; 336 337 /* 338 * Convert the binary address and port to printable form. 339 */ 340 if (sa == 0) { 341 sa = (struct sockaddr *) &sin6; 342 sin6_len = sizeof(sin6); 343 sa_len = &sin6_len; 344 } else { 345 if (sa_len == 0) 346 msg_panic("haproxy_srvr_parse: sockaddr length not specified"); 347 if (*sa_len < sizeof(sin6)) 348 msg_panic("haproxy_srvr_parse: sockaddr size %d too small", 349 (int) *sa_len); 350 *sa_len = sizeof(sin6); 351 } 352 memset((void *) sa, 0, *sa_len); 353 SOCK_ADDR_IN6_FAMILY(sa) = AF_INET6; 354 memcpy(&SOCK_ADDR_IN6_ADDR(sa), sin6_addr, sizeof(SOCK_ADDR_IN6_ADDR(sa))); 355 SOCK_ADDR_IN6_PORT(sa) = sin6_port; 356 normalize_v4mapped_sockaddr(sa, sa_len); 357 if (sockaddr_to_hostaddr(sa, *sa_len, addr, port, 0) < 0) 358 return (-1); 359 return (0); 360 } 361 362 #endif 363 364 /* haproxy_srvr_parse_v2_hdr - parse v2 header address info */ 365 366 static const char *haproxy_srvr_parse_v2_hdr(const char *str, ssize_t *str_len, 367 int *non_proxy, 368 MAI_HOSTADDR_STR *smtp_client_addr, 369 MAI_SERVPORT_STR *smtp_client_port, 370 MAI_HOSTADDR_STR *smtp_server_addr, 371 MAI_SERVPORT_STR *smtp_server_port, 372 struct sockaddr *client_sa, 373 SOCKADDR_SIZE *client_sa_len, 374 struct sockaddr *server_sa, 375 SOCKADDR_SIZE *server_sa_len) 376 { 377 const char myname[] = "haproxy_srvr_parse_v2_hdr"; 378 struct proxy_hdr_v2 *hdr_v2; 379 380 if (*str_len < PP2_HEADER_LEN) 381 return ("short protocol header"); 382 hdr_v2 = (struct proxy_hdr_v2 *) str; 383 if (memcmp(hdr_v2->sig, PP2_SIGNATURE, PP2_SIGNATURE_LEN) != 0) 384 return ("unrecognized protocol header"); 385 if ((hdr_v2->ver_cmd & PP2_VERSION_MASK) != PP2_VERSION) 386 return ("unrecognized protocol version"); 387 if (*str_len < PP2_HEADER_LEN + ntohs(hdr_v2->len)) 388 return ("short version 2 protocol header"); 389 390 switch (hdr_v2->ver_cmd & PP2_CMD_MASK) { 391 392 /* 393 * Proxied connection, use the proxy-provided connection info. 394 */ 395 case PP2_CMD_PROXY: 396 switch (hdr_v2->fam) { 397 case PP2_FAM_INET | PP2_TRANS_STREAM:{ /* TCP4 */ 398 if (strchr((char *) proto_info->sa_family_list, AF_INET) == 0) 399 return ("Postfix IPv4 support is disabled"); 400 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET) 401 return ("short address field"); 402 if (haproxy_srvr_parse_v2_addr_v4(hdr_v2->addr.ip4.src_addr, 403 hdr_v2->addr.ip4.src_port, 404 smtp_client_addr, smtp_client_port, 405 client_sa, client_sa_len) < 0) 406 return ("client network address conversion error"); 407 if (msg_verbose) 408 msg_info("%s: smtp_client_addr=%s smtp_client_port=%s", 409 myname, smtp_client_addr->buf, smtp_client_port->buf); 410 if (haproxy_srvr_parse_v2_addr_v4(hdr_v2->addr.ip4.dst_addr, 411 hdr_v2->addr.ip4.dst_port, 412 smtp_server_addr, 413 smtp_server_port, 414 server_sa, 415 server_sa_len) < 0) 416 return ("server network address conversion error"); 417 if (msg_verbose) 418 msg_info("%s: smtp_server_addr=%s smtp_server_port=%s", 419 myname, smtp_server_addr->buf, smtp_server_port->buf); 420 break; 421 } 422 case PP2_FAM_INET6 | PP2_TRANS_STREAM:{/* TCP6 */ 423 #ifdef HAS_IPV6 424 if (strchr((char *) proto_info->sa_family_list, AF_INET6) == 0) 425 return ("Postfix IPv6 support is disabled"); 426 if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET6) 427 return ("short address field"); 428 if (haproxy_srvr_parse_v2_addr_v6(hdr_v2->addr.ip6.src_addr, 429 hdr_v2->addr.ip6.src_port, 430 smtp_client_addr, 431 smtp_client_port, 432 client_sa, 433 client_sa_len) < 0) 434 return ("client network address conversion error"); 435 if (msg_verbose) 436 msg_info("%s: smtp_client_addr=%s smtp_client_port=%s", 437 myname, smtp_client_addr->buf, smtp_client_port->buf); 438 if (haproxy_srvr_parse_v2_addr_v6(hdr_v2->addr.ip6.dst_addr, 439 hdr_v2->addr.ip6.dst_port, 440 smtp_server_addr, 441 smtp_server_port, 442 server_sa, 443 server_sa_len) < 0) 444 return ("server network address conversion error"); 445 if (msg_verbose) 446 msg_info("%s: smtp_server_addr=%s smtp_server_port=%s", 447 myname, smtp_server_addr->buf, smtp_server_port->buf); 448 break; 449 #else 450 return ("Postfix IPv6 support is not compiled in"); 451 #endif 452 } 453 default: 454 return ("unsupported network protocol"); 455 } 456 /* For now, skip and ignore TLVs. */ 457 *str_len = PP2_HEADER_LEN + ntohs(hdr_v2->len); 458 return (0); 459 460 /* 461 * Non-proxied connection, use the proxy-to-server connection info. 462 */ 463 case PP2_CMD_LOCAL: 464 /* For now, skip and ignore TLVs. */ 465 *non_proxy = 1; 466 *str_len = PP2_HEADER_LEN + ntohs(hdr_v2->len); 467 return (0); 468 default: 469 return ("bad command in proxy header"); 470 } 471 } 472 473 /* haproxy_srvr_parse_sa - parse haproxy line */ 474 475 const char *haproxy_srvr_parse_sa(const char *str, ssize_t *str_len, 476 int *non_proxy, 477 MAI_HOSTADDR_STR *smtp_client_addr, 478 MAI_SERVPORT_STR *smtp_client_port, 479 MAI_HOSTADDR_STR *smtp_server_addr, 480 MAI_SERVPORT_STR *smtp_server_port, 481 struct sockaddr *client_sa, 482 SOCKADDR_SIZE *client_sa_len, 483 struct sockaddr *server_sa, 484 SOCKADDR_SIZE *server_sa_len) 485 { 486 const char *err; 487 488 if (proto_info == 0) 489 proto_info = inet_proto_info(); 490 491 *non_proxy = 0; 492 493 /* 494 * XXX We don't accept connections with the "UNKNOWN" protocol type, 495 * because those would sidestep address-based access control mechanisms. 496 */ 497 498 /* 499 * Try version 1 protocol. 500 */ 501 if (strncmp(str, "PROXY ", 6) == 0) { 502 char *saved_str = mystrndup(str, *str_len); 503 char *cp = saved_str; 504 char *beyond_header = split_at(saved_str, '\n'); 505 int addr_family; 506 507 #define NEXT_TOKEN mystrtok(&cp, " \r") 508 if (beyond_header == 0) 509 err = "missing protocol header terminator"; 510 else if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0) 511 err = "bad or missing protocol header"; 512 else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0) 513 err = "bad or missing protocol type"; 514 else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr, 515 addr_family, client_sa, 516 client_sa_len) < 0) 517 err = "bad or missing client address"; 518 else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr, 519 addr_family, server_sa, 520 server_sa_len) < 0) 521 err = "bad or missing server address"; 522 else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port, 523 client_sa) < 0) 524 err = "bad or missing client port"; 525 else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port, 526 server_sa) < 0) 527 err = "bad or missing server port"; 528 else { 529 err = 0; 530 *str_len = beyond_header - saved_str; 531 } 532 myfree(saved_str); 533 534 return (err); 535 } 536 537 /* 538 * Try version 2 protocol. 539 */ 540 else { 541 return (haproxy_srvr_parse_v2_hdr(str, str_len, non_proxy, 542 smtp_client_addr, smtp_client_port, 543 smtp_server_addr, smtp_server_port, 544 client_sa, client_sa_len, 545 server_sa, server_sa_len)); 546 } 547 } 548 549 /* haproxy_srvr_parse - ABI compatibility */ 550 551 #undef haproxy_srvr_parse 552 553 const char *haproxy_srvr_parse(const char *str, ssize_t *str_len, 554 int *non_proxy, 555 MAI_HOSTADDR_STR *smtp_client_addr, 556 MAI_SERVPORT_STR *smtp_client_port, 557 MAI_HOSTADDR_STR *smtp_server_addr, 558 MAI_SERVPORT_STR *smtp_server_port); 559 560 const char *haproxy_srvr_parse(const char *str, ssize_t *str_len, 561 int *non_proxy, 562 MAI_HOSTADDR_STR *smtp_client_addr, 563 MAI_SERVPORT_STR *smtp_client_port, 564 MAI_HOSTADDR_STR *smtp_server_addr, 565 MAI_SERVPORT_STR *smtp_server_port) 566 { 567 return (haproxy_srvr_parse_sa(str, str_len, non_proxy, 568 smtp_client_addr, smtp_client_port, 569 smtp_server_addr, smtp_server_port, 570 (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0, 571 (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)); 572 } 573 574 /* haproxy_srvr_receive_sa - receive and parse haproxy protocol handshake */ 575 576 int haproxy_srvr_receive_sa(int fd, int *non_proxy, 577 MAI_HOSTADDR_STR *smtp_client_addr, 578 MAI_SERVPORT_STR *smtp_client_port, 579 MAI_HOSTADDR_STR *smtp_server_addr, 580 MAI_SERVPORT_STR *smtp_server_port, 581 struct sockaddr *client_sa, 582 SOCKADDR_SIZE *client_sa_len, 583 struct sockaddr *server_sa, 584 SOCKADDR_SIZE *server_sa_len) 585 { 586 const char *err; 587 VSTRING *escape_buf; 588 char read_buf[HAPROXY_HEADER_MAX_LEN + 1]; 589 ssize_t read_len; 590 591 /* 592 * We must not read(2) past the end of the HaProxy handshake. The v2 593 * protocol assumes that the handshake will never be fragmented, 594 * therefore we peek, parse the entire input, then read(2) only the 595 * number of bytes parsed. 596 */ 597 if ((read_len = recv(fd, read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) { 598 msg_warn("haproxy read: EOF"); 599 return (-1); 600 } 601 602 /* 603 * Parse the haproxy handshake, and determine the handshake length. 604 */ 605 read_buf[read_len] = 0; 606 607 if ((err = haproxy_srvr_parse_sa(read_buf, &read_len, non_proxy, 608 smtp_client_addr, smtp_client_port, 609 smtp_server_addr, smtp_server_port, 610 client_sa, client_sa_len, 611 server_sa, server_sa_len)) != 0) { 612 escape_buf = vstring_alloc(read_len * 2); 613 escape(escape_buf, read_buf, read_len); 614 msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf)); 615 vstring_free(escape_buf); 616 return (-1); 617 } 618 619 /* 620 * Try to pop the haproxy handshake off the input queue. 621 */ 622 if (recv(fd, read_buf, read_len, 0) != read_len) { 623 msg_warn("haproxy read: %m"); 624 return (-1); 625 } 626 return (0); 627 } 628 629 /* haproxy_srvr_receive - ABI compatibility */ 630 631 #undef haproxy_srvr_receive 632 633 int haproxy_srvr_receive(int fd, int *non_proxy, 634 MAI_HOSTADDR_STR *smtp_client_addr, 635 MAI_SERVPORT_STR *smtp_client_port, 636 MAI_HOSTADDR_STR *smtp_server_addr, 637 MAI_SERVPORT_STR *smtp_server_port); 638 639 int haproxy_srvr_receive(int fd, int *non_proxy, 640 MAI_HOSTADDR_STR *smtp_client_addr, 641 MAI_SERVPORT_STR *smtp_client_port, 642 MAI_HOSTADDR_STR *smtp_server_addr, 643 MAI_SERVPORT_STR *smtp_server_port) 644 { 645 return (haproxy_srvr_receive_sa(fd, non_proxy, 646 smtp_client_addr, smtp_client_port, 647 smtp_server_addr, smtp_server_port, 648 (struct sockaddr *) 0, 649 (SOCKADDR_SIZE *) 0, 650 (struct sockaddr *) 0, 651 (SOCKADDR_SIZE *) 0)); 652 } 653