如何查找已连接的套接字使用的网络接口

如何解决如何查找已连接的套接字使用的网络接口

如何查找已连接的套接字使用的接口。以便我可以为不同的接口设置状态代码。我使用了下面的代码。但是我没有得到它。

我在下面的测试代码中尝试了两种不同的方法,但是都失败了。第一个连接到远程服务器,并且将ioctl与SIOCGIFNAME一起使用,但是由于“没有这样的设备”而失败。相反,第二个将getockopt与SO_BINDTODEVICE一起使用,但这又失败了(将名称长度设置为0)。

关于为什么这些失败或如何获得I / F名称的任何想法?编译后,将测试代码作为测试“ abcd”运行,其中abcd是在端口80上侦听的任何IPV4地址。请注意,我已经在Centos 7上对此进行了编译,它在,因此您可能必须注释掉#define IFNAMSZ行才能使其在其他系统上编译。

谢谢。

          #include <stdio.h>
        #include <string.h>
        #include <sys/socket.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <sys/ioctl.h>
        #include <net/if.h>
        int main(int argc,char **argv) {
        int sock;
        struct sockaddr_in dst_sin;
        struct in_addr     haddr;
        if(argc != 2)
          return 1;
        if(inet_aton(argv[1],&haddr) == 0) {
          printf("'%s' is not a valid IP address\n",argv[1]);
          return 1;
        }
        dst_sin.sin_family = AF_INET;
        dst_sin.sin_port   = htons(80);
        dst_sin.sin_addr   = haddr;
        if((sock = socket(AF_INET,SOCK_STREAM,0)) < 0) {
           perror("socket");
           return 1;
        }
     
        if(connect(sock,(struct sockaddr*)&dst_sin,sizeof(dst_sin)) < 0) {
           perror("connect");
           return 1;
        }
        printf("connected to %s:%d\n",inet_ntoa(dst_sin.sin_addr),ntohs(dst_sin.sin_port));

        #if 0 // ioctl fails with 'no such device'
        struct ifreq ifr;
        memset(&ifr,sizeof(ifr));

        // get the socket's interface index into ifreq.ifr_ifindex
        if(ioctl(sock,SIOCGIFINDEX,&ifr) < 0) {
           perror("SIOCGIFINDEX");
           return 1;
        }

       // get the I/F name for ifreq.ifr_ifindex
       if(ioctl(sock,SIOCGIFNAME,&ifr) < 0) {
          perror("SIOCGIFNAME");
          return 1;
       }
        printf("I/F is on '%s'\n",ifr.ifr_name);

        #else // only works on Linux 3.8+
        #define IFNAMSZ IFNAMSIZ               // Centos7 bug in if.h??
        char      optval[IFNAMSZ] = {0};
         socklen_t optlen = IFNAMSZ;
         if(getsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,&optval,&optlen) < 0) {
        perror("getsockopt");
        return 1;
          }
        if(!optlen) {
           printf("invalid optlen\n");
           return 1;
        }
        printf("I/F is on '%s'\n",optval);
        #endif
        close(sock);
        return 0;

解决方法

Idea based on another post

  1. 创建套接字
  2. 连接
  3. 获取接口地址
  4. 从接口地址获取接口ID和名称
$ 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,&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;

}

似乎没有一个名为IFNAMSZ的标识符。 中定义的IFNAMS I Z应该是任何接口恕我直言的名称所允许的最大长度(包括“ \ 0”)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?