目录:
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 原始套接字编程
参考文献[1]Windows网络编程基础教程
[2]链接:https://pan.baidu.com/s/1cB_fLBX9HbTIiF4InddxCA 密码:kdi7