Ajith C Narayanan
Ajith C Narayanan

Reputation: 33

capturing both incoming and outgoing packets using raw socket

I am writing a tool in C for logging data usage of different applications running on my Linux system. For this i had created a raw socket and then I bind it with "eth0" which is the name of my interface. But my problem is that, this sockets captures only incoming packets (ie: packets with destination MAC address as my system's MAC address). I can't find any packets that has source MAC address as my system's MAC address. So it means packets written by my own machine are not captured by the raw socket. But i want to capture packets in both directions for identifying uploaded and downloaded data size. Can anybody help?

int main()
{
    int rs,len;
    struct sockaddr_ll addr;
    char buf[65535];

    rs = socket(PF_PACKET,SOCK_RAW,htons(ETH_ALL));
    setsockopt(rs,SOL_SOCKET,SO_BINDDEVICE,"eth0",4);
    while(recvfrom(rs,buf,65535,&addr,&len) > 0){
        //print packets
    }
    return 0;
}

Upvotes: 3

Views: 4580

Answers (2)

Gil Hamilton
Gil Hamilton

Reputation: 12337

From socket(7):

SO_BINDTODEVICE

Bind this socket to a particular device like “eth0”, as specified in the passed interface name. [...] Note that this works only for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).

You should be looking at the packet(7) man page for this.

It may be instructive to download the libpcap library source and look at what it's doing (if you can't just use libpcap instead of rolling your own). It definitely gets outgoing packets as well as incoming ones.

It appears to make these calls (there are many supported options and configurations so you have to wend through a myriad of ifdefs to discover exactly what's going on -- see pcap-linux.c):

fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL);
...
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(sll));
sll.sll_family          = AF_PACKET;
sll.sll_ifindex         = ifindex;   // Interface index from SIOCGIFINDEX
sll.sll_protocol        = htons(ETH_P_ALL);
bind(fd, (struct sockaddr *) &sll, sizeof(sll));
...
struct packet_mreq      mr;
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = handlep->ifindex;
mr.mr_type    = PACKET_MR_PROMISC;
setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr))

One other thing to keep in mind. When receiving packets sent by your own box, it is frequently the case that the checksums (IP, TCP, and UDP) in the outgoing packets will be incorrect. That's because most modern network controllers support checksum offload. That means the card will calculate the checksums after the packets have been DMA'd into card memory. Hence, those for outgoing packets will not be correct in your program's buffer (which is filled by the kernel from local memory).

Upvotes: 2

Shihab Pullissery
Shihab Pullissery

Reputation: 196

I have found this while searching over your problem. I haven't tried this. May be this will work.

  int v=0;
    v = PACKET_MASK_ANY & ~(1<<PACKET_OUTGOING) & ~(1 << PACKET_LOOPBACK);
    setsockopt( raw_sock, SOL_PACKET, PACKET_RECV_TYPE, &v, sizeof(v));

Upvotes: 1

Related Questions