Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

linux

tcp

sockets

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 might be interfaces with the same address/subnet values. It's Linux based, and there's no need for the code to be portable.

All I could find were functions to get all interfaces, or a single interface by index. I could not find any way to get the interface associated with an accepted TCP socket.

Any ideas? Something I've missed?

EDIT: To reiterate, IP addresses are not unique in my case. Neither the destination addresses (the server itself) nor the source addresses (the clients). Yes, this is a very extreme IP scheme.

like image 831
Leeor Avatar asked May 11 '09 13:05

Leeor


People also ask

How is a TCP socket connection identified?

One subtle difference between a TCP socket and a UDP socket is that a TCP socket is identified by a four-tuple: (source IP address, source port number, destination IP address, destination port number).

What is a socket interface?

A socket programming interface provides the routines required for interprocess communication between applications, either on the local system or spread in a distributed, TCP/IP based network environment. Once a peer-to-peer connection is established, a socket descriptor is used to uniquely identify the connection.


1 Answers

Use getsockname() to get IP of local end of the TCP connection. Then use getifaddrs() to find the corresponding interface:

struct sockaddr_in addr;
struct ifaddrs* ifaddr;
struct ifaddrs* ifa;
socklen_t addr_len;

addr_len = sizeof (addr);
getsockname(sock_fd, (struct sockaddr*)&addr, &addr_len);
getifaddrs(&ifaddr);

// look which interface contains the wanted IP.
// When found, ifa->ifa_name contains the name of the interface (eth0, eth1, ppp0...)
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
    if (ifa->ifa_addr)
    {
        if (AF_INET == ifa->ifa_addr->sa_family)
        {
            struct sockaddr_in* inaddr = (struct sockaddr_in*)ifa->ifa_addr;

            if (inaddr->sin_addr.s_addr == addr.sin_addr.s_addr)
            {
                if (ifa->ifa_name)
                {
                    // Found it
                }
            }
        }
    }
}
freeifaddrs(ifaddr);

Above is just a dirty example, some modifications are needed:

  1. Add missing error checks
  2. IPv6 support
like image 174
SKi Avatar answered Oct 19 '22 14:10

SKi