BUG/MEDIUM: tcp: don't use SO_ORIGINAL_DST on non-AF_INET sockets

There's an issue when using SO_ORIGINAL_DST to retrieve the original
destination of a connection's address before being translated by
Netfilter's DNAT/REDIRECT or the old TPROXY. SO_ORIGINAL_DST is
able to retrieve an IPv4 address when the original destination was
IPv4 mapped into IPv6. At first glance it's not a big deal, but it
is for logging and for the proxy protocol, because we then have
two different address families for the source and destination. In
this case, the proxy protocol correctly detects the issue and emits
"UNKNOWN".

In order to fix this, we perform getsockname() first, and only if
the address family is AF_INET, then we perform the getsockopt() call.

This fix must be backported to 1.5, and probably even to 1.4 and 1.3.
This commit is contained in:
Willy Tarreau 2014-10-29 21:46:01 +01:00
parent 43e7958def
commit 5e0d0e046a

View File

@ -555,12 +555,24 @@ int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
{
if (dir)
return getpeername(fd, sa, &salen);
else {
int ret = getsockname(fd, sa, &salen);
if (ret < 0)
return ret;
#if defined(TPROXY) && defined(SO_ORIGINAL_DST)
else if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0)
return 0;
/* For TPROXY and Netfilter's NAT, we can retrieve the original
* IPv4 address before DNAT/REDIRECT. We must not do that with
* other families because v6-mapped IPv4 addresses are still
* reported as v4.
*/
if (((struct sockaddr_storage *)sa)->ss_family == AF_INET
&& getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0)
return 0;
#endif
else
return getsockname(fd, sa, &salen);
return ret;
}
}
/* Tries to drain any pending incoming data from the socket to reach the