需要帮助使用 Windows 套接字查看所有传入的数据包
Posted
技术标签:
【中文标题】需要帮助使用 Windows 套接字查看所有传入的数据包【英文标题】:need help using windows sockets to view all incoming packets 【发布时间】:2014-04-29 15:52:13 【问题描述】:我正在尝试创建一个程序,该程序可以接收和显示所有传入家庭网络的数据包。这只是一个“好玩”的项目,因为我正在努力更好地使用计算机网络。
我找到了一些关于使用套接字的教程,我正在尝试模仿他们正在做的事情。 (目前正在使用this(初始化内容来自this)教程)。
但是,我在使代码正常工作时遇到了一些问题。这是我到目前为止的代码:(因为我知道我只会在 windows 上使用它,所以我只是省略了 mac 和 unix 的其他 marcos)
#define PLATFORM_WINDOWS 1
#if defined(_WIN32)
#define PLATFORM PLATFORM_WINDOWS
#endif
#if PLATFORM == PLATFORM_WINDOWS
#include <WinSock2.h>
#endif
#pragma comment( lib, "wsock32.lib" );
#pragma comment( lib, "Ws2_32.lib" );
#include <iostream>
bool InitializeSockets()
#if PLATFORM == PLATFORM_WINDOWS
WSADATA WsaData;
return WSAStartup( MAKEWORD(2,2), &WsaData);
#else
return true;
#endif
void ShutdownSockets()
#if PLATFORM == PLATFORM_WINDOWS
WSACleanup();
#endif
void printIpPacket(unsigned char* data, int length)
printf("-----------------Packet Begins-----------------\n");
printf("IP Version: %i, Packet Size: %ibytes, Id: %i\n",
(data[0]>>4), (data[2]*256)+data[3], (data[4]*256)+data[5]);
printf("Fragment: %i, TTL: %i, HL: %iwds, Protocol: %i\n",
((int)(data[6]>>4)*256)+data[7], data[8], ((char)(data[0]<<4))>>4, data[9]);
printf("Source: %i.%i.%i.%i, Destination: %i.%i.%i.%i\n",
data[12], data[13], data[14], data[15],
data[16], data[17], data[18], data[19]);
//the data inside the packet starts at --> data+(((char)(data[0]<<4))>>2)
//new data length --> length-(((char)(data[0]<<4))>>2)
//continue printing the rest of the headers :o
printf("\n------------------Packet Ends------------------\n");
int main()
InitializeSockets();
int thisSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
int optVal = 1;
setsockopt(thisSocket, IPPROTO_IP, 2, (char *)&optVal, sizeof(optVal));
int inn = 1, outt;
long rett;
int err = WSAIoctl(thisSocket, 0x98000001, &inn, sizeof(inn), &outt, sizeof(outt), &rett, 0, 0);
int a = WSAGetLastError();
我在使WSAIoctl
函数工作时遇到了一些问题。本教程声称可以工作的代码甚至无法编译。我得到了错误:
error C2664: 'WSAIoctl' : cannot convert parameter 7 from 'long *' to 'LPDWORD'
然后,我将 WSAIoctl 函数行更改为:
int err = WSAIoctl(thisSocket, 0x98000001, &inn, sizeof(inn), &outt, sizeof(outt), (LPDWORD)&rett, 0, 0);
这已编译,但随后 WSAGetLastError() 返回错误代码 10022,根据 this 表示无效参数。
然后我想,“好吧,与其试图强制将错误的类型转换为正确的类型,我想我应该只传递正确的类型。”
然后我创建了一个变量
LPDWORD rett = new DWORD;
这样做,我编译成功,但我再次收到错误代码 10022。
在这一点上,我不知道还能做什么。有人可以帮我让这个程序运行吗?
【问题讨论】:
关于你的变量,改变 variable 的类型有什么问题吗? :DWORD rett = 0;
,然后像以前一样通过&rett
?关于你的错误。关于您的错误,如果您要使用SIO_RCVALL
嗅探数据包,则套接字应该是SOCK_RAW
,而不是SOCK_STREAM
。我意识到documentation for WSAIoctl 很广泛,但功能本身的力量也是如此。拥有强大的力量......无论如何,祝你好运。
所以我创建了 DWORD 并按照您所说的传递了它的地址,现在我收到错误代码 10038:Socket operation on nonsocket. An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
确保thisSocket
创建成功。我想你使用了 SOCK_RAW。您需要提升权限才能执行此操作。
@user58697 啊,检查套接字创建的错误,我收到错误 10013,意味着我没有正确设置权限。我的机器上当前没有运行任何防病毒/防火墙。还有什么我可以尝试解决的吗?
@xcdemon05:你需要使用SOCK_RAW
来进行数据包捕获,但是正如user58697所说,SOCK_RAW
需要管理员权限,并且是documented这样:“原始套接字提供了以下能力操纵底层传输,因此它们可用于构成安全威胁的恶意目的。因此,只有管理员组的成员才能在 Windows 2000 及更高版本上创建 SOCK_RAW 类型的套接字。
【参考方案1】:
试试这样的:
#define PLATFORM_WINDOWS 1
#if defined(_WIN32)
#define PLATFORM PLATFORM_WINDOWS
#endif
#if PLATFORM == PLATFORM_WINDOWS
#include <WinSock2.h>
#endif
#pragma comment( lib, "wsock32.lib" );
#pragma comment( lib, "Ws2_32.lib" );
#include <iostream>
bool InitializeSockets()
#if PLATFORM == PLATFORM_WINDOWS
WSADATA WsaData;
int a = WSAStartup( MAKEWORD(2,2), &WsaData);
if (a != 0)
printf("WSAStartup() failed. Error %d\n", a);
return false;
#endif
return true;
void ShutdownSockets()
#if PLATFORM == PLATFORM_WINDOWS
WSACleanup();
#endif
#if PLATFORM != PLATFORM_WINDOWS
void closesocket(int socket)
close(socket);
#endif
int GetLastSocketError()
#if PLATFORM == PLATFORM_WINDOWS
return WSAGetLastError();
#else
return errno;
#endif
int main()
if (!InitializeSockets())
return -1;
int thisSocket = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
if (thisSocket == -1)
printf("socket() failed. Error %d\n", GetLastSocketError());
ShutdownSockets();
return -1;
sockaddr_in bindaddr = 0;
bindaddr.sin_family = AF_INET;
// set bindaddr.sin_addr.s_addr to the desired local IP that you want to sniff from...
if (bind(thisSocket, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1)
printf("bind() failed. Error %d\n", GetLastSocketError());
closesocket(thisSocket);
ShutdownSockets();
return -1;
u_long optVal = 1;
if (setsockopt(thisSocket, IPPROTO_IP, IP_HDRINCL, (char *)&optVal, sizeof(optVal)) == -1)
printf("setsockopt() failed. Error %d\n", GetLastSocketError());
closesocket(thisSocket);
ShutdownSockets();
return -1;
#if PLATFORM == PLATFORM_WINDOWS
DWORD inn = RCVALL_ON;
if (WSAIoctl(thisSocket, SIO_RCVALL, &inn, sizeof(inn), NULL, 0, NULL, NULL, NULL) == -1)
printf("WSAIoctl() failed. Error %d\n", GetLastSocketError());
closesocket(thisSocket);
ShutdownSockets();
return -1;
#endif
u_char Buffer[0xffff];
while(1)
int len = recvfrom(thisSocket, (char*)Buffer, sizeof(Buffer), NULL, 0, 0);
if (len == -1)
printf("recvfrom() failed. Error %d\n", GetLastSocketError());
closesocket(thisSocket);
ShutdownSockets();
return -1;
printIpPacket(Buffer, len);
closesocket(thisSocket);
ShutdownSockets();
return 0;
【讨论】:
它没有编译 :( VS 无法识别一些 MACROS,包括 SIO_RCVALL、IP_HDRINCL 和 RCVALL_ON。还收到一些关于 recvfrom 无法从 u_char 转换 par 2 的编译错误[65535] 到 char*,但这似乎没什么大不了的。 你需要#include
相关的头文件,如Mstcpip.h
、Ws2tcpip.h
和winsock2.h
。下次遇到有关未知符号的错误时,请阅读相关的 MSDN 文档。以上是关于需要帮助使用 Windows 套接字查看所有传入的数据包的主要内容,如果未能解决你的问题,请参考以下文章