目录:
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 原始套接字编程