winpcap抓包示例原始碼

在南京看海發表於2016-07-06

最近測試了下winpcap抓包功能,將原始碼共享出來。

啟動程式格式:程式名  ip

程式啟動需要輸入一個引數,即期望抓包的網路卡的IP。

 

程式碼如下:

#include "pcap.h"
 
#ifndef WIN32
         #include <sys/socket.h>
         #include <netinet/in.h>
#else
         #include <winsock.h>
#endif
 
#define PKT_MAX_LEN 65535
#define PKT_TIMEOUT 1000
#define PKT_ETH_MODE false


#define  PA_ICMP 1 //控制資訊協議  
#define  PA_TCP 6 //傳輸控制協議  
#define  PA_EGP 8 //外部閘道器協議  
#define  PA_IGP 9 //內部閘道器協議  
#define  PA_UDP 17 //使用者資料包協議 


typedef struct ethhdr
{  
u_int8_t dhost[6]; //目的Mac地址   
u_int8_t shost[6]; //源Mac地址   
u_int16_t type;    //協議型別   
}ETH_HDR;


typedef struct ip_hdr   //IP頭
{  
  #if defined(WORDS_BIENDIAN)   
  u_int8_t   version:4,  
             header_length:4;  
  #else   
  u_int8_t   header_length:4,  
             version:4;  
  #endif   
  u_int8_t    tos;  
  u_int16_t   length;  
  u_int16_t   id;  
  u_int16_t   off;  
  u_int8_t    ttl;  
  u_int8_t    proto;  
  u_int16_t   checksum;  
  struct in_addr souce_addr;  
  struct in_addr dest_addr;  
}IP_HDR;


typedef struct udp_hdr
{
 unsigned short sport;
 unsigned short dport;
 unsigned short length;
 unsigned short checksum;
}UDP_HDR;


typedef struct tcp_hdr  //TCP頭
{
 unsigned short sport; //16位源埠 
 unsigned short dport; //16位目的埠 
 unsigned int seq; //32位序列號 
 unsigned int ack; //32位確認號 
 unsigned char lenres; //4位首部長度/6位保留字 
 unsigned char flag; //6位標誌位 
 unsigned short win; //16位視窗大小 
 unsigned short sum; //16位校驗和 
 unsigned short urp; //16位緊急資料偏移量
}TCP_HDR;


#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 *)&in;


         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];


}


/* 處理資料包的回撥函式*/
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{


IP_HDR* ip_head;
TCP_HDR * tcp_head;
UDP_HDR * udp_head;
struct tm *ltime;
time_t tCurTime;
 
ip_head = (IP_HDR*)(pkt_data + sizeof(ETH_HDR));


if ( ip_head->proto == PA_TCP )
{
   /* 轉換時間戳為可以閱讀的格式 */
tCurTime = header->ts.tv_sec;
ltime=localtime(&tCurTime);


ip_head->header_length;
tcp_head = (TCP_HDR *) ((u_char*)ip_head + ip_head->header_length); 
// printf("%s,%.6d len:%d\n", timestr, , header->len);
/*printf("TCP %u:%u:%u:%u %s:%d-->%s:%d\n",ltime->tm_hour,ltime->tm_min,ltime->tm_sec,header->ts.tv_usec/1000,
inet_ntoa(ip_head->souce_addr), ntohs(tcp_head->sport), inet_ntoa(ip_head->dest_addr), ntohs(tcp_head->dport));
*/
pcap_dump(dumpfile, header, pkt_data);


}
else if ( ip_head->proto == PA_UDP )
{
   /* 轉換時間戳為可以閱讀的格式 */
tCurTime = header->ts.tv_sec;
ltime=localtime(&tCurTime);


ip_head->header_length;
udp_head = (UDP_HDR *) ((u_char*)ip_head + ip_head->header_length); 
/*
printf("UDP %u:%u:%u:%u %s:%d-->%s:%d\n",ltime->tm_hour,ltime->tm_min,ltime->tm_sec,header->ts.tv_usec/1000,
inet_ntoa(ip_head->souce_addr), ntohs(udp_head->sport), inet_ntoa(ip_head->dest_addr), ntohs(udp_head->dport));
*/
pcap_dump(dumpfile, header, pkt_data);
   
}
}
 
/* Print all the available information on the given interface */
void ifprint(pcap_if_t *d)


{


pcap_addr_t *a;
 
/* 名稱 */
//printf("%s\n",d->name);
 
/* 描述 */
if (d->description)
printf("\tDescription: %s\n",d->description);
 
/* 迴環地址 */
//printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
 
/* IP 地址 */
for(a=d->addresses;a;a=a->next) 

{


//printf("\tAddress Family: #%d\n",a->addr->sa_family);
  
switch(a->addr->sa_family)

{
case AF_INET:


//printf("\tAddress Family Name: AF_INET\n");


if (a->addr)


/* Y- IP 地址 */
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));


if (a->netmask)
    
/* Y- 掩碼 */
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));

