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

时间:2015-01-06 11:41:31

标签: sockets winapi routing udp posix

当我从绑定到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));

使用什么源地址发送数据包?理想情况下会有sendtofrom()函数,如recvfrom(),它返回内核选择的地址。

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

我要解决这个问题的方法是

  1. 从收到的数据包中获取接口名称
  2. 将套接字绑定到特定接口
  3. unbind socket
  4. 示例:

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