全部博文(403)
分类: LINUX
2006-11-22 13:59:06
Tcpdump 打印出 在某个 网络界面 上, 匹配 布尔表达式 expression 的 报头.
对于 SunOS 的 nit 或 bpf 界面: 要 运行 tcpdump , 你 必须 有 /dev/nit 或 /dev/bpf* 的 读访问 权限.
对于 Solaris 的 dlpi: 你 必须 有 网络仿真设备 (network pseudo device), 如 /dev/le 的 读访问 权限.
对于 HP-UX 的 dlpi: 你 必须 是 root, 或者 把它 安装成 root 的 设置uid 程序. 对于 IRIX 的 snoop: 你 必须 是 root, 或者 把它 安装成 root 的 设置uid 程序. 对于 Linux: 你 必须 是 root, 或者 把它 安装成 root 的 设置uid 程序.
对于 Ultrix 和 Digital UNIX: 一旦 超级用户 使用 (8) 开放了 promiscuous 操作模式 (promiscuous-mode), 任何用户 都可以 运行 tcpdump.
对于 BSD: 你 必须 有 /dev/bpf* 的 读访问 权限.
expression 一个或多个 原语 (primitive) 组成. 原语 通常 由 一个 标识 (id, 名称或数字), 和 标识 前面的 一个或多个 修饰子(qualifier) 组成. 修饰子 有 三种 不同的类型:
[`fddi' 实际上 是 `ether' 的 别名; 分析器 把 它们 视为 ``用在 指定 网络接口 上的 数据链路层.'' FDDI 报头 包含 类似于 以太协议的 源目地址, 而且 通常 包含 类似于 以太协议 的 报文类型, 因此 你 可以过滤 FDDI 域, 就象 分析 以太协议 一样. FDDI 报头 也 包含 其他 域, 但是你 不能 在 过滤器 表达式 里 显式描述.]
作为 上述 的 补充, 有一些 特殊的 `原语' 关键字, 它们 不同于 上面的模式: gateway, broadcast, less, greater 和 数学表达式. 这些 在 后面 有 叙述.
更复杂的 过滤器表达式 可以 通过 and, or 和 not 连接 原语 来 组建. 例如, `host foo and not port ftp and not port ftp-data'. 为了少敲点键, 可以忽略 相同的 修饰子. 例如, `tcp dst port ftp or ftp-data or domain' 实际上 就是 `tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.
允许的 原语 有:
ip host host它等价于:
ether proto \ip and host host如果 host 是 拥有 多个 IP 地址 的 主机名, 它的 每个地址 都会 被查验.
ether host ehost and not host host对于 host / ehost, 它既可以是 名字, 也可以是 数字.)
tcp src port port它 只匹配 源端口 是 port 的 TCP 报文.
len <= length.
len >= length.
ether proto p的 简写 形式, 其中 p 为 上述 协议 的 一种.
ether proto p的 简写 形式, 其中 p 为 上述 协议 的 一种. 注意 tcpdump 目前 不知道 如何 分析 这些 协议.
ip proto p的 简写 形式, 其中 p 为 上述 协议 的 一种.
proto [ expr : size ]Proto 是 ether, fddi, ip, arp, rarp, tcp, udp, or icmp 之一, 同时 也指出了 下标 操作 的协议层. expr 给出 字节单位 的 偏移量, 该 偏移量 相对于 指定的 协议层. Size 是 可选项, 指出 感兴趣的 字节数; 它可以 是 1, 2, 4, 缺省为 1 字节. 由 关键字 len 给出的 长度运算符 指明 报文 的 长度.
例如, `ether[0] & 1 != 0' 捕捉 所有的 多目传送 报文. 表达式 `ip[0] & 0xf != 5' 捕捉 所有 带 可选域 的 IP 报文. 表达式 `ip[6:2] & 0x1fff = 0' 只捕捉 未分片 和 片偏移为0 的 数据报. 这种 检查 隐含在 tcp 和 udp 下标操作 中. 例如, tcp[0] 一定是 TCP 报头 的 第一个 字节, 而不是 其中 某个 IP片 的 第一个 字节.
原语 可以 用 下述 方法 结合使用:
取反操作 有 最高优先级. 或操作 和 连结操作 有 相同的 优先级, 运算时 从左到右 结合. 注意 连结操作 需要 显式的 and 算符, 而不是 并列放置.
如果 给出 标识符, 但没给 关键字, 那么 暗指 最近使用 的 关键字. 例如,
not host vs and ace作为
not host vs and host ace的 简写形式, 不应该 和
not ( host vs or ace )混淆.
表达式参数 可以 作为 单个 参数 传给 tcpdump, 也可以 作为 复合参数, 后者 更方便 一些. 一般说来, 如果 表达式 包含 Shell 元字符(metacharacter), 传递 单个 括起来的 参数 要 容易 一些. 复合参数 在 被解析前 用 空格 联接 一起.
显示 所有 进出 sundown 的 报文:
tcpdump host sundown
显示 helios 和 主机 hot, ace 之间 的 报文 传送:
tcpdump host helios and \( hot or ace \)
显示 ace 和 除了 helios 以外的 所有 主机 的 IP报文:
tcpdump ip host ace and not helios
显示 本地的主机 和 Berkeley的主机 之间 的 网络数据:
tcpdump net ucb-ether
显示 所有 通过 网关 snup 的 ftp 报文 (注意 这个 表达式 被 单引号 括起, 防止 shell 解释 园括弧):
tcpdump 'gateway snup and (port ftp or ftp-data)'
显示 既不是 来自 本地主机, 也不是 传往 本地主机 的 网络数据 (如果 你 把 网关 通往 某个 其他网络, 这个 做法 将不会 把 数据 发往 你的本地网络).
tcpdump ip and not net localnet
显示 每个 TCP会话 的 起始 和 结束 报文 (SYN 和 FIN 报文), 而且 会话方 中有一个 远程主机.
tcpdump 'tcp[13] & 3 != 0 and not src and dst net localnet'
显示 经过 网关 snup 中 大于 576 字节的 IP 数据报:
tcpdump 'gateway snup and ip[2:2] > 576'
显示 IP 广播 或 多目传送 的 数据报, 这些 报文 不是 通过 以太网 的 广播 或 多目传送 形式 传送的:
tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'
显示 所有 不是 回响请求/应答 的 ICMP 报文 (也就是说, 不是 ping 报文):
tcpdump 'icmp[0] != 8 and icmp[0] != 0"
tcpdump 的 输出格式 取决于 协议. 下面的 描述 给出 大多数 格式 的简要说明 和 范例.
链路层报头 (Link Level Headers)
如果 给出 '-e' 选项 就 显示 链路层报头. 在 以太网上, 显示 报文的 源目地址, 协议 和 报文长度.
在 FDDI 网络上, '-e' 选项 导致 tcpdump 显示出 `帧控制(frame control)' 域, 源目地址 和 报文长度. (`帧控制' 域 负责 解释 其余的 报文. 普通报文 (比如说 载有 IP数据报) 是 `异步' 报文, 优先级 介于 0 到 7; 例如, `async4'. 这些 被认为 载有 802.2 逻辑链路控制(LLC) 报文; 如果 它们 不是 ISO 数据报 或者 所谓的 SNAP 报文, 就显示出 LLC 报头.
(注意: 以下 描述中 假设 你 熟悉 RFC-1144 中说明的 SLIP 压缩算法.)
在 SLIP 链路上, tcpdump 显示出 方向指示 (``I'' 指 inbound, ``O'' 指 outbound), 报文类型 和 压缩信息. 首先显示的 是 报文类型. 有三种 类型 ip, utcp 和 ctcp. 对于 ip 报文 不再 显示 更多的 链路信息. 对于 TCP 报文, 在 类型 后面 显示 连接标识. 如果 报文 是 压缩过的, 就显示出 编码的报头. 特殊 情形 以 *S+n 和 *SA+n 的 形式 显示, 这里的 n 是 顺序号 (或顺序号 及其 确认) 发生 的 改变 总和. 如果 不是 特殊 情形, 就显示 0 或 多少个 改变. 改变 由 U (urgent pointer), W (window), A (ack), S (sequence number) 和 I (packet ID) 指明, 后跟 一个 变化量(+n or -n), 或 另一个 值(=n). 最后显示 报文中 的 数据总和, 以及 压缩报头 的 长度.
例如, 下面一行 显示了 一个 传出的 压缩的 TCP 报文, 有一个 隐含的 连接标识; 确认(ack)的 变化量是 6, 顺序号 是 49, 报文ID 是 6; 有三个字节的数据 和六个字节 的 压缩报头:
O ctcp * A+6 S+49 I+6 3 (6)
ARP/RARP 报文
Arp/rarp 报文 的 输出 显示 请求类型 及其 参数. 输出格式 倾向于 能够 自我解释. 这里 是一个 简单的例子, 来自 主机 rtsg 到 主机 csam 的 'rlogin' 开始 部分:
arp who-has csam tell rtsg arp reply csam is-at CSAM
如果 用 tcpdump -n 看上去 要 清楚一些:
arp who-has 128.3.254.6 tell 128.3.254.68 arp reply 128.3.254.6 is-at 02:07:01:00:01:c4
如果 用 tcpdump -e, 可以 看到 实际上 第一个 报文 是 广播, 第二个报文 是 点到点 的:
RTSG Broadcast 0806 64: arp who-has csam tell rtsg CSAM RTSG 0806 64: arp reply csam is-at CSAM
TCP 报文
(注意: 以下的描述中 假设 你 熟悉 RFC-793 中 说明的 TCP 协议, 如果 你不了解 这个 协议, 无论是 本文 还是 tcpdump 都对你 用处 不大)
一般说来 tcp 协议的 输出格式是:
src > dst: flags data-seqno ack window urgent options
Src, dst 和 flags 肯定 存在. 其他域 依据 报文的 tcp 报头 内容, 只输出 有必要 的 部分.
下面 是 从 主机 rtsg rlogin 到 主机 csam 的 开始部分.
rtsg.1023 > csam.login: S 768512:768512(0) win 4096csam.login > rtsg.1023: S 947648:947648(0) ack 768513 win 4096 rtsg.1023 > csam.login: . ack 1 win 4096 rtsg.1023 > csam.login: P 1:(1) ack 1 win 4096 csam.login > rtsg.1023: . ack 2 win 4096 rtsg.1023 > csam.login: P 2:21(19) ack 1 win 4096 csam.login > rtsg.1023: P 1:(1) ack 21 win 4077 csam.login > rtsg.1023: P 2:(1) ack 21 win 4077 urg 1 csam.login > rtsg.1023: P 3:(1) ack 21 win 4077 urg 1
Csam 用类似的 形式 应答, 只是 增加了 一个 对 rtsg SYN 的 捎带确认. 然后 Rtsg 确认 csam 的 SYN. `.' 意味着 没有 设置 标志. 这个 报文 不包含 数据, 因此 也就 没有 数据的流序号. 注意这个 确认流序号 是一个 小整数(1). 当 tcpdump 第一次 发现 一个 tcp 会话时, 它 显示 报文 携带的 流序号. 在 随后收到的 报文里, 它 显示 当前报文 和 最初那个 报文 的 流序号 之 差. 这 意味着 从第一个报文 开始, 以后的 流序号 可以 理解成 数据流 中的 相对位移 as relative byte positions in the conversation's data stream (with the first data byte each direction being `1'). `-S' 选项 能够 改变 这个 特性, 直接 显示 原始的 流序号.
在 第六行, rtsg 传给 csam 19 个字节 的 数据 (字节 2 到 20). 报文中 设置了 PUSH 标志. 第七行 csam 表明 它 收到了 rtsg 的 数据, 字节序号是 21, 但不包括 第21个 字节. 显然 大多数 数据 在 socket 的 缓冲区内, 因为 csam 的 接收窗口 收到的 数据小于 19 个 字节. 同时 csam 向 rtsg 发送了 一个字节 的 数据. 第八和第九行 显示 csam 发送了 两个字节 的 紧急数据 到 rtsg.
如果 捕捉区 设置的 过小, 以至于 tcpdump 不能 捕捉到 完整的 TCP 报头, tcpdump 会 尽可能的 翻译 已捕获的 部分, 然后 显示 ``[|tcp]'', 表明 无法 翻译 其余 部分. 如果 报头 包含 一个 伪造的 选项 (one with a length that's either too small or beyond the end of the header), tcpdump 显示 ``[bad opt]'' 并且 不再 翻译 其他 选项部分 (因为 它 不可能 判断出从哪儿 开始). 如果 报头长度 表明 存在 选项, 但是 IP 数据报 长度 不够, 不可能 真的 保存 选项, tcpdump 就显示 ``[bad hdr length]''.
UDP 报文
UDP 格式 就象 这个 rwho 报文 显示的:
actinide.who > broadcast.who: udp 84
某些 UDP 服务 能够 识别出来(从 源目端口号 上), 因而 显示出 更高层的 协议信息. 特别是 域名服务请求(RFC-1034/1035) 和 NFS 的 RPC 调用(RFC-1050).
UDP 域名服务请求 (Name Server Requests)
(注意: 以下的描述中 假设 你 熟悉 RFC-1035 说明的 域名服务协议. 如果你 不熟悉 这个协议, 下面的内容 就象是 天书.)
域名服务请求 的 格式 是
src > dst: id op? flags qtype qclass name (len) h2opolo.1538 > helios.domain: 3+ A? ucbvax.berkeley.edu. (37)
Tcpdump 会检查 一些 不规则 情况, 相应的 结果 作为 补充域 放在 方括号内: 如果 某个 查询 包含 回答, 名字服务 或 管理机构部分, 就把 ancount, nscount, 或 arcount 显示成 `[na]', `[nn]' 或 `[nau]', 这里的 n 代表 相应的 数量. 如果 在 第二和第三字节 中, 任何一个 回答位(AA, RA 或 rcode) 或 任何一个 `必须为零' 的位 被 置位, 就显示 `[b2&3=x]', 这里的 x 是 报头 第二和第三字节 的 16进制数.
UDP 名字服务回答
名字服务回答的 格式 是
src > dst: id op rcode flags a/n/au type class data (len) helios.domain > h2opolo.1538: 3 3/3/7 A 128.32.137.3 (273) helios.domain > h2opolo.1537: 2 NXDomain* 0/1/0 (97)
在第二个例子里, helios 对 标识为2 的 询问 作出 域名不存在 (NXDomain) 的 回答, 没有 回答记录, 一个 名字服务记录, 而且 没有 管理结构.
`*' 表明 设置了 权威回答(authoritative answer). 由于 没有 回答记录, 这里就 不显示 type, class 和 data.
其他 标志 字符 可以 显示为 `-' (没有设置递归有效(RA)) 和 `|' (设置 消息截短(TC)). 如果 `问题' 部分 没有 有效的 内容, 就 显示 `[nq]'.
注意 名字服务的 询问和回答 一般说来 比较大, 68 字节的 snaplen 可能无法 捕捉到 足够的 报文内容. 如果 你 的确 在 研究 名字服务 的 情况, 可以使用 -s 选项 增大 捕捉缓冲区. `-s 128' 应该 效果 不错了.
NFS 请求和响应
Sun NFS (网络文件系统) 的 请求和响应 显示格式 是:
src.xid > dst.nfs: len op args src.nfs > dst.xid: reply stat len op results sushi.6709 > wrl.nfs: 112 readlink fh 21,24/10.73165 wrl.nfs > sushi.6709: reply ok 40 readlink "../var" sushi.201b > wrl.nfs: 144 lookup fh 9,74/4096.6878 "xcolors" wrl.nfs > sushi.201b: reply ok 128 lookup fh 9,74/4134.3150
在第三行, sushi 请求 wrl 在 目录文件 9,74/4096.6878 中 查找 `xcolors'. 注意 数据的 打印格式 取决于 操作类型. 格式 应该是 可以自我说明的.
给出 -v (verbose) 选项 可以 显示 附加信息. 例如:
sushi.1372a > wrl.nfs: 148 read fh 21,11/12.195 8192 bytes @ 24576 wrl.nfs > sushi.1372a: reply ok 1472 read REG 100664 ids 417/0 sz 29388
如果再给一个 -v 选项 (-vv), 还能 显示 更多的细节.
注意 NFS 请求 的 数据量 非常大, 除非 增加 snaplen, 否则 很多细节 无法显示. 试一试 `-s 192' 选项.
NFS 应答报文 没有明确 标明 RPC 操作. 因此 tcpdump 保留有 ``近来的'' 请求 记录, 根据 交易号 匹配 应答报文. 如果 应答报文 没有 相应的 请求报文, 它 就 无法分析.
KIP Appletalk (UDP 上的 DDP)
Appletalk DDP 报文 封装在 UDP 数据报 中, 解包后 按 DDP 报文 转储 (也就是说, 忽略 所有的 UDP 报头 信息). 文件 /etc/atalk.names 用来 把 appletalk 网络和节点号 翻译成 名字. 这个文件 的 行格式 是
number name 1.254 ether 16.1 icsd-net 1.254.110 ace
Appletalk 地址 按 这个格式 显示
net.host.port 144.1.209.2 > icsd-net.112.220 office.2 > icsd-net.112.220 jssmag.149.235 > icsd-net.2
Tcpdump 可以 翻译 NBP (名字联结协议) 和 ATP (Appletalk 交互协议) 的 报文内容. 其他协议 只转储 协议名称 (或号码, 如果 还 没给 这个协议 注册 名称) 和 报文大小.
NBP 报文 的 输出格式 就象 下面的 例子:
icsd-net.112.220 > jssmag.2: nbp-lkup 190: "=:LaserWriter@*" jssmag.209.2 > icsd-net.112.220: nbp-reply 190: "RM1140:LaserWriter@*" 250 techpit.2 > icsd-net.112.220: nbp-reply 190: "techpit:LaserWriter@*" 186
ATP 报文 格式 如 下例 所示:
jssmag.209.165 > helios.132: atp-req 12266<0-7> 0xae030001 helios.132 > jssmag.209.165: atp-resp 12266:0 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:1 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:2 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:4 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:6 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp*12266:7 (512) 0xae040000 jssmag.209.165 > helios.132: atp-req 12266<3,5> 0xae030001 helios.132 > jssmag.209.165: atp-resp 12266:3 (512) 0xae040000 helios.132 > jssmag.209.165: atp-resp 12266:5 (512) 0xae040000 jssmag.209.165 > helios.132: atp-rel 12266<0-7> 0xae030001 jssmag.209.133 > helios.132: atp-req* 12267<0-7> 0xae030002
Helios 用 8 个 512字节 的 报文 应答. 跟在 交易号 后面的 `:digit' 给出了 交易过程中 报文的 序列号, 括弧内的 数字 是 报文的 数据量, 不包括 atp 报头. 报文 7 的 `*' 表明 设置了 EOM 位.
然后 Jssmag.209 请求 重传 第 3 & 5 报文. Helios 做了 重传后 jssmag.209 结束 这次 交易. 最后, jssmag.209 发起 下一次 交易请求. 请求中的 `*' 表明 没有 设置 XO (只有一次) 位.
IP 分片
分片的 Internet 数据报 显示为
(frag id:size@offset+) (frag id:size@offset)
Id 是 分片 标识号. Size 是 分片 大小 (字节), 不包括 IP 报头. Offset 是 该分片 在 原数据报 中 的 偏移 (单位是字节).
每一个 分片 的 信息 都可以 打印出来. 第一个 分片 包含了 高层 协议 报头, 显示 协议信息 后 显示 分片 的 信息. 第一个 分片 以后的 分片 不再 含有高层协议 报头, 所以 在 源目地址 后面 只显示 分片 信息. 例如, 下面是 从 arizona.edu 到 lbl-rtsg.arpa 的 一部分 ftp 传输, 途经的 CSNET 看上去 处理不了 576 字节的 数据报:
arizona.ftp-data > rtsg.1170: . 1024:1332(308) ack 1 win 4096 (frag 595a:328@0+) arizona > rtsg: (frag 595a:204@328) rtsg.1170 > arizona.ftp-data: . ack 1536 win 2560
如果 报文的 IP 标有 不要分片 标志, 显示时 在尾部 加上 (DF).
时戳
缺省情况下, 所有 输出行 的 前面 都有 时戳. 时戳 就是 当前时间, 显示格式为
hh:mm:ss.frac
当前 版本 可以 从 匿名ftp 获得:
NIT 不允许 监视 你自己的 传出数据, BPF 可以. 我们 建议 你 使用 后者.
应该 试着 重组 IP 分片, 至少可以 为 更高层的 协议 计算出 正确的 长度.
名字服务逆向询问 转储的 不正确: 打印出 (空的)问题部分, 而实际上 询问 放在了回答部分. 有人 认为 这种 逆向询问 本身就是 bug, 应该 修改 产生问题 的 程序, 而非 tcpdump.
苹果 Ethertalk DDP 的 报文 应该 象 KIP DDP 的 报文 一样 容易 转储, 事实却 不是 这样. 即使 我们 有意 作点什么 来 促销 Ethertalk (我们没有), LBL 也不允许 Ethertalk 出现在 它的 任何网络上, 所以 我们 没办法 测试 这些代码.
如果 报文的 路径上 出现 夏时制时间 变化, 可能 导致 时戳 混乱. (这个时间变化将忽略)
操作 FDDI 报头的 过滤器表达式 假设 所有的 FDDI 报文 被封装在 以太报文 中. 这对 IP, ARP 和 DECNET Phase IV 无疑是 正确的, 但对 某些 协议 如 ISO CLNS 不正确. 因此, 过滤器 有可能会 糊里糊涂的 的 接收 一些 并不真正 匹配过滤器表达式 的 报文.