Raw Socket无法捕获指定接口的DHCP数据包但Wireshark可捕获
问题原因
你创建Raw Socket时指定了IPPROTO_TCP作为第三个参数:
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
Linux内核会根据这个参数过滤数据包,只将TCP协议的IP数据包交付给该socket,UDP、ICMP等其他协议的数据包会被内核直接忽略,不会传递到你的程序中——这就是DHCP(UDP协议)流量抓不到,但TCP流量能正常捕获的核心原因。
修复方案
将socket创建时的协议参数改为IPPROTO_IP,这样内核会把所有IP层的数据包(包括TCP、UDP、ICMP、IGMP等)都交付给你的socket:
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_IP);
修改后的关键代码片段如下(同时补充了错误信息输出,方便排查问题):
int main() { unsigned char *buffer = (unsigned char *)malloc(65536); // 足够容纳最大IP数据包 printf("Starting...\n"); // 修改协议参数为IPPROTO_IP,接收所有IP层数据包 int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_IP); if(sock_raw < 0) { perror("socket creation failed"); abort(); } int r = setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, "wlp3s0", strlen("wlp3s0")); if (r == -1) { perror("bind to device failed"); abort(); } while(1) { int data_size = recv(sock_raw , buffer , 65536 , 0); if(data_size <0 ) { perror("recv failed"); abort(); } ProcessPacket(buffer , data_size); } ::close(sock_raw); return 0; }
补充说明
Raw Socket协议参数的作用:
IPPROTO_TCP:仅接收TCP协议的IP数据包IPPROTO_UDP:仅接收UDP协议的IP数据包IPPROTO_IP:接收所有IP层数据包(需root权限)- 其他协议值对应各自的网络层/传输层协议
若仅需捕获特定几种协议(比如TCP+UDP),也可以分别创建两个Raw Socket,分别指定
IPPROTO_TCP和IPPROTO_UDP,再用select()或epoll()实现多路复用,但这种方式比直接使用IPPROTO_IP更复杂,适合有严格过滤需求的场景。始终以sudo权限运行程序,Linux下Raw Socket的创建需要root权限。
内容的提问来源于stack exchange,提问作者intrigued_66
相关产品推荐
相关产品推荐

