嗅探器的实现 对协议的分析(转)

#include <stdio.h>
#include<conio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
using namespace std;
#pragma  comment (lib, "ws2_32.lib")
#define SIO_RCVALL      _WSAIOW(IOC_VENDOR,1)
#define MAX_PACK_LEN 65535 // 最大包长度
#define MAX_ADDR_LEN 16 // 最大地址长度
#define MAX_PROTO_TEXT_LEN 16 // 子协议名称最大长度
#define MAX_PROTO_NUM 12 // 子协议数量
#define MAX_HOSTNAME_LEN 255 // 最大主机名长度

// 定义IP首部格式
typedef struct _IPHeader      
{ 
    unsigned char h_verlen;    // 版本和首部长度  
    unsigned char tos;         // 服务类型       
    unsigned short total_len;  // 总长度 
    unsigned short ident;      // 标识号     
    unsigned short frag_and_flags;  // 段偏移量
    unsigned char ttl;         // 生存时间       
    unsigned char proto;       // 协议   
    unsigned short checksum;   // 首部校验和
    unsigned int sourceIP;     // 源IP地址  
    unsigned int destIP;       // 目的地址   
}IPHEADER;

// 定义TCP首部格式
typedef struct _TCPHeader 
{ 
    unsigned short th_sport;  // 源端口号        
    unsigned short th_dport;  // 目的端口号       
    unsigned int th_seq;  // SEQ序号    
    unsigned int th_ack;  // ACK序号
    unsigned char th_lenres;  //  首部长度    
    unsigned char th_flag;   // 控制位  
    unsigned short th_win;  // 窗口大小        
    unsigned short th_sum;  // 校验和        
    unsigned short th_urp;  // 紧急指针         
}TCPHEADER;

// 定义UDP首部格式
typedef struct _UDPHeader
{
	unsigned short uh_sport; // 16位源端口
	unsigned short uh_dport; // 16位目的端口
	unsigned short uh_len; // 16位长度
	unsigned short uh_sum; // 16位校验和
}UDPHEADER;

// 定义ICMP首部格式
typedef struct _ICMPHeader
{
	BYTE i_type; // 8位类型
	BYTE i_code; // 8位代码
	unsigned short i_cksum; // 16位校验和
	unsigned short i_id; // 识别号
	unsigned short i_seq; // 报文序列号
	unsigned long timestamp; // 时间戳
}ICMPHEADER;
//----------------------------------------------------------------------------------------------
// 定义子协议映射表
typedef struct _protomap 
{
	int ProtoNum;
	char ProtoText[MAX_PROTO_TEXT_LEN];
}PROTOMAP;

// 为子协议映射表赋值
PROTOMAP ProtoMap[MAX_PROTO_NUM]={
	{IPPROTO_IP,"IP"},
	{IPPROTO_ICMP,"ICMP"},
	{IPPROTO_IGMP,"IGMP"},
	{IPPROTO_GGP,"GGP"},
	{IPPROTO_TCP,"TCP"},
	{IPPROTO_PUP,"PUP"},
	{IPPROTO_UDP,"UDP"},
	{IPPROTO_IDP,"IDP"},
	{IPPROTO_ND,"ND"},
	{IPPROTO_RAW,"RAW"},
	{IPPROTO_MAX,"MAX"},
	{NULL,""}
};

SOCKET SockRaw; // 全局套接字
char TcpFlag[6]={'F','S','R','P','A','U'}; // TCP标志位
bool paramAll = false; // 嗅探所有的数据包
bool paramTcp = false; // 嗅探TCP数据包
bool paramUdp = false; // 嗅探UDP数据包
bool paramIcmp = false; // 嗅探ICMP数据包

int packet_totallen = 0; // 数据包总长度

char paramHostAddr_A[20]; // 嗅探的主机A
char paramHostAddr_B[20]; // 嗅探的主机B
char keyword[100]; // 嗅探的关键信息

// IP数据包解析函数
int DecodeIpPack(char *);
// TCP数据包解析函数
int DecodeTcpPack(char *);
// UDP数据包解析函数
int DecodeUdpPack(char *);
// ICMP数据包解析函数
int DecodeIcmpPack(char *);
// 显示数据包信息
void ShowPackInfo(char *buf, int iProtocol, char *szSoueceIP, char *szDestIP, char *szProtocol);
// 显示子协议数据包函数
void ShowSubPackInfo(char *, int);
// 错误检测函数
void CheckSockError(int, char*);
// 协议检测函数
char *CheckProtocol(int);
// 设置嗅探器参数函数
bool SetSnifferParam();
//-----------------------------------------------------------------------------------------------------
// SOCK错误处理函数
void CheckSockError(int iErrorCode, char *pErrorMsg)
{
	if(iErrorCode == SOCKET_ERROR)
	{
		printf("%s 出错了: %d",pErrorMsg,GetLastError());
		closesocket(SockRaw);
		exit(0);
	}
}
//------------------------------------------------------------------------------------------------------
// 协议识别函数
char *CheckProtocol(int iProtocol)
{
	for(int i=0; i<MAX_PROTO_NUM;i++)
	{
		// 如果找到对应的子协议,则返回名称
		if(ProtoMap[i].ProtoNum == iProtocol)
		{
			return ProtoMap[i].ProtoText;
		}
	}
	return "";
}
//---------------------------------------------------------------------------------------------------------
// TCP解包函数
int DecodeTcpPack(char *TcpBuf)
{
	TCPHEADER *pTcpHeader;
	char data[MAX_PACK_LEN];
	int i;
	// 转换成TCP首部格式
	pTcpHeader = (TCPHEADER*)TcpBuf;
	// 输出源端口和目的端口
	printf("  端口 : %d-->%d  ",ntohs(pTcpHeader->th_sport),ntohs(pTcpHeader->th_dport));
	unsigned char FlagMask = 1;
	// 输出标志位
	//printf("标志位:");
	for(i=0;i<6;i++)
	{
		if((pTcpHeader->th_flag) & FlagMask)
		{
			printf("标志位:%c",TcpFlag[i]);
		}
		else
		{
			printf("-");
		}
		FlagMask = FlagMask<<1;
	}
	printf("
");
    // 求数据段长度
	int totalheadlen = sizeof(IPHEADER)+sizeof(TCPHEADER);
	int tcpheadlen = sizeof(TCPHEADER);
	memcpy(data,TcpBuf+tcpheadlen,packet_totallen-totalheadlen);
	return true;
}
//-------------------------------------------------------------------------------------------------------------
// UDP 解包函数
int DecodeUdpPack(char *UdpBuf)
{
	UDPHEADER *pUdpHeader;
	char data[MAX_PACK_LEN];
	pUdpHeader = (UDPHEADER *)UdpBuf;
	// 输出端口和数据长度
	printf(" 端口号: %d-->%d ",ntohs(pUdpHeader->uh_sport),ntohs(pUdpHeader->uh_dport));
	printf(" 长度: %d
",ntohs(pUdpHeader->uh_len));
	int totalheadlen = sizeof(IPHEADER)+sizeof(UDPHEADER);
	int udpheadlen = sizeof(UDPHEADER);
	memcpy(data,UdpBuf+udpheadlen,packet_totallen-totalheadlen);
	return true;
}
//---------------------------------------------------------------------------------------------------------------------
// ICMP 解包函数
int DecodeIcmpPack(char *IcmpBuf)
{
	ICMPHEADER *pIcmpHeader;
	pIcmpHeader = (ICMPHEADER *)IcmpBuf;
	// 输出ICMP数据包类型、ID和SEQ
	printf("  Type : %d,%d",pIcmpHeader->i_type,pIcmpHeader->i_code);
	printf("  ID = %d SEQ = %d
",pIcmpHeader->i_id,pIcmpHeader->i_seq);
	return true;
}

//-----------------------------------------------------------------------------------------------------------------------
// 根据过滤条件显示数据包信息
void ShowPackInfo(char *buf, int iProtocol, char *szSoueceIP, char *szDestIP, char *szProtocol)
{
	// 如果设置了主机B的IP,没有设置主机A的IP
	if((!strcmp(paramHostAddr_A,"all")) && (strcmp(paramHostAddr_B,"all")))
	{
		if((!strcmp(paramHostAddr_B,szSoueceIP)) 
			|| (!strcmp(paramHostAddr_B,szDestIP)))
		{
		printf(" -------------------------------------------------------------------------------
");
		printf("| 协议|    源IP地址     |   目的IP地址   |  ");
		printf("------------------------------------------------------------------------------
");
		printf("
| %s | ",szProtocol);
		printf(" %s | %s  |",szSoueceIP,szDestIP);
			// 显示子协议数据包相关信息
			ShowSubPackInfo(buf,iProtocol);
		}
	}
	// 如果设置主机A的IP,没有设置主机B的IP
	else if((strcmp(paramHostAddr_A,"all")) && (!strcmp(paramHostAddr_B,"all")))
	{
		if((!strcmp(paramHostAddr_A,szSoueceIP)) 
			|| (!strcmp(paramHostAddr_A,szDestIP)))
		{
		printf(" -------------------------------------------------------------------------------
");
		printf("| 协议|    源IP地址     |   目的IP地址   |
  ");
		printf("------------------------------------------------------------------------------");
		printf("
| %s | ",szProtocol);
		printf(" %s | %s  |",szSoueceIP,szDestIP);
			ShowSubPackInfo(buf,iProtocol);
		}
	}
	// 如果主机A和B的IP都进行了设置
	else if((strcmp(paramHostAddr_A,"all")) && (strcmp(paramHostAddr_B,"all")))
	{
		if((!strcmp(paramHostAddr_A,szSoueceIP) 
			&& !strcmp(paramHostAddr_B,szDestIP))
			|| (!strcmp(paramHostAddr_B,szSoueceIP) 
			&& !strcmp(paramHostAddr_A,szDestIP)))
		{
			
		printf(" -------------------------------------------------------------------------------
");
		printf("| 协议|    源IP地址     |   目的IP地址   |
  ");
		printf("------------------------------------------------------------------------------");
		printf("
| %s | ",szProtocol);
		printf(" %s | %s  |",szSoueceIP,szDestIP);
			ShowSubPackInfo(buf,iProtocol);
		}
	}
	// 如果主机A和B的IP都没有进行设置
	else
	{
		printf(" -------------------------------------------------------------------------------
");
		printf("| 协议|    源IP地址     |   目的IP地址   |
  ");
		printf("------------------------------------------------------------------------------");
		printf("
| %s | ",szProtocol);
		printf(" %s | %s  |",szSoueceIP,szDestIP);
		ShowSubPackInfo(buf,iProtocol);
	}
}
//-----------------------------------------------------------------------------------------------------------------------

// 显示子协议数据包信息
void ShowSubPackInfo(char *buf, int iProtocol)
{
	switch(iProtocol)
	{
	case IPPROTO_TCP: // TCP数据包
		DecodeTcpPack(buf);
		break;
	case IPPROTO_UDP: // UDP数据包
		DecodeUdpPack(buf);
		break;
	case IPPROTO_ICMP: // ICMP数据包
		DecodeIcmpPack(buf);
		break;
	default:
		break;
	}
}
// IP 解包函数
int DecodeIpPack(char *buf)
{

	//cout<<"发送的buffer:"<<buf<<endl<<endl; 郁闷,这是个结构体,打印的时候都显示E
	IPHEADER *pIpHeader;
	int iProtocol;
	// 定义协议
	char szProtocol[MAX_PROTO_TEXT_LEN];
	char szSourceIP[MAX_ADDR_LEN];
	char szDestIP[MAX_ADDR_LEN];
	SOCKADDR_IN saSource,saDest;
	pIpHeader = (IPHEADER *)buf;
	// 检测协议是哪种类型
	iProtocol = pIpHeader->proto;
	strncpy(szProtocol,CheckProtocol(iProtocol),MAX_PROTO_TEXT_LEN);
	// 检测源地址
	saSource.sin_addr.s_addr = pIpHeader->sourceIP;
	strncpy(szSourceIP,inet_ntoa(saSource.sin_addr),MAX_ADDR_LEN);
	// 检测目的地址
	saDest.sin_addr.s_addr = pIpHeader->destIP;
	strncpy(szDestIP,inet_ntoa(saDest.sin_addr),MAX_ADDR_LEN);

	int iIpLen = sizeof(unsigned long)*(pIpHeader->h_verlen & 0xf);
	packet_totallen = ntohs(pIpHeader->total_len);

	// 下面显示过滤信息
	if(paramAll) // 显示所有协议类型数据包
	{
		ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);
	}
	// 显示TCP类型数据包
	else if(paramTcp && (iProtocol == IPPROTO_TCP))
	{ 
		ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);
	}
	// 显示UDP类型数据包
	else if(paramUdp && (iProtocol == IPPROTO_UDP))
	{
		ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);
	}
	// 显示ICMP类型数据包
	else if(paramIcmp && (iProtocol == IPPROTO_ICMP))
	{
		ShowPackInfo(buf+iIpLen,iProtocol,szSourceIP,szDestIP,szProtocol);
	}
	return true;
}
//------------------------------------------------------------------------------------------------------------
// 设置嗅探器参数
bool SetSnifferParam()
{
	int ret;
	bool check_input = false;
	while(!check_input)
	{
                printf("*************************基于原始套接字的网络嗅探器*****************************

");
				printf("   学号:3109005953   姓名:卫海鹏   专业班级:2009级计算机科学与技术(2)班 

");
                printf("==>>请选择要嗅探的数据包类型: 0. 全部  1. TCP  2. UDP  3. ICMP : ");
		scanf("%d",&ret);
		switch(ret)
		{
		case 0:
			paramAll = true;
			check_input = true;
			break;
		case 1:
			paramTcp = true;
			check_input = true;
			break;
		case 2:
			paramUdp = true;
			check_input = true;
			break;
		case 3:
			paramIcmp = true;
			check_input = true;
			break;
		default:
			printf("==>>o(︶︿︶)o唉,输入错误!!!
");
			check_input = false;
			break;
		}
	}

	printf("
==>>请输入嗅探的主机A的IP地址(输入all即为全部主机):");
	scanf("%s",paramHostAddr_A);
	printf("
==>>请输入嗅探的主机B的IP地址(输入all即为全部主机):");
    scanf("%s",paramHostAddr_B);
      
	return true;
}
//----------------------------------------------------------------------------------------------------------------------
void main(int argc, char **argv)
{
	int i,temp;
	int iErrorCode;
	char RecvBuf[MAX_PACK_LEN] = {0};
	SetSnifferParam();
	WSADATA wsaData;
	// 初始化Winsock库
	iErrorCode = WSAStartup(MAKEWORD(2,1),&wsaData);
	CheckSockError(iErrorCode, "WSAStartup");
	SockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
	CheckSockError(SockRaw, "socket");
	// 获取本机IP地址,并且判断Socket版本,建立原始套接字
	char FAR name[MAX_HOSTNAME_LEN];
	iErrorCode = gethostname(name, MAX_HOSTNAME_LEN);
	CheckSockError(iErrorCode, "gethostname");

	printf("%s
",name);

	struct hostent FAR *pHostent;
	pHostent = (struct hostent *)malloc(sizeof(struct hostent));

	pHostent = gethostbyname(name);
	
	cout<<"pHostent->h_name:"<<pHostent->h_name<<endl;
	cout<<"pHostent->h_aliases:"<<pHostent->h_aliases<<endl;
	cout<<"pHostent->h_addrtype:"<<pHostent->h_addrtype<<endl;
    cout<<"pHostent->h_length:"<<pHostent->h_length<<endl;
	cout<<"pHostent->h_addr_list:"<<pHostent->h_addr_list<<endl;
    



	// 设置地址结构,端口为本地的6000
	SOCKADDR_IN sa;
	sa.sin_family = AF_INET;
	sa.sin_port = htons(6000);

	memcpy(&sa.sin_addr.S_un.S_addr,pHostent->h_addr_list[0],pHostent->h_length);

	// 绑定地址结构
	iErrorCode = bind(SockRaw, (PSOCKADDR)&sa, sizeof(sa));
	CheckSockError(iErrorCode, "bind");
	// 设置套接字为SIO_RCVALL,以便接收所有的IP包
	DWORD dwBufferLen[10];
	DWORD dwBufferInLen = 1;
	DWORD dwBytesReturned = 0;

	//为什么要有下面这一行,还不是很清楚
	iErrorCode = WSAIoctl(SockRaw, SIO_RCVALL , &dwBufferInLen, sizeof(dwBufferInLen),
		&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL);

	CheckSockError(iErrorCode, "Ioctl");
	// 监听IP报文
   L1:  printf("
==>>请输入要嗅探数据包的个数:");
                scanf("%d",&temp);
                i=temp;

    	while(i)
	{

		// 每次将接收缓冲区清零
		memset(RecvBuf, 0, sizeof(RecvBuf));
		// 开始接收缓冲区的数据
		iErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf),0);
		CheckSockError(iErrorCode, "recv");
		// 对接收到的数据包进行解析
		iErrorCode = DecodeIpPack(RecvBuf);
		CheckSockError(iErrorCode, "Decode");
		Sleep(100);
		i--;
	}
     if(i % 10 == 0) {
	   system("pause");
       goto L1;
     } //等待输入一个字符(不回显)后继续输出.

}

  

原文地址:https://www.cnblogs.com/mynona/p/3485733.html