diff --git a/common.c b/common.c index 541bac1..ca17354 100644 --- a/common.c +++ b/common.c @@ -161,6 +161,48 @@ int start_listen_sockets(int *sockfd[], struct addrinfo *addr_list) return num_addr; } + +/* returns 1 if given address is on the local machine: iterate through all + * network interfaces and check their addresses */ +int is_same_machine(struct addrinfo* from) +{ + struct ifaddrs *ifaddrs_p = NULL, *ifa; + int match = 0; + + getifaddrs(&ifaddrs_p); + + for (ifa = ifaddrs_p; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr) + continue; + 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 = (struct sockaddr_in*)from->ai_addr; + struct sockaddr_in *ifa_addr = (struct sockaddr_in*)ifa->ifa_addr; + if (from_addr->sin_addr.s_addr == ifa_addr->sin_addr.s_addr) { + match = 1; + break; + } + } + else if (family == AF_INET6) + { + struct sockaddr_in6 *from_addr = (struct sockaddr_in6*)from->ai_addr; + struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6*)ifa->ifa_addr; + if (!memcmp(from_addr->sin6_addr.s6_addr, ifa_addr->sin6_addr.s6_addr, 16)) { + match = 1; + break; + } + } + } + } + freeifaddrs(ifaddrs_p); + return match; +} + + /* Transparent proxying: bind the peer address of fd to the peer address of * fd_from */ #define IP_TRANSPARENT 19 @@ -178,39 +220,11 @@ 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 = (struct sockaddr_in*)from.ai_addr; - struct sockaddr_in *ifa_addr = (struct sockaddr_in*)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 = (struct sockaddr_in6*)from.ai_addr; - struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6*)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; - } - + if (is_same_machine(&from)) + return 0; + #ifndef IP_BINDANY /* use IP_TRANSPARENT */ res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans)); CHECK_RES_DIE(res, "setsockopt");