使用原始套接字捕获传入和传出的数据包

时间:2017-03-03 08:52:02

标签: c sockets network-programming raw-sockets

我正在用C编写一个工具,用于记录在我的Linux系统上运行的不同应用程序的数据使用情况。为此我创建了一个原始套接字然后用“eth0”绑定它,这是我的接口的名称。但我的问题是,这个套接字只捕获传入的数据包(即:目的MAC地址作为我系统的MAC地址的数据包)。我找不到任何源MAC地址作为我系统的MAC地址的数据包。所以它意味着我自己的机器写的数据包不会被原始套接字捕获。但我想在两个方向捕获数据包,以识别上传和下载的数据大小。有人可以帮忙吗?

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

2 个答案:

答案 0 :(得分:1)

我在搜索您的问题时发现了这一点。我没试过这个。可能会有用。

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

答案 1 :(得分:1)

来自socket(7)

  

SO_BINDTODEVICE

     
    

将此套接字绑定到特定设备,如“eth0”,如传递的接口名称中所指定。 [...] 请注意,这仅适用于某些套接字类型,                   特别是AF_INET插座。数据包套接字不支持(在那里使用普通绑定(2))。

  

您应该查看packet(7)手册页。

下载libpcap库源并查看它正在做什么(如果你不能只使用libpcap而不是自己编写)可能是有益的。它肯定会得到传出的数据包以及传入的数据包。

它似乎会进行这些调用(有许多支持的选项和配置,所以你必须通过无数的ifdef来发现究竟发生了什么 - 请参阅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))

要记住的另一件事。当接收到您自己的盒子发送的数据包时,通常情况是传出数据包中的校验和(IP,TCP和UDP)将不正确。那是因为大多数现代网络控制器都支持校验和卸载。这意味着卡将在数据包被DMA进入卡存储器后计算校验和。因此,传出数据包的那些在程序的缓冲区中是不正确的(由内核从本地内存填充)。