#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("\n");
// 求数据段长度
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\n",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\n",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(" -------------------------------------------------------------------------------\n");
printf("| 协议| 源IP地址 | 目的IP地址 | ");
printf("------------------------------------------------------------------------------\n");
printf("\n| %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(" -------------------------------------------------------------------------------\n");
printf("| 协议| 源IP地址 | 目的IP地址 |\n ");
printf("------------------------------------------------------------------------------");
printf("\n| %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(" -------------------------------------------------------------------------------\n");
printf("| 协议| 源IP地址 | 目的IP地址 |\n ");
printf("------------------------------------------------------------------------------");
printf("\n| %s | ",szProtocol);
printf(" %s | %s |",szSoueceIP,szDestIP);
ShowSubPackInfo(buf,iProtocol);
}
}
// 如果主机A和B的IP都没有进行设置
else
{
printf(" -------------------------------------------------------------------------------\n");
printf("| 协议| 源IP地址 | 目的IP地址 |\n ");
printf("------------------------------------------------------------------------------");
printf("\n| %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("*************************基于原始套接字的网络嗅探器*****************************\n\n");
printf(" 学号:3109005953 姓名:卫海鹏 专业班级:2009级计算机科学与技术(2)班 \n\n");
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唉,输入错误!!!\n");
check_input = false;
break;
}
}
printf("\n==>>请输入嗅探的主机A的IP地址(输入all即为全部主机):");
scanf("%s",paramHostAddr_A);
printf("\n==>>请输入嗅探的主机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\n",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("\n==>>请输入要嗅探数据包的个数:");
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;
} //等待输入一个字符(不回显)后继续输出.
}