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.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 2aa93bb..cfa62f7 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -555,12 +555,24 @@
 {
 	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