From c105c9213fadcf0f43cb20a08a90084bca18ce35 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 25 Oct 2021 08:17:11 +0200 Subject: [PATCH] MEDIUM: connection: Assign session addresses when PROXY line is received When PROXY protocol line is received, the retrieved client source and destination addresses are set at the session level. This leaves those at the connection level intact. --- src/connection.c | 76 +++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/connection.c b/src/connection.c index 2e3f274ef..57cdd9c37 100644 --- a/src/connection.c +++ b/src/connection.c @@ -757,6 +757,7 @@ static inline size_t get_tlv_length(const struct tlv *src) */ int conn_recv_proxy(struct connection *conn, int flag) { + struct session *sess = conn->owner; char *line, *end; struct proxy_hdr_v2 *hdr_v2; const char v2sig[] = PP2_SIGNATURE; @@ -767,9 +768,6 @@ int conn_recv_proxy(struct connection *conn, int flag) if (!conn_ctrl_ready(conn)) goto fail; - if (!sockaddr_alloc(&conn->src, NULL, 0) || !sockaddr_alloc(&conn->dst, NULL, 0)) - goto fail; - if (!fd_recv_ready(conn->handle.fd)) goto not_ready; @@ -841,15 +839,18 @@ int conn_recv_proxy(struct connection *conn, int flag) if (*line++ != '\n') goto bad_header; - /* update the session's addresses and mark them set */ - ((struct sockaddr_in *)conn->src)->sin_family = AF_INET; - ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = htonl(src3); - ((struct sockaddr_in *)conn->src)->sin_port = htons(sport); + if (!sess || !sockaddr_alloc(&sess->src, NULL, 0) || !sockaddr_alloc(&sess->dst, NULL, 0)) + goto fail; - ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET; - ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = htonl(dst3); - ((struct sockaddr_in *)conn->dst)->sin_port = htons(dport); - conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET; + /* update the session's addresses and mark them set */ + ((struct sockaddr_in *)sess->src)->sin_family = AF_INET; + ((struct sockaddr_in *)sess->src)->sin_addr.s_addr = htonl(src3); + ((struct sockaddr_in *)sess->src)->sin_port = htons(sport); + + ((struct sockaddr_in *)sess->dst)->sin_family = AF_INET; + ((struct sockaddr_in *)sess->dst)->sin_addr.s_addr = htonl(dst3); + ((struct sockaddr_in *)sess->dst)->sin_port = htons(dport); + sess->flags |= SESS_FL_ADDR_FROM_SET | SESS_FL_ADDR_TO_SET; } else if (memcmp(line, "TCP6 ", 5) == 0) { u32 sport, dport; @@ -902,15 +903,18 @@ int conn_recv_proxy(struct connection *conn, int flag) if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1) goto bad_header; - /* update the session's addresses and mark them set */ - ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, &src3, sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)conn->src)->sin6_port = htons(sport); + if (!sess || !sockaddr_alloc(&sess->src, NULL, 0) || !sockaddr_alloc(&sess->dst, NULL, 0)) + goto fail; - ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, &dst3, sizeof(struct in6_addr)); - ((struct sockaddr_in6 *)conn->dst)->sin6_port = htons(dport); - conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET; + /* update the session's addresses and mark them set */ + ((struct sockaddr_in6 *)sess->src)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)sess->src)->sin6_addr, &src3, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)sess->src)->sin6_port = htons(sport); + + ((struct sockaddr_in6 *)sess->dst)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)sess->dst)->sin6_addr, &dst3, sizeof(struct in6_addr)); + ((struct sockaddr_in6 *)sess->dst)->sin6_port = htons(dport); + sess->flags |= SESS_FL_ADDR_FROM_SET | SESS_FL_ADDR_TO_SET; } else if (memcmp(line, "UNKNOWN\r\n", 9) == 0) { /* This can be a UNIX socket forwarded by an haproxy upstream */ @@ -949,26 +953,32 @@ int conn_recv_proxy(struct connection *conn, int flag) if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET) goto bad_header; - ((struct sockaddr_in *)conn->src)->sin_family = AF_INET; - ((struct sockaddr_in *)conn->src)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr; - ((struct sockaddr_in *)conn->src)->sin_port = hdr_v2->addr.ip4.src_port; - ((struct sockaddr_in *)conn->dst)->sin_family = AF_INET; - ((struct sockaddr_in *)conn->dst)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr; - ((struct sockaddr_in *)conn->dst)->sin_port = hdr_v2->addr.ip4.dst_port; - conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET; + if (!sess || !sockaddr_alloc(&sess->src, NULL, 0) || !sockaddr_alloc(&sess->dst, NULL, 0)) + goto fail; + + ((struct sockaddr_in *)sess->src)->sin_family = AF_INET; + ((struct sockaddr_in *)sess->src)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr; + ((struct sockaddr_in *)sess->src)->sin_port = hdr_v2->addr.ip4.src_port; + ((struct sockaddr_in *)sess->dst)->sin_family = AF_INET; + ((struct sockaddr_in *)sess->dst)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr; + ((struct sockaddr_in *)sess->dst)->sin_port = hdr_v2->addr.ip4.dst_port; + sess->flags |= SESS_FL_ADDR_FROM_SET | SESS_FL_ADDR_TO_SET; tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET; break; case 0x21: /* TCPv6 */ if (ntohs(hdr_v2->len) < PP2_ADDR_LEN_INET6) goto bad_header; - ((struct sockaddr_in6 *)conn->src)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)conn->src)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16); - ((struct sockaddr_in6 *)conn->src)->sin6_port = hdr_v2->addr.ip6.src_port; - ((struct sockaddr_in6 *)conn->dst)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)conn->dst)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16); - ((struct sockaddr_in6 *)conn->dst)->sin6_port = hdr_v2->addr.ip6.dst_port; - conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET; + if (!sess || !sockaddr_alloc(&sess->src, NULL, 0) || !sockaddr_alloc(&sess->dst, NULL, 0)) + goto fail; + + ((struct sockaddr_in6 *)sess->src)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)sess->src)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16); + ((struct sockaddr_in6 *)sess->src)->sin6_port = hdr_v2->addr.ip6.src_port; + ((struct sockaddr_in6 *)sess->dst)->sin6_family = AF_INET6; + memcpy(&((struct sockaddr_in6 *)sess->dst)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16); + ((struct sockaddr_in6 *)sess->dst)->sin6_port = hdr_v2->addr.ip6.dst_port; + sess->flags |= SESS_FL_ADDR_FROM_SET | SESS_FL_ADDR_TO_SET; tlv_offset = PP2_HEADER_LEN + PP2_ADDR_LEN_INET6; break; }