绑定到设备的原始套接字未接收所有数据包

Raw socket bound to device not receiving all packets

我有一个原始套接字设置绑定到一个已经处于混杂模式的设备:

int sock = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sock == -1)
{
   return -1;
}

struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
{
    close(sock);
    return -2;
}

while(1) {
  packet_size = recvfrom(sock , buffer , 65536 , 0 , NULL, NULL);
  // packet processing...
}

我的问题是我只在我的套接字上接收数据包,其 IP 目标与我绑定的设备 (eth0) 的 IP 相匹配。如何接收设备正在接收的所有 TCP 数据包?我可以在 Wireshark 中看到设备上的所有 TCP 数据包,但我在原始套接字中看到的唯一数据包是那些寻址到设备 IP 的数据包。

收到仅指向您设备 IP 的数据包的原因是您正在使用 PF_INET 原始套接字。当使用 PF_INET 原始套接字时 - skb 在跨越堆栈时面临不同的健全性检查(见下文)。

F.e。 :

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
    /*...*/

    /* When the interface is in promisc. mode, drop all the crap
     * that it receives, do not try to analyse it.
     */
    if (skb->pkt_type == PACKET_OTHERHOST)
        goto drop;

所以调用跟踪是这样的:__netif_receive_skb_core()->ip_rcv()->...->ip_local_deliver()->...->raw_local_deliver()- >raw_rcv()->...->tcp_rcv()(您可以通过trace-cmd查看trace)。

但是 tcpdump/Wireshark 在 __netif_receive_skb_core() 左右获取数据包,即在进行一些健全性检查之前。因此,差异使您感到困惑。

因此,如果您希望 skb 绕过大部分 Linux 内核网络堆栈 - 您应该使用 PF_PACKET 原始套接字。

Useful link