TheoretiCAL
TheoretiCAL

Reputation: 20571

Raw socket bound to device not receiving all packets

I have a raw socket set up bound to a device that is already in promiscuous mode:

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...
}

And my issue is that I am only receiving packets on my socket with IP destination matching the IP of the device (eth0) I am bound to. How can I receive all the TCP packets that the device is receiving? I can see all the TCP packets on the device in Wireshark, but the only packets that I see in my raw socket are those addressed to the device IP.

Upvotes: 2

Views: 1362

Answers (1)

red0ct
red0ct

Reputation: 5055

The reason of receiving packets directed only to IP of your device is that you are using PF_INET raw socket. When PF_INET raw socket is used - skb faces different sanity checks when goes across the stack (see below).

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;

So the call trace is something like: __netif_receive_skb_core()->ip_rcv()->...->ip_local_deliver()->...->raw_local_deliver()->raw_rcv()->...->tcp_rcv() (you can check trace through the trace-cmd).

But tcpdump/Wireshark obtains packets around __netif_receive_skb_core(), i.e. before some sanity checks. Hence is discrepancy that confused you.

Therefore if you want skb's to bypass a large part of Linux kernel network stack - you should use PF_PACKET raw sockets.

Useful link

Upvotes: 3

Related Questions