WinSock原始套接字编程(Raw Socket)

匿名 (未验证) 提交于 2019-12-03 00:34:01

目录:

1.原始套接字及其功能

2.原始套接字的通信流程

3.收发ICMP数据包

3.1ping

3.2 Trace Route(tracert)

4发送自定义的IP分组

5.捕获IP数据包(网络嗅探Sniffer)


1.收发ICMP包之ping程序:

// Ping.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h"  #include <iostream> #include <winsock2.h> #pragma comment(lib, "WS2_32") #define DATALEN 1012 #define  PACKAGENUM 10  //发送ICMP会从请求报文的个数 using namespace std; /***定义ICMP包结构***/ typedef struct icmp_hdr {     unsigned char   icmp_type;		// ICMP包类型     unsigned char   icmp_code;		// 代码     unsigned short  icmp_checksum;	// 校验和     unsigned short  icmp_id;		// 惟一确定此请求的标识,通常设置为进程ID     unsigned short  icmp_sequence;	// 序列号     unsigned long   icmp_timestamp; // 时间戳 } IcmpHeader; unsigned short checksum(unsigned short* buff, int size);  //校验和计算函数的声明 int main(int argc, char *argv[ ]) { 	/***加载Winsock2.2***/ 	WSADATA wsaData; 	int ret; 	if((ret=WSAStartup(MAKEWORD(1,0),&wsaData))!=0) 	{ 		cout<<"初始化WinSock2.2出错!"; 		exit(0); 	} 	char szDestIp[256] ={0};//存放要Ping的IP地址或域名 	//检查ping命令的使用格式是否正确,程序调试时可用后面的代码替换 	/*if (argc < 2) 	 { 	 cout<<"\n用法: ping IP地址|域名\n"; 	  return -1; 	 } 	strcpy(szDestIp,argv[1]);*/ 	/***输入对方IP地址,调试程序时使用***/ 	cout<<"请输入你要Ping的IP地址...\n"; 	cin.getline(szDestIp,sizeof(szDestIp)); 	/***将点分十进制IP地址转换为32位二进制表示的IP地址***/ 	unsigned long ulDestIP= inet_addr(szDestIp);    	/****转换不成功时按域名解析****/ 	if(ulDestIP == INADDR_NONE) 	{ 		hostent* pHostent = gethostbyname(szDestIp); 		if (pHostent!=NULL) 			ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr; 		else //解析主机名失败 		{ 			cout<<"域名解析失败:"<<argv[1]<<"错误码:"<<WSAGetLastError()<<endl; 			WSACleanup(); 			return -1; 		} 	} 	/**** 创建收发ICMP包的原始套接字***/ 	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 	/***设置接收超时时间***/ 	int nTime=1000; 	ret = setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, (char*)&nTime, sizeof(nTime)); 	if(ret == SOCKET_ERROR) 	{ 	cout<<"套接字选项设置出错!错误码:"<<WSAGetLastError()<<endl; 		return -1;; 	} 	/***设置ICMP包发送的目的地址***/ 	SOCKADDR_IN dest; 	dest.sin_family = AF_INET; 	dest.sin_port = htons(0); 	dest.sin_addr.S_un.S_addr = ulDestIP; 	/***创建ICMP包***/ 	char buff[sizeof(IcmpHeader) + DATALEN]; 	IcmpHeader* pIcmp = (IcmpHeader*)buff; 	/***填写ICMP包数据***/ 	pIcmp->icmp_type = 8;	// ICMP回送请求 	pIcmp->icmp_code = 0; 	pIcmp->icmp_id = (unsigned short)GetCurrentProcessId();//获取进程号作为ID  	pIcmp->icmp_timestamp = 0; //时间戳暂设置为0,具体值发送时再填 	pIcmp->icmp_checksum = 0;  //校验和在计算前应先设置为0 	pIcmp->icmp_sequence = 0;  //初始序列号 	/***填充数据部分,可以为任意***/ 	memset(&buff[sizeof(IcmpHeader)], 'A', DATALEN); 	/***调用connect()函数为原始套接字指定通信对端地址***/ 	connect(sRaw,(SOCKADDR *)&dest, sizeof(dest)); 	/***收发ICMP报文***/ 	int n=0; 	bool bTimeout;   	unsigned short	nSeq = 0;//发送的ICMP报文的序号 	char recvBuf[32+DATALEN];//定义接收缓冲区 	SOCKADDR_IN from;  //保存收到的数据的源地址 	int nLen = sizeof(from);  //地址长度 	IcmpHeader* pRecvIcmp;  //指向ICMP报文首部的指针 	while(TRUE) 	{ 		static int nCount = 0; 		int nRet; 		if(nCount++ == PACKAGENUM) 			break; 		/***填写发送前才能填写的一些字段并发送ICMP包***/ 		pIcmp->icmp_checksum = 0;  		pIcmp->icmp_timestamp = GetTickCount();//时间戳 		pIcmp->icmp_sequence = nSeq++;  //包序号         pIcmp->icmp_checksum=checksum((unsigned short*)buff, sizeof(IcmpHeader)+DATALEN); 		nRet = send(sRaw, buff, sizeof(IcmpHeader) + DATALEN, 0); 		if(nRet == SOCKET_ERROR) 		{ 			cout<<"发送失败!错误码:"<<WSAGetLastError()<<endl; 			closesocket(sRaw); 			WSACleanup(); 			return -1; 		} 		//接收对方返回的ICMP应答 		bTimeout=FALSE; 		n=0; do{ 			n++;//接收预期ICMP应答报文的尝试次数加1 			memset((void *)recvBuf,0,sizeof(recvBuf)); 			nRet = recvfrom(sRaw, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&from, &nLen); 			if(nRet == SOCKET_ERROR) 			{ 				if(WSAGetLastError() == WSAETIMEDOUT) 				{ 					cout<<" timed out!\n"; 					bTimeout=TRUE;   //接收时间超时 					break; 				} 				cout<<"接收失败!错误码:"<<WSAGetLastError()<<endl; 				return -1; 			} 			 pRecvIcmp = (IcmpHeader*)(recvBuf + 20); //收到的数据包含20个字节的IP首部,加20才是ICMP首部位置  			if(pRecvIcmp->icmp_id != GetCurrentProcessId()) //收到报文是否为本程序发送的请求报文的应答报文 			{ 				//不是则重新接收	 				cout<<" 收到一个非预期的ICMP报文,忽略!\n"; 			} 			else  //是则退出循环 				break; 		}while(n<10);//重新接收次数不超过10则继续重试 		if(n>10)// 收到太多非预期的ICMP报文则退出 		{ 			cout<<"对方机器向本机发送了太多的ICMP报文.\n"; 			closesocket(sRaw); 			WSACleanup(); 			return -1; 		} 		if(bTimeout)continue;  //接收超时则发送下一个ICPM报文 		/****解析接收到的ICMP包****/ 		int nTick = GetTickCount(); 		if(nRet < 20+ sizeof(IcmpHeader))  //收到的报文长度不足则不予解析 		{ 			cout<<"Too few bytes from"<<inet_ntoa(from.sin_addr)<<endl; 			continue; 		} 		else 		{   			//解析收到报文 			cout<<nRet<<" bytes from :"<<inet_ntoa(from.sin_addr); 			cout <<" icmp_seq = "<<pRecvIcmp->icmp_sequence; 			cout<<" time:"<< nTick - pRecvIcmp->icmp_timestamp<<" ms \n"; 			Sleep(1000);  //延时1秒再发送下一个数据包 		} 	} 	closesocket(sRaw); 	WSACleanup(); 	system("pause"); 	return 0; } /*************计算校验和的函数***************/ unsigned short checksum(unsigned short* buff, int size) { 	unsigned long cksum = 0; 	while(size>1) 	{ 		cksum += *buff++; 		size -= sizeof(unsigned short); 	} 	if(size)// 是奇数 		cksum += *(char*)buff; 	//将32位的chsum高16位和低16位相加然后取反 	cksum = (cksum >> 16) + (cksum & 0xffff); 	cksum += (cksum >> 16);			 	return (unsigned short)(~cksum); }  /* 请输入你要Ping的IP地址... 101.132.67.215 1044 bytes from :101.132.67.215 icmp_seq = 0 time:15 ms 1044 bytes from :101.132.67.215 icmp_seq = 1 time:15 ms 1044 bytes from :101.132.67.215 icmp_seq = 2 time:16 ms 1044 bytes from :101.132.67.215 icmp_seq = 3 time:0 ms 1044 bytes from :101.132.67.215 icmp_seq = 4 time:16 ms 1044 bytes from :101.132.67.215 icmp_seq = 5 time:16 ms 1044 bytes from :101.132.67.215 icmp_seq = 6 time:15 ms 1044 bytes from :101.132.67.215 icmp_seq = 7 time:16 ms 1044 bytes from :101.132.67.215 icmp_seq = 8 time:0 ms 1044 bytes from :101.132.67.215 icmp_seq = 9 time:32 ms 请按任意键继续. . .  */

2.路由跟踪程序Traceroute

// Traceroute.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h"  #include <iostream> #include <winsock2.h> #include "ws2tcpip.h" #pragma comment(lib, "WS2_32") #define DEF_ICMP_DATA_SIZE  1024 #define MAX_ICMP_PACKET_SIZE 2048 /***ICMP回送请求报文首部***/ using namespace std; typedef struct icmp_hdr {     unsigned char   icmp_type;		// 消息类型     unsigned char   icmp_code;		// 代码     unsigned short  icmp_checksum;	// 校验和     unsigned short  icmp_id;		// 用来惟一标识此请求的ID号,通常设置为进程ID     unsigned short  icmp_sequence;	// 序列号     unsigned long   icmp_timestamp; // 时间戳 } IcmpHeader; /*********ICMP报文首部校验和计算函数***********/ unsigned short Checksum(unsigned short* pBuf, int iSize)  { unsigned long cksum = 0; while (iSize>1)  { cksum += *pBuf++; iSize -= sizeof(unsigned short); } if (iSize)  cksum += *(char*)pBuf; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (unsigned short)(~cksum); }  /*********************主函数**********************/ int main(int argc, char *argv[ ]) { 	char szDestIp[256];//存放目的IP地址	 	WSADATA wsaData; 	int ret; 	if((ret=WSAStartup(MAKEWORD(2,2),&wsaData))!=0) 	{ 		cout<<"初始化WinSock出错!\n"; 		return -1; 	} 	cout<<"请输入目的IP地址或域名:\n"; 	cin.getline(szDestIp,sizeof(szDestIp)); 	unsigned long ulDestIP= inet_addr(szDestIp); 	if(ulDestIP == INADDR_NONE) 	{ 		 //转换不成功时按域名解析  		hostent* pHostent = gethostbyname(szDestIp); 		if (pHostent!=NULL) 			ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr; 		else //解析主机名失败  		{ 			cout<<"不能解析域名:"<< szDestIp <<".错误码:"<<WSAGetLastError()<<endl; 			WSACleanup(); 			return -1; 		} 	} 	cout<<"路由跟踪:"<<szDestIp<<"("<<inet_ntoa(*(in_addr*)(&ulDestIP)) << ")"<<endl; 	/******创建用于接收ICMP包的原始套节字,绑定到本地端口*****/  	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 	sockaddr_in in; 	in.sin_family = AF_INET; 	in.sin_port = 0; 	in.sin_addr.S_un.S_addr = INADDR_ANY; 	if(bind(sRaw, (sockaddr*)&in, sizeof(in)) == SOCKET_ERROR) 	{ 		cout<<"地址绑定失败\n "; 		WSACleanup(); 		return -1; 	} 	int nTime=10*1000; 	setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, (char*)&nTime, sizeof(nTime));	 	/******构造待发送的ICMP包******/ 	char IcmpSendBuf[sizeof( IcmpHeader)+DEF_ICMP_DATA_SIZE];//发送缓存 	char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE] ;//接收缓存 	memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); 	memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); 	 //填充待发送的ICMP包  	IcmpHeader* pIcmpHeader = (IcmpHeader*)IcmpSendBuf; 	pIcmpHeader->icmp_type = 8; 	pIcmpHeader->icmp_id  = 0; 	pIcmpHeader->icmp_id  = (unsigned short)GetCurrentProcessId(); 	memset(IcmpSendBuf+sizeof(IcmpHeader), 'E', DEF_ICMP_DATA_SIZE); 	 /*****填充发送目的地址****/  	sockaddr_in destAddr; 	destAddr.sin_family = AF_INET; 	destAddr.sin_port = htons(22); 	destAddr.sin_addr.S_un.S_addr =ulDestIP; 	int nRet, nTick, nTTL=1, iSeqNo=0; 	/***发送报文并接收路由器的差错报告报文***/ 	IcmpHeader *pICMPHdr;  //指向ICMP报文首部的指针 	char *szIP; 	SOCKADDR_IN recvAddr; 	int n; 	do 	{ 		/***设置TTL值***/  		setsockopt(sRaw, IPPROTO_IP, IP_TTL, (char*)&nTTL, sizeof(nTTL)); 		nTick = GetTickCount(); 		/*** 填写ICMP报文的序列号并计算校验和***/ 		((IcmpHeader*)IcmpSendBuf)->icmp_checksum = 0; 		((IcmpHeader*)IcmpSendBuf)->icmp_sequence = htons(iSeqNo++); 		((IcmpHeader*)IcmpSendBuf)->icmp_checksum =  Checksum((unsigned short*)IcmpSendBuf, sizeof(IcmpHeader)+DEF_ICMP_DATA_SIZE); 		/***发送数据***/ 		nRet = sendto(sRaw, IcmpSendBuf,sizeof(IcmpSendBuf), 0,  (sockaddr*)&destAddr, sizeof(destAddr)); 		if(nRet == SOCKET_ERROR) 		{ 			cout<<"发送数据出错!错误码:"<<WSAGetLastError()<<endl; 		    break; 		} 		/****接收路由器返回的ICMP差错报文***/         int nLen = sizeof(recvAddr); 		n=0; 		do{ 			n++; 		    nRet=recvfrom(sRaw, IcmpRecvBuf,sizeof(IcmpRecvBuf),0,(sockaddr*)&recvAddr,&nLen); 			if(nRet == SOCKET_ERROR) 			{ 				cout<<"接收数据出错!错误码:"<<WSAGetLastError()<<endl; 				 closesocket(sRaw); 				WSACleanup(); 				return -1; 			} 			pICMPHdr = (IcmpHeader*)&IcmpRecvBuf [20];  			szIP = inet_ntoa(recvAddr.sin_addr); 			if(pICMPHdr->icmp_type==11|| pICMPHdr->icmp_type == 0 || pICMPHdr-> icmp_type== 3) 				break; 		}while(n<10); 		if(n>10)continue; 		printf("第%d个路由器,IP地址:%s 用时%d毫秒\n",nTTL,szIP,GetTickCount() - nTick);	 		if(pICMPHdr->icmp_type == 3 ) 		{ 			switch(pICMPHdr->icmp_code) 			{ 			case 0: cout<<"目的网络不可达!\n";break; 			case 1: cout<<"目的主机不可达!\n";break; 			case 6: cout<<"不知道的目的网络!\n";break; 			case 7: cout<<"不知道的目的主机!\n";break; 			} 			break; 		} 		if(destAddr.sin_addr.S_un.S_addr == recvAddr.sin_addr.S_un.S_addr) 		{	 			cout<<"目标可达。\n";	break; 		} 	}while(nTTL++ <30); 	closesocket(sRaw); 	WSACleanup(); 	system("pause"); 	return 0; }   

3.发送自定义的IP分组

// SendUDP.cpp : 定义控制台应用程序的入口点。 // //使用例7.3的程序可收到本程序发出的UDP包, #include "stdafx.h"  #include <iostream>  #include <winsock2.h>  #include <ws2tcpip.h>  #pragma comment(lib,"ws2_32.lib") #define DestPort 65432  //目的UDP端口 #define SourcePort 65431 //源UDP端口 using namespace std; typedef struct _IPHeader // 定义IP首部结构 { 	unsigned char iphVerLen; // 版本号和头长度各占4位 	unsigned char ipTOS;  // 服务类型 	unsigned short ipLength; // 分组总长度 	unsigned short ipID; //分组标识,惟一标识发送的每一个数据报 	unsigned short ipFlags; // 标志 	unsigned char ipTTL; // 生存时间,TTL 	unsigned char ipProtocol; // 协议可以是TCP、UDP、ICMP等 	unsigned short ipChecksum; // 校验和 	unsigned long ipSource; // 源IP地址 	unsigned long ipDestination; // 目的IP地址 } IPHeader; typedef struct _UDPHeader //定义UDP首部结构 { 	unsigned short sourcePort;    // 源端口号 	unsigned short destinationPort;// 目的端口号 	unsigned short len;          // 包长度 	unsigned short checksum;    // 校验和 } UDPHeader; typedef struct tsd_hdr //定义UDP伪首部结构 {  	unsigned long saddr; //源IP地址  	unsigned long daddr; //目的IP地址 	char mbz;     //填充 	char ptcl; //协议型  	unsigned short udpl; //TCP长度  }PSDHEADER;  /********CheckSum:计算校验和的函数***************/  unsigned short checksum(unsigned short *buffer, int size)  {  	unsigned long cksum=0;  	while(size >1)  	{  		cksum+=*buffer++;  		size -=sizeof(unsigned short);  	}  	if(size )  	{  		cksum += *(char *)buffer;  	}  	cksum = (cksum >> 16) + (cksum & 0xffff);  	cksum += (cksum >>16);  	return (unsigned short)(~cksum);  }  /****************主函数************************/  int main(int argc, char* argv[]) { 	// 输入参数信息 	char szDestIp[] = "192.168.2.116";// 目的IP地址 	char szSourceIp[] = "192.168.2.116";//源IP地址,必须是本机IP地址 	char szMsg[] = "Hellow! This is a test UDP Package!\n"; 	int nMsgLen = strlen(szMsg); 	WSADATA WSAData; 	if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)  	{  		cout<<"WSAStartup Error!\n";  		return false;  	}  	/*** 创建原始套接字***/ 	SOCKET sRaw =socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 	/***设置IP_HDRINCL选项***/ 	int bIncl =1; 	setsockopt(sRaw, IPPROTO_IP, IP_HDRINCL, (char *)&bIncl, sizeof(bIncl)); 	/****创建并填充IP头****/ 	char buff[1024] = { 0 };//存放自定义IP分组的存储区 	//填充IP分组首部 	IPHeader *pIphdr = (IPHeader *)buff; 	pIphdr->iphVerLen = (4<<4 | (sizeof(IPHeader)/sizeof(unsigned long))); //版本与长度 	pIphdr->ipLength=htons(sizeof(IPHeader)+sizeof(UDPHeader)+nMsgLen);//分组长度 	pIphdr->ipTTL = 128;  //生存时间 	pIphdr->ipProtocol = IPPROTO_UDP;//协议为UDP 	pIphdr->ipSource = inet_addr(szSourceIp);   //源IP地址 	pIphdr->ipDestination = inet_addr(szDestIp);  //目的IP地址 	pIphdr->ipChecksum = checksum((unsigned short*)pIphdr, sizeof(IPHeader)); //校验和 	/**** 填充UDP首部***/ 	UDPHeader *pUdphdr = (UDPHeader *)&buff[sizeof(IPHeader)]; 	pUdphdr->sourcePort = htons(SourcePort);   //源端口 	pUdphdr->destinationPort = htons(DestPort);//目的端口 	pUdphdr->len = htons(sizeof(UDPHeader) + nMsgLen);//报头长度¨ 	pUdphdr->checksum = 0;  //校验和 	/***填充UDP数据****/ 	char *pData = &buff[sizeof(IPHeader) + sizeof(UDPHeader)]; 	memcpy(pData, szMsg, nMsgLen);  	/****计算UDP校验和***/ 	PSDHEADER psdHeader;//构造伪首部 	psdHeader.saddr=pIphdr->ipSource;  	psdHeader.daddr=pIphdr->ipDestination;  	psdHeader.mbz=0;  	psdHeader.ptcl=IPPROTO_UDP;  	psdHeader.udpl=htons(sizeof(UDPHeader)+nMsgLen);  	char szBuff[1024]; 	memcpy(szBuff, &psdHeader, sizeof(psdHeader)); 	memcpy(szBuff+sizeof(psdHeader),pUdphdr, sizeof(UDPHeader));  	memcpy(szBuff+sizeof(psdHeader)+sizeof(UDPHeader),pData, nMsgLen); 	pUdphdr->checksum =  checksum((unsigned short *)szBuff,  	sizeof(psdHeader)+sizeof(UDPHeader)+nMsgLen); 	/*** 设置目的地址***/ 	SOCKADDR_IN destAddr = { 0 }; 	destAddr.sin_family = AF_INET; 	destAddr.sin_port = htons(DestPort); 	destAddr.sin_addr.S_un.S_addr = inet_addr(szDestIp); 	/***发送5个同样的原始UDP数据报***/ 	int nRet; 	for(int i=0; i<5; i++) 	{ 		nRet =sendto(sRaw, buff,sizeof(IPHeader) + sizeof(UDPHeader) + nMsgLen,0, (sockaddr*)&destAddr, sizeof(destAddr)); 		if(nRet == SOCKET_ERROR) 		{ 			cout<<" 发送错误,错误码:"<<WSAGetLastError()<<endl; 			break; 		} 		else 			cout<<"发送字节数:"<< nRet<<endl; 		Sleep(1000); 	} 	/***结束处理***/ 	closesocket(sRaw); 	WSACleanup(); 	return 0; }  

4.捕获IP数据包

// CaptuerIP.cpp : 定义控制台应用程序的入口点。 //  #include "stdafx.h"  #include <iostream> #include <winsock2.h> #include "mstcpip.h" #pragma comment(lib, "WS2_32") using namespace std; void DecodeIPPacket(char *pData); void DecodeTCPPacket(char *pData); void DecodeUDPPacket(char *pData); void DecodeICMPPacket(char *pData); /*****IP分组首部结构******/ typedef struct _IPHeader // 定义IP首部结构 { 	unsigned char iphVerLen; // 版本号和头长度各占4位 	unsigned char ipTOS;  // 服务类型 	unsigned short ipLength; // 分组总长度 	unsigned short ipID; //分组标识,惟一标识发送的每一个数据报 	unsigned short ipFlags; // 标志 	unsigned char ipTTL; // 生存时间,TTL 	unsigned char ipProtocol; // 协议可以是TCP、UDP、ICMP等 	unsigned short ipChecksum; // 校验和 	unsigned long ipSource; // 源IP地址 	unsigned long ipDestination; // 目的IP地址 } IPHeader, *PIPHeader;  /****ICMP包头结构******/ typedef struct icmphdr { 	char  i_type;  // ICMP包类型码 	char  i_code;  //代码 	unsigned short  i_cksum;  //校验和 	unsigned short  i_id;    //标识符,一般可设为发送进程的ID 	unsigned short  i_seq;   //序列号 	unsigned long  timestamp;  //时间戳 }ICMPHeader;  /**********UDP包头结构******/ typedef struct _UDPHeader { unsigned short sourcePort;    // 源端口号 unsigned short destinationPort; // 目的端口号 unsigned short len;          // 包长度 unsigned short checksum;    // 校验和 } UDPHeader; /******TCP包头结构******/ typedef struct _TCPHeader { 	unsigned short sourcePort;		// 16位源端口号 	unsigned short destinationPort;	// 16位目的端口号 	unsigned long sequenceNumber;	// 32位序列号 	unsigned long acknowledgeNumber;	// 32位确认号 	char	 dataoffset;	//高4位表示数据偏移 	char flags;    //低6位为URG、ACK、PSH、RST、SYNhe FIN六个标志位 	unsigned short windows;		// 16位窗口大小 	unsigned short checksum;		// 16位校验和 	unsigned short urgentPointer;		// 16位紧急数据偏移量  } TCPHeader; /*****主函数******/ int  main() { 	WSADATA wsaData; 	int ret; 	if((ret=WSAStartup(MAKEWORD(2,2),&wsaData))!=0) 	{ 		cout<<"初始化WinSock出错!"; 		return -1; 	} 	/**** 创建原始套节字******/ 	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP); 	/****** 获取本地IP地址******/ 	char sHostName[256]; 	SOCKADDR_IN addr_in; 	struct hostent *hptr; 	gethostname(sHostName, sizeof(sHostName)); 	if((hptr = gethostbyname(sHostName)) == NULL) 	{ 		cout<<"未能获取本地IP地址。错误码"<<WSAGetLastError()<<endl; 		WSACleanup(); 		return -1; 	} 	char **pptr=hptr->h_addr_list; 	/******在屏幕上显示本机所有的IP地址******/ 	cout<<"本机IP地址:\n"; 	while(*pptr!=NULL) 	{ 		cout<<inet_ntoa(*(struct in_addr *)(*pptr))<<endl; 		pptr++; 	} 	/*****输入想要要监听的接口的IP地址******/ 	cout<<"请输入要监听接口的IP地址:\n"; 	char snfIP[20]; 	cin.getline(snfIP,sizeof(snfIP)); 	 	addr_in.sin_family  = AF_INET; 	addr_in.sin_port    = htons(80); 	addr_in.sin_addr.S_un.S_addr  = inet_addr(snfIP); 	/****绑定网卡IP地址******/ 	if(bind(sRaw, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR) 	{ 		cout<<"地址绑定出错!错误码"<<WSAGetLastError()<<endl; 		closesocket(sRaw); 		WSACleanup(); 		return -1; 	} 	/****在调用ioctlsocket将网卡设为混杂模式前,套节字必须绑定该网卡的IP地址******/ 	DWORD dwValue = 1; 	if(ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0)	 	{ 		cout<<"设置网卡为混杂模式时出错!错误码:"<<WSAGetLastError()<<endl; 		closesocket(sRaw); 		WSACleanup(); 		return -1; 	} 	// 开始抓取IP分组 	char buff[50][4096]; 	int packetNumber; 	cout<<"请输入要抓取的分组数量(不超过50):"<<endl; 	cin>>packetNumber; 	cout<<"正在等待抓取IP数据包..."; 	int i, nRet; 	for(i=0;i<packetNumber;i++) 	{ 		if(i>=50)break; 		nRet = recv(sRaw, buff[i], 4096, 0); 		cout<<"#"; 		if(nRet<=0) 		{ 			cout<<"抓取数据时出错!错误码:"<<WSAGetLastError()<<endl; 			break; 		} 	} 	//解析IP包 	int j=0; 	for(j=0;j<i;j++) 	{ 		cout<<endl<<j<<"-------------------------------"<<endl; 		DecodeIPPacket(buff[j]);//解析IP包 	} 	closesocket(sRaw); 	WSACleanup(); 	return 0; } /**********IP分组解析函数*************/ void DecodeIPPacket(char *pData) { 	IPHeader *pIPHdr = (IPHeader*)pData;	 	in_addr source, dest; 	char szSourceIp[32], szDestIp[32];  	/***从IP头中取出源IP地址和目的IP地址***/  	source.S_un.S_addr = pIPHdr->ipSource; 	dest.S_un.S_addr = pIPHdr->ipDestination; 	strcpy(szSourceIp, inet_ntoa(source)); 	strcpy(szDestIp, inet_ntoa(dest)); 	cout<<"Source IP:"<< szSourceIp; 	cout<<" Destionation IP: "<< szDestIp<<endl; 	int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);// IP头长度 	switch(pIPHdr->ipProtocol) 	{ 	case IPPROTO_TCP: // 调用函数解析TCP包 		DecodeTCPPacket(pData + nHeaderLen); 		break; 	case IPPROTO_UDP:// 调用函数解析UDP包 		DecodeUDPPacket(pData + nHeaderLen); 		break;  	case IPPROTO_ICMP:// 调用函数解析ICMP包 		DecodeICMPPacket(pData + nHeaderLen); 		break;   	default: 		cout<<" 协议号:"<<(int)pIPHdr->ipProtocol<<endl; 	} } /*********TCP包解析函数***********/  void DecodeTCPPacket(char *pData) { 	TCPHeader *pTCPHdr = (TCPHeader *)pData; 	cout<<"TCP Source Port: "<<ntohs(pTCPHdr->sourcePort); 	cout<<"  Destination Port: "<< ntohs(pTCPHdr->destinationPort)<<endl;	 } /***********UDP包解析函数**********/  void DecodeUDPPacket(char *pData) { 	UDPHeader *pUDPHdr = (UDPHeader *)pData; 	cout<<"UDP Source Port: "<< ntohs(pUDPHdr->sourcePort);  	cout<< "  Destination Port: "<< ntohs(pUDPHdr->destinationPort)<<endl;	 } /***********ICMP包解析函数 **********/ void DecodeICMPPacket(char *pData) { 	ICMPHeader *pICMPHdr = (ICMPHeader *)pData; 	cout<<"ICMP Type: "<< pICMPHdr->i_type <<"Code: "<<pICMPHdr->i_code<<endl; 	switch(pICMPHdr->i_type) 	{ 		case 0: 			cout<<"Echo Response.\n" ; break; 		case 8: 			cout<<"Echo Request.\n"; break; 		case 3: 			cout<<"Destination Unreachable.\n"; break; 		case 11: 			cout<<"Datagram Timeout(TTL=0).\n"; break; 	} } 
WinSock 原始套接字编程
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!