程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> c語言Winpcap編程構造並接收解析arp包,winpcaparp

c語言Winpcap編程構造並接收解析arp包,winpcaparp

編輯:關於C語言

c語言Winpcap編程構造並接收解析arp包,winpcaparp


/*

程序功能:

1、構造arp包,並發送。程序參數順序:源IP、目的IP、mac地址、flag

2、獲取網絡中的ARP數據包,解析數據包的內容。程序參數:日志文件名

winpacp中文技術文檔(基本是英文的):http://www.ferrisxu.com/WinPcap/html/index.html

*/

一、構造arp包

在構造之前先了解一下arp包的結構,先從網上找了張圖

從圖中可以看出以太網首部占14字節,以太網ARP字段占28字節。其中op字段為操作類型,1表示ARP請求、2表示ARP應答

再介紹幾個要用到的pcap函數

函數功能:列出當前所有可用的網絡設備(網卡),將設備信息存入pcap_if_t結構列表中

參數:1、alldevsp    指向pcap_if_t結構列表的指針的地址(注意這裡是pcap_if_t指針的地址,而不是pcap_if_t結構的地址)

    有些地方這裡可能會寫pcap_if結構,其實pcap_if和pcap_if_t就是同一個東西,我們來看看在pcap.h中是怎麼定義的

   pcap_if結構體成員:

Struct pcap_if { 

   struct pcap_if  *next;  //指向下一個鏈表成員

   char *name; //網卡名稱

   chat *description; //網卡描述信息

   struct pcap_addr address; 

   u_int flags; //接口標志

}

    2、errbuf   錯誤緩沖區,要求長度至少為PCAP_ERRBUF_SIZE 字節,那麼PCAP_ERRBUF_SIZE是多大呢

          這在pcap.h中宏定義的,如下圖

     這個錯誤緩沖區用來做什麼呢?在函數錯誤返回時(返回值為-1)會向錯誤緩沖中填充錯誤信息,錯誤信息為可打印ASCII碼

     函數正確時返回0

  2、pcap_t * pcap_open_live ( char * device, int snaplen, int promisc,int to_ms, char * errbuf )

函數功能:在網絡中打開一個活動的捕獲<這是winpcap技術文檔給出的說明,也就是指定從一個網絡設備捕獲數據包,我是這麼理解的>

    函數的返回值為一個結構體指針pcap_t即為struct pcap。pcap_t結構體有點長就不做說明了,裡面就是捕獲句柄的一些信息

參數: <文檔是英文的不知道有沒有翻譯對>

    device 設備名     

    snaplen 單包最大捕捉字節數(若數據包大於snaplen,只有前面snaplen字節大小的數據被捕獲)  

    promisc 混雜模式(即使該參數是false,也可能由其他原因導致網絡接口為混雜模式)

    to_ms 指定毫秒級讀超時(當一個數據包被發現時,並不一定立即返回數據包,它會等待一段時間,允許一個操作從系統內核讀取多個數據  包。不是所有的平台都支持讀超時,在不支持的平台上讀超時會被忽略。)<在支持讀超時的平台上若讀超時為0,將導致永不超時>

    errbuf 用於返回錯誤或警告信息

  3、void pcap_close ( pcap_t  *p )

    關閉pcap_open_live()獲取的包捕獲句柄,釋放相關資源

