一个简单的嗅探器

#include <cstdio>
#include <iostream>

#include <cstring>
#include <winsock2.h>
#include <mstcpip.h>
#include <Windows.h>
using namespace std;
#define STATUS_FAILED 0xFFFF //异常出错代码
#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
#define CMD_PARAM_HELP true
#pragma comment (lib,"Ws2_32.lib")
typedef struct _iphead
{
  unsigned char headLenIpVersion;
  unsigned char serviceType;
  unsigned short totalLength;
  unsigned short ident;
  unsigned short frag_and_flags;
  unsigned char ttl;
  unsigned char protocal;
  unsigned short checksum;
  unsigned int   sourceIp;
  unsigned int   destIp;
}IPHEAD,*pIPHEAD;
typedef struct _tcphead
{
	USHORT sourcePort;
	USHORT destPort;
	UINT    seqNum;
	UINT    ackNum;
	UCHAR  headLen_reserve;
	UCHAR  reserve_flag;
	USHORT winLen;
	USHORT checkSum;
	USHORT mergencyPointer;
}TCPHEAD,pTCPHEAD;
typedef struct _udphead
{
   USHORT sourcePort;
   USHORT destPort;
   USHORT totalLen;
   USHORT checkSum;
}UDPHEAD,pUDPHEAD;
typedef struct _icmp
{
   BYTE   type;
   BYTE   code;
   USHORT checkSum;
   USHORT id;
   USHORT seq;
   ULONG  timeStamp;

}ICMPHEAD,pICMPHEAD;
typedef struct _ProtoMap
{
  int num;
  char protoname[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 ParamTcp=false; //关注TCP
bool ParamUdp=false;//关注UDP
bool ParamIcmp=false;//关注ICMP
bool ParamDecode=true;
char *strFromIpFilter=NULL;
char *strDestIpFilter=NULL;

int DecodeIpPack(char *,int );
int DecodeTcpPack(char *);
int DecodeUdpPack(char *);
int DecodeIcmpPack(char *);
void CheckSockError(int,char * );
char * CheckProtocol(int);
void usage(void);
bool GetCmdLine(int,char **);

int main(int argc,char **argv)
{
 

	printf("%d %s %s %s %s\n",argc,argv[0],argv[1],argv[2],argv[3]);
 int iErrorCode;
 char RecvBuf[MAX_PACK_LEN]={0};
 usage();
 if(GetCmdLine(argc,argv)==CMD_PARAM_HELP)
	 exit(0);
 
 WSADATA wsaData;


 iErrorCode=WSAStartup(MAKEWORD(2,2),&wsaData);
 
 CheckSockError(iErrorCode,"WSAStartup");
 SockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
 CheckSockError(SockRaw,"socket");
 //Get the ip address of my host
 char FAR name[MAX_HOSTNAME_LEN];
 iErrorCode=gethostname(name,MAX_HOSTNAME_LEN);
 CheckSockError(iErrorCode,"gethostname");
 struct hostent FAR *pHostent;
 pHostent=(struct hostent *)malloc(sizeof(struct hostent));
 pHostent=(struct hostent *)gethostbyname(name);


 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,(SOCKADDR *)&sa,sizeof(SOCKADDR_IN));
 CheckSockError(iErrorCode,"bind");

 DWORD dwBufferLen[10];
 DWORD dwBufferInLen=1;
 DWORD dwBufferReturned=0;
 iErrorCode=WSAIoctl(
	 SockRaw,
	 SIO_RCVALL,
	 &dwBufferInLen,
	 sizeof(dwBufferInLen),
	 &dwBufferLen,
	 sizeof(dwBufferLen),
	 &dwBufferReturned,
	 NULL,
	 NULL
     );
 printf("%d",WSAGetLastError());
 if(WSAGetLastError()==WSAEINVAL)
	 cout<<"参数不合法"<<endl;
 CheckSockError(iErrorCode,"WSAloctl");
 while(1)
 {
	 memset(RecvBuf,0,sizeof(RecvBuf));
	 iErrorCode=recv(SockRaw,RecvBuf,sizeof(RecvBuf),0);
	 CheckSockError(iErrorCode,"recv");
	 iErrorCode=DecodeIpPack(RecvBuf,iErrorCode);
	 CheckSockError(iErrorCode,"DecodeIpPack");
 }
     return 0;
}
char *CheckProtocal(int iProtocal)
{
  int i=0;
  for(;i<MAX_PROTO_NUM;i++)
  {
	  if(protoMap[i].num==iProtocal)
		  return protoMap[i].protoname;
	  
  }
  return "";

}
int DecodeIpPack(char *buf,int iBufSize)
{
	IPHEAD *pIpHead;
	int iProtocal,iTTL;
	char szProtocal[MAX_PROTO_TEXT_LEN];
	char szSourceIp[MAX_ADDR_LEN],szDestIp[MAX_ADDR_LEN];
	SOCKADDR_IN source,dest;
	pIpHead=(IPHEAD *)buf;
	//协议识别程序,如果程序中没有指定ip协议中的几个上层协议,则退出
	iProtocal=pIpHead->protocal;
	strncpy(szProtocal,CheckProtocal(iProtocal),MAX_PROTO_TEXT_LEN);
	if(iProtocal==IPPROTO_TCP&&!ParamTcp)
		return true;
    if(iProtocal==IPPROTO_UDP&&!ParamUdp)
		return true;
	if(iProtocal==IPPROTO_ICMP&&!ParamIcmp)
		return true;
	
	source.sin_addr.S_un.S_addr=pIpHead->sourceIp;
	strncpy(szSourceIp,inet_ntoa(source.sin_addr),MAX_ADDR_LEN);
	if(strFromIpFilter)
	if(strcmp(szSourceIp,strFromIpFilter))
		return true;

	dest.sin_addr.S_un.S_addr=pIpHead->destIp;
	strncpy(szDestIp,inet_ntoa(dest.sin_addr),MAX_ADDR_LEN);
	if(strDestIpFilter)
	if(strcmp(szDestIp,strDestIpFilter))
		return true;

	iTTL=pIpHead->ttl;
	printf("%s:",szProtocal);
	printf("%s-->%s\n",szSourceIp,szDestIp);
	printf(" BYTES is %d,TTL is %d\n",iBufSize,iTTL);

	//计算IP数据包头部长度 
	int iIpHeadLen=sizeof(ULONG)*(pIpHead->headLenIpVersion&0x0F);
    //解码上层协议信息
	switch (iProtocal)
	{
	case IPPROTO_TCP:

		DecodeTcpPack(buf+iIpHeadLen);  
         break;
	case  IPPROTO_UDP:
		DecodeUdpPack(buf+iIpHeadLen);
		  break;
	case  IPPROTO_ICMP:
		DecodeIcmpPack(buf+iIpHeadLen);
	     break;
	default:
	   	break;
	}
	return true;
}
int DecodeTcpPack( char *TcpPack )
{
	TCPHEAD *pTcpHead;
	pTcpHead=(TCPHEAD *)TcpPack;
	printf(" tcp port %d-->tcp port %d\n",ntohs(pTcpHead->sourcePort),ntohs(pTcpHead->destPort));
	UCHAR mask=1;
	for(int i=0;i<6;i++)
	{
		if(pTcpHead->reserve_flag&mask)
			printf("%c",tcpFlag[i]);
		else
			printf("-");
		mask=mask<<1;
	}
	printf("\n");
	return true;
}
int DecodeUdpPack( char *UdpPack )
{
	UDPHEAD *pUdpHead;
	pUdpHead=(UDPHEAD *)UdpPack;
	printf("udp port %d--> udp port %d\n",ntohs(pUdpHead->sourcePort),ntohs(pUdpHead->destPort));
	printf(" Udp len -->%d\n",ntohs( pUdpHead->totalLen ));
	printf("\n");
	return true;
}
int DecodeIcmpPack(char *IcmpPack)
{
    ICMPHEAD *pIcmpHead;
	pIcmpHead=(ICMPHEAD *)IcmpPack;
	printf("Type %d %d",pIcmpHead->type,pIcmpHead->code);
	printf("ID = %d, SEQ=%d\n",pIcmpHead->id,pIcmpHead->seq);
	return true;
}

void CheckSockError(int iErrorCode,char *pErrorMsg)
{
	if(iErrorCode==SOCKET_ERROR)
	{
		printf("%s Error: %s",pErrorMsg,GetLastError());
		closesocket(SockRaw);
	exit(0);
	}
	
}

bool GetCmdLine(int argc,char **argv)
{
   cout<<"参数有四个"<<endl;
  
	if(argc<2)
		return CMD_PARAM_HELP;
	for(int i=1;i<argc;i++)
	{
	  if(argv[i][0]!='/')
		  return CMD_PARAM_HELP;
	  else
	      switch(argv[i][1])
	      {
		  case 't':
		  case 'T': ParamTcp=true; break;
		  case 'u':
		  case 'U': ParamUdp=true; break;
		  case 'i': 
		  case 'I': ParamIcmp=true;  break;
		  case 'p':
		  case 'P': ParamDecode=true; break;
		  case 'f':
		  case 'F': 
		  {
			  strFromIpFilter=(char *)malloc(sizeof(char)); 
			  memset(strFromIpFilter,0,sizeof(char)*16);
			  strcpy(strFromIpFilter,argv[i]+3);
              break;
		  }
		  case 'd':
		  case 'D': 
		  {
			  strFromIpFilter=(char *)malloc(sizeof(char)); 
			  memset(strFromIpFilter,0,sizeof(char)*16);
			  strcpy(strFromIpFilter,argv[i]+3);
			  break;
		  }
       }
	      
	}
	cout<<"\nNow I Will Sniff"<<endl;
	if(ParamTcp)
		cout<<"TCP"<<endl;
	if(ParamUdp)
		cout<<"UDP"<<endl;
	if(ParamIcmp)
		cout<<"ICMP"<<endl;
	if(strFromIpFilter)
		cout<<"From Ip:%s"<<strFromIpFilter<<endl;
	if(strDestIpFilter)
		cout<<"Dest Ip:%s"<<strDestIpFilter<<endl; 
	return false;
}

void usage()
{
  cout<<"sniffer program!"<<endl;
  cout<<"/t output tcp pakets!"<<endl;
   cout<<"/u output udp pakets!"<<endl;
    cout<<"/i output icmp pakets!"<<endl;
	 cout<<"/p Decode pakets!"<<endl;
	  cout<<"/f output packet from IP"<<endl;
       cout<<"/d output packet dest IP"<<endl;
	  
	

}






经验1   如果编译后很多错误,一般是windows.h位置不对,要放入头文件包含的最后面

经验2  注意参数····socket函数的三个参数··不要写成SOCK_STREAM

—————————————————————— Hearen's SimpleSniffer —————————————————————— 一、功能简介: .针对同一局域网中的所有主机进行监听并返回处理优化后的数据供研究使用; .在数据表中显示了所有当前侦听到的数据包包括源IP、源端口、目的IP、目的端口、数据包协议类型、数据包捕获时间及数据包简略信息(仅应用层数据); .可以针对某一特定IP地址(源或目的),某特定端口(源或目的)以及特定类型数据包进行侦听 -- 捕获前过滤; .当数据过多时可以随时点击‘清理’对当前的数据表进行清空 -- 不过捕获的数据是不会被清除的,仅清除列表中显示的数据; .双击‘清理’时清空所有嗅探到的数据 -- 不仅仅是列表中显示的数据; .选择列表中的数据时,数据详细信息会显示在下方的面板中; 此时可以通过选择特定字符串来查看在其左侧的十六进制表示以供研究之用; .左下角会显示当前在该局域网中捕获到的数据包个数及总大小(该大小包含IP协议及其建立在该协议以上协议的头部)-- 数据单位会自动进行切换当数据大小达到2G时将重置清零; .在获取数据包后可以针对某一IP,PORT,IP:PORT或IP/PORT及协议进行筛选,同时可以查阅当前所有捕获的数据包(如果没有设置捕获前过滤,否则只能查阅过滤后的数据)。 二、使用说明:本应用的使用环境为Windows 7、Windows 8及Windows 8.1。 在使用过程中需要获得管理员权限 - 捕获数据包需要访问底层数据,需要获得最高权限才可以正常运行该应用; 三、作者留言 该应用的开发环境为VS2013,所用语言为C#,界面设计属于WinForm(比较老式的界面风格,推荐使用WPF)。因本人水平有限,在该应用中不免存在很多漏洞和不足;如果你有更多更好的想法或者发现该小应用中的bug还望批评指正。
一、功能简介: 1.针对同一局域网中的所有主机进行监听并返回处理优化后的数据供用户研究使用; 2.在数据表中显示了所有当前侦听到的数据包包括源IP、源端口、目的IP、目的端口、数据包协议类型、数据包捕获时间及数据包简略信息(仅应用层数据); 3.可以对某种特定类型协议的数据进行针对性监听; 4.可以针对某一特定源IP地址进行侦听; 5.当数据过多时可以随时点击‘清理’对当前的数据表进行清空 - 不过捕获的数据是不会被清除的,仅清除列表中的数据; 6.在数据显示区域可以通过选择特定字符串以此查看在其左侧的十六进制表示以供研究之用; 7.在应用左下角显示当前应用在该局域网中捕获到的数据包个数及总大小(该大小包含IP协议及其建立在该协议以上协议的头部)- 当数据大小达到2G时将重置清零; 8.在获取数据包后可以针对某一IP或IP:PORT或IP/PORT及协议进行筛选,同时可以查阅当前所有的捕获的数据包(如果没有设置捕获前过滤,否则只能查阅过滤后的数据)。 二、安装环境说明:本应用的安装环境为Windows 7、Windows 8及Windows 8.1。 三、安装过程说明 1.在安装过程中需要获得管理员权限 - 捕获数据包需要访问底层数据,需要获得最高权限才可以正常运行该应用; 2.在安装结束时,用户可以选择此时启动应用还是结束安装流程;当选择此时启动时系统会再次提醒用户允许应用获取管理员权限-原因同上。 四、作者留言 该应用的开发环境为VS2013,所用语言为C#,界面设计属于WinForm(比较老式的界面风格,推荐使用WPF),在后期程序发布打包使用的是InstallShield Limited Edition(如果需要长期打包窗体应用发布最好购买正版,可以获得更多个性化的功能)。因本人水平有限,在该应用中不免存在很多漏洞和不足;如果你有更多更好的想法或者发现该小应用中的bug还望批评指正。 ||联系方式:LHearen@gmail.com|| 五、免责声明 本系统仅用于学习交流之用,本人不承担该应用的技术及版权问题,且不对该应用负法律责任。
—————————————————————— Hearen's SimpleSniffer —————————————————————— 一、功能简介: 1.针对同一局域网中的所有主机进行监听并返回处理优化后的数据供研究使用; 2.在数据表中显示了所有当前侦听到的数据包包括源IP、源端口、目的IP、目的端口、数据包协议类型、数据包捕获时间及数据包简略信息(仅应用层数据); 3.可以针对某一特定IP地址(源或目的),某特定端口(源或目的)以及特定类型数据包进行侦听 -- 捕获前过滤; 4.当数据过多时可以随时点击‘清理’对当前的数据表进行清空 -- 不过捕获的数据是不会被清除的,仅清除列表中显示的数据; 5.双击‘清理’时清空所有嗅探到的数据 -- 不仅仅是列表中显示的数据; 6.选择列表中的数据时,数据详细信息会显示在下方的面板中; 此时可以通过选择特定字符串来查看在其左侧的十六进制表示以供研究之用; 7.左下角会显示当前在该局域网中捕获到的数据包个数及总大小(该大小包含IP协议及其建立在该协议以上协议的头部)-- 数据单位会自动进行切换当数据大小达到2G时将重置清零; 8.在获取数据包后可以针对某一IP,PORT,IP:PORT或IP/PORT及协议进行筛选,同时可以查阅当前所有捕获的数据包(如果没有设置捕获前过滤,否则只能查阅过滤后的数据)。 二、使用说明:本应用的使用环境为Windows 7、Windows 8及Windows 8.1。 在使用过程中需要获得管理员权限 - 捕获数据包需要访问底层数据,需要获得最高权限才可以正常运行该应用; 三、作者留言 该应用的开发环境为VS2013,所用语言为C#,界面设计属于WinForm(比较老式的界面风格,推荐使用WPF)。因本人水平有限,在该应用中不免存在很多漏洞和不足;如果你有更多更好的想法或者发现该小应用中的bug还望批评指正。 ||联系方式:LHearen@126.com|| 四、免责声明 本系统仅用于学习交流之用,本人不承担该应用的技术及版权问题,且不对该应用负法律责任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值