Raw Socket混杂模式不会嗅到我写的东西

我在混杂模式下编写一个带有Raw Socket的程序,我需要原始套接字不会嗅探我发送的数据包。 我只需要通过以太网rx线(而不是tx线)读取数据。 这是可能的吗?

非常感谢。

解决方案是查看读取数据包是否为PACKET_OUTGOING。 使用此选项,您可以区分放在以太网tx线路中的数据包和从rx线路读取的数据包。

以混杂模式打开套接字:

char* i = "eth0"; int fd; struct ifreq ifr; struct sockaddr_ll interfaceAddr; struct packet_mreq mreq; if ((fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) < 0) return -1; memset(&interfaceAddr,0,sizeof(interfaceAddr)); memset(&ifr,0,sizeof(ifr)); memset(&mreq,0,sizeof(mreq)); memcpy(&ifr.ifr_name,i,IFNAMSIZ); ioctl(fd,SIOCGIFINDEX,&ifr); interfaceAddr.sll_ifindex = ifr.ifr_ifindex; interfaceAddr.sll_family = AF_PACKET; if (bind(fd, (struct sockaddr *)&interfaceAddr,sizeof(interfaceAddr)) < 0) return -2; mreq.mr_ifindex = ifr.ifr_ifindex; mreq.mr_type = PACKET_MR_PROMISC; mreq.mr_alen = 6; if (setsockopt(fd,SOL_PACKET,PACKET_ADD_MEMBERSHIP, (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) return -3; //... 

并阅读。 现在,我们可以区分Rx和Tx以太网线:

 unsigned char buf[1500]; struct sockaddr_ll addr; socklen_t addr_len = sizeof(addr); n = recvfrom(fd, buf, 2000, 0, (struct sockaddr*)&addr, &addr_len); if (n <= 0) { //Error reading } else if (addr.sll_pkttype == PACKET_OUTGOING) { //The read data are not writing by me. //Use only this data to copy in the other network. } 

这就是全部。 使用它我不读我写的数据。 当我将网络1帧复制到网络2并且网络2帧复制到网络1时,我避免了循环。

您需要创建与传入数据包对应的BPF (BSD数据包filter)filter:

 /* To obtain the BPF filter corresponding to incoming traffic: * sudo tcpdump -dd -i eth0 dst host YOUR_IP_ADDRESS and not src host YOUR_IP_ADDRESS * The filter given below is what i get on my local machine (192.168.1.7): * sudo tcpdump -dd -i eth0 dst host 192.168.1.7 and not src host 192.168.1.7 */ struct sock_filter incoming_filter[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 4, 0x00000800 }, { 0x20, 0, 0, 0x0000001e }, { 0x15, 0, 9, 0xc0a80107 }, { 0x20, 0, 0, 0x0000001a }, { 0x15, 7, 6, 0xc0a80107 }, { 0x15, 1, 0, 0x00000806 }, { 0x15, 0, 5, 0x00008035 }, { 0x20, 0, 0, 0x00000026 }, { 0x15, 0, 3, 0xc0a80107 }, { 0x20, 0, 0, 0x0000001c }, { 0x15, 1, 0, 0xc0a80107 }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 }, }; int s; struct sockaddr_ll sock_address; struct sock_fprog prog; /* Init the program filter */ prog.len = 14; prog.filter = incoming_filter; 

然后你的RAW套接字,并绑定和…:

 /* Create the raw socket */ s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (s < 0) { /* Error handling */ } /* Build our socket */ sock_address.sll_family = AF_PACKET; sock_address.sll_protocol = htons(ETH_P_IP); sock_address.sll_ifindex = if_nametoindex(your_interface_name); /* Bind */ if (bind(s, (struct sockaddr*)&sock_address, sizeof(sock_address)) < 0) { /* Error handling */ } /* Apply the filter */ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) { /* Error handling */ } /* Infinite listen loop */ while (1) { /* Handle received packet */ } 

编辑 :如果你想通过Mac地址过滤,这很简单,生成你的filter(我在这里使用我的Mac地址):

 sudo tcpdump -dd -i eth0 ether dst 00:0f:b0:68:0f:92 and not ether src 00:0f:b0:68:0f:92 { 0x20, 0, 0, 0x00000002 }, { 0x15, 0, 7, 0xb0680f92 }, { 0x28, 0, 0, 0x00000000 }, { 0x15, 0, 5, 0x0000000f }, { 0x20, 0, 0, 0x00000008 }, { 0x15, 0, 2, 0xb0680f92 }, { 0x28, 0, 0, 0x00000006 }, { 0x15, 1, 0, 0x0000000f }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 }, 

您可以轻松过滤来自您IP地址的内容,并将其从列表中排除。

遗憾的是,Linux没有提供任何选项来指定不接收原始套接字的传出数据包。

如果允许重建Linux内核,我建议只使用packet_socket_type.patch修补内核。

在用户程序中,您可以指定您希望接收的数据包类型。

 int mask=0; mask = PACKET_MASK_ANY & ~(1< 

IMO,这是真正解决问题的解决方案。