获取从INADDR_ANY发送的 UDP 数据报的源地址



当我从绑定到INADDR_ANY的 UDP 套接字发送数据包时,如何找出操作系统选择使用的 IP 地址?

int s = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in src;
src.sin_family = AF_INET;
src.sin_port = 12345;
src.sin_addr.s_addr = INADDR_ANY;
bind(s, (struct sockaddr*)&src, sizeof(src));
char msg[] = "Hello";
sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = 12345;
dest.sin_addr.s_addr = (in_addr_t)0xdeadbeef;
sendto(s, msg, sizeof(msg), 0, (struct sockaddr*)&dest, sizeof(dest));

用于发送数据包的源地址是什么?理想情况下,会有一个像 recvfrom() 这样的sendtofrom()函数,它返回内核选择的地址。

在我的应用程序中,我绑定到INADDR_ANY并将数据包发送到 STUN 服务器(我不想玩转路由表来选择源地址:内核的选择很好)。但是,要做ICE,我需要获取"服务器反射地址"的"基址",即。我需要知道哪个本地地址用于发送 STUN 请求。我会接受特定于Windows或POSIX的答案,建议从路由表中查找地址。

遗憾的是,无法查询使用了哪个源 IP 地址。 例如,在 Windows 上,您必须编写低级别 NDIS 驱动程序才能获取该信息。 但是,如果使用 WSASendMsg()/sendmsg() 而不是 sendto() ,则可以传入in_pktinfo结构来指定要用于传出数据包的源 IP 地址。

我最近遇到了同样的问题。

我为解决这个问题所做的是

  1. 从收到的数据包中获取接口名称
  2. 将套接字绑定到特定接口
  3. 解绑套接字

例:

  struct ifreq ifr;
  ...
  recvmsg(fd, &msg...)
  ...
  //
  if (msg.msg_controllen >= sizeof(struct cmsghdr))
    for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
      if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
      {
        iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
      }
  if_indextoname(iface_index , ifr.ifr_name);
  mret=setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
  sendmsg(...);
  memset(&ifr, 0, sizeof(ifr));
  snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "");
  mret=setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));

最新更新