C++使用原始套接字抓包

最近在研究使用原始套接字抓包,在网上找各种资料,下面是自己整理的测试代码

编程实现主要有以下几个步骤:
1.初始化WINSOCK库;
2.创建SOCKET句柄;
3.绑定SOCKET句柄到一个本地地址;
4.设置该SOCKET为接收所有数据的模式;
5.接收数据包;
6.关闭SOCKET句柄,清理WINSOCK库.

#include 
#include  
#include 
#include 
#pragma comment(lib,"WS2_32.lib")

#pragma pack(1)
struct TCPHeader
{ 
	WORD SrcPort;		// 源端口
	WORD DstPort;		// 目的端口
	DWORD SeqNum;		// 顺序号
	DWORD AckNum;		// 确认号
	BYTE DataOff;		// TCP头长
	BYTE Flags;			// 标志(URG、ACK等)
	WORD Window;		// 窗口大小
	WORD Chksum;		// 校验和
	WORD UrgPtr;		// 紧急指针
};

struct UDPHeader
{ 
	WORD SrcPort;		// 源端口
	WORD DstPort;		// 目的端口
	WORD DataOff;		// UDP头长
	WORD Chksum;		// 校验和
};

struct IPHeader
{
	union{ 
		BYTE Version;	// 版本
		BYTE HdrLen;	// IHL
	};
	BYTE ServiceType;	// 服务类型
	WORD TotalLen;		// 总长
	WORD ID;			// 标识
	union{
		WORD Flags;		// 标志
		WORD FragOff;	// 分段偏移
	};
	BYTE TimeToLive;	// 生命期
	BYTE Protocol;		// 协议
	WORD HdrChksum;		// 头校验和
	DWORD SrcAddr;		// 源地址
	DWORD DstAddr;		// 目的地址
	//BYTE Options;		// 选项
}; 

// test
struct NetData
{
	UINT	iDataNo;		// 消息No
	int		iType;			// 消息类型
	int		iTime;			// 次数
	int		iDataLen;		// 数据长度
	char	chChche[8];		// 缓存
	char	strData[1000];	// 数据
	NetData(){
		memset(this, 0, sizeof(NetData));
	}
};
#pragma pack()

// 使用原始套接字抓取网卡数据包
int capturenetpackage()
{
	WSADATA wsaData;
	SOCKET sock = SOCKET_ERROR;
	int iRet = 0;
	
	iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iRet != 0){
		printf("WSAStartup failed with error %d\n", WSAGetLastError());
		return -1;
	}

	// 此处必须以管理员运行VS,否则返回10013
	sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
	if (sock == SOCKET_ERROR){
		printf("socket failed with error %d\n", WSAGetLastError());
		goto tag_end;
	}

	char strHostName[255];
	iRet = gethostname(strHostName, sizeof(strHostName));
	if (iRet != 0){
		printf("gethostname failed with error %d\n", WSAGetLastError());
		goto tag_end;
	}

	// 根据主机名取得主机地址
	hostent *pHostent = gethostbyname(strHostName);
	sockaddr_in addrSelf;
	addrSelf.sin_family = AF_INET;
	addrSelf.sin_port = htons(0);
	memcpy(&addrSelf.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

	printf("self local ip addr is %s\n\n",inet_ntoa(addrSelf.sin_addr));

	iRet = bind(sock, (PSOCKADDR)&addrSelf, sizeof(addrSelf));
	if (iRet != 0){
		printf("bind failed with error %d\n", WSAGetLastError());
		goto tag_end;
	} 

	DWORD dwBufferLen[10] = {0};
	DWORD dwBufferInLen = 1;
	DWORD dwBytesReturned = 0;
	// 设置该SOCKET为接收所有流经绑定的IP的网卡的所有数据,包括接收和发送的数据包
	iRet = WSAIoctl(sock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), 
		&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL);
	if (iRet != 0){
		printf("WSAIoctl failed with error %d\n", WSAGetLastError());
		goto tag_end;
	}

	sockaddr_in addrFrom;
	int fromlen = sizeof(addrFrom);
	time_t temp;
	char strFromIP[16] = {0}, strCurTime[32] = {0};
	char strBuffer[1024 * 10], strData[4096] = {0};
	IPHeader ipData;
	TCPHeader tcpData;
	UDPHeader udpData;
	NetData netData;
	
	while (true)
	{
		memset(strBuffer, 0, sizeof(strBuffer));
		
		iRet = recvfrom(sock, strBuffer, sizeof(strBuffer), 0, (sockaddr*)&addrFrom, &fromlen);
		if (iRet <= 0){
			printf("recv failed with error %d\n", WSAGetLastError());
			break;
		}

		strcpy(strFromIP, inet_ntoa(addrFrom.sin_addr));
// 		if(strcmp(strFromIP, "192.168.0.104") == 0
// 			|| strcmp(strFromIP, "192.168.0.1") == 0
// 			|| strcmp(strFromIP, "192.168.0.103") == 0){
// 			continue;
// 		}

		if(strcmp(strFromIP, "192.168.0.104") != 0){
			continue;
		}
		
		// 处理IP包头数据
		memcpy(&ipData, strBuffer, sizeof(ipData));

		BYTE Protocol = 0;
		sockaddr_in addrSrc, addrDst;
		char strSrcIP[16] = {0}, strDstIP[16] = {0};

		addrSrc.sin_addr.S_un.S_addr = ipData.SrcAddr;
		addrDst.sin_addr.S_un.S_addr = ipData.DstAddr;
		strcpy(strSrcIP, inet_ntoa(addrSrc.sin_addr));
		strcpy(strDstIP, inet_ntoa(addrDst.sin_addr));
		if(strcmp(strSrcIP, "192.168.0.104") != 0 || strcmp(strDstIP, "192.168.0.104") != 0){
			continue;
		}

		// UDP协议
		if(ipData.Protocol == IPPROTO_UDP)
		{
			if(iRet != 1052){
				continue;
			}
			memcpy(&udpData, strBuffer + sizeof(ipData), sizeof(udpData));
			int iSrcPort = ntohs(udpData.SrcPort);
			int iDstPort = ntohs(udpData.DstPort);

			memcpy(&netData, strBuffer + sizeof(ipData) + sizeof(udpData), sizeof(netData));
		}
		// TCP协议
		else if(ipData.Protocol == IPPROTO_TCP)
		{
			if(iRet != 1064){
				continue;
			}
			memcpy(&tcpData, strBuffer + sizeof(ipData), sizeof(tcpData));
			int iSrcPort = ntohs(tcpData.SrcPort);
			int iDstPort = ntohs(tcpData.DstPort);
			
			memcpy(&netData, strBuffer + sizeof(ipData) + sizeof(tcpData), sizeof(netData));
		}
		else{}

		time(&temp);
		strftime(strCurTime, sizeof(strCurTime), "%Y-%m-%d %H:%M:%S",localtime(&temp) );
 		printf("Time:%s Length:%d from %s\n", strCurTime, iRet, strFromIP);
	}

tag_end:
	if(sock != SOCKET_ERROR){
		if (closesocket(sock) == SOCKET_ERROR){
			printf("closesocket failed with error %d\n", WSAGetLastError());
			return -1;
		}
	}

	if (WSACleanup() == SOCKET_ERROR){
		printf("WSACleanup failed with error %d\n", WSAGetLastError());
		return -1;
	}

	return 0;
}

你可能感兴趣的:(C++)