if (a->broadaddr)
   
/* Y- 廣播地址 */
//printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
   
if (a->dstaddr)


/* Y - 目標地址 */
//printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));


break;

default:
  
/* 未知 */
// printf("\tAddress Family Name: Unknown\n");


break;


}


}
 
printf("\n");


}


bool check_ip(pcap_if_t *d, const char* ip)
{
bool ret = false;
char szip[32];
pcap_addr_t *a;
 
/* 名稱 */
// printf("%s\n",d->name);
 
/* 描述 */
if (d->description)
//printf("\tDescription: %s\n",d->description);
 
/* 迴環地址 */
// printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
 
/* IP 地址 */
for(a=d->addresses;a;a=a->next) 
{
// printf("\tAddress Family: #%d\n",a->addr->sa_family);
  
 switch(a->addr->sa_family)
 {
 case AF_INET:


 // printf("\tAddress Family Name: AF_INET\n");


  if (a->addr)
/* Y- IP 地址 */
  {
strcpy(szip, iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
//printf("\tAddress: %s\n", szip);


if ( strcmp(szip, ip) == 0 )
ret = true;
  }


  if (a->netmask)
/* Y- 掩碼 */
//printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));


  if (a->broadaddr)
/* Y- 廣播地址 */
//printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));


  if (a->dstaddr)
/* Y - 目標地址 */
//printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));


  break;


 default:


  /* 未知 */
  //printf("\tAddress Family Name: Unknown\n");


  break;


 }


}


//printf("\n");


return ret;


}




int main(int argc, char **argv)


{
pcap_if_t *alldevs;


pcap_if_t *d;


int i=0;


pcap_t *adhandle;


char errbuf[PCAP_ERRBUF_SIZE];

pcap_dumper_t *dumpfile;

printf("\n\n\n");


if(argc != 2)
{
printf("\tStart params lost, and you need too params as local ip.\n");
printf("\tFor example:winPcap4BLJ 192.168.6.6\n");
getchar();
return 0;
}


/* 獲取裝置列表 */
if (pcap_findalldevs(&alldevs, errbuf) == -1)


{


fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);


exit(1);


}


/* 遍歷所有元素 */
for(d=alldevs;d;d=d->next)


{


ifprint(d);


}


/* 遍歷所有元素 */
for(d=alldevs;d;d=d->next)


{


//找到有這個ip的網路卡
if ( check_ip(d, *(argv+1)) )


break;


}


if(!d)
{
printf("\tThe device is not found(%s)!\n",*(argv+1));
getchar();
return 0;
}

/* 開啟裝置 */
if ( (adhandle= pcap_open_live(d->name, //裝置名
 PKT_MAX_LEN, // 捕捉完整的資料包
 PKT_ETH_MODE, // 混雜模式
 PKT_TIMEOUT, // 讀入超時
 errbuf // 錯誤緩衝
 ) ) == NULL)

{


 /* Y- 開啟失敗*/
 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");


 /* 釋放列表 */
 pcap_freealldevs(alldevs);


 return -1;


}


u_int netmask;
u_int net_ip;
char error_content[PCAP_ERRBUF_SIZE] = {0};
pcap_lookupnet(d->name,&net_ip,&netmask,error_content); //這個就是用函式獲得了網路地址和子網掩碼,其返回的資料都放在net_ip和net_mask中的了,




printf("\tnetmask: 0x%02x\n",netmask); //簡單的輸出


struct bpf_program fcode;
 
char packet_filter[] = "ip and tcp and not port ftp-data";
 


// complie the filter 
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)


{


 printf("\n\tUnable to compile the packet filter\n");
 // Free the devices list
 pcap_freealldevs(alldevs);


 return -1;


}
 
// set the filter 
if (pcap_setfilter(adhandle, &fcode) < 0)


{


 printf("\n\tError setting the filter.\n");


 // Free the devices list
 pcap_freealldevs(alldevs);


 return -1;


}
 
printf("\n\tlistening on %s...\n", d->description);

char path[MAX_PATH];
GetCurrentDirectory(MAX_PATH,path); // 檔案目錄儲存在path這個字元陣列中,


sprintf(path,"%s\\test.cap",path);


printf("\n\tWrite to file %s\n\t",path);


dumpfile = pcap_dump_open(adhandle, path);


if(dumpfile==NULL)
{
printf("\n\tError opening output file\n");
getchar();
return -1;
}


/* 我們已經不需要裝置列表了, 釋放它 */
pcap_freealldevs(alldevs);
 
/* 開始捕捉 */
pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);


pcap_close(adhandle);


getchar();
 
return 0;
}

相關文章