源碼:

  1 /*
  2 構造並發送ARP包
  3 2015年6月24日15:44:21
  4 blog:http://www.cnblogs.com/wd1001/
  5 */
  6 #include <stdlib.h>
  7 #include <stdio.h>
  8 #include <pcap.h> 
  9 
 10 #pragma comment(lib, "wpcap.lib")
 11 #pragma comment(lib, "wsock32.lib")
 12 #pragma comment(lib, "ws2_32.lib")
 13 
 14 main(int argc, char **argv) 
 15 { 
 16     u_char packet[100];
 17     pcap_if_t *alldevs; 
 18     pcap_if_t *d; 
 19     int inum; 
 20     int i=0,j,k,temp[3]; 
 21     pcap_t * adhandle; 
 22     char errbuf[PCAP_ERRBUF_SIZE]; 
 23     /* 獲取設備列表 */ 
 24     
 25     if (argc != 5)//argc==5,及程序後面有四個參數
 26     {
 27         printf("usage: %s inerface", argv[0]);
 28         return -1;
 29     }
 30     
 31     
 32     if (pcap_findalldevs(&alldevs, errbuf) == -1) 
 33     { 
 34         fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 
 35         exit(1); 
 36     } 
 37     /* 數據列表 */ 
 38     for(d=alldevs; d; d=d->next) 
 39     { 
 40         printf("%d. %s", ++i, d->name); 
 41         if (d->description) 
 42             printf(" (%s)\n", d->description); 
 43         else 
 44             printf(" (No description available)\n"); 
 45     } 
 46     if(i==0) 
 47     { 
 48         printf("\n找不到網卡! 檢查是否安裝WinPcap.\n"); 
 49         return -1; 
 50     } 
 51     printf("Enter the interface number (1-%d):",i); 
 52     scanf("%d", &inum); 
 53     if(inum < 1 || inum > i) 
 54     { 
 55         printf("\nInterface number out of range.\n"); 
 56         /* 釋放設備列表 */ 
 57         pcap_freealldevs(alldevs); 
 58         return -1; 
 59     } 
 60     /* 轉到選擇的設備 */ 
 61     for(d=alldevs, i=0; i< inum-1;d=d->next, i++); 
 62     /* 打開設備 */ 
 63     if ( (adhandle= pcap_open_live(d->name, //設備名 
 64         65536, // 最大捕捉字節數 
 65         1, // 混雜模式 
 66         1000, // 讀入超時 
 67         errbuf // 錯誤緩沖 
 68         ) ) == NULL) 
 69     { 
 70         /*打開失敗*/ 
 71         fprintf(stderr,"\n打開失敗. %s 不被winpcap支持\n",d->name); 
 72         /* 釋放列表 */ 
 73         pcap_freealldevs(alldevs); 
 74         return -1; 
 75     } 
 76     /* 釋放設備列表 */ 
 77     pcap_freealldevs(alldevs); 
 78     
 79     /* 填充數據段 */ 
 80     
 81     //flag為1表示ARP請求
 82     if('1'==argv[4][0])
 83     {
 84         //源MAC地址
 85         k=0;    
 86         for(i=0;i<18;i=i+3)
 87         {
 88             temp[0]=(int)argv[3][i];
 89             temp[1]=(int)argv[3][i+1];
 90             if(temp[0]>96)         //當輸入mac為小寫字母時字符轉換為16進制
 91                 temp[0]=temp[0]-87;
 92             else if(temp[0]>64)
 93                 temp[0]=temp[0]-55;//當輸入mac為大寫字母時字符轉換為16進制
 94             else
 95                 temp[0]=temp[0]-48;//當輸入mac為數字時字符轉換為16進制
 96             if(temp[1]>96)
 97                 temp[1]=temp[1]-87;
 98             else if(temp[1]>64)
 99                 temp[1]=temp[1]-55;
100             else
101                 temp[1]=temp[1]-48;
102             packet[22+k]=packet[6+k]=temp[0]*16+temp[1];
103             k++;
104         }
105         
106         //發送ARP請求時目的MAC全置為ff
107         for(i=0;i<6;i++)
108         {
109             packet[i]=packet[32+i]=0xff;
110         }
111     }
112     
113     //flag=2:ARP應答
114     else
115     {
116         //目的MAC地址
117         k=0;    
118         for(i=0;i<18;i=i+3)
119         {
120             temp[0]=(int)argv[3][i];
121             temp[1]=(int)argv[3][i+1];
122             if(temp[0]>96)
123                 temp[0]=temp[0]-87;
124             else if(temp[0]>64)
125                 temp[0]=temp[0]-55;
126             else
127                 temp[0]=temp[0]-48;
128             if(temp[1]>96)
129                 temp[1]=temp[1]-87;
130             else if(temp[1]>64)
131                 temp[1]=temp[1]-55;
132             else
133                 temp[1]=temp[1]-48;
134             packet[k]=packet[32+k]=temp[0]*16+temp[1];
135             k++;
136         }
137         //應答ARP請求時把源MAC置為0
138         for(i=0;i<6;i++)
139         {
140             packet[6+i]=packet[22+i]=0x00;
141         }
142     }
143     
144     //源IP地址
145     k=0;
146     temp[2]=0;  //指向每個字節初始位置
147     for(i=0;i<4;i++)
148     {
149         temp[0]=0;
150         temp[1]=0;
151         for(j=0;j<4;j++)
152         {
153             if(argv[1][j+temp[2]]>='0'&&argv[1][j+temp[2]]<='9')
154             {
155                 temp[0]=(int)argv[1][j+temp[2]]-48;
156                 temp[1]=temp[1]*10+temp[0];
157                 //printf("%d %d\n",temp[0],temp[1]);
158             }
159             else
160             {
161                 //當遇到點時j自加1目的是讓temp[2]+j指向下一字節的第一位
162                 j++;
163                 break;
164             }
165         }
166         packet[28+k]=temp[1];
167         k++;
168         temp[2]+=j;
169     }
170     //目標IP地址
171     k=0;
172     temp[2]=0;
173     for(i=0;i<4;i++)
174     {
175         temp[0]=0;
176         temp[1]=0;
177         for(j=0;j<4;j++)
178         {
179             if(argv[2][j+temp[2]]>='0'&&argv[2][j+temp[2]]<='9')
180             {
181                 temp[0]=(int)argv[2][j+temp[2]]-48;
182                 temp[1]=temp[1]*10+temp[0];
183                 //printf("%d %d\n",temp[0],temp[1]);
184             }
185             else
186             {
187                 j++;
188                 break;
189             }
190         }
191         packet[38+k]=temp[1];
192         k++;
193         temp[2]+=j;
194     }
195     //ARP首部
196     packet[12]=0x08;//12、13位為幀類型
197     packet[13]=0x06;
198     packet[14]=0x00;//14、15位為硬件類型
199     packet[15]=0x01;
200     packet[16]=0x08;//16、17位為協議類型
201     packet[17]=0x00;
202     packet[18]=0x06;//硬件地址長度
203     packet[19]=0x04;//協議地址長度
204     packet[20]=0x00;//op
205     packet[21]=(int)argv[4][0]-48;//op(1為請求2為應答)
206     
207     
208     /* 填充發送包的剩余部分 */
209     for(i=0;i<18;i++)
210     {
211         packet[42+i]=0;
212     }
213     //這裡後四個字節本應該是校驗位,這裡就不算了,寫個日期紀念一下
214     packet[60]=0x20;
215     packet[61]=0x15;
216     packet[62]=0x6;
217     packet[63]=0x24;
218     /* 發送包 */
219     pcap_sendpacket(adhandle, packet, 64);
220     printf("Success!\n");
221     
222     return 0; 
223 }

