?? winpcapsniffer.cpp
字號:
#include <stdio.h>
#include "pcap.h"
#pragma comment(lib,"ws2_32.lib")
#define MAX_PROTO_TEXT_LEN 16 // 子協(xié)議名稱最大長度
#define MAX_PROTO_NUM 12 // 子協(xié)議數(shù)量
// 定義IP地址結構
typedef struct ip_address
{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
// 定義IP首部格式
typedef struct ip_header
{
u_char ver_ihl; // 版本和首部長度
u_char tos; // 服務類型
u_short tlen; // 總長度
u_short identification; // 標識號
u_short flags_fo; // 段偏移量
u_char ttl; // 生存時間
u_char proto; // 協(xié)議
u_short crc; // 首部校驗和
ip_address saddr; // 源IP地址
ip_address daddr; // 目的地址
u_int op_pad; // 選項和填補位
}ip_header;
// 定義TCP首部格式
typedef struct tcp_header
{
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; // 緊急指針
}tcp_header;
// 定義UDP首部格式
typedef struct udp_header
{
u_short sport; // 16位源端口
u_short dport; // 16位目的端口
u_short len; // 16位長度
u_short crc; // 16位校驗和
}udp_header;
// 定義ICMP首部格式
typedef struct icmp_header
{
BYTE i_type; // 8位類型
BYTE i_code; // 8位代碼
unsigned short i_cksum; // 16位校驗和
unsigned short i_id; // 識別號
unsigned short i_seq; // 報文序列號
unsigned long timestamp; // 時間戳
}icmp_header;
// 定義子協(xié)議映射表
typedef struct _protomap
{
int ProtoNum;
char ProtoText[MAX_PROTO_TEXT_LEN];
}PROTOMAP;
// 為子協(xié)議映射表賦值
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,""}
};
char TcpFlag[6]={'F','S','R','P','A','U'}; // TCP標志位
// 將一個unsigned long 型的IP轉換為字符串類型的IP
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;
p = (u_char *)∈
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
// 格式化字符串
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}
// 輸出網(wǎng)卡信息
void ifprint(pcap_if_t *d, int num)
{
pcap_addr_t *a;
printf("\n\n************網(wǎng)卡%d信息************\n",num);
// 輸出網(wǎng)卡名稱
printf("網(wǎng)卡名 : %s \n",d->name);
// 網(wǎng)卡描述信息
if (d->description)
{
printf("網(wǎng)卡描述: %s \n",d->description);
}
// 反饋
printf("反饋 : %s \n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
// IP地址
for(a=d->addresses;a;a=a->next)
{
switch(a->addr->sa_family)
{
case AF_INET:
printf("IP地址類型: AF_INET\n");//打印網(wǎng)絡地址類型
if (a->addr)//打印IP地址
printf("IP地址 : %s\n",
iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)//打印掩碼
printf("掩碼 : %s\n",
iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)//打印廣播地址
printf("廣播地址: %s\n",
iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)//目的地址
printf("Destination Address: %s\n",
iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;
default:
printf("Address Family Name: Unknown\n");
break;
}
}
}
// 協(xié)議識別函數(shù)
char *check_protocol(int iProtocol)
{
for(int i=0; i<MAX_PROTO_NUM;i++)
{
// 如果找到對應的子協(xié)議,則返回名稱
if(ProtoMap[i].ProtoNum == iProtocol)
{
return ProtoMap[i].ProtoText;
}
}
return "";
}
// TCP解包函數(shù)
int decode_tcp(char *tcpbuf)
{
tcp_header *ptcpheader;
int i;
// 轉換成TCP首部格式
ptcpheader = (tcp_header*)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;
}
return true;
}
// UDP 解包函數(shù)
int decode_udp(char *udpbuf)
{
udp_header *pudpheader;
pudpheader = (udp_header *)udpbuf;
// 輸出端口和數(shù)據(jù)長度
printf(" Port : %d-->%d",ntohs(pudpheader->sport),ntohs(pudpheader->dport));
return true;
}
// ICMP 解包函數(shù)
int decode_icmp(char *icmpbuf)
{
icmp_header *picmpheader;
picmpheader = (icmp_header *)icmpbuf;
// 輸出ICMP數(shù)據(jù)包類型、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;
}
// IP解包函數(shù)
int decode_ip(char *ipbuf, int protocol)
{
switch(protocol)
{
case IPPROTO_TCP: // TCP類型數(shù)據(jù)包
decode_tcp(ipbuf);
break;
case IPPROTO_UDP: // UDP類型數(shù)據(jù)包
decode_udp(ipbuf);
break;
case IPPROTO_ICMP: // ICMP類型數(shù)據(jù)包
decode_icmp(ipbuf);
break;
default:
break;
}
return true;
}
// 包處理回調(diào)函數(shù),對于每個嗅探到的數(shù)據(jù)包
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
ip_header *ih;
u_int ip_len;
// 返回IP首部的位置
ih = (ip_header *) (pkt_data +
14); //以太網(wǎng)的首部長度是14
// IP首部長度
ip_len = (ih->ver_ihl & 0xf) * 4;
printf("%s ",check_protocol(ih->proto));
// 輸出源地址IP和目的地址IP
printf("%d.%d.%d.%d -> %d.%d.%d.%d ",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4
);
decode_ip((char*)(pkt_data+14+ip_len),ih->proto);
printf("\n");
}
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int netmask;
char packet_filter[20];
struct bpf_program fcode;
// 獲取網(wǎng)卡列表
if(pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"pcap_findalldevs發(fā)生錯誤: %s\n", errbuf);
exit(1);
}
// 輸出網(wǎng)卡信息
for(i=0,d=alldevs; d; d=d->next,i++)
{
ifprint(d,i+1);
}
if(i==0)
{
printf("\n沒有找到任何網(wǎng)卡,請確認Winpcap已經(jīng)安裝.\n");
return -1;
}
printf("\n\n請輸入網(wǎng)卡編號 (1-%d):",i);
scanf("%d", &inum);
// 檢測用戶是否指定了有效網(wǎng)卡
if(inum < 1 || inum > i)
{
printf("\n網(wǎng)卡編號超出范圍.\n");
// 釋放設備列表
pcap_freealldevs(alldevs);
return -1;
}
// 跳轉到選擇的網(wǎng)卡
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
// 打開網(wǎng)卡設備
if ((adhandle= pcap_open_live(d->name, // 設備名稱
65536, // 捕獲全部的數(shù)據(jù)包
1, // 設置網(wǎng)卡為混雜模式
1000, // 讀超時為1秒
errbuf // 錯誤緩存
)) == NULL)
{
fprintf(stderr,"\n不能打開網(wǎng)卡. %s 不被Winpcap支持\n");
// 釋放設備列表
pcap_freealldevs(alldevs);
return -1;
}
// 檢測鏈接層,只支持以太網(wǎng)模式
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\n此程序只能運行在以太網(wǎng)上.\n");
// 釋放設備列表
pcap_freealldevs(alldevs);
return -1;
}
if(d->addresses != NULL)
{ // 返回接口的第一個地址的掩碼
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
}
else
{ // 如果沒有掩碼,則默認設置為C類
netmask=0xffffff;
}
// 選擇過濾包類型
int protocol_type; // 0->ip 1->tcp 2->udp 3->icmp
printf("\n請選擇監(jiān)聽的數(shù)據(jù)包協(xié)議類型(0->ip 1->tcp 2->udp 3->icmp) : ");
scanf("%d",&protocol_type);
switch(protocol_type)
{
case 0:
strcpy(packet_filter,"ip");
break;
case 1:
strcpy(packet_filter,"ip and tcp");
break;
case 2:
strcpy(packet_filter,"ip and udp");
break;
case 3:
strcpy(packet_filter,"ip and icmp");
break;
default:
break;
}
// 編譯過濾器
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\n不能編譯過濾器. 請檢測語法.\n");
// 釋放設備列表
pcap_freealldevs(alldevs);
return -1;
}
//設置過濾器
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr,"\n設置過濾器出錯.\n");
pcap_freealldevs(alldevs);
return -1;
}
printf("\n在網(wǎng)卡 %s 開始監(jiān)聽...\n", d->description);
// 不再需要任何設備列表,進行釋放
pcap_freealldevs(alldevs);
// 開始嗅探
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -