- Match any traffic involving 192.168.1.1 as destination or source
# tcpdump -i eth1 host 192.168.1.1
不区分源地址和目的地址,过滤IP
- As soure only
# tcpdump -i eth1 src host 192.168.1.1
过滤源地址
- As destination only
# tcpdump -i eth1 dst host 192.168.1.1
过滤目的地址
Filtering ports :
-----------------
- Match any traffic involving port 25 as source or destination
# tcpdump -i eth1 port 25
不区分源端口和目的端口,过滤端口
- Source
# tcpdump -i eth1 src port 25
过滤源端口
- Destination
# tcpdump -i eth1 dst port 25
过滤目的端口
Network filtering :
-------------------
过滤网络
# tcpdump -i eth1 net 192.168
# tcpdump -i eth1 src net 192.168
# tcpdump -i eth1 dst net 192.168
Protocol filtering :
--------------------
过滤协议
# tcpdump -i eth1 arp
# tcpdump -i eth1 ip
# tcpdump -i eth1 tcp
# tcpdump -i eth1 udp
# tcpdump -i eth1 icmp
Let's combine expressions :
---------------------------
Negation : ! or "not" (without the quotes)
Concatanate : && or "and"
Alternate : || or "or"
- This rule will match any TCP traffic on port 80 (web) with 192.168.1.254 or 192.168.1.200 as destination host
# tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
过滤80端口的TCP协议,目的地址是254或200
- Will match any ICMP traffic involving the destination with physical/MAC address 00:01:02:03:04:05
# tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
过滤icmp协议,并且MAC地址为00:01:02:03:04:05
- Will match any traffic for the destination network 192.168 except destination host 192.168.1.200
# tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
过滤协议为TCP,目的网络为192.168的数据,这之中除去192.168.1.200的主机的数据
Advanced header filtering :
===========================
Before we continue, we need to know how to filter out info from headers
proto[x:y] : will start filtering from byte x for y bytes. ip[2:2] would filter bytes 3 and 4 (first byte begins by 0)
proto[x:y] & z = 0 : will match bits set to 0 when applying mask z to proto[x:y]
proto[x:y] & z !=0 : some bits are set when applying mask z to proto[x:y]
proto[x:y] & z = z : every bits are set to z when applying mask z to proto[x:y]
proto[x:y] = z : p[x:y] has exactly the bits set to z
Operators : >, <, >=, <=, =, !=
高级包头过滤
============
首先了解如何从包头过滤信息
proto[x:y] : 过滤从x 字节开始的y 字节数。比如ip[2:2]过滤出3、4 字节(第一
字节从0 开始排)
proto[x:y] & z = 0 : proto[x:y]和z 的与操作为0
proto[x:y] & z !=0 : proto[x:y]和z 的与操作不为0
proto[x:y] & z = z : proto[x:y]和z 的与操作为z
proto[x:y] = z : proto[x:y]等于z
操作符: >, <, >=, <=, =, !=
IP 头
This may not be clear in the first place but you'll find examples below involving these.
Of course, it is important to know what the protocol headers look like before diving into more advanced filters.
IP header
---------
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
I'll consider we are only working with the IPv4 protocol suite for these examples.
In an ideal world, every field would fit inside one byte. This is not the case, of course.
Are IP options set ?
--------------------
Let's say we want to know if the IP header has options set. We can't just try to filter out the 21st byte
because if no options are set, data start at the 21st byte. We know a "normal" header is usually 20 bytes
(160 bits) long. With options set, the header is longer than that. The IP header has the header
length field which we will filter here to know if the header is longer than 20 bytes.
+-+-+-+-+-+-+-+-+
|Version| IHL |
+-+-+-+-+-+-+-+-+
Usually the first byte has a value of 01000101 in binary.
通常第一个字节的二进制为01000101
Anyhow, we need to divide the first byte in half...
先把第一个字节分成二半
0100 = 4 in decimal. This is the IP version.代表IP的版本
0101 = 5 in decimal. This is the number of blocks of 32 bits in the headers. 5 x 32 bits = 160 bits or 20 bytes.报头长度,160个小b(bit)或是20个大B(字节)
The second half of the first byte would be bigger than 5 if the header had IP options set.
如果报头有IP选项设置,IHL将比5大
We have two ways of dealing with that kind of filters.
我们有两种方式处理过滤器
1. Either try to match a value bigger than 01000101. This would trigger matches for IPv4 traffic with IP options set,
but ALSO any IPv6 traffic !
当是IPV6的情况时,版本信息肯定是超过01000101,如果是带有IP选项设置的IPV4也有可能在版本信息中超过01000101
In decimal 01000101 equals 69.
01000101十进制为69
Let's recap how to calculate in decimal.
让我们来复习下在十进制中如何计算
0 : 0 \
1 : 2^6 = 64 \ First field (IP version)
0 : 0 /
0 : 0 /
-
0 : 0 \
1 : 2^2 = 4 \ Second field (Header length)
0 : 0 /
1 : 2^0 = 1 /
64 + 4 + 1 = 69
The first field in the IP header would usually have a decimal value of 69.
If we had IP options set, we would probably have 01000110 (IPv4 = 4 + header = 6), which in decimal equals 70.
如果进行IP选项设置,二进制有可能是01000110,十进制为70
This rule should do the job :这个规则应该这样设置
# tcpdump -i eth1 'ip[0] > 69'
Somehow, the proper way is to mask the first half/field of the first byte, because as mentionned earlier,
this filter would match any IPv6 traffic.
不管怎么样,这个方法来过滤第一字节的一半/全部,正像以前提到的那样,肯定可以适用于匹配IPV6的情况
2. The proper way : masking the first half of the byte
适合的方法:过滤一个字节的前面一半
0100 0101 : 1st byte originally 第一字节原来的样子
0000 1111 : mask (0x0f in hex or 15 in decimal). 0 will mask the values while 1 will keep the values intact. 0用过滤,1用来保留
=========
0000 0101 : final result 与操作以后的结果
The correct filter :正确的过滤表达式
# tcpdump -i eth1 'ip[0] & 15 > 5'
or
# tcpdump -i eth1 'ip[0] & 0x0f > 5'
DF bit (don't fragment) set ?
-----------------------------
fragment (which has the 2nd bit set to 0).
匹配MF标志(还有后续分片设置)?这个设置是用来匹配不是最后一个分片的数据报
匹配分片和最后一片
# tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
从第6个字节开始往后数2个字节大于0,并且第6个字节的十进制不等于64,这意味不是最后一个分片We can try to find if someone on our network is using traceroute by using something like this on the gateway :
在网关上,我们可以发现是否有人用traceroute这种类似的命令进行测试,设置一个比较小的TTL值进行发包
我们可以想像用十进制源和目的地址来进行过滤
我们也可以通过匹配第十个字节来过滤指定协议
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
value of 00000010 which equals 2 in decimal.
当我们只想过滤仅有SYN标志的包时,第14个字节的二进制是00000010,十进制是2
If no IP options are set.. the GET command will use the byte 20, 21 and 22
如查没有IP选项设置,GET命令将用到20、21和22三个字节
tcpdump 高级过滤技巧
===================
Sebastien Wains <sebastien -the at sign- wains -dot- be>
http://www.wains.be
$Id: tcpdump_advanced_filters.txt 33 2008-05-07 17:40:11Z sw $
http://www.wains.be/pub/networking/tcpdump_advanced_filters.txt
注意:
例子中都用-i 参数指定了抓取的网卡为eth1,实际使用时请自行变化。
翻译此文的目的是加深记忆,可能理解有偏差,建议看原文或man 手册。
注:由于大部分是翻译的,所以只是高级技巧,并非权威指南!
基本语法
========
过滤主机
--------
- 抓取所有经过eth1,目的或源地址是192.168.1.1 的网络数据
# tcpdump -i eth1 host 192.168.1.1
- 源地址
# tcpdump -i eth1 src host 192.168.1.1
- 目的地址
# tcpdump -i eth1 dst host 192.168.1.1
过滤端口
--------
- 抓取所有经过eth1,目的或源端口是25 的网络数据
# tcpdump -i eth1 port 25
- 源端口
# tcpdump -i eth1 src port 25
- 目的端口
# tcpdump -i eth1 dst port 25
网络过滤
--------
# tcpdump -i eth1 net 192.168
# tcpdump -i eth1 src net 192.168
# tcpdump -i eth1 dst net 192.168
协议过滤
--------
# tcpdump -i eth1 arp
# tcpdump -i eth1 ip
# tcpdump -i eth1 tcp
# tcpdump -i eth1 udp
# tcpdump -i eth1 icmp
常用表达式
----------
非: ! or "not" (去掉双引号)
且: && or "and"
或: || or "or"
- 抓取所有经过eth1,目的地址是192.168.1.254 或192.168.1.200 端口是80 的TCP 数据
# tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host
192.168.1.200)))'
- 抓取所有经过eth1,目标MAC 地址是00:01:02:03:04:05 的ICMP 数据
# tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
- 抓取所有经过eth1,目的网络是192.168,但目的主机不是192.168.1.200 的TCP 数据
# tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
高级包头过滤
============
首先了解如何从包头过滤信息
proto[x:y] : 过滤从x 字节开始的y 字节数。比如ip[2:2]过滤出3、4 字节(第一
字节从0 开始排)
proto[x:y] & z = 0 : proto[x:y]和z 的与操作为0
proto[x:y] & z !=0 : proto[x:y]和z 的与操作不为0
proto[x:y] & z = z : proto[x:y]和z 的与操作为z
proto[x:y] = z : proto[x:y]等于z
操作符: >, <, >=, <=, =, !=
IP 头
----
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
本文只针对IPv4。
IP 选项设置了吗?
----------------
“一般”的IP 头是20 字节,但IP 头有选项设置,不能直接从偏移21 字节处读取数据。IP
头
有个长度字段可以知道头长度是否大于20 字节。
+-+-+-+-+-+-+-+-+
|Version| IHL |
+-+-+-+-+-+-+-+-+
通常第一个字节的二进制值是:01000101,分成两个部分:
0100 = 4 表示IP 版本
0101 = 5 表示IP 头32 bit 的块数,5 x 32 bits = 160 bits or 20 bytes
如果第一字节第二部分的值大于5,那么表示头有IP 选项。
下面介绍两种过滤方法(第一种方法比较操蛋,可忽略):
1. 比较第一字节的值是否大于01000101,这可以判断IPv4 带IP 选项的数据和IPv6 的数
据。
01000101 十进制等于69,计算方法如下(小提示:用计算器更方便)
0 : 0 \
1 : 2^6 = 64 \ 第一部分(IP 版本)
0 : 0 /
0 : 0 /
-
0 : 0 \
1 : 2^2 = 4 \ 第二部分(头长度)
0 : 0 /
1 : 2^0 = 1 /
64 + 4 + 1 = 69
如果设置了IP 选项,那么第一自己是01000110(十进制70),过滤规则:
# tcpdump -i eth1 'ip[0] > 69'
IPv6 的数据也会匹配,看看第二种方法。
2. 位操作
0100 0101 : 第一字节的二进制
0000 1111 : 与操作
=========
0000 0101 : 结果
正确的过滤方法
# tcpdump -i eth1 'ip[0] & 15 > 5'
或者
# tcpdump -i eth1 'ip[0] & 0x0f > 5'
分片标记
--------
当发送端的MTU 大于到目的路径链路上的MTU 时就会被分片,这段话有点拗口,权威的
请参考《TCP/IP 详解》。唉,32 借我的书没还,只能凑合写,大家记得看书啊。
分片信息在IP 头的第七和第八字节:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit 0: 保留,必须是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片.
Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片.
Fragment Offset 字段只有在分片的时候才使用。
要抓带DF 位标记的不分片的包,第七字节的值应该是:
01000000 = 64
# tcpdump -i eth1 'ip[6] = 64'
抓分片包
--------
- 匹配MF,分片包
# tcpdump -i eth1 'ip[6] = 32'
最后分片包的开始3 位是0,但是有Fragment Offset 字段。
- 匹配分片和最后分片
# tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
测试分片可以用下面的命令:
ping -M want -s 3000 192.168.1.1
匹配小TTL
---------
TTL 字段在第九字节,并且正好是完整的一个字节,TTL 最大值是255,二进制为11111111。
可以用下面的命令验证一下:
$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range
+-+-+-+-+-+-+-+-+
| Time to Live |
+-+-+-+-+-+-+-+-+
- 在网关可以用下面的命令看看网络中谁在使用traceroute
# tcpdump -i eth1 'ip[8] < 5'
抓大于X 字节的包
---------------
- 大于600 字节
# tcpdump -i eth1 'ip[2:2] > 600'
更多的IP 过滤
------------
首先还是需要知道TCP 基本结构,再次推荐《TCP/IP 详解》,卷一就够看的了,避免
走火入魔。
TCP 头
-----
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 抓取源端口大于1024 的TCP 数据包
# tcpdump -i eth1 'tcp[0:2] > 1024'
- 匹配TCP 数据包的特殊标记
TCP 标记定义在TCP 头的第十四个字节
+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+
重复一下TCP 三次握手,两个主机是如何勾搭的:
1. 源发送SYN
2. 目标回答SYN, ACK
3. 源发送ACK
没女朋友的童鞋要学习一下:
1. MM,你的手有空吗?-_-
2. 有空,你呢?~_~
3. 我也有空*_*
失败的loser 是酱紫的:
1. MM,这是你掉的板砖吗?(SYN)
2. 不是,找拍啊?(RST-ACK)
- 只抓SYN 包,第十四字节是二进制的00000010,也就是十进制的2
# tcpdump -i eth1 'tcp[13] = 2'
- 抓SYN, ACK (00010010 or 18)
# tcpdump -i eth1 'tcp[13] = 18'
- 抓SYN 或者SYN-ACK
# tcpdump -i eth1 'tcp[13] & 2 = 2'
用到了位操作,就是不管ACK 位是啥。
- 抓PSH-ACK
# tcpdump -i eth1 'tcp[13] = 24'
- 抓所有包含FIN 标记的包(FIN 通常和ACK 一起,表示幽会完了,回见)
# tcpdump -i eth1 'tcp[13] & 1 = 1'
- 抓RST(勾搭没成功,伟大的greatwall 对她认为有敏感信息的连接发RST 包,典型的棒
打鸳鸯)
# tcpdump -i eth1 'tcp[13] & 4 = 4'
详细描述了TCP 各种状态的标记,方便分析。
吴吖哦注
--------
tcpdump 考虑了一些数字恐惧症者的需求,提供了部分常用的字段偏移名字:
icmptype (ICMP 类型字段)
icmpcode (ICMP 符号字段)
tcpflags (TCP 标记字段)
ICMP 类型值有:
icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo,
icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp,
icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply
TCP 标记值:
tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg
这样上面按照TCP 标记位抓包的就可以写直观的表达式了:
- 只抓SYN 包
# tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'
- 抓SYN, ACK
# tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'
抓SMTP 数据
----------
# tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'
抓取数据区开始为"MAIL"的包,"MAIL"的十六进制为0x4d41494c。
抓HTTP GET 数据
--------------
# tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'
"GET "的十六进制是47455420
抓SSH 返回
---------
# tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'
"SSH-"的十六进制是0x5353482D
# tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2]
= 0x312E)'
抓老版本的SSH 返回信息,如"SSH-1.99.."
吴吖哦注
--------
如果是为了查看数据内容,建议用tcpdump -s 0 -w filename 把数据包都保存下来,
然后用wireshark 的Follow TCP Stream/Follow UDP Stream 来查看整个会话的内容。
"-s 0"是抓取完整数据包,否则默认只抓68 字节。
另外,用tcpflow 也可以方便的获取TCP 会话内容,支持tcpdump 的各种表达式。
UDP 头
-----
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
| |
| DATA ... |
+-----------------------------------+
- 抓DNS 请求数据
# tcpdump -i eth1 udp dst port 53
其他
----
-c 参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C 还是
抓的太多,于是可以用-c 参数指定抓多少个包。
# time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null
上面的命令计算抓10000 个SYN 包花费多少时间,可以判断访问量大概是多少。
原文地址:http://blog.csdn.net/lepton126/article/details/8162926