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
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);
}