大多数人恐怕已经听说过Wireshark,这是一款人气非常旺、功能非常强的网络协议分析工具。但是大家可能不知道的是,还有一个控制台版本的Wireshark,名叫tshark。tshark的两个主要优点就是,它可以用在脚本中,也可以通过SSH连接用在远程计算机上。主要缺点就是,它没有图形用户界面(GUI),如果你要搜索大量的网络数据,要是有GUI,确实方便得很。
你可以从官方网站获得tshark、自行编译,也可以从你的Linux发行版获得它(它作为预先编译的程序包)。第二种方法更快捷、更简单。想把tshark安装到Debian 7系统上,你就要以根用户身份,运行下列命令:
# apt-get install tshark Reading package lists... Done Building dependency tree Reading state information... Done The following extra packages will be installed: libc-ares2 libcap2-bin libpam-cap libsmi2ldbl libwireshark-data libwireshark2 libwiretap2 libwsutil2 wireshark-common Suggested packages: libcap-dev snmp-mibs-downloader wireshark-doc The following NEW packages will be installed: libc-ares2 libcap2-bin libpam-cap libsmi2ldbl libwireshark-data libwireshark2 libwiretap2 libwsutil2 tshark wireshark-common 0 upgraded, 10 newly installed, 0 to remove and 0 not upgraded. Need to get 15.6 MB of archives. After this operation, 65.7 MB of additional disk space will be used. Do you want to continue [Y/n]? Y ...
想查明tshark是否已正确安装,并查明其版本,请执行这个命令:
$ tshark -v TShark 1.8.2 ...
注意:本文假设你已经很熟悉网络数据、TCP/IP和数据包捕获,还可能熟悉Wireshark,并假设你想了解关于tshark的更多信息。
tshark简介
凡是Wireshark具有的功能,tshark都有,前提条件是它不需要GUI。它还可以用来替代tcpdump,tcpdump过去是网络数据捕获方面的行业标准。除了捕获方面外(两种工具在这方面功能相当),tshark的功能比tcpdump来得强大;因此,如果你只想学用一种工具,tshark应该是你的选择。
正如你设想的那样,tshark有好多命令行选项。请参阅其参考手册页,即可了解完整列表。
使用tshark捕获网络流量
你应该运行的头一个命令是sudo tshark –D,即可列出可用网络接口:
$ sudo tshark -D 1. eth0 2. nflog (Linux netfilter log (NFLOG) interface) 3. any (Pseudo-device that captures on all interfaces) 4. lo
如果你以普通用户的身份运行tshark,极有可能会得到下列输出结果,因为普通用户无权直接访问网络接口设备:
$ tshark -D tshark: There are no interfaces on which a capture can be done
想捕获数据,最简单的办法就是运行不带任何参数的tshark,这会在屏幕上显示所有数据。只要按Ctrl-C组合键,就可以停止数据捕获。
在忙碌的网络上,输出结果会飞快地滚动显示,所以一点也没有帮助。比较旧的计算机可能跟不上忙碌的网络,所以tshark和tcpdump之类的程序过去常常丢失网络数据包。由于现代计算机功能相当强大,这不再是个问题。
使用文件,保存和阅读网络数据
最有用的一个命令行参数是-w,后面跟以文件名。这个参数让你可以将网络数据保存到文件中,以便以后处理它。下面这个tshark命令可捕获500个网络数据包(-c 500),并将它们保存到名为LJ.pcap的文件(-w LJ.pcap)。
$ tshark -c 500 -w LJ.pcap
第二有用的参数是-r。后面跟以有效的文件名时,它让你可以阅读和处理之前捕获的含有网络数据的文件。
捕获过滤器
捕获过滤器是数据捕获过程中所应用的过滤器;因此,它们让tshark丢弃不符合过滤器标准的网络流量,避免生成庞大的捕获文件。这可以使用-f命令行参数(后面跟以双引号里面的过滤器)来实现。
捕获过滤器中使用的最重要的与TCP相关的字段名有:tcp.port(用于过滤源头或目的地TCP端口)、tcp.srcport(用于检查TCP源头端口)以及tcp.dstport(用于检查目的地端口)。
通常来说,数据捕获后应用过滤器被认为比在捕获过程中进行过滤来得更实用、功能更广泛,因为大多数时候,你并不事先知道想要检查什么。然而,如果你确实知道要做什么,使用捕获过滤器就能为你节省时间和磁盘空间,这也是使用捕获过滤器的主要原因。
切记:过滤器字符串始终应该使用小写字母。
显示过滤器
显示过滤器是数据包捕获后所应用的过滤器;因此,它们只是“隐藏”网络流量,而不实际删除。你总是可以去除显示过滤器的影响,找回你的所有数据。
显示过滤器支持比较运算符和逻辑运算符。http.response.code == 404 && ip.addr == 192.168.10.1显示过滤器显示了来自192.168.10.1 IP地址或前往192.168.10.1 IP地址的流量,该流量里面还有404 (Not Found) HTTP响应代码。!bootp && !ip过滤器将BOOTP和IP流量排除在输出结果之外。eth.addr == 01:23:45:67:89:ab && tcp.port == 25过滤器显示了前往或来自拥有01:23:45:67:89:ab MAC地址的网络设备的流量,使用TCP端口25用于入站或出站连接。
定义规则时,要切记:ip.addr != 192.168.1.5表达式并不意味着没有一个ip.addr字段含有192.168.1.5 IP地址。它意味着,其中一个ip.addr字段不应该含有192.168.1.5 IP地址!因此,另一个ip.addr字段值可能相当于192.168.1.5!你可以看成是“有一个不是192.168.1.5的ip.addr字段”。正确的表达方式是,键入!(ip.addr == 192.168.1.5)。这是显示过滤器方面的一个常见误解。
还要牢记:如果你想跟踪局域网上的某一个机器,MAC地址确实很有用,因为如果该机器使用DHCP,其IP地址就会变化,但是MAC地址变化的话比较困难。
如果使用得当,显示过滤器是极其有用的工具,不过你仍得自行解读结果,找到问题,并考虑可能的解决办法。建议访问显示过滤器参考网站:http://www.wireshark.org/docs/dfref/t/tcp.html,即可关注与TCP有关的流量。想查看与UDP流量有关的所有可用字段名,请访问http://www.wireshark.org/docs/dfref/u/udp.html。
导出数据
设想一下:你想提取帧数、帧相对时间、源头IP地址、目的地IP地址、数据包协议,以及来自之前捕获的网络流量的网络数据包的长度。下面这个tshark命令就能为你做到这一切:
$ tshark -r login.tcpdump -T fields -e frame.number -e frame.time_relative -e ip.src -e ip.dst -e frame.protocols -e frame.len -E header=y -E quote=n -E occurrence=f
-E header=y选项指令tshark先输出报头行。-E quote=n规定tshark不包括引号里面的数据,而-E occurrence=f指令tshark使用有多个occurrence的字段的头一个occurrence。
以明文格式输出意味着,你很容易以UNIX方式来处理它。下面这个命令使用来自ip.src字段的输出,显示了十个最常见的IP地址:
$ tshark -r ~/netData.pcap -T fields -e ip.src | sort | sed '/^\s*$/d' | uniq -c | sort -rn | awk {'print $2 " " $1'} | head
使用tshark的两个Python脚本
现在,我们不妨看一下读取tshark文本输出并处理它的两个Python脚本。我无法想象用Wireshark之类的GUI应用程序来处理同一项任务!
代码片段1列出了检查IP地址有效性的第一个脚本的完整Python代码。
代码片段1. checkIP.py
# 编程员:Mihalis Tsoukalos # 日 期:Tuesday 28 October 2014 import socket import sys import re def valid_ip(address): try: socket.inet_aton(address) return True except: return False # IP地址计数器 total = 0 valid = 0 invalid = 0 # 逐行读取来自stdin的文件 for line in sys.stdin: line = line.rstrip('\n') if valid_ip(line): valid = valid + 1 # 输出"The IP is valid!" else: # 输出"The IP is not valid!" invalid = invalid + 1 total = total + 1 # 显示已检查的IP地址总数 print "Total number of IPs checked:", total print "Valid IPs found:", valid print "Invalid IPs found:", invalid checkIP.py Python脚本的目的仅仅是找到无效的IP地址,它表明网络数据已经是用tshark捕获的。你可以按如下方式使用它: $ tshark -r ~/networkData.pcap -T fields -e ip.src | python checkIP.py Total number of IPs checked: 1000 Valid IPs found: 896 Invalid IPs found: 104
代码片段2显示了第二个Python脚本(storeMongo.py)的完整代码。
代码片段2. store Mongo.py
# 编程员:Mihalis Tsoukalos # 日 期:Tuesday 28 October 2014 # # 描述:该Python脚本读取来自tshark的输入,对其解析后,存储到MongoDB数据库 import sys import pymongo import re # 编写的BSON文档的数量 total = 0 # 打开MongoDB连接 connMongo = pymongo.Connection('mongodb://localhost:27017') # 连接至名为LJ(Linux日志)的数据库 db = connMongo.LJ # 选择保存网络数据包的组合 traffic = db.netdata # 逐行读取来自stdin的文件 for line in sys.stdin: line = line.rstrip('\n') parsed = line.split("\t") total = total + 1 # 构建“待插入的文档” netpacket = { 'framenumber': parsed[0], 'sourceIP': parsed[1], 'destIP': parsed[2], 'framelength': parsed[3], 'IPlength': parsed[4] } # 保存它! net_id = traffic.insert(netpacket) connMongo.close() # 显示编写的BSON文档的总数 print "Total number of documents stored: ", total
代码片段2中显示的Python脚本将网络数据插入到MongoDB数据库中,以便进一步处理和查询。你想使用什么数据库,随你喜欢。我使用MongoDB的主要原因是,因为我喜欢它在存储可能含有一些不规则记录(字段丢失的记录)的结构化数据时具有的那种灵活性。
Python脚本的名称是storeMongo.py,它假设网络数据已经使用tshark或tcpdump捕获。下一个外壳命令运行Python脚本,其输入来自tshark:
$ tshark -r ~/var/test.pcap -T fields -e frame.number -e ip.src -e ip.dst -e frame.len -e ip.len -E header=n -E quote=n -E occurrence=f | python storeMongo.py Total number of documents stored: 500
tshark命令的文本输出类似如下:
5 yy.xx.zz.189 yyy.74.xxx.253 66 52 6 197.224.xxx.145 yyy.74.xxx.253 86 72 7 109.xxx.yyy.253 zzz.224.xxx.145 114 100 8 197.xxx.zzz.145 zzz.xxx.xxx.253 86 72 9 109.zzz.193.yyy 197.224.zzz.145 114 100
目前,所有数值都以字符串的形式存储起来,不过你很容易将它们转换成数字,如果你想这么做的话。下面这个命令将来自IPlength列的所有字符串值转换成相应的整数值:
> db.netdata.find({IPlength : {$exists : true}}).forEach( function(obj) { obj.IPlength = new NumberInt( obj.IPlength ); db.netdata.save(obj); } );
现在,你可以开始查询MongoDB数据库了。下列命令找到含有某个目的地IP地址的所有“记录”(用NoSQL术语来说就是文档):
> use LJ switched to db LJ > db.netdata.find({ "destIP": "192.168.1.12" }) ... >
下一个命令找到frame.len值小于70的所有项:
> use LJ switched to db LJ > db.netdata.find({ "framelength": {"$lt" : "70" }}) ... >
下一个命令找到IPlength值大于100、小于200的所有项:
> use LJ switched to db LJ > db.netdata.find({ "IPlength": {"$lt" : "200", "$gt": "100" }}) ... >
你应该记住的不是实际命令,而是这一点:你可以使用自己喜欢的查询语言查询所选择的数据库,并找到有用的信息,不需要重新运行tshark、再次解析网络数据。
你在测试查询后,可以将它们作为计划任务(cron job)来运行。就是这么简单!
使用tshark分析Nmap ping扫描
下一步,不妨分析由Nmap在执行ping扫描后生成的网络流量。ping扫描的目的只是查明IP地址是否正常(up)而已。简而言之,对ping扫描中的Nmap来说重要的不是已收到数据包的实际数据,而是响应数据包确实存在。局域网里面的Nmap ping扫描使用ARP协议,而局域网外面的主机使用ICMP协议来扫描。已执行的扫描ping的是局域网外面的IP地址。
下面这个Nmap命令扫描64个IP地址,从2.x.yy.1到2.x.yy.64:
# nmap -sP 2.x.yy.1-64 Starting Nmap 6.00 ( http://nmap.org ) at 2014-10-29 11:55 EET Nmap scan report for ppp-4.home.SOMEisp.gr (2.x.yy.4) Host is up (0.067s latency). Nmap scan report for ppp-6.home.SOMEisp.gr (2.x.yy.6) Host is up (0.084s latency). ... Nmap scan report for ppp-64.home.SOMEisp.gr (2.x.yy.64) Host is up (0.059s latency). Nmap done: 64 IP addresses (35 hosts up) scanned in 3.10 seconds
结果显示,在执行时段,只有35个主机正常,或者确切地说,只有35个主机回应了Nmap扫描。Nmap还计算了往返程时延(延迟)。这相当准确地估计了由Nmap发送的初始数据包传输到目标设备所需要的时间,加上响应数据包返回到Nmap所需要的时间。
下面这个tshark命令用于捕获,可以按组合键Ctrl-C来终止:
# tshark -w nmap.pcap Running as user "root" and group "root". This could be dangerous. Capturing on eth0 2587 ^C 18 packets dropped # ls -l nmap.pcap -rw------- 1 root root 349036 Oct 29 11:55 nmap.pcap
现在,不妨使用tshark,分析已生成的流量。下面这个命令搜索前往或来自2.x.yy.6 IP地址的流量:
$ tshark -r nmap.pcap -R "ip.src == 2.x.yy.6 || ip.dst == 2.x.yy.6" 712 3.237125000 109.zz.yyy.253 -> 2.x.yy.6 ICMP 42 Echo (ping) request id=0xa690, seq=0/0, ttl=54 1420 5.239804000 109.zz.yyy.253 -> 2.x.yy.6 ICMP 42 Echo (ping) request id=0x699a, seq=0/0, ttl=49 1432 5.240111000 109.zz.yyy.253 -> 2.x.yy.6 TCP 58 41242 > https [SYN] Seq=0 Win=1024 Len=0 MSS=1460 1441 5.296861000 2.x.yy.6 -> 109.zz.yyy.253 ICMP 60 Timestamp reply id=0x0549, seq=0/0, ttl=57
正如你所见,只要存在来自2.x.yy.6的响应数据包(1441),就足以让Nmap认为该主机是正常的;因此,不需要对该IP进行任何的额外测试了。
现在,不妨看一下被认为宕机(down)的IP地址的流量:
$ tshark -r nmap.pcap -R "ip.src == 2.x.yy.2 || ip.dst == 2.x.yy.2" 708 3.236922000 109.zz.yyy.253 -> 2.x.yy.2 ICMP 42 Echo (ping) request id=0xb194, seq=0/0, ttl=59 1407 5.237255000 109.zz.yyy.253 -> 2.x.yy.2 ICMP 42 Echo (ping) request id=0x24ed, seq=0/0, ttl=47 1410 5.237358000 109.zz.yyy.253 -> 2.x.yy.2 TCP 58 41242 > https [SYN] Seq=0 Win=1024 Len=0 MSS=1460 1413 5.237448000 109.zz.yyy.253 -> 2.x.yy.2 TCP 54 41242 > http [ACK] Seq=1 Ack=1 Win=1024 Len=0 1416 5.237533000 109.zz.yyy.253 -> 2.x.yy.2 ICMP 54 Timestamp request id=0xf7af, seq=0/0, ttl=51 1463 5.348871000 109.zz.yyy.253 -> 2.x.yy.2 ICMP 54 Timestamp request id=0x9d7e, seq=0/0, ttl=39 1465 5.349006000 109.zz.yyy.253 -> 2.x.yy.2 TCP 54 41243 > http [ACK] Seq=1 Ack=1 Win=1024 Len=0 1467 5.349106000 109.zz.yyy.253 -> 2.x.yy.2 TCP 58 41243 > https [SYN] Seq=0 Win=1024 Len=0 MSS=1460
由于ICMP数据包没有收到回应,Nmap发送HTTP数据包和HTTPS数据包,对2.x.yy.2 IP地址进行更多次尝试,可是依然没有一次成功。之所以出现这种情况,是因为Nmap给标准的ping(ICMP协议)增添了智能:万一ICMP请求由于某种原因而被阻挡,试一试几个常见的TCP端口。
借助下面这个命令,就能找到已发送ICMP数据包的总数:
$ tshark -r nmap.pcap -R "icmp" | grep "2.x" | wc -l 233
显示特定协议的统计数字
tshark让你可以显示关于某个特定协议的有用的统计数字。下面这个命令显示了关于HTTP协议的统计数字,使用含有网络数据的现有文件:
$ tshark -q -r http.pcap -R http -z http,tree ===================================================== HTTP/Packet Counter value rate percent ----------------------------------------------------- Total HTTP Packets 118 0.017749 HTTP Request Packets 66 0.009928 55.93% GET 66 0.009928 100.00% HTTP Response Packets 52 0.007822 44.07% ???: broken 0 0.000000 0.00% 1xx: Informational 0 0.000000 0.00% 2xx: Success 51 0.007671 98.08% 200 OK 51 0.007671 100.00% 3xx: Redirection 0 0.000000 0.00% 4xx: Client Error 1 0.000150 1.92% 404 Not Found 1 0.000150 100.00% 5xx: Server Error 0 0.000000 0.00% Other HTTP Packets 0 0.000000 0.00% =====================================================
所有工作由-z选项和-q选项来完成,前者用于计算统计数字,后者用于禁止根据每个数据包输出信息。-R选项在进行其他任何处理之前丢弃了不匹配指定过滤器的所有数据包。
下面是另一个有用的命令,显示了协议层次结构方面的统计数字:
$ tshark -nr ~/var/http.pcap -qz "io,phs"
你本人可以试一试,看看输出结果!
总结
如果你深入了解了显示过滤器,并且通晓TCP/IP和网络,那么借助tshark或Wireshark,与网络有关的问题将不再是问题。
掌握tshark需要花点时间,不过我认为这个时间值得一花。
参考资源
tshark:http://www.wireshark.org/docs/man-pages/tshark.html
Wireshark:http://www.wireshark.org
显示过滤器参考网站:http://www.wireshark.org/docs/dfref