tcpdump

TCP/IP协议

tcpdump使用范例

# 调试keepalived/lvs时,抓包分析:
# 把125.70.148.77改成你自己的IP,避免远程登录的流量。
tcpdump -n -i bond0 -s 0 -l -w - 'not host 125.70.148.77'|strings|more
tcpdump -n -i bond0 -s 0 -l -w - 'not host 125.70.148.77'
tcpdump -n -i bond0 -s 0 -l 'not host 125.69.149.152'|grep VRRP

# 截取eth1,端口号6881的tcp数据包。数据文件保存为test.pcap。
tcpdump -w test.pcap -i eth1 tcp port 6881

# 同时截取udp端口号33210和33220的数据包呢?
tcpdump -w test.pcap -i eth1 tcp port 6881 or udp \( 33210 or 33220 \)

# 显示指定目标ip的、端口不为80、2222的流量
tcpdump -i eth0 'dst 118.123.242 and ! port 80 and ! port 2222'
tcpdump -i eth0 'dst 118.123.242 and ( port 80 or port 8008)'

# 读取数据包文件(-nn不做名称转换,r读取包):
tcpdump -nnr test.pcap
# 添加 -tttt 选项使时间戳格式更加可读。
tcpdump -ttttnnr test.pcap
# 读取数据包中所有内容,转换为文本形式
tcpdump -ttttnnr test.pcap -w -|strings|more

cat test.pcap|tcpdump -ttttnr -|more
cat test.pcap|tcpdump -s 0 -X -ttttnr -|more

# 显示数据内容
tcpdump -s 0 -X -ttttnnr test.pcap|more

# 有些版本的tcpdump允许指定端口范围,下述指令为针对一定端口范围截取数据。
tcpdump tcp portrange 20-24

# 显示所有非80、2222的tcp流量:
tcpdump -i eth0 'tcp and ! port 80 and ! port 2222'

# 显示dns流量:
tcpdump -i eth1 'udp port 53'

# 显示所有ipv4 http、端口为80的流量?
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

# 显示所有到202.54.1.5的FTP会话:
tcpdump -i eth1 'dst 202.54.1.5 and (port 21 or 20)'

# 显示192.168.1.5的所有http会话:
tcpdump -ni eth0 'dst 192.168.1.5 and tcp and port http'

# 记录到文件(记录可使用wireshark查看):
tcpdump -n -i eth1 -s 0 -w output.txt src or dst port 80

# 抓取nginx与fcgi之间的数据包:
tcpdump -i lo -w - -s 1500 '(src host 127.0.0.1 and (src or dst port 8004  or src or dst port 8005))'|strings

# 指定主机、端口
tcpdump -n -s 0 -i wlan0 -w - 'host 115.182.65.216 and port 8005'
tcpdump -n -s 0 -i wlan0 -w - 'host 118.123.242.105 and port 9099'
tcpdump -nn -s 0 -i eth0 -w tcp5010_20131021_1.tcpdump tcp port 5010

TCPDUMP的使用

命令格式

选项介绍

选项 说明
-a 将网络地址和广播地址转变成名字;
-d 将匹配信息包的代码以人们能够理解的汇编格式给出;
-dd 将匹配信息包的代码以c语言程序段的格式给出;
-ddd 将匹配信息包的代码以十进制的形式给出;
-e 在输出行打印出数据链路层的头部信息;
-f 将外部的Internet地址以数字的形式打印出来;
-l 使标准输出变为缓冲行形式;
-n 不把网络地址转换成名字;
-t 在输出的每一行不打印时间戳;
-v 输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
-vv 输出详细的报文信息;
-c 在收到指定的包的数目后,tcpdump就会停止;
-F 从指定的文件中读取表达式,忽略其它的表达式;
-i 指定监听的网络接口;
-r 从指定的文件中读取包(这些包一般通过-w选项产生);
-w 直接将包写入文件中,并不分析和打印出来;
-T 将监听到的包直接解释为指定的类型的报文,常见的类型有rpc(远程过程调用)和snmp(简单网络管理协议)

表达式

表达式是一个逻辑表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会 被截获。

在表达式中一般如下几种类型的关键字:

一种是关于类型的关键字,主要包括host,net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明202.0.0.0是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是host.

第二种是确定传输方向的关键字,主要包括src,dst,dst or src,dst and src,这些关键字指明了传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是210.27.48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0 。如果没有指明方向关键字,则缺省是src or dst关键字。

第三种是协议的关键字,主要包括fddi,ip ,arp,rarp,tcp,udp等类型。Fddi指明是在FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是"ether"的别名,fddi和e ther具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。

其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会监听所有协议的信息包。

除了这三种类型的关键字之外,其他重要的关键字如下:gateway, broadcast,less,greater。

还有三种逻辑运算,

  1. 非运算 'not ' '! '
  2. 与运算 'and','&&'
  3. 或运算 'or' ,'||'

这些关键字可以组合起来构成强大的组合条件来满足人们的需要,下面举几个例子来说明。

例子

tcpdump host 210.27.48.1

tcpdump host 210.27.48.1 and \(210.27.48.2 or 210.27.48.3\)

  1. 如果想要获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包,使用命令:

tcpdump ip host 210.27.48.1 and ! 210.27.48.2

  1. 如果想要获取主机210.27.48.1接收或发出的telnet包,使用如下命令:

tcpdump tcp port 23 host 210.27.48.1

输出结果介绍

下面我们介绍几种典型的tcpdump命令的输出信息

使用命令tcpdump --e host ice

ice 是一台装有linux的主机,她的MAC地址是0:90:27:58:af:1a

H219是一台装有SOLARIC的SUN工作站,它的MAC地址是8:0:20:79:5b:46

命令的输出结果如下所示:

21:50:12.847509 eth0 < 8:0:20:79:5b:46 0:90:27:58:af:1a ip 60: h219.33357 > ice.telnet 0:0(0) ack 22535 win 8760 (DF)

分析:

  1. 21:50:12 是显示的时间
  2. 847509 是ID号
  3. eth0 < 表示从网络接口eth0 接受该数据包
  4. eth0 > 表示从网络接口设备发送数据包
  5. 8:0:20:79:5b:46 是主机H219的MAC地址,它表明是从源地址H219发来的数据包
  6. 0:90:27:58:af:1a 是主机ICE的MAC地址,表示该数据包的目的地址是ICE
  7. ip 是表明该数据包是IP数据包,
  8. 60 是数据包的长度,
  9. h219.33357 > ice.telnet 表明该数据包是从主机H219的33357端口发往主机ICE的TELNET(23)端口
  10. ack 22535 表明对序列号是222535的包进行响应
  11. win 8760 表明发送窗口的大小是8760

使用命令#tcpdump arp

得到的输出结果是:

22:32:42.802509 eth0 > arp who-has route tell ice (0:90:27:58:af:1a)
22:32:42.802902 eth0 < arp reply route is-at 0:90:27:12:10:66 (0:90:27:58:af:1a)

分析:

  1. 22:32:42 时间戳
  2. 802509 ID号
  3. eth0 > 表明从主机发出该数据包
  4. arp 表明是ARP请求包
  5. who-has route tell ice 表明是主机ICE请求主机ROUTE的MAC地址
  6. 0:90:27:58:af:1a 是主机ICE的MAC地址。

用TCPDUMP捕获的TCP包的一般输出信息是:

src > dst: flags data-seqno ack window urgent options

  1. src > dst 表明从源地址到目的地址
  2. flags 是TCP包中的标志信息,S 是SYN标志, F(FIN), P(PUSH) , R(RST) "."(没有标记)
  3. data-seqno 是数据包中的数据的顺序号
  4. ack 是下次期望的顺序号
  5. window 是接收缓存的窗口大小
  6. urgent 表明数据包中是否有紧急指针
  7. options 是选项

用TCPDUMP捕获的UDP包的一般输出信息是:

route.port1 > ice.port2: udp lenth

UDP十分简单,上面的输出行表明从主机ROUTE的port1端口发出的一个UDP数据包到主机ICE的port2端口,类型是UDP, 包的长度是lenth

wireshark查看

要让wireshark能分析tcpdump的包,关键的地方是 -s 参数, 还有要保存为-w文件,例如下面的例子:

./tcpdump -i eth0 -s 0 -w SuccessC2Server.pcap host 192.168.1.20 # 抓该主机的所有包,在wireshark中过滤
./tcpdump -i eth0 'dst host 239.33.24.212' -w raw.pcap           # 抓包的时候就进行过滤

wireshark的过滤,很简单的,比如:

tcp.port eq 5541  
ip.addr eq 192.168.2.1

过滤出来后, 用fllow tcp 查看包的内容。

其他

混杂模式

TCP协议状态

TCP的状态 (SYN, FIN, ACK, PSH, RST, URG)

在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.

其中,对于我们日常的分析有用的就是前面的五个字段。它们的含义是:

其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,如果只是单个的一个SYN,它表示的只是建立连接。

TCP的几次握手就是通过这样的ACK表现出来的。

但SYN与FIN是不会同时为1的,因为前者表示的是建立连接,而后者表示的是断开连接。

RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。

一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;而当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。

PSH为1的情况,一般只出现在DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。

TCP的连接建立和连接关闭,都是通过请求-响应的模式完成的。

概念补充-TCP三次握手

TCP(Transmission Control Protocol)传输控制协议

TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;
第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;
第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。