How to Get the Interface Name/Index Associated with a Tcp Socket

How to find the network interface used by a connected socket

Idea based on another post

  1. Create socket
  2. Connect
  3. Get interface address
  4. Get interface id and name from interface address
$ gcc -std=gnu11 -Wall so_q_63899229.c
$ ./a.out 93.184.216.34 # example.org
interface index : 2
interface name : wlp2s0
interface address : 192.168.1.223
remote address : 93.184.216.34

so_q_63899229.c

#include <arpa/inet.h>
#include <assert.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>

int sockfd=-1;

void connect2(const char *const dst){

sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd>=3);

struct sockaddr_in sin={
.sin_family=AF_INET,
.sin_port=htons(80),
.sin_addr={}
};
assert(1==inet_pton(AF_INET,dst,&(sin.sin_addr)));

assert(0==connect(sockfd,(struct sockaddr*)(&sin),sizeof(struct sockaddr_in)));

}

void getsockname2(struct sockaddr_in *const sin){
socklen_t addrlen=sizeof(struct sockaddr_in);
assert(0==getsockname(sockfd,(struct sockaddr*)sin,&addrlen));
assert(addrlen==sizeof(struct sockaddr_in));
}

void disconnect(){
close(sockfd);
sockfd=-1;
}

void addr2iface_ifconf(const struct in_addr *const sin_addr,int *const index,char *const name){

struct ifconf ifc={
.ifc_len=0,
.ifc_req=NULL
};

int ioctlfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
assert(ioctlfd>=3);
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));

const int sz=ifc.ifc_len;
assert(sz%sizeof(struct ifreq)==0);
const int n=sz/sizeof(struct ifreq);

char buf[sz];
bzero(buf,sz);
ifc.ifc_buf=buf;
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));
assert(
ifc.ifc_len==sz &&
(char*)ifc.ifc_req==buf
);

for(int i=0;i<n;++i)if(0==memcmp(
&(((struct sockaddr_in*)(&(ifc.ifc_req[i].ifr_addr)))->sin_addr),
sin_addr,
sizeof(struct in_addr)
)){
*index=ifc.ifc_req[i].ifr_ifindex;
assert(name==strncpy(name,ifc.ifc_req[i].ifr_name,IFNAMSIZ));
return;
}

assert(0);

}

int main(int argc,const char *argv[]){

assert(argc==2);
assert(argv[1]&&strlen(argv[1]));
const char *const remoteaddr_s=argv[1];
// const char *const remoteaddr_s="93.184.216.34";

connect2(remoteaddr_s);

struct sockaddr_in ifaddr={};
getsockname2(&ifaddr);

disconnect();

int index=0;
char ifname[IFNAMSIZ]={};
addr2iface_ifconf(&(ifaddr.sin_addr),&index,ifname);

char ifaddr_s[INET_ADDRSTRLEN]={};
assert(ifaddr_s==inet_ntop(AF_INET,&(ifaddr.sin_addr),ifaddr_s,INET_ADDRSTRLEN));

printf("interface index : %d\n",index);
printf("interface name : %s\n",ifname);
printf("interface address : %s\n",ifaddr_s);
printf("remote address : %s\n",remoteaddr_s);
// printf("#%d %s %s -> %s\n",
// index,
// ifname,
// ifaddr_s,
// remoteaddr_s
// );

return 0;

}

Also there doesn't seem to be an identifier named IFNAMSZ. IFNAMSIZ defined in <net/if.h> should be the maxinum legth (including '\0') allowed for the name of any interface IMHO.

Check incoming interface on TCP socket

When your TCP server accepted a client connection, you will have a socket to represent the connection, you could call getsockname on the socket, it will give you the address associated on the socket, namely the ip addresses on your side.
Next step, you can call getifaddrs to get all the interfaces and their information on your system, including name(like eth0) and ip address. At this point, you can search this list with the ip obtained previously via getsockname, you can get the interface you want as a result.

reference:

http://linux.die.net/man/2/getsockname

http://linux.die.net/man/3/getifaddrs

Get the interface to be used by socket according to IP on Linux, with C/C++

You can open a netlink socket and query the routes then filter the one you need. Here is an article on Linux Journal that describes this method:

https://www.linuxjournal.com/article/7356

And here is an implementation in C of it:

https://gist.github.com/javiermon/6272065

It just needs a bit of adjustment for your needs.

Determine the actual interface via which a client connected if listening on INADDR_ANY?

Once you have accepted the connection, you can get the local address of the new (connected) socket that accept returned, with the getsockname function.



Related Topics



Leave a reply



Submit