最近无意中看到博客园中一篇介绍wireshark的文章,写得不错,它简单清楚介绍了wireshark的使用

简介

wireshark以前叫做Ethereal, 在大学时候的网络课程中就常看到它,它是世界上最流行的网络抓包分析工具(world's most popular network protocol analyzer),它是基于图形界面的,官网有介绍wireshark是1998年的一个项目衍生出来的,它有比较强大的特性,可以用来分析数百种网络协议。wireshark是在GNU General Public Lisence下发布的。

以下是我自己使用wireshark的一个截图, 照着上面的博客中去抓取和查看一次http请求前的tcp三次握手,下面详细显示的那行及其上下行就是我从本机浏览器访问自己博客园博客的时候产生的tcp三次握手,可以看到是先握手成功才传输的http报文

可以看到wireshark提供了一个非常友好和详细的界面,可以看到一个包从链路层ethernet,网络层ip,传输层tcp的包信息。详细的使用参加上面提到的博客

tcpdump其实和wireshark很像,区别只是tcpdump是命令行界面的,wireshark和tcpdump都共同使用 libpcap作为其底层抓包的库,  tcpdump最早是由 Van Jacobson于1987年开发的,后来在1999年http://www.tcpdump.org/创立,这上面有关于tcpdump和pcap详细的文档。

 

tcpdump的输出

tcpdump的输出格式是和协议相关的,在协议栈的同一层会有不同的协议,比如在Transport Layer会有TCP,UDP协议。下图摘自wikipedia

对于tcpdump,-e表示输出link level header,以下是一个例子   tcpdump -i eth2 -e -n

要以看到用了-e打印出了网卡MAC地址,链路层的协议(ethertype), 网络层的协议(IPv4), 第一个length是表示链路层包的长度。然后打出的是里面的tcp packet的信息,发送端和接收端的ip地址,tcp中的Flags等,可以看到后三个包都是广播的包。最后一个是一个ARP查询的包

用tcpdump来看一下三次握手

用这样的命令形式,sudo tcpdump -i eth2 -n '(tcp[13] & 2 == 2 or tcp[13] & 16 ==16)'  , 注意tcpdump是需要superviser的权限的, 输出很多,从中提了一个三次握手

上面的 -n 表示输出结果全用数字表示而不用域名和端口代表的服务名,而后面那个是传递给tcpdump中的libpcap模块的过滤expression, 关于这个过滤expression的语法,在man pcap-filter中有详细的说明,上面这个表达式的意思是 , tcp[13]是包中的tcp子包的第13个字节的值,字节数是从第0个字节开始的。而这个字节正好是Flags这个字节。 而上面Flags的字段中 S表示SYN,   .(一个点)表示ACK

上图是TCP的结构,从图中可以看出,对于Flags这个字节,2表示只有SYN这一位为1, 16则是只有ACK那一位为1, 而上面的tcp[13] & 2 == 2表示SYN这一位为1, 其他位不管。在tcp协议中,只有建立连接的两个端口发的第一个包才会设置SYN位,表示起始的sequence number。从上面可以看到起始的seq num是一个随机值。

libpcap , 以及基于libpcap实现一个简单的抓包程序

安装

libpcap是一个c库,用于网络抓包和过滤,源于tcpdump项目,是从最开始tcpdump中剥离出来的一个库, tcpdump中抓包,过滤,capture file的读写的代码被提取出来成了libpcap。现在也是由tcpdump项目的开发者维护。

从tcpdump的官网上下载下来后,包里面有一个INSTALL.txt文件,也就是三步的内容,./configure;   make;   make install;在这个过程中我安装了flex(一个lexical analyzer generator)和yacc才成功了

写的一个简单程序

pcap实际上是从链路层抓包的,所以可以从中提出取出从链路层开始的包信息,官网里(这里)有详细的基于pcap的编程文档。这个文档中有提到基于libpcap编程的基本步骤, 如何应用过滤条件,如何拿到一个包后回调,以及在回调函数中(下面的call_back)怎样提取包的详细信息,因为是得到这个链路层包的实际内容的(以字串的形式),所以是可以提取出从链路层开始,网络程ip, 传输层如tcp的所有信息的,  基本上不同的基于libpcap的软件也就是这里不同了,怎样提取和展示包的信息。基于这个文档我写了一个简单的程序

  1. 1 #include<stdio.h>
  2. 2 #include<pcap.h>
  3. 3 #include<string>
  4. 4
  5. 5 using namespace std;
  6. 6
  7. 7 static const unsigned int ETHER_ADDR_LEN = 6;
  8. 8 void call_back(u_char * args, const struct pcap_pkthdr * header, const u_char * packet);
  9. 9 string generate_mac_address(char macChars[ETHER_ADDR_LEN]);
  10. 10
  11. 11 int main(){
  12. 12 pcap_t * handle; // Sesion handle
  13. 13 char dev[] = "eth2"; //device to sniff on
  14. 14 char errbuf[PCAP_ERRBUF_SIZE]; // error string
  15. 15 char filter_exp[] = ""; //filter expression
  16. 16 bpf_u_int32 mask; //The netmask of our sniffing device
  17. 17 bpf_u_int32 net; //The IP of our sniffing device
  18. 18
  19. 19 struct bpf_program fp; //the compiled filter expression
  20. 20
  21. 21 //查询device的mask和ip
  22. 22 if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1){
  23. 23 fprintf(stderr, "Can't get netmask for device %s\n", dev);
  24. 24 net = 0;
  25. 25 mask = 0;
  26. 26 }
  27. 27
  28. 28 //obtaining packet capture descriptor
  29. 29 handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
  30. 30 if(handle == NULL){
  31. 31 fprintf(stderr, "Can't open device %s\n", dev);
  32. 32 return 2;
  33. 33 }
  34. 34
  35. 35 // before apply filter exp, compile it
  36. 36 if(pcap_compile(handle, &fp, filter_exp, 0, net) == -1){
  37. 37 fprintf(stderr, "can't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
  38. 38 return 2;
  39. 39 }
  40. 40 //apply filter to this session
  41. 41 if(pcap_setfilter(handle, &fp) == -1){
  42. 42 fprintf(stderr, "can't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
  43. 43 return 2;
  44. 44 }
  45. 45
  46. 46 // now the device is prepared to sniff under the filter condition
  47. 47 struct pcap_pkthdr header; // packet header struct
  48. 48 const u_char * packet; // actual packet
  49. 49
  50. 50 //5表示积累5个包pcap_loop才返回,但每个包都会调一次call_back
  51. 51 while(!pcap_loop(handle, 5, call_back, NULL)){
  52. 52 printf("-------\n"); //每8行才会输出一次这个
  53. 53 }
  54. 54 pcap_close(handle);
  55. 55 }
  56. 56
  57. 57 struct sniff_ethernet {
  58. 58 char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
  59. 59 char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
  60. 60 u_short ether_type; /* IP? ARP? RARP? etc */
  61. 61 };
  62. 62
  63. 63 // call_back function的统一原型
  64. 64 void call_back(u_char * args, const struct pcap_pkthdr * header, const u_char * packet){
  65. 65 static int count = 0;
  66. 66 struct sniff_ethernet * ethernet; //ethernet header
  67. 67 ethernet = (struct sniff_ethernet*)(packet);
  68. 68
  69. 69 //把6字节的字符串转换成mac地址的表示形式
  70. 70 std::string source_mac_address = generate_mac_address(ethernet->ether_shost);
  71. 71 std::string dst_mac_address = generate_mac_address(ethernet->ether_dhost);
  72. 72
  73. 73 printf("wy: call_back called %d, %s->%s, packet length:%d\n", count++, source_mac_address.c_str(), dst_mac_address.c_str(), header->len);
  74. 74 }
  75. 75
  76. 76 //由字节为单位字符串生成mac地址,16进制数的字串
  77. 77 string generate_mac_address(char macChars[ETHER_ADDR_LEN]){
  78. 78 string macAddr;
  79. 79 char temp[2];
  80. 80 for(int i = 0; i < ETHER_ADDR_LEN; i++){
  81. 81 //把一个字节转化成16进制表示形式
  82. 82 sprintf(temp, "%x", macChars[i]);
  83. 83 if(i != 0){
  84. 84 macAddr.append(":");
  85. 85 }
  86. 86 macAddr.append(temp, 2);
  87. 87 }
  88. 88 return macAddr;
  89. 89 }

这个程序上面有比较详细的注释,就是把通用的基于libpcap编程的流程走了一遍,最后打印出每个包链路层from和to的MAC地址,以及每个包的长度.

对于call_back的第二个参数 struct pcap_pkthdr, 这是pcap.h中定义的一个结构体,包含了这个包的一些信息,捕获时间,包长度, 可以看到程序中的包长度就是从中提取的,定义如下

  1. 1 struct pcap_pkthdr {
  2. 2 struct timeval ts; /* time stamp */
  3. 3 bpf_u_int32 caplen; /* length of portion present */
  4. 4 bpf_u_int32 len; /* length this packet (off wire) */
  5. 5 };

上面的参数char * packet实际上是整个包在内存在的地址,为了从这当中提取出信息,必须要自己定义相应的数据结构从这个纯字符串中去提, 可以看到我照着文档中去定义了一个 struct  sniff_ethernet,这个是需要自己定义的,pcap.h中是没有的,然后可以看到我如何写了一个函数 generate_mac_address把这个6字节的字符串转换成mac地址标准的表达形式。以下是程序运行输出

比较奇怪的是,我本机网卡 eth2的MAC地址是  bc:30:5b:a4:40:40, 但是程序的输出是 ff:30:5b:ff:40:40

本来想选择就用c来写这个程序,但是写到字串转换那里,对字符串的操作用c确实比较麻烦和难看,所以我还是用的c++, 我想到了陈皓的一篇文章,他感慨c的编译器gcc已经开始用c++来实现了,他列举出了c++比c优雅的地方,就我的感觉是很赞同的。

一个链接错误

很奇怪的是我编译程序遇到了一个错误, g++ -o test_pcap test_pcap.cpp -L/usr/local/lib -lpcap

错误提示是

/usr/local/lib/libpcap.so: undefined reference to `pcap_parse'
collect2: ld returned 1 exit status

google了一下,发现这个问题很普遍却都没给出一个明确的原因解释,有篇文章提到把libpcap重装也一遍,也就是cd到下载下来的包目录,make clean ; ./configure; make ; make install ;  我这样试了之后竟然好了,没有明白是为什么,网上也没有找到,在这里做一个记录吧

网络抓包工具wireshark and tcpdump 及其实现基于的libpcap的更多相关文章

  1. 网络抓包工具-Wireshark学习资料

    wireshark一个非常牛逼的网络抓包工具.转载一系列博文 一站式学习Wireshark(一):Wireshark基本用法 一站式学习Wireshark(二):应用Wireshark观察基本网络协议 ...

  2. Wireshark 网络抓包工具Wireshark的使用

    阅读目录 wireshark介绍 wireshark不能做的 wireshark VS Fiddler 同类的其他工具 什么人会用到wireshark wireshark 开始抓包 wireshark ...

  3. 网络抓包工具 wireshark 入门教程

    Wireshark Wireshark(前称Ethereal)是一个网络数据包分析软件.网络数据包分析软件的功能是截取网络数据包,并尽可能显示出最为详细的网络数据包数据.Wireshark使用WinP ...

  4. 网络抓包工具wireshark常用封装过滤规则

    过滤器的区别 捕捉过滤器(CaptureFilters):用于决定将什么样的信息记录在捕捉结果中.需要在开始捕捉前设置.显示过滤器(DisplayFilters):在捕捉结果中进行详细查找.他们可以在 ...

  5. 网络抓包工具Wireshark和Fidder

    http://fangxin.blog.51cto.com/1125131/735178 http://blog.csdn.net/jiangwei0910410003/article/details ...

  6. socket和抓包工具wireshark

    socket和抓包工具wireshark 最近在学习Python代码中的socket和抓包工具wireshark,故又将socket等概念又学习了一遍,温故而知新: Python代码如下: serve ...

  7. 抓包工具Wireshark过滤器

    抓包工具WireShark分为两种过滤器: 捕捉过滤器(CaptureFilters) 显示过滤器(DisplayFilters) 捕捉过虑器语法: Protocol  Direction  Host ...

  8. 跨平台网络抓包工具-Microsoft Message Analyzer

    Microsoft Message Analyzer (MMA 2013)是微软最受欢迎的Netmon的最新版本. 在Netmon网络跟踪和排除故障功能的基础上提供了更强大的跨平台网络分析追踪能力.园 ...

  9. Microsoft Message Analyzer (微软消息分析器,“网络抓包工具 - Network Monitor”的替代品)官方正式版现已发布

    来自官方日志的喜悦 被誉为全新开始的消息分析器时代,由MMA为您开启,博客原文写的很激动,大家可以点击这里浏览:http://blogs.technet.com/b/messageanalyzer/a ...

随机推荐

  1. Archiving not possible: No primary destinations errors

    If space ran out in an archive destination, after you fix the problem, you may still recieve the fol ...

  2. [luoguP2447] [SDOI2010]外星千足虫(高斯消元 + bitset)

    传送门 用bitset优化,要不然n^3肯定超时 消元过程中有几点需要注意,找到最大元后break,保证题目中所说的K最小 如果有自由元说明解很多,直接返回 #include <bitset&g ...

  3. msp430项目编程05

    msp430中项目---TFT彩屏显示(续) 1.TFT彩屏工作原理 2.电路原理说明 3.代码(静态显示) 4.代码(动态显示) 5.项目总结 msp430项目编程 msp430入门学习

  4. windows下的asp.net core开发及docker下的发布

    参照下面,搭建好开发环境.Docker及配置好Docker加速器 http://www.cnblogs.com/windchen/p/6257846.html 参照下面,将windows共享目录挂载到 ...

  5. CodeForces 596C Wilbur and Points

    先对n个点分类,然后按题意要求构造,构造的时候判断这个点的右上方之前是否有点,判断可以用线段树来操作. #include<cstdio> #include<cstring> # ...

  6. webstorm 添加markdown支持

    第一步:file---setting---plugins---搜索markdown support 安装 第二步:file---settind---file types---增加*.md处理

  7. bzoj4161 (k^2logn求线性递推式)

    分析: 我们可以写把转移矩阵A写出来,然后求一下它的特征多项式,经过手动计算应该是这样的p(x)=$x^k-\sum\limits_{i=1}^ka_i*x^{k-i}$ 根据Cayley-Hamil ...

  8. jQuery的一些总结(持续更新中...)

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p http://www.cnblogs.com/zt-blog/p/6693399.html 1. $.expr[':']  过滤 ...

  9. md5sum使用注意事项

    1. linux 命令行的 md5sum命令 echo -n "123456" | md5sum     //echo的时候, 默认是自带回车的, 必须要去掉 -n 去掉回车. 2 ...

  10. Bootstrap的js插件之弹出框(popover)

    data-toggle="popover"--使弹出框可以切换状态: title--设置弹出框的标题: data-content--设置弹出框的内容部分: data-placeme ...