How can I get the interface name/index associated with a TCP socket?

前端 未结 9 486
伪装坚强ぢ
伪装坚强ぢ 2021-01-12 04:17

I\'m writing a TCP server that needs to know which interface each connection arrived from. I cannot use the address/subnet to deduce which interface was used, since there mi

9条回答
  •  抹茶落季
    2021-01-12 05:08

    Here's some C++11 code to find the interface name of a socket:

    std::string to_string(sockaddr_in const& addr)
    {
        char buf[INET_ADDRSTRLEN];
        if (inet_ntop(AF_INET, &addr.sin_addr, buf, sizeof(buf)) == nullptr)
        {
            std::clog << "inet_ntop: " << strerror(errno) << '\n';
            return {};
        }
        return buf;
    }
    
    std::string to_string(sockaddr_in6 const& addr)
    {
        char buf[INET6_ADDRSTRLEN];
        if (inet_ntop(AF_INET6, &addr.sin6_addr, buf, sizeof(buf)) == nullptr)
        {
            std::clog << "inet_ntop: " << strerror(errno) << '\n';
            return {};
        }
        return buf;
    }
    
    std::string to_string(sockaddr_storage const& addr, socklen_t len)
    {
        switch (addr.ss_family)
        {
        case AF_INET:
        {
            auto& a = reinterpret_cast(addr);
            if (len < sizeof(a))
            {
                std::clog << "Invalid sockaddr length: " << len << '\n';
                return {};
            }
            return to_string(a);
        }
        case AF_INET6:
        {
            auto& a = reinterpret_cast(addr);
            if (len < sizeof(a))
            {
                std::clog << "Invalid sockaddr length: " << len << '\n';
                return {};
            }
            return to_string(a);
        }
        default:
        {
            std::clog << "Invalid sockaddr family: " << addr.ss_family << '\n';
            return {};
        }
        }
    }
    
    std::string get_iface_name(sockaddr_in const& addr)
    {
        ifaddrs *ifa = nullptr;
        if (getifaddrs(&ifa) == -1)
        {
            std::clog << "getifaddrs: " << strerror(errno) << '\n';
            return {};
        }
        std::unique_ptr
            finally{ifa, freeifaddrs};
    
        for (; ifa; ifa = ifa->ifa_next)
        {
            if (!ifa->ifa_addr)
                continue;
            if (!ifa->ifa_name)
                continue;
            if (ifa->ifa_addr->sa_family != AF_INET)
                continue;
            auto& a = reinterpret_cast(*ifa->ifa_addr);
            if (a.sin_addr.s_addr == addr.sin_addr.s_addr)
                return ifa->ifa_name;
        }
    
        std::clog << "No interface found for IPv4 address " << to_string(addr) << '\n';
        return {};
    }
    
    std::string get_iface_name(sockaddr_in6 const& addr)
    {
        ifaddrs *ifa = nullptr;
        if (getifaddrs(&ifa) == -1)
        {
            std::clog << "getifaddrs: " << strerror(errno) << '\n';
            return {};
        }
        std::unique_ptr
            finally{ifa, freeifaddrs};
    
        for (; ifa; ifa = ifa->ifa_next)
        {
            if (!ifa->ifa_addr)
                continue;
            if (!ifa->ifa_name)
                continue;
            if (ifa->ifa_addr->sa_family != AF_INET6)
                continue;
            auto& a = reinterpret_cast(*ifa->ifa_addr);
            if (memcmp(a.sin6_addr.s6_addr,
                       addr.sin6_addr.s6_addr,
                       sizeof(a.sin6_addr.s6_addr)) == 0)
                return ifa->ifa_name;
        }
    
        std::clog << "No interface found for IPv6 address " << to_string(addr) << '\n';
        return {};
    }
    
    std::string get_iface_name(sockaddr_storage const& addr, socklen_t len)
    {
        switch (addr.ss_family)
        {
        case AF_INET:
        {
            auto& a = reinterpret_cast(addr);
            if (len < sizeof(a))
            {
                std::clog << "Invalid sockaddr length: " << len << '\n';
                return {};
            }
            return get_iface_name(a);
        }
        case AF_INET6:
        {
            auto& a = reinterpret_cast(addr);
            if (len < sizeof(a))
            {
                std::clog << "Invalid sockaddr length: " << len << '\n';
                return {};
            }
            return get_iface_name(a);
        }
        default:
        {
            std::clog << "Invalid sockaddr family: " << addr.ss_family << '\n';
            return {};
        }
        }
    }
    
    std::string get_iface_name(int sockfd)
    {
        sockaddr_storage addr;
        socklen_t len = sizeof(addr);
        if (getsockname(sockfd, (sockaddr*)&addr, &len) == -1)
        {
            std::clog << "getsockname: " << strerror(errno) << '\n';
            return {};
        }
        std::clog << "getsockname '" << to_string(addr, len) << '\'' << '\n';
        return get_iface_name(addr, len);
    }
    

提交回复
热议问题