Raw Socket(原始套接字)实现Sniffer(嗅探)但是收不到数据包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Raw Socket(原始套接字)实现Sniffer(嗅探)但是收不到数据包相关的知识,希望对你有一定的参考价值。

// 检查 Winsock 版本号,WSAData为WSADATA结构对象
int iResult = WSAStartup(MAKEWORD(2, 2), &WSAData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");

// 创建原始套接字
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock == INVALID_SOCKET)

printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 1;


// 设置IP头操作选项,其中flag 设置为ture,亲自对IP头进行处理
int sckopterr = setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
if (sckopterr != 0)
printf("Error at setsockopt()\n");

// 获取本机名
gethostname((char*)LocalName, sizeof(LocalName)); printf("name: %s \n",LocalName);

// 获取本地 IP 地址
pHost = gethostbyname((char*)LocalName); printf("ip: %s\n",inet_ntoa(*(in_addr *)pHost->h_addr_list[0]));

// 填充SOCKADDR_IN结构
addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(57274);

// 把原始套接字sock 绑定到本地网卡地址上
int binderr = bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in));
if (binderr == SOCKET_ERROR )
printf("Error at bind()\n");

// dwValue为输入输出参数,为1时执行,0时取消
DWORD dwValue = 1;

// 设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL
// 的定义为: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
int ioctlsckterr = ioctlsocket(sock, SIO_RCVALL, &dwValue);
if (ioctlsckterr != NO_ERROR)
printf("Error at ioctlsocket()\n");

while (true)


// 接收原始数据包信息
int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);

if (ret > 0)

// 对数据包进行分析,并输出分析结果
ip = *(IP*)RecvBuf;
tcp = *(TCP*)(RecvBuf + ip.HdrLen);
printf("协议: %s\r\n",GetProtocolTxt(ip.Protocol));
printf("IP源地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.SrcAddr));
printf("IP目标地址: %s\r\n",inet_ntoa(*(in_addr*)&ip.DstAddr));
printf("TCP源端口号: %d\r\n",tcp.SrcPort);
printf("TCP目标端口号:%d\r\n",tcp.DstPort);
printf("数据包长度: %d\r\n\r\n\r\n",ntohs(ip.TotalLen));

但是收不到数据包 一直卡在 int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);
我也是用的管理员权限运行的了

参考技术A sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW),这里有问题,应该是
sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP)
参考技术B 我在这一步就有问题了ioctlsocket,一直返回-1

socket

 

一、什么是Socket
socket即套接字,用于描述地址和端口,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);前两种较常用。
基于TCP的socket编程是采用的流式套接字。
(1)SOCK_STREAM表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,
但效率相对较慢。常用的HTTP协议就使用SOCK_STREAM传输数据,因为要确保数据的正确性,否则网页不能正常解析。
(2)SOCK_DGRAM表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,
或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为SOCK_DGRAM所做的校验工作少,
所以效率比SOCK_STREAM高。

QQ视频聊天和语音聊天就使用SOCK_DGRAM传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响。

注意:SOCK_DGRAM没有想象中的糟糕,不会频繁的丢失数据,数据错读只是小概率事件。

有可能多种协议使用同一种数据传输方式,所以在socket编程中,需要同时指明数据传输方式和协议。

二、客户端/服务端模式:
在TCP/IP网络应用中,通信的两个进程相互作用的主要模式是客户/服务器模式,即客户端向服务器发出请求,服务器接收请求后,
提供相应的服务。客户/服务器模式的建立基于以下两点:
(1)建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而就让拥有众多资源的主机提供服务,
资源较少的客户请求服务这一非对等作用。
(2)网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区。

因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务端模式的TCP/IP。

服务端:建立socket,声明自身的端口号和地址并绑定到socket,使用listen打开监听,然后不断用accept去查看是否有连接,
如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket,如果不再需要
等待任何客户端连接,那么用closeSocket关闭掉自身的socket。

客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后
调用closeSocket关闭socket。


三、编程步骤
(1)服务端
1、加载套接字库,创建套接字(WSAStartup()/socket());
2、绑定套接字到一个IP地址和一个端口上(bind());
3、将套接字设置为监听模式等待连接请求(listen());
4、请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
5、用返回的套接字和客户端进行通信(send()/recv());
6、返回,等待另一个连接请求;
7、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());


(2)客户端
1、加载套接字库,创建套接字(WSAStartup()/socket());
2、向服务器发出连接请求(connect());
3、和服务器进行通信(send()/recv());
4、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

 

以上是关于Raw Socket(原始套接字)实现Sniffer(嗅探)但是收不到数据包的主要内容,如果未能解决你的问题,请参考以下文章

关于socket(AF_INET, SOCK_RAW,...)这个原始套接字

Python 原始套接字 (Windows):嗅探以太网帧

原始套接字的问题

python使用原始套接字 解析原始ip头数据

原始套接字的学习和问题

Python Raw Socket 无法接收 ICMP 消息;出现在 Wireshark 中