運行結果:

輸入參數:隨意設置源IP,目的IP和mac地址

選擇網卡並發送,抓包結果如下

 


 

二、獲取網絡中的ARP數據包,解析數據包的內容

在上面的基礎上再解析ARP數據包就簡單了

同樣在解析前先介紹幾個要用到的函數

  1、int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str,int optimize , bpf_u_int32 netmask )

 函數功能:將字符串str編譯進一個過濾程序,將程序中高級的過濾表達式,轉換成能被內核級的過濾引擎所處理的東西

參數:1、p為pcap_open_live返回的一個捕獲句柄

   2、fp為一個指向bpf_program結構的指針,由pcap_compile()函數填寫

bpf_program結構為:

struct bpf_program {
u_int bf_len;
struct bpf_insn *bf_insns;
};

bpf_insn結構為:

struct bpf_insn {
u_short code;
u_char jt;
u_char jf;
bpf_int32 k;
};

    3、str 過濾串表達式

    4、optimize 優化控制,是否執行結果代碼優化(optimize controls whether optimization on the resulting code is performed)

    5、netmask 子網掩碼

  2、int pcap_setfilter (pcap_t *p, struct bpf_program *fp)

函數功能:在捕獲過程中綁定一個過濾器

源碼:

 

  1 /*
  2 獲取網絡中的ARP數據包,解析數據包的內容
  3 2015年6月24日19:36:36
  4 blog:http://www.cnblogs.com/wd1001/
  5  */
  6 #include <stdlib.h>
  7 #include <stdio.h>
  8 #include <pcap.h> 
  9 #pragma comment(lib, "wpcap.lib")
 10 #pragma comment(lib, "wsock32.lib")
 11 #pragma comment(lib, "ws2_32.lib")
 12 //定義ARP包數據
 13 typedef struct arppkt
 14 {
 15     unsigned short hdtyp;//硬件類型
 16     unsigned short protyp;//協議類型
 17     unsigned char hdsize;//硬件地址長度
 18     unsigned char prosize;//協議地址長度
 19     unsigned short op;//(操作類型)操作值:ARP/RARP
 20     u_char smac[6];//源MAC地址
 21     u_char sip[4];//源IP地址
 22     u_char dmac[6];//目的MAC地址
 23     u_char dip[4];//目的IP地址
 24 }arpp;
 25 int main(int argc,char * argv[] )
 26 {
 27     struct tm * timeinfo;
 28     struct tm *ltime;
 29     time_t rawtime;
 30     FILE * fp=NULL;
 31     int result;
 32     int i=0,inum;
 33     pcap_if_t * alldevs;//指向pcap_if_t結構列表指針
 34     pcap_if_t * d; 
 35     pcap_t * adhandle;//定義包捕捉句柄
 36     char errbuf[PCAP_ERRBUF_SIZE];//錯誤緩沖最小為256
 37     u_int netmask; //定義子網掩碼
 38     char packet_filter[]="ether proto \\arp";
 39     struct bpf_program fcode;
 40     struct pcap_pkthdr * header;
 41     const u_char * pkt_data;
 42     //打開日志文件
 43     if((fp=fopen(argv[1],"a"))==NULL)
 44     {
 45         printf("打開文件失敗!\n");
 46         exit(0);
 47     }
 48     if (argc != 2)//argc==2,及程序後面有1個參數
 49     {
 50         printf("程序%s需要一個日志文件名參數!\n", argv[0]);
 51         return -1;
 52     }
 53     //當前所有可用的網絡設備
 54     if (pcap_findalldevs(&alldevs, errbuf) == -1) 
 55     { 
 56         fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 
 57         exit(1); 
 58     }
 59     //列出網絡設備
 60     for(d=alldevs; d; d=d->next) 
 61     { 
 62         printf("%d. %s", ++i, d->name); 
 63         if (d->description) 
 64             printf(" (%s)\n", d->description); 
 65         else 
 66             printf(" (沒有描述可用)\n"); 
 67     } 
 68     if(i==0) 
 69     { 
 70         printf("\n找不到網卡! 檢查是否安裝WinPcap.\n"); 
 71         return -1; 
 72     } 
 73     printf("選擇對應網卡編號 (1-%d):",i); 
 74     scanf("%d", &inum); 
 75     if(inum < 1 || inum > i) 
 76     { 
 77         printf("\n輸入的編號超出范圍!\n"); 
 78         /* 釋放設備列表 */ 
 79         pcap_freealldevs(alldevs); 
 80         return -1; 
 81     }
 82     /* 轉到選擇的設備 */
 83     i=0;
 84     d=alldevs;
 85     while(i<inum-1)
 86     {
 87         d=d->next;
 88         i++;
 89     }
 90     if ( (adhandle= pcap_open_live(d->name,65536, 1,1000,errbuf) ) == NULL) 
 91     { 
 92         /*打開失敗*/ 
 93         fprintf(stderr,"\n打開失敗. %s 不被winpcap支持\n",d->name); 
 94         /* 釋放設備列表 */ 
 95         pcap_freealldevs(alldevs); 
 96         return -1; 
 97     } 
 98     /* 釋放設備列表 */ 
 99     pcap_freealldevs(alldevs);
100     
101     //獲得子網掩碼
102     netmask=((sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
103     //編譯過濾器,只捕獲ARP包
104     if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0)
105     {
106         printf("\nUnable to compile the packet filter.Check the syntax.\n");
107         pcap_freealldevs(alldevs);
108         return -1;
109     }
110     //設置過濾器
111     if(pcap_setfilter(adhandle,&fcode)<0)
112     {
113         printf("\nError setting the filter.\n");
114         pcap_freealldevs(alldevs);
115         return -1;
116     }
117     //輸出每次修改文件時間
118     time ( &rawtime );
119     timeinfo = localtime ( &rawtime );
120     printf("--------------修改時間:%s",asctime (timeinfo));
121     fprintf(fp,"-----------修改時間:%s",asctime (timeinfo));
122     fflush(fp);//刷新緩沖流
123     while((result=pcap_next_ex(adhandle,&header,&pkt_data))>=0)
124     {
125         //循環解析ARP數據包
126         if(result==0)
127             continue;
128         //解析ARP包,結果輸出到屏幕與文件
129         arppkt* arph = (arppkt *)(pkt_data +14);
130         //輸出操作時間
131         ltime=localtime(&header->ts.tv_sec);
132         printf("時間:%s",asctime (ltime));
133         fprintf(fp,"時間:%s",asctime (ltime));
134         //輸出源IP
135         printf("源IP:");
136         fprintf(fp,"源IP:");
137         for(i=0;i<3;i++)
138         {
139             printf("%d.",arph->sip[i]);
140             fprintf(fp,"%d.",arph->sip[i]);
141         }
142         printf("%d\t",arph->sip[3]);
143         fprintf(fp,"%d.\t",arph->sip[3]);
144         //輸出目的IP
145         printf("目的IP:");
146         fprintf(fp,"目的IP:");
147         for(i=0;i<3;i++)
148         {
149             printf("%d.",arph->dip[i]);
150             fprintf(fp,"%d.",arph->dip[i]);
151         }
152         printf("%d\t",arph->dip[3]);
153         fprintf(fp,"%d\t",arph->dip[3]);
154         //輸出源mac
155         printf("源mac:");
156         fprintf(fp,"源mac:");
157         for(i=0;i<5;i++)
158         {
159             printf("%x-",arph->smac[i]);
160             fprintf(fp,"%x-",arph->smac[i]);
161         }
162         printf("%x\t",arph->smac[5]);
163         fprintf(fp,"%x\t",arph->smac[5]);
164         //輸出目的mac
165         printf("目的mac:");
166         fprintf(fp,"目的mac:");
167         for(i=0;i<5;i++)
168         {
169             printf("%x-",*(pkt_data+i));
170             fprintf(fp,"%x-",*(pkt_data+i));
171         }
172         printf("%x\t",*(pkt_data+5));
173         fprintf(fp,"%x\t",*(pkt_data+5));
174         //輸出操作類型
175         printf("操作類型(ARP/RARP):");
176         fprintf(fp,"操作類型(ARP/RARP):");
177         if(arph->op==256)
178         {
179             printf("ARP\t");
180             fprintf(fp,"ARP\t");
181         }
182         else
183         {
184             printf("RARP\t");
185             fprintf(fp,"RARP\t");
186         }
187         printf("\n");
188         fprintf(fp,"\n");
189         printf("--------------------------------------\n");
190         fprintf(fp,"--------------------------------------\n");
191         fflush(fp);
192     }
193     fclose(fp);
194     return 0;
195 }

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved