附录B 过滤表达式规范

说明 此文档是在tcpdump的文档基础上改写而成,源文档可以在www.tcpdump.org上找到。

wpcap过滤器基于一个陈述形式的谓词语法。一个过滤表达式就是一个ASCII字符串,pcap_compile函数把该表达式转换成内核空间数据包模块可执行的一段小程序。

内核空间的过滤模块通过过滤表达式选择接受哪些数据包。如果没有设置该表达式,网络上所有的数据包都会被接受。否则,只有该过滤表达式结果为true'的数据包才会被接受。

表达式包含了一个或多个原语。原语通常包含一个id(名称或数字),并有一个或多个前置限定语。其中,有三种不同类型的限定语:

❑type:该限定语表明id名称或数字指代的是什么类型的事物。可能的类型为host、net和port。如host foo'、net 128.3'、port 20'。如果没有显式的限定语,就假设为host类型。

❑dir:该限定语描述一个特定的传输方向,to与/或from id。可能的方向为src、dst、src or dst与src and dst,如src foo'、dst net 128.3'、src or dst port ftp-data'。如果没有显式的限定语,就假设为src or dst类型。对于null'连接层(比如点对点协议,诸如slip)inbound与outbound限定语可用来描述一个希望的传输方向。

❑proto:该限定语描述一个特定的协议。可能的协议为ether、fddi、tr、ip、ip6、arp、rarp、decnet、tcp与udp,如ether src foo'、arp net 128.3'、tcp port 21'。如果没有协议的限定语,则默认是所有与该类型相一致的协议。例如,src foo'意味着(ip or arp or rarp)src foo'(除了后者是非法语法),net bar'意味着(ip or arp or rarp)net bar'与port 53'意味着(tcp or udp)port 53'。

注意 实际上fddi'是ether'的一个别名。对于“数据链路层被使用在特定网络接口上”的情况,分析器会同等对待它们。FDDI头包含类以太网的源与目标地址,并且经常包含类以太网的数据包类型,故可以仅使用这些类似的以太网字段过滤这些FDDI字段。FDDI头也包含其他字段,但是不能在一个过滤器表达式中显式指定它们。同样地,tr'也是ether'的一个别名,前面所提及的关于FDDI头的说明也适用于令牌环网头。

除上述的情况外,还有一些特殊的primitive'关键字并不遵循该模式,如gateway、broadcast、less、greater与运算表达式。所有这些都将在下面详细讨论。

使用and、or与not来关联原语,可构建更复杂的过滤表达式。例如host foo and not port ftp and not port ftp-data'。为了节省打字输入,同样的限定语列表可被忽略。例如,tcp dst portftp or ftp-data or domain'与tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'是一样的。

允许使用的原语如下:

❑dst host host:如果IPv4/v6数据包的目的地址字段是host,则结果为True。host可为一个地址也可为一个名称。

❑src host host:如果IPv4/v6数据包的源地址字段是host,则结果为True。

❑host host:如果IPv4/v6数据包的目的地址字段或源地址字段是host,则结果为True。任何一个上述的主机表达式都可以使用ip、arp、rarp或ip6前置关键字,例如:ip host host等价于ether proto ip and host host。如果host是一个带有多个IP地址的名称,则检查每个地址进行匹配。

❑ether dst ehost:如果以太网目标地址为ehost,则结果为True。ehost既可能为一个从/etc/ethers中获得的名称,也可能为一个数字。

❑ether src ehost:如果以太网源地址为ehost,则结果为True。

❑ether host ehost:如果以太网目标地址或源地址为ehost,则结果为True。

❑gateway host:如果数据包使用host作为一个网关,则结果为True。例如,以太网源或目标地址是host,但host既不是IP源地址也不是IP目标地址。host必须是一个名称,并且必须能被机器的主机名到IP地址解析机制(主机名文件、DNS、NIS等等)与主机名到以太网地址解析机制(/etc/ethers等等)找到。一个与其等价的表达式为:ether host ehost and not host host

host/ehost可为名称或数字。目前情况下在IPv6中不支持该语法。

❑dst net net:如果数据包的IPv4/v6目标地址的网络数字为net,则结果为True。net既可以为/etc/networks中的一个名称,也可以为一个网络数字。

❑src net net:如果数据包的IPv4/v6源地址的网络数字为net,则结果为True。

❑net net:如果数据包的IPv4/v6源地址或目标地址的网络数字为net,则结果为True。

❑net net mask netmask:如果IP地址通过特定的netmask与net匹配,则结果为True。可以使用src或dst作为限定语。注意该语法对IPv6不可用。

❑net net/len:如果IPv4/v6地址通过一个网络掩码的len字位宽度与net匹配,则结果为True。可以使用src或dst作为限定语。

❑dst port port:如果数据包是ip/tcp、ip/udp、ip6/tcp或ip6/udp,并且有一个目标端口port,则结果为True。port可以为一个数值或一个/etc/services文件中的名称。如果使用的是一个名称,则端口号与协议都被检查。如果使用的是一个数值或一个不明确的名称,则仅端口号被检查(例如,dst port 513将会显示tcp/login网络流量与udp/who网络流量,port domain将会显示tcp/domain和udp/domain网络流量)。

❑src port port:如果数据包的源端口为port,则结果为True。

❑port port:如果数据包的源或目标端口为port,则结果为True。任何上述端口表达式都可被前置关键字tcp或udp,如tcp src port port,其仅匹配源端口为port的tcp数据包。

❑less length:如果数据包的长度小于或等于length,则结果为True。等价于数据包长度len<=length。

❑greater length:如果数据包的长度大于或等于length,则结果为True。等价于数据包长度len>=length。

❑ip proto protocol:如果数据包是协议类型为protocol的一个IP数据包,则结果为True。protocol可以为一个数值或一个名称,如icmp、icmp6、igmp、igrp、pim、ah、esp、vrrp、udp或tcp。注意,标识符tcp、udp和icmp也是关键字,并且必须通过转义字符(\)进行转义。还要注意这个原语是不能捕获协议头链的。

❑ip6 proto protocol:如果数据包是协议类型为protocol的一个IPv6数据包,则结果为True。注意这个原语是不能捕获协议头链的。

❑ip6 protochain protocol:如果数据包是IPv6数据包,并且在协议头链里包含protocol类型协议头,则结果为True。例如:ip6 protochain 6。匹配在协议头链里是TCP协议头的所有的IPv6协议数据包。这个数据包在IPv6报头和TCP报头之间可能包含一些内容,例如鉴别头、路由头或点对点头。由这些原语生成的BPF字节码很复杂,所以BPF优化器无法对此进行优化,可能导致过滤的速度有点慢。

❑ip protochain protocol:等价于ip6 protochain protocol,但是这个对应于IPv4。

❑ether broadcast:如果数据包是一个以太网广播数据包,则结果为True。关键字ether可选。

❑ip broadcast:如果数据包是一个IP广播数据包,则结果为True。检查全0与全1的广播惯例,并查寻本地子网掩码。

❑ether multicast:如果数据包是一个以太网多播数据包,则结果为True。关键字ether可选。这是ether[0]&1!=0'的速记。

❑ip multicast:如果数据包是一个IP多播数据包,则结果为True。

❑ip6 multicast:如果数据包是一个IPv6多播数据包,则结果为True。

❑ether proto protocol:如果是以太网类型protocol的数据包,则结果为True。protocol可以为一个数字或ip、ip6、arp、rarp、atalk、aarp、decnet、sca、lat、mopdl、moprc、iso、stp、ipx、netbeui这些名称之一。注意这些限定语也是关键字,使用时必须通过转义字符(\)进行转义。

注意 在FDDI(如fddi protocol arp')与令牌环网(如tr protocol arp')的情况下,对于大多数协议来说,这种协议标识符来自比FDDI和令牌类型网络更高层的802.2 LLC层(逻辑链路层)。当过滤FDDI或令牌环网的大多数协议时,tcpdump仅检查一个LLC头协议的ID字段,该字段采用SNAP的格式并带一个0x000000的组织单位标识(Organizational Unit Identifier,OUI)。对封装的以太网,tcpdump则不检查数据包是否是SNAP格式并带一个0x000000的OUI。而iso、stp、netbeui和atalk例外。对iso,则检查LLC头的DSAP(目标服务接入点,Destination Service Access Point)与SSAP(源服务接入点,Source Service Access Point)字段。对于stp与netbeui,检查LLC头的DSAP。对atalk,则检查一个采用SNAP格式的数据包,数据包的OUI为0x080007(包括Appletalk类型)。对于以太网,tcpdump可检查大部分协议的以太网类型域,但是以下协议存在特殊性:对iso、sap与netbeui,先做一个802.3协议帧格式的匹配,然后才(与在FDDI和令牌网下一样)检查LLC头信息。对atalk协议,它将在一个以太网帧中检查Appletalk协议类型,同时会与在FDDI和令牌网下一样,对一个SNAP格式的数据包进行检查。对aarp协议,要检查Appletalk ARP协议类型,既可以在一个以太网帧中,也可以在一个OUI是0x000000的802.2 SNAP的帧中。还有IPX协议,它要进行很多匹配检查:检查在一个以太网帧中的IPX类型,在LLC头中检查IPX的DSAP(目标服务接入点),检查802.3下没有被LLC头信息封装的IPX,以及检查在一个SNAP帧中的IPX。

