?? rawsocketsniffer.cpp
字號:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#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 paramkeyword = 0; // 是否進行關鍵字查詢
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 Error : %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(" Port : %d-->%d ",ntohs(pTcpHeader->th_sport),ntohs(pTcpHeader->th_dport));
unsigned char FlagMask = 1;
// 輸出標志位
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);
// 進行關鍵字尋求和輸出
if(paramkeyword == 1)
{
// 如果找到關鍵字,則輸出數據段
if(strstr(data,keyword))
{
printf("\n************************DATA******************************\n");
for(i =0 ;i<packet_totallen-totalheadlen;i++)
{
printf("%c",data[i]);
}
printf("\n************************DATA******************************\n");
}
}
return true;
}
// UDP 解包函數
int DecodeUdpPack(char *UdpBuf)
{
UDPHEADER *pUdpHeader;
char data[MAX_PACK_LEN];
pUdpHeader = (UDPHEADER *)UdpBuf;
// 輸出端口和數據長度
printf(" Port : %d-->%d ",ntohs(pUdpHeader->uh_sport),ntohs(pUdpHeader->uh_dport));
printf(" Len = %d\n",ntohs(pUdpHeader->uh_len));
int totalheadlen = sizeof(IPHEADER)+sizeof(UDPHEADER);
int udpheadlen = sizeof(UDPHEADER);
memcpy(data,UdpBuf+udpheadlen,packet_totallen-totalheadlen);
// 進行關鍵字尋求和輸出
if(paramkeyword == 1)
{
// 如果找到關鍵字,則輸出數據段
if(strstr(data,keyword))
{
printf("\n************************DATA******************************\n");
for(int i =0 ;i<packet_totallen-totalheadlen;i++)
{
printf("%c",data[i]);
}
printf("\n************************DATA******************************\n");
}
}
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%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%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%s ",szProtocol);
printf("%s-->%s",szSoueceIP,szDestIP);
ShowSubPackInfo(buf,iProtocol);
}
}
// 如果主機A和B的IP都沒有進行設置
else
{
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)
{
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("請選擇要嗅探的數據包類型 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("輸入錯誤!!!\n");
check_input = false;
break;
}
}
printf("\n請輸入嗅探的主機A的IP地址(輸入all即為全部主機):");
scanf("%s",paramHostAddr_A);
printf("\n請輸入嗅探的主機B的IP地址(輸入all即為全部主機):");
scanf("%s",paramHostAddr_B);
printf("\n是否進行關鍵字搜索? 0->否 1->是 : ");
scanf("%d",¶mkeyword);
if( paramkeyword == 1)
{
printf("\n請輸入關鍵字:");
scanf("%s",keyword);
}
return true;
}
void main(int argc, char **argv)
{
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");
struct hostent FAR *pHostent;
pHostent = (struct hostent *)malloc(sizeof(struct hostent));
pHostent = gethostbyname(name);
// 設置地址結構,端口為本地的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報文
while(1)
{
// 每次將接收緩沖區清零
memset(RecvBuf, 0, sizeof(RecvBuf));
// 開始接收緩沖區的數據
iErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf),0);
CheckSockError(iErrorCode, "recv");
// 對接收到的數據包進行解析
iErrorCode = DecodeIpPack(RecvBuf);
CheckSockError(iErrorCode, "Decode");
Sleep(10);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -