From b108809a78dbedce34bf8dee060fd4a2e72480c8 Mon Sep 17 00:00:00 2001 From: ViKing Date: Wed, 7 Oct 2015 00:09:33 +0800 Subject: [PATCH] Fix the connection problem in transparent mode. When the source and destination are the same, the bind_peer() will fail, thus end the connection. Therefore a check of all the interface IPs are checked to skip bind() if they are the same. --- common.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/common.c b/common.c index 0120047..6d2732c 100644 --- a/common.c +++ b/common.c @@ -8,6 +8,10 @@ #include #include +#include +#include +#include + #include "common.h" #include "probe.h" @@ -120,6 +124,39 @@ int bind_peer(int fd, int fd_from) * got here */ res = getpeername(fd_from, from.ai_addr, &from.ai_addrlen); CHECK_RES_RETURN(res, "getpeername"); + + // if the destination is the same machine, there's no need to do bind + struct ifaddrs *ifaddrs_p = NULL, *ifa; + + getifaddrs(&ifaddrs_p); + + for (ifa = ifaddrs_p; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr) + continue; + int match = 0; + if (from.ai_addr->sa_family == ifa->ifa_addr->sa_family) + { + int family = ifa->ifa_addr->sa_family; + if (family == AF_INET) + { + struct sockaddr_in *from_addr = from.ai_addr; + struct sockaddr_in *ifa_addr = ifa->ifa_addr; + if (from_addr->sin_addr.s_addr == ifa_addr->sin_addr.s_addr) + match = 1; + } + else if (family == AF_INET6) + { + struct sockaddr_in6 *from_addr = from.ai_addr; + struct sockaddr_in6 *ifa_addr = ifa->ifa_addr; + if (!memcmp(from_addr->sin6_addr.s6_addr, ifa_addr->sin6_addr.s6_addr, 16)) + match = 1; + } + } + if (match) // the destination is the same as the source, should not create a transparent bind + return 0; + } + #ifndef IP_BINDANY /* use IP_TRANSPARENT */ res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans)); CHECK_RES_DIE(res, "setsockopt");