❑decnet src host:当DECNET(DECNET为一种协议类型)的源地址为host类型时,结果为True。其中host可以是“10.123”这种格式的地址,或者是一个DECNET协议的host名称。DECNET host名称只在已经配置并运行DECNET的Ultrix系统上可用。

❑decnet dst host:当DECNET协议的目标地址是host类型时,结果为True。

❑decnet host host:当DECNET的源地址或者目标地址是host类型时,结果为True。

❑ip,ip6,arp,rarp,atalk,aarp,decnet,iso,stp,ipx,netbeui:缩略的写法为ether proto p。其中p是上面11种协议中的任一种。

❑lat,moprc,mopdl:缩略的写法为ether proto p。其中p指代以上三种协议中的任一种,但需要注意的是,tcpdump目前并不能准确地区分这些协议类型。

❑vlan[vlan_id]:当数据包是一个IEEE 802.1Q VLAN类型的协议包时,结果为True。如果指定了[vlan_id],只有当数据包包含了此指定的vlan_id时结果才为True。注意,假设这个数据包是VLAN类型,在表达式中遇到第一个vlan关键字时要更改解码偏移,转到表达式剩余的部分。

❑tcp,udp,icmp:缩略的写法为ip proto p or ip6 proto p。其中p是tcp,udp,icmp中的任一种。

❑iso proto protocol:当数据包是一个OSI数据包并且为protocol协议类型时,结果为True。其中protocol可以是一个数字或者是clnp、esis或者isis三种类型中的一种。

❑clnp,esis,isis:缩略的写法为iso proto p。其中p是以上协议中的任一种,需要注意的是tcpdump还没有完全支持这些协议的解析工作。

❑expr relop expr:当表达式的运算正确时,结果为True。其中relop是下列运算符>,<,>=,<=,=,!=之一。而expr是一个算术表达式,可以使用整数常量(使用标准的C语法)、常规的二元运算符(+,-,*,/,&,|)、长度运算符(使用len关键字定义)和特殊的数据包数据访问器。

如果需要访问数据包里的数据,可使用如下语法:

proto[expr:size]

proto是ether、fddi、tr、ip、arp、rarp、tcp、udp、icmp、ip6中的任一种,用来表明这些索引操作所处的协议层。注意,tcp、udp和其他一些上层协议类型只适用于IPv4,不适用于IPv6(这个我们将在以后解决)。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头的第一个字节,绝不会代表一个中间碎片数据包的第一个字节(注:对分段数据报而言)。

一些偏移与字段值可以用名称表示而不是用数值。下面一些协议头字段偏移是可用的: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。

原语可以按一组被圆括号括起来的原语与操作符格式组合。圆括号对于Shell来说是特殊的,所以必须转义使用。具体的组合格式如下所示:

❑非(!'ornot')

❑与(&&'orand')

❑或(||'oror')

“非”操作符具有最高的优先级,“与”操作符和“或”操作符具有相同的优先级,且符合从左到右的优先级关系。注意,当显式使用一个and标识符时,不是表示并列,而是表示连接。

如果给定一个标识符而没有关键字,则假设其关键字为最近的那个。例如:

not host vs and ace

是下面的缩略写法:

not host vs and host ace

不要理解成下面的含义:

not(host vs or ace)

可以以单个参数或者是多个参数的方式将过滤表达式的参数传递给tcpdump,具体应用哪种方式应根据情况,看哪种方式更便利。一般情况下,如果表达式包含Shell元字符,按单一的被放在引号内的参数形式传递更简单些。而多个参数在被解析前会先用空格连接起来。