我正在关注原始套接字嗅探器的 C 应用程序示例:
https://www.binarytides.com/packet-sniffer-code-c-linux/
除非我在创建套接字后将套接字绑定到我的接口:
const std::string& iff = "wlp3s0";
int r = setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, iff.c_str(), iff.length());
if (r == -1)
{
std::abort();
}
然后我让应用程序运行:
sudo ./the_app
我打开 Wireshark 并监听 wlp3s0 无线接口。我从捕获中删除了有线以太网接口。
然后,我运行sudo dhclient -r
并sudo dhclient
停止/启动 DHCP,Wireshark 检测到 4 或 5 个 DHCP 数据包,如预期的那样:
然而,C 原始套接字嗅探器显示绝对没有收到 UDP 数据包。
如果我随后打开 Web 浏览器,它就会开始显示 TCP 数据包(Wireshark 报告 DHCP 数据包是 UDP)。
发生了什么?我使用的是 Ubuntu 22.04
最小的例子:
#include<stdio.h> //For standard things
#include<stdlib.h> //malloc
#include<string.h> //memset
#include<netinet/ip_icmp.h> //Provides declarations for icmp header
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
#include<sys/socket.h>
#include<arpa/inet.h>
#include <unistd.h>
void ProcessPacket(unsigned char* , int);
int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j;
struct sockaddr_in source,dest;
int main()
{
unsigned char *buffer = (unsigned char *)malloc(65536); //Its Big!
printf("Starting...\n");
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(sock_raw < 0)
{
std::abort();
}
int r = setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, "wlp3s0", strlen("wlp3s0"));
if (r == -1)
{
std::abort();
}
while(1)
{
int data_size = recv(sock_raw , buffer , 65536 , 0);
if(data_size <0 )
{
std::abort();
}
ProcessPacket(buffer , data_size);
}
::close(sock_raw);
return 0;
}
void ProcessPacket(unsigned char* buffer, int size)
{
//Get the IP Header part of this packet
struct iphdr *iph = (struct iphdr*)buffer;
++total;
switch (iph->protocol) //Check the Protocol and do accordingly...
{
case 1: //ICMP Protocol
++icmp;
//print_icmp_packet(buffer, size);
break;
case 2: //IGMP Protocol
++igmp;
break;
case 6: //TCP Protocol
++tcp;
//print_tcp_packet(buffer , size);
break;
case 17: //UDP Protocol
++udp;
//print_udp_packet(buffer , size);
break;
default: //Some Other Protocol like ARP etc.
++others;
break;
}
printf("TCP : %d UDP : %d ICMP : %d IGMP : %d Others : %d Total : %d\r",tcp,udp,icmp,igmp,others,total);
}
嗯,当然你没有收到 UDP 数据包。您明确只要求 TCP 数据包
IPPROTO_TCP
:毕竟,您所遵循的指南告诉您这一点:
现在您可能会考虑使用
IPPROTO_RAW
,但这只能用于发送,如下man 7 raw
所示:所以你不能用一个
AF_INET
套接字接收多个协议。您将需要一个AF_PACKET
套接字和稍微复杂的代码。请参阅man 7 packet
获取更多信息。bind(2)
请注意,在这种情况下,您必须使用and进行绑定struct sockaddr_ll
,不能setsockopt(SO_BINDTODEVICE, ...)
与AF_PACKET
套接字一起使用,如下man 7 socket
所示: