|
|
@ -0,0 +1,131 @@ |
|
|
|
From a72d39058a7a5d004e0c6b69a91663591bb3bf89 Mon Sep 17 00:00:00 2001 |
|
|
|
From: Vincent Bernat <vincent@bernat.im> |
|
|
|
Date: Thu, 19 May 2016 11:15:51 +0200 |
|
|
|
Subject: [PATCH 1/4] BUG/MAJOR: fix listening IP address storage for frontends |
|
|
|
|
|
|
|
When compiled with GCC 6, the IP address specified for a frontend was |
|
|
|
ignored and HAProxy was listening on all addresses instead. This is |
|
|
|
caused by an incomplete copy of a "struct sockaddr_storage". |
|
|
|
|
|
|
|
With the GNU Libc, "struct sockaddr_storage" is defined as this: |
|
|
|
|
|
|
|
struct sockaddr_storage |
|
|
|
{ |
|
|
|
sa_family_t ss_family; |
|
|
|
unsigned long int __ss_align; |
|
|
|
char __ss_padding[(128 - (2 * sizeof (unsigned long int)))]; |
|
|
|
}; |
|
|
|
|
|
|
|
Doing an aggregate copy (ss1 = ss2) is different than using memcpy(): |
|
|
|
only members of the aggregate have to be copied. Notably, padding can be |
|
|
|
or not be copied. In GCC 6, some optimizations use this fact and if a |
|
|
|
"struct sockaddr_storage" contains a "struct sockaddr_in", the port and |
|
|
|
the address are part of the padding (between sa_family and __ss_align) |
|
|
|
and can be not copied over. |
|
|
|
|
|
|
|
Therefore, we replace any aggregate copy by a memcpy(). There is another |
|
|
|
place using the same pattern. We also fix a function receiving a "struct |
|
|
|
sockaddr_storage" by copy instead of by reference. Since it only needs a |
|
|
|
read-only copy, the function is converted to request a reference. |
|
|
|
|
|
|
|
This is a backport for 1.5 of 6e6158 and 6e46ff1. |
|
|
|
---
|
|
|
|
src/cfgparse.c | 4 ++-- |
|
|
|
src/connection.c | 2 +- |
|
|
|
src/proto_http.c | 12 ++++++------ |
|
|
|
src/proto_tcp.c | 2 +- |
|
|
|
4 files changed, 10 insertions(+), 10 deletions(-) |
|
|
|
|
|
|
|
diff --git a/src/cfgparse.c b/src/cfgparse.c
|
|
|
|
index 39abf6b..9331415 100644
|
|
|
|
--- a/src/cfgparse.c
|
|
|
|
+++ b/src/cfgparse.c
|
|
|
|
@@ -280,7 +280,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
|
|
|
|
} |
|
|
|
|
|
|
|
/* OK the address looks correct */ |
|
|
|
- ss = *ss2;
|
|
|
|
+ memcpy(&ss, ss2, sizeof(ss));
|
|
|
|
|
|
|
|
for (; port <= end; port++) { |
|
|
|
l = (struct listener *)calloc(1, sizeof(struct listener)); |
|
|
|
@@ -291,7 +291,7 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf,
|
|
|
|
l->bind_conf = bind_conf; |
|
|
|
|
|
|
|
l->fd = fd; |
|
|
|
- l->addr = ss;
|
|
|
|
+ memcpy(&l->addr, &ss, sizeof(ss));
|
|
|
|
l->xprt = &raw_sock; |
|
|
|
l->state = LI_INIT; |
|
|
|
|
|
|
|
diff --git a/src/connection.c b/src/connection.c
|
|
|
|
index dab1c90..09fd04e 100644
|
|
|
|
--- a/src/connection.c
|
|
|
|
+++ b/src/connection.c
|
|
|
|
@@ -620,7 +620,7 @@ int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connec
|
|
|
|
const char pp2_signature[] = PP2_SIGNATURE; |
|
|
|
int ret = 0; |
|
|
|
struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf; |
|
|
|
- struct sockaddr_storage null_addr = {0};
|
|
|
|
+ struct sockaddr_storage null_addr = { .ss_family = 0 };
|
|
|
|
struct sockaddr_storage *src = &null_addr; |
|
|
|
struct sockaddr_storage *dst = &null_addr; |
|
|
|
#ifdef USE_OPENSSL |
|
|
|
diff --git a/src/proto_http.c b/src/proto_http.c
|
|
|
|
index b3aa4d8..0b13c5e 100644
|
|
|
|
--- a/src/proto_http.c
|
|
|
|
+++ b/src/proto_http.c
|
|
|
|
@@ -3220,15 +3220,15 @@ int http_handle_stats(struct session *s, struct channel *req)
|
|
|
|
/* Sets the TOS header in IPv4 and the traffic class header in IPv6 packets |
|
|
|
* (as per RFC3260 #4 and BCP37 #4.2 and #5.2). |
|
|
|
*/ |
|
|
|
-static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
|
|
|
|
+static inline void inet_set_tos(int fd, struct sockaddr_storage *from, int tos)
|
|
|
|
{ |
|
|
|
#ifdef IP_TOS |
|
|
|
- if (from.ss_family == AF_INET)
|
|
|
|
+ if (from->ss_family == AF_INET)
|
|
|
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); |
|
|
|
#endif |
|
|
|
#ifdef IPV6_TCLASS |
|
|
|
- if (from.ss_family == AF_INET6) {
|
|
|
|
- if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr))
|
|
|
|
+ if (from->ss_family == AF_INET6) {
|
|
|
|
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)from)->sin6_addr))
|
|
|
|
/* v4-mapped addresses need IP_TOS */ |
|
|
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); |
|
|
|
else |
|
|
|
@@ -3366,7 +3366,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
|
|
|
|
|
|
|
case HTTP_REQ_ACT_SET_TOS: |
|
|
|
if ((cli_conn = objt_conn(s->req->prod->end)) && conn_ctrl_ready(cli_conn)) |
|
|
|
- inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
|
|
|
|
+ inet_set_tos(cli_conn->t.sock.fd, &cli_conn->addr.from, rule->arg.tos);
|
|
|
|
break; |
|
|
|
|
|
|
|
case HTTP_REQ_ACT_SET_MARK: |
|
|
|
@@ -3563,7 +3563,7 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
|
|
|
|
|
|
|
case HTTP_RES_ACT_SET_TOS: |
|
|
|
if ((cli_conn = objt_conn(s->req->prod->end)) && conn_ctrl_ready(cli_conn)) |
|
|
|
- inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
|
|
|
|
+ inet_set_tos(cli_conn->t.sock.fd, &cli_conn->addr.from, rule->arg.tos);
|
|
|
|
break; |
|
|
|
|
|
|
|
case HTTP_RES_ACT_SET_MARK: |
|
|
|
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
|
|
|
|
index cfa62f7..8c06441 100644
|
|
|
|
--- a/src/proto_tcp.c
|
|
|
|
+++ b/src/proto_tcp.c
|
|
|
|
@@ -394,7 +394,7 @@ int tcp_connect_server(struct connection *conn, int data, int delack)
|
|
|
|
struct sockaddr_storage sa; |
|
|
|
|
|
|
|
ret = 1; |
|
|
|
- sa = src->source_addr;
|
|
|
|
+ memcpy(&sa, &src->source_addr, sizeof(sa));
|
|
|
|
|
|
|
|
do { |
|
|
|
/* note: in case of retry, we may have to release a previously |
|
|
|
--
|
|
|
|
2.7.3 |
|
|
|
|