互联网扫描器 ZMap 完全手册

初识 ZMap

ZMap被设计用来针对整个IPv4地址空间或其中的大部分实施综合扫描的工具。ZMap是研究者手中的利器,但在运行ZMap时,请注意,您很有可能正在以每秒140万个包的速度扫描整个IPv4地址空间 。我们建议用户即使在实施小范围扫描之前,也联系一下本地网络的管理员并参考我们列举的最佳扫描体验

默认情况下,ZMap会对于指定端口实施尽可能大速率的TCP SYN扫描。较为保守的情况下,对10,000个随机的地址的80端口以10Mbps的速度扫描,如下所示:

$ zmap --bandwidth=10M --target-port=80 --max-targets=10000 --output-file=results.csv

或者更加简洁地写成:

$ zmap -B 10M -p 80 -n 10000 -o results.csv

ZMap也可用于扫描特定子网或CIDR地址块。例如,仅扫描10.0.0.0/8和192.168.0.0/16的80端口,运行指令如下:

zmap -p 80 -o results.csv 10.0.0.0/8 192.168.0.0/16

如果扫描进行的顺利,ZMap会每秒输出类似以下内容的状态更新:

0% (1h51m left); send: 28777 562 Kp/s (560 Kp/s avg); recv: 1192 248 p/s (231 p/s avg); hits: 0.04%
0% (1h51m left); send: 34320 554 Kp/s (559 Kp/s avg); recv: 1442 249 p/s (234 p/s avg); hits: 0.04%
0% (1h50m left); send: 39676 535 Kp/s (555 Kp/s avg); recv: 1663 220 p/s (232 p/s avg); hits: 0.04%
0% (1h50m left); send: 45372 570 Kp/s (557 Kp/s avg); recv: 1890 226 p/s (232 p/s avg); hits: 0.04%

这些更新信息提供了扫描的即时状态并表示成:

完成进度% (剩余时间); send: 发出包的数量 即时速率 (平均发送速率); recv: 接收包的数量 接收率 (平均接收率); hits: 命中率

如果您不知道您所在网络能支持的扫描速率,您可能要尝试不同的扫描速率和带宽限制直到扫描效果开始下降,借此找出当前网络能够支持的最快速度。

默认情况下,ZMap会输出不同IP地址的列表(例如,根据SYN ACK数据包的情况),像下面这样。其输出结果还有几种附加的格式(如,JSON和Redis),可以用作生成程序可解析的扫描统计。 同样,可以指定附加的输出字段并使用输出过滤来过滤输出的结果。

115.237.116.119
23.9.117.80
207.118.204.141
217.120.143.111
50.195.22.82

我们强烈建议您使用黑名单文件,以排除预留的/未分配的IP地址空间(如,RFC1918 规定的私有地址、组播地址),以及网络中需要排除在您扫描之外的地址。默认情况下,ZMap将采用位于 /etc/zmap/blacklist.conf的这个简单的黑名单文件中所包含的预留和未分配地址。如果您需要某些特定设置,比如每次运行ZMap时的最大带宽或黑名单文件,您可以在文件/etc/zmap/zmap.conf中指定或使用自定义配置文件

如果您正试图解决扫描的相关问题,有几个选项可以帮助您调试。首先,您可以通过添加–dryrun实施预扫,以此来分析包可能会发送到网络的何处。此外,还可以通过设置’–verbosity=n`来更改日志详细程度

最佳扫描体验

我们为针对互联网进行扫描的研究者提供了一些建议,以此来引导养成良好的互联网合作氛围。

  • 密切协同本地的网络管理员,以减少风险和调查
  • 确认扫描不会使本地网络或上游供应商瘫痪
  • 在发起扫描的源地址的网页和DNS条目中申明你的扫描是善意的
  • 明确解释你的扫描中所有连接的目的和范围
  • 提供一个简单的退出扫描的方法并及时响应请求
  • 实施扫描时,不使用比研究对象需求更大的扫描范围或更快的扫描频率
  • 如果可以,将扫描流量分布到不同的时间或源地址上

即使不声明,使用扫描的研究者也应该避免利用漏洞或访问受保护的资源,并遵守其辖区内任何特殊的法律规定。

命令行参数

通用选项

这些选项是实施简单扫描时最常用的选项。我们注意到某些选项取决于所使用的探测模块输出模块(如,在实施ICMP Echo扫描时是不需要使用目的端口的)。

-p, –target-port=port

要扫描的目标TCP端口号(例如,443)

-o, –output-file=name

将结果写入该文件,使用代表输出到标准输出。

-b, –blacklist-file=path

文件中被排除的子网使用CIDR表示法(如192.168.0.0/16),一个一行。建议您使用此方法排除RFC 1918地址、组播地址、IANA预留空间等IANA专用地址。在conf/blacklist.example中提供了一个以此为目的示例黑名单文件。

扫描选项

-n, –max-targets=n

限制探测目标的数量。后面跟的可以是一个数字(例如’-n 1000),或可扫描地址空间的百分比(例如,-n 0.1%`,不包括黑名单)

-N, –max-results=n

收到多少结果后退出

-t, –max-runtime=secs

限制发送报文的时间

-r, –rate=pps

设置发包速率,以包/秒为单位

-B, –bandwidth=bps

以比特/秒设置传输速率(支持使用后缀G,M或K(如-B 10M就是速度10 mbps)的。设置会覆盖–rate

-c, –cooldown-time=secs

发送完成后等待多久继续接收回包(默认值= 8)

-e, –seed=n

地址排序种子。如果要用多个ZMap以相同的顺序扫描地址,那么就可以使用这个参数。

–shards=n

将扫描分片/区,使其可多个ZMap中执行(默认值= 1)。启用分片时,–seed参数是必需的。

–shard=n

选择扫描的分片(默认值= 0)。n的范围在[0,N),其中N为碎片的总数。启用分片时,–seed参数是必需的。

-T, –sender-threads=n

用于发送数据包的线程数(默认值= 1)

-P, –probes=n

发送到每个IP的探测数(默认值= 1)

-d, –dryrun

用标准输出打印出每个包,而不是将其发送(用于调试)

网络选项

-s, –source-port=port|range

发送数据包的源端口

-S, –source-ip=ip|range

发送数据包的源地址。可以仅仅是一个IP,也可以是一个范围(如,10.0.0.1-10.0.0.9)

-G, –gateway-mac=addr

数据包发送到的网关MAC地址(用以防止自动检测不工作的情况)

-i, –interface=name

使用的网络接口

探测选项

ZMap允许用户指定并添加自己所需要的探测模块。 探测模块的职责就是生成要发送的探测包,并处理主机回复的响应包。

–list-probe-modules

列出可用探测模块(如tcp_synscan)

-M, –probe-module=name

选择探测模块(默认值= tcp_synscan)

–probe-args=args

向模块传递参数

–list-output-fields

列出可用的输出模块

输出选项

ZMap允许用户指定和编写他们自己的输出模块。输出模块负责处理由探测模块返回的字段,并将它们输出给用户。用户可以指定输出的字段,并过滤相应字段。

–list-output-modules

列出可用输出模块(如tcp_synscan)

-O, –output-module=name

选择输出模块(默认值为csv)

–output-args=args

传递给输出模块的参数

-f, –output-fields=fields

输出的字段列表,以逗号分割

–output-filter

指定输出过滤器探测模块定义字段进行过滤

附加选项

-C, –config=filename

加载配置文件,可以指定其他路径。

-q, –quiet

不必每秒刷新输出

-g, –summary

在扫描结束后打印配置和结果汇总信息

-v, –verbosity=n

日志详细程度(0-5,默认值= 3)

-h, –help

打印帮助并退出

-V, –version

打印版本并退出

附加信息

TCP SYN 扫描

在执行TCP SYN扫描时,ZMap需要指定一个目标端口,也支持指定发起扫描的源端口范围。

-p, –target-port=port

扫描的TCP端口(例如 443)

-s, –source-port=port|range

发送扫描数据包的源端口(例如 40000-50000)

警示! ZMap基于Linux内核使用RST包来应答SYN/ACK包响应,以关闭扫描器打开的连接。ZMap是在Ethernet层完成包的发送的,这样做是为了减少跟踪打开的TCP连接和路由寻路带来的内核开销。因此,如果您有跟踪连接建立的防火墙规则,如类似于-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT的netfilter规则,将阻止SYN/ACK包到达内核。这不会妨碍到ZMap记录应答,但它会阻止RST包被送回,最终被扫描主机的连接会一直打开,直到超时后断开。我们强烈建议您在执行ZMap时,选择一组主机上未使用且防火墙允许访问的端口,加在-s后(如 -s ‘50000-60000’ )。

ICMP Echo 请求扫描

虽然在默认情况下ZMap执行的是TCP SYN扫描,但它也支持使用ICMP echo请求扫描。在这种扫描方式下ICMP echo请求包被发送到每个主机,并以收到ICMP应答包作为答复。实施ICMP扫描可以通过选择icmp_echoscan扫描模块来执行,如下:

$ zmap --probe-module=icmp_echoscan

UDP 数据报扫描

ZMap还额外支持UDP探测,它会发出任意UDP数据报给每个主机,并接收UDP或ICMP不可达的应答。ZMap可以通过使用–probe-args命令行选项来设置四种不同的UDP载荷。这些是:可在命令行设置可打印的ASCII 码的‘text’载荷和十六进制载荷的‘hex’,外部文件中包含载荷的‘file’,和通过动态字段生成的载荷的‘template’。为了得到UDP响应,请使用-f参数确保您指定的“data”字段处于输出范围。

下面的例子将发送两个字节’ST’,即PCAnwywhere的’status’请求,到UDP端口5632。

$ zmap -M udp -p 5632 --probe-args=text:ST -N 100 -f saddr,data -o -

下面的例子将发送字节“0X02”,即SQL Server的’client broadcast’请求,到UDP端口1434。

$ zmap -M udp -p 1434 --probe-args=hex:02 -N 100 -f saddr,data -o -

下面的例子将发送一个NetBIOS状态请求到UDP端口137。使用一个ZMap自带的载荷文件。

$ zmap -M udp -p 1434 --probe-args=file:netbios_137.pkt -N 100 -f saddr,data -o -

下面的例子将发送SIP的’OPTIONS’请求到UDP端口5060。使用附ZMap自带的模板文件。

$ zmap -M udp -p 1434 --probe-args=file:sip_options.tpl -N 100 -f saddr,data -o -

UDP载荷模板仍处于实验阶段。当您在更多的使用一个以上的发送线程(-T)时可能会遇到崩溃和一个明显的相比静态载荷性能降低的表现。模板仅仅是一个由一个或多个使用${}将字段说明封装成序列构成的载荷文件。某些协议,特别是SIP,需要载荷来反射包中的源和目的包。其他协议,如portmapper和DNS,每个请求包含的字段应该是随机的,或降低被Zamp扫描的多宿主系统的风险。

以下的载荷模板将发送SIP OPTIONS请求到每一个目的地:

OPTIONS sip:${RAND_ALPHA=8}@${DADDR} SIP/2.0
Via: SIP/2.0/UDP ${SADDR}:${SPORT};branch=${RAND_ALPHA=6}.${RAND_DIGIT=10};rport;alias
From: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT};tag=${RAND_DIGIT=8}
To: sip:${RAND_ALPHA=8}@${DADDR}
Call-ID: ${RAND_DIGIT=10}@${SADDR}
CSeq: 1 OPTIONS
Contact: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT}
Content-Length: 0
Max-Forwards: 20
User-Agent: ${RAND_ALPHA=8}
Accept: text/plain

就像在上面的例子中展示的那样,注意每行行末以rn结尾,请求以rnrn结尾,大多数SIP实现都可以正确处理它。一个可以工作的例子放在ZMap的examples/udp-payloads目录下 (sip_options.tpl).

当前实现了下面的模板字段:

  • SADDR: 源IP地址的点分十进制格式
  • SADDR_N: 源IP地址的网络字节序格式
  • DADDR: 目的IP地址的点分十进制格式
  • DADDR_N: 目的IP地址的网络字节序格式
  • SPORT: 源端口的ascii格式
  • SPORT_N: 源端口的网络字节序格式
  • DPORT: 目的端口的ascii格式
  • DPORT_N: 目的端口的网络字节序格式
  • RAND_BYTE: 随机字节(0-255),长度由=(length) 参数决定
  • RAND_DIGIT: 随机数字0-9,长度由=(length) 参数决定
  • RAND_ALPHA: 随机大写字母A-Z,长度由=(length) 参数决定
  • RAND_ALPHANUM: 随机大写字母A-Z和随机数字0-9,长度由=(length) 参数决定

配置文件

ZMap支持使用配置文件来代替在命令行上指定所有要求的选项。配置中可以通过每行指定一个长名称的选项和对应的值来创建:

interface "eth1"
source-ip 1.1.1.4-1.1.1.8
gateway-mac b4:23:f9:28:fa:2d # upstream gateway
cooldown-time 300 # seconds
blacklist-file /etc/zmap/blacklist.conf
output-file ~/zmap-output
quiet
summary

然后ZMap就可以按照配置文件并指定一些必要的附加参数运行了:

$ zmap --config=~/.zmap.conf --target-port=443

详细

ZMap可以在屏幕上生成多种类型的输出。默认情况下,Zmap将每隔1秒打印出相似的基本进度信息。可以通过设置–quiet来禁用。

0:01 12%; send: 10000 done (15.1 Kp/s avg); recv: 144 143 p/s (141 p/s avg); hits: 1.44%

ZMap同样也可以根据扫描配置打印如下消息,可以通过’–verbosity`参数加以控制。

Aug 11 16:16:12.813 [INFO] zmap: started
Aug 11 16:16:12.817 [DEBUG] zmap: no interface provided. will use eth0
Aug 11 16:17:03.971 [DEBUG] cyclic: primitive root: 3489180582
Aug 11 16:17:03.971 [DEBUG] cyclic: starting point: 46588
Aug 11 16:17:03.975 [DEBUG] blacklist: 3717595507 addresses allowed to be scanned
Aug 11 16:17:03.975 [DEBUG] send: will send from 1 address on 28233 source ports
Aug 11 16:17:03.975 [DEBUG] send: using bandwidth 10000000 bits/s, rate set to 14880 pkt/s
Aug 11 16:17:03.985 [DEBUG] recv: thread started

ZMap还支持在扫描之后打印出一个的可grep的汇总信息,类似于下面这样,可以通过调用–summary来实现。

cnf target-port             443
cnf source-port-range-begin         32768
cnf source-port-range-end           61000
cnf source-addr-range-begin         1.1.1.4
cnf source-addr-range-end           1.1.1.8
cnf maximum-packets             4294967295
cnf maximum-runtime             0
cnf permutation-seed            0
cnf cooldown-period             300
cnf send-interface              eth1
cnf rate                    45000
env nprocessors             16
exc send-start-time             Fri Jan 18 01:47:35 2013
exc send-end-time               Sat Jan 19 00:47:07 2013
exc recv-start-time             Fri Jan 18 01:47:35 2013
exc recv-end-time               Sat Jan 19 00:52:07 2013
exc sent                    3722335150
exc blacklisted             572632145
exc first-scanned               1318129262
exc hit-rate                0.874102
exc synack-received-unique          32537000
exc synack-received-total           36689941
exc synack-cooldown-received-unique     193
exc synack-cooldown-received-total      1543
exc rst-received-unique         141901021
exc rst-received-total          166779002
adv source-port-secret          37952
adv permutation-gen             4215763218

结果输出

ZMap可以通过输出模块生成不同格式的结果。默认情况下,ZMap只支持csv的输出,但是可以通过编译支持redisjson 。可以使用输出过滤来过滤这些发送到输出模块上的结果。输出模块输出的字段由用户指定。默认情况如果没有指定输出文件,ZMap将以csv格式返回结果,而不会生成特定结果。也可以编写自己的输出模块;请参阅编写输出模块

-o, –output-file=p

输出写入文件地址

-O, –output-module=p

调用自定义输出模块

-f, –output-fields=p

以逗号分隔的输出的字段列表

–output-filter=filter

对给定的探测指定字段输出过滤

–list-output-modules

列出可用输出模块

–list-output-fields

列出给定的探测的可用输出字段

输出字段

除了IP地址之外,ZMap有很多字段。这些字段可以通过在给定探测模块上运行–list-output-fields来查看。

$ zmap --probe-module="tcp_synscan" --list-output-fields
saddr           string: 应答包中的源IP地址
saddr-raw          int: 网络字节格式的源IP地址
daddr           string: 应答包中的目的IP地址
daddr-raw          int: 网络字节格式的目的IP地址
ipid               int: 应答包中的IP识别号
ttl                int: 应答包中的ttl(存活时间)值
sport              int: TCP 源端口
dport              int: TCP 目的端口
seqnum             int: TCP 序列号
acknum             int: TCP Ack号
window             int: TCP 窗口
classification  string: 包类型
success            int: 是应答包成功
repeat             int: 是否是来自主机的重复响应
cooldown           int: 是否是在冷却时间内收到的响应
timestamp-str   string: 响应抵达时的时间戳使用ISO8601格式
timestamp-ts       int: 响应抵达时的时间戳使用UNIX纪元开始的秒数
timestamp-us       int: 时间戳的微秒部分(例如 从'timestamp-ts'的几微秒)

可以通过使用–output-fields=fields-f来选择选择输出字段,任意组合的输出字段可以被指定为逗号分隔的列表。例如:

$ zmap -p 80 -f "response,saddr,daddr,sport,seq,ack,in_cooldown,is_repeat,timestamp" -o output.csv

过滤输出

在传到输出模块之前,探测模块生成的结果可以先过滤。过滤是针对探测模块的输出字段的。过滤使用类似于SQL的简单过滤语法写成,通过ZMap的–output-filter选项来指定。输出过滤通常用于过滤掉重复的结果,或仅传输成功的响应到输出模块。

过滤表达式的形式为<字段名> <操作符> <值><值>的类型必须是一个字符串或一串无符号整数并且匹配<字段名>类型。对于整数比较有效的操作符是= !=, <, >, <=, >=。字符串比较的操作是=,!=。–list-output-fields可以打印那些可供探测模块选择的字段和类型,然后退出。

复合型的过滤操作,可以通过使用&&(逻辑与)和||(逻辑或)这样的运算符来组合出特殊的过滤操作。

示例

书写一则过滤仅显示成功的、不重复的应答

--output-filter="success = 1 && repeat = 0"

过滤出RST分类并且TTL大于10的包,或者SYNACK分类的包

--output-filter="(classification = rst && ttl > 10) || classification = synack"

CSV

csv模块将会生成以逗号分隔各个要求输出的字段的文件。例如,以下的指令将生成名为output.csv的CSV文件。

$ zmap -p 80 -f "response,saddr,daddr,sport,seq,ack,in_cooldown,is_repeat,timestamp" -o output.csv

#响应, 源地址, 目的地址, 源端口, 目的端口, 序列号, 应答, 是否是冷却模式, 是否重复, 时间戳
response, saddr, daddr, sport, dport, seq, ack, in_cooldown, is_repeat, timestamp
synack, 159.174.153.144, 10.0.0.9, 80, 40555, 3050964427, 3515084203, 0, 0,2013-08-15 18:55:47.681
rst, 141.209.175.1, 10.0.0.9, 80, 40136, 0, 3272553764, 0, 0,2013-08-15 18:55:47.683
rst, 72.36.213.231, 10.0.0.9, 80, 56642, 0, 2037447916, 0, 0,2013-08-15 18:55:47.691
rst, 148.8.49.150, 10.0.0.9, 80, 41672, 0, 1135824975, 0, 0,2013-08-15 18:55:47.692
rst, 50.165.166.206, 10.0.0.9, 80, 38858, 0, 535206863, 0, 0,2013-08-15 18:55:47.694
rst, 65.55.203.135, 10.0.0.9, 80, 50008, 0, 4071709905, 0, 0,2013-08-15 18:55:47.700
synack, 50.57.166.186, 10.0.0.9, 80, 60650, 2813653162, 993314545, 0, 0,2013-08-15 18:55:47.704
synack, 152.75.208.114, 10.0.0.9, 80, 52498, 460383682, 4040786862, 0, 0,2013-08-15 18:55:47.707
synack, 23.72.138.74, 10.0.0.9, 80, 33480, 810393698, 486476355, 0, 0,2013-08-15 18:55:47.710

Redis

Redis的输出模块允许地址被添加到一个Redis的队列,而不是保存到文件,允许ZMap将它与之后的处理工具结合使用。

注意! ZMap默认不会编译Redis功能。如果你从源码构建ZMap,可以在CMake的时候加上-DWITH_REDIS=ON来增加Redis支持。

JSON

JSON输出模块用起来类似于CSV模块,只是以JSON格式写入到文件。JSON文件能轻松地导入到其它可以读取JSON的程序中。

注意!,ZMap默认不会编译JSON功能。如果你从源码构建ZMap,可以在CMake的时候加上-DWITH_JSON=ON来增加JSON支持。

黑名单和白名单

ZMap同时支持对网络前缀做黑名单和白名单。如果ZMap不加黑名单和白名单参数,他将会扫描所有的IPv4地址(包括本地的,保留的以及组播地址)。如果指定了黑名单文件,那么在黑名单中的网络前缀将不再扫描;如果指定了白名单文件,只有那些网络前缀在白名单内的才会扫描。白名单和黑名单文件可以协同使用;黑名单优先于白名单(例如:如果您在白名单中指定了10.0.0.0/8并在黑名单中指定了10.1.0.0/16,那么10.1.0.0/16将不会扫描)。白名单和黑名单文件可以在命令行中指定,如下所示:

-b, –blacklist-file=path

文件用于记录黑名单子网,以CIDR(无类域间路由)的表示法,例如192.168.0.0/16

-w, –whitelist-file=path

文件用于记录限制扫描的子网,以CIDR的表示法,例如192.168.0.0/16

黑名单文件的每行都需要以CIDR的表示格式书写,一行单一的网络前缀。允许使用#加以备注。例如:

# IANA(英特网编号管理局)记录的用于特殊目的的IPv4地址
# http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
# 更新于2013-05-22

0.0.0.0/8           # RFC1122: 网络中的所有主机
10.0.0.0/8          # RFC1918: 私有地址
100.64.0.0/10       # RFC6598: 共享地址空间
127.0.0.0/8         # RFC1122: 回环地址
169.254.0.0/16      # RFC3927: 本地链路地址
172.16.0.0/12       # RFC1918: 私有地址
192.0.0.0/24        # RFC6890: IETF协议预留
192.0.2.0/24        # RFC5737: 测试地址1
192.88.99.0/24      # RFC3068: IPv6转换到IPv4的任播
192.168.0.0/16      # RFC1918: 私有地址
192.18.0.0/15       # RFC2544: 检测地址
198.51.100.0/24     # RFC5737: 测试地址2
203.0.113.0/24      # RFC5737: 测试地址3
240.0.0.0/4         # RFC1112: 预留地址
255.255.255.255/32  # RFC0919: 限制广播地址

# IANA记录的用于组播的地址空间
# http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
# 更新于2013-06-25

224.0.0.0/4         # RFC5771: 组播/预留地址ed

如果您只是想扫描因特网中随机的一部分地址,使用抽样检出,来代替使用白名单和黑名单。

注意!ZMap默认设置使用/etc/zmap/blacklist.conf作为黑名单文件,其中包含有本地的地址空间和预留的IP空间。通过编辑/etc/zmap/zmap.conf可以改变默认的配置。

速度限制与抽样

默认情况下,ZMap将以您当前网卡所能支持的最快速度扫描。以我们对于常用硬件的经验,这通常是理论上Gbit以太网速度的95-98%,这可能比您的上游提供商可处理的速度还要快。ZMap是不会自动的根据您的上游提供商来调整发送速率的。您可能需要手动的调整发送速率来减少丢包和错误结果。

-r, –rate=pps

设置最大发送速率以包/秒为单位

-B, –bandwidth=bps

设置发送速率以比特/秒(支持G,M和K后缀)。这会覆盖–rate参数。

ZMap同样支持对IPv4地址空间进行指定最大目标数和/或最长运行时间的随机采样。由于每次对主机的扫描是通过随机排序生成的,限制扫描的主机个数为N就会随机抽选N个主机。命令选项如下:

-n, –max-targets=n

探测目标上限数量

-N, –max-results=n

结果上限数量(累积收到这么多结果后退出)

-t, –max-runtime=s

发送数据包时间长度上限(以秒为单位)

-s, –seed=n

种子用以选择地址的排列方式。使用不同ZMap执行扫描操作时将种子设成相同的值可以保证相同的扫描顺序。

举个例子,如果您想要多次扫描同样的一百万个互联网主机,您可以设定排序种子和扫描主机的上限数量,大致如下所示:

zmap -p 443 -s 3 -n 1000000 -o results

为了确定哪一百万主机将要被扫描,您可以执行预扫,只打印数据包而非发送,并非真的实施扫描。

zmap -p 443 -s 3 -n 1000000 --dryrun | grep daddr
    | awk -F'daddr: ' '{print $2}' | sed 's/ |.*//;'

发送多个数据包

ZMap支持向每个主机发送多个探测。增加这个数量既增加了扫描时间又增加了到达的主机数量。然而,我们发现,增加的扫描时间(每个额外扫描的增加近100%)远远大于到达的主机数量(每个额外扫描的增加近1%)。

-P, –probes=n

向每个IP发出的独立探测个数(默认值=1)

示例应用

ZMap专为向大量主机发起连接并寻找那些正确响应而设计。然而,我们意识到许多用户需要执行一些后续处理,如执行应用程序级别的握手。例如,用户在80端口实施TCP SYN扫描也许想要实施一个简单的GET请求,还有用户扫描443端口可能希望完成TLS握手。

Banner获取

我们收录了一个示例程序,banner-grab,伴随ZMap使用可以让用户从监听状态的TCP服务器上接收到消息。Banner-grab连接到提供的服务器上,发送一个可选的消息,然后打印出收到的第一个消息。这个工具可以用来获取banner,例如HTTP服务的回复的具体指令,telnet登陆提示,或SSH服务的字符串。

下面的例子寻找了1000个监听80端口的服务器,并向每个发送一个简单的GET请求,存储他们的64位编码响应至http-banners.out

$ zmap -p 80 -N 1000 -B 10M -o - | ./banner-grab-tcp -p 80 -c 500 -d ./http-req > out

如果想知道更多使用banner-grab的细节,可以参考examples/banner-grab中的README文件。

注意! ZMap和banner-grab(如例子中)同时运行可能会比较显著的影响对方的表现和精度。确保不让ZMap占满banner-grab-tcp的并发连接,不然banner-grab将会落后于标准输入的读入,导致阻塞ZMap的输出写入。我们推荐使用较慢扫描速率的ZMap,同时提升banner-grab-tcp的并发性至3000以内(注意 并发连接>1000需要您使用ulimit -SHn 100000ulimit -HHn 100000来增加每个进程的最大文件描述符数量)。当然,这些参数取决于您服务器的性能、连接成功率(hit-rate);我们鼓励开发者在运行大型扫描之前先进行小样本的试验。

建立套接字

我们也收录了另一种形式的banner-grab,就是forge-socket, 重复利用服务器发出的SYN-ACK,连接并最终取得banner。在banner-grab-tcp中,ZMap向每个服务器发送一个SYN,并监听服务器发回的带有SYN+ACK的应答。运行ZMap主机的内核接受应答后发送RST,这样就没有与该包关联活动连接。程序banner-grab必须在这之后创建一个新的TCP连接到从服务器获取数据。

在forge-socket中,我们利用内核中同名的模块,使我们可以创建任意参数的TCP连接。可以通过抑制内核的RST包,并重用SYN+ACK的参数取代该包而创建套接字,通过这个套接字收发数据和我们平时使用的连接套接字并没有什么不同。

要使用forge-socket,您需要forge-socket内核模块,从github上可以获得。您需要git clone git@github.com:ewust/forge_socket.git至ZMap源码根目录,然后cd进入forge_socket目录,运行make。以root身份运行insmod forge_socket.ko 来安装该内核模块。

您也需要告知内核不要发送RST包。一个简单的在全系统禁用RST包的方法是使用iptables。以root身份运行iptables -A OUTPUT -p tcp -m tcp –tcp-flgas RST,RST RST,RST -j DROP即可,当然您也可以加上一项–dport X将禁用局限于所扫描的端口(X)上。扫描完成后移除这项设置,以root身份运行iptables -D OUTPUT -p tcp -m tcp –tcp-flags RST,RST RST,RST -j DROP即可。

现在应该可以建立forge-socket的ZMap示例程序了。运行需要使用extended_fileZMap输出模块

$ zmap -p 80 -N 1000 -B 10M -O extended_file -o - |
    ./forge-socket -c 500 -d ./http-req > ./http-banners.out

详细内容可以参考examples/forge-socket目录下的README。


编写探测和输出模块

ZMap可以通过探测模块来扩展支持不同类型的扫描,通过输出模块增加不同类型的输出结果。注册过的探测和输出模块可以在命令行中列出:

–list-probe-modules

列出安装过的探测模块

–list-output-modules

列出安装过的输出模块

输出模块

ZMap的输出和输出后处理可以通过实现和注册扫描器的输出模块来扩展。输出模块在接收每一个应答包时都会收到一个回调。然而默认提供的模块仅提供简单的输出,这些模块同样支持更多的输出后处理(例如:重复跟踪或输出AS号码来代替IP地址)。

通过定义一个新的output_module结构来创建输出模块,并在output_modules.c中注册:

typedef struct output_module {
    const char          *name;           // 在命令行如何引用输出模块
    unsigned            update_interval; // 以秒为单位的更新间隔

    output_init_cb      init;            // 在扫描器初始化的时候调用
    output_update_cb    start;           // 在扫描器开始的时候调用
    output_update_cb    update;          // 每次更新间隔调用,秒为单位
    output_update_cb    close;           // 扫描终止后调用

    output_packet_cb    process_ip;      // 接收到应答时调用

    const char          *helptext;       // 会在--list-output-modules时打印在屏幕上

} output_module_t;

输出模块必须有名称,通过名称可以在命令行调用,并且通常会实现success_ip和常见的other_ip回调。process_ip的回调由每个收到并经由probe module过滤的应答包调用。应答是否被认定为成功并不确定(比如,它可以是一个TCP的RST)。这些回调必须定义匹配output_packet_cb定义的函数:

int (*output_packet_cb) (

    ipaddr_n_t    saddr,         // 网络字节格式的发起扫描主机IP地址
    ipaddr_n_t    daddr,         // 网络字节格式的目的IP地址

    const char*   response_type, // 发送模块的数据包分类

    int           is_repeat,     // {0: 主机的第一个应答, 1: 后续的应答}
    int           in_cooldown,   // {0: 非冷却状态, 1: 扫描器处于冷却中}

    const u_char* packet,        // 指向IP包的iphdr结构体的指针
    size_t        packet_len     // 包的长度,以字节为单位
);

输出模块还可以通过注册回调,执行在扫描初始化的时候(诸如打开输出文件的任务)、在扫描开始阶段(诸如记录黑名单的任务)、在扫描的常规间隔(诸如状态更新的任务)、在关闭的时候(诸如关掉所有打开的文件描述符)。提供的这些回调可以完整的访问扫描配置和当前状态:

int (*output_update_cb)(struct state_conf*, struct state_send*, struct state_recv*);

这些定义在output_modules.h中。在src/outputmodules/modulecsv.c中有可用示例。

探测模块

数据包由探测模块构造,它可以创建各种包和不同类型的响应。ZMap默认拥有两个扫描模块:tcp_synscanicmp_echoscan。默认情况下,ZMap使用tcp_synscan来发送TCP SYN包并对每个主机的响应分类,如打开时(收到SYN+ACK)或关闭时(收到RST)。ZMap允许开发者编写自己的ZMap探测模块,使用如下的API:

任何类型的扫描都必须通过开发和注册send_module_t结构中的回调来实现:

typedef struct probe_module {
    const char               *name;             // 如何在命令行调用扫描
    size_t                   packet_length;     // 探测包有多长(必须是静态的)

    const char               *pcap_filter;      // 对收到的响应实施PCAP过滤
    size_t                   pcap_snaplen;      // libpcap 捕获的最大字节数
    uint8_t                  port_args;         // 设为1,如果ZMap需要用户指定--target-port

    probe_global_init_cb     global_initialize; // 在扫描初始化会时被调用一次
    probe_thread_init_cb     thread_initialize; // 每个包缓存区的线程中被调用一次
    probe_make_packet_cb     make_packet;       // 每个主机更新包的时候被调用一次
    probe_validate_packet_cb validate_packet;   // 每收到一个包被调用一次,
                                                // 如果包无效返回0,
                                                // 非零则有效。

    probe_print_packet_cb    print_packet;      // 如果在预扫模式下被每个包都调用
    probe_classify_packet_cb process_packet;    // 由区分响应的接收器调用
    probe_close_cb           close;             // 扫描终止后被调用

    fielddef_t               *fields            // 该模块指定的字段的定义
    int                      numfields          // 字段的数量

} probe_module_t;

在扫描操作初始化时会调用一次global_initialize,可以用来实施一些必要的全局配置和初始化操作。然而,global_initialize并不能访问包缓冲区,那里是线程特定的。代替的,thread_initialize在每个发送线程初始化的时候被调用,提供对于缓冲区的访问,可以用来构建探测包和全局的源和目的值。此回调应用于构建主机不可知的包结构,甚至只有特定值(如:目的主机和校验和),需要随着每个主机更新。例如,以太网头部信息在交换时不会变更(减去校验和是由NIC硬件计算的)因此可以事先定义以减少扫描时间开销。

调用回调参数make_packet是为了让被扫描的主机允许探测模块更新主机指定的值,同时提供IP地址、一个非透明的验证字符串和探测数目(如下所示)。探测模块负责在探测中放置尽可能多的验证字符串,即便当服务器返回的应答为空时,探测模块也能验证它的当前状态。例如,针对TCP SYN扫描,tcp_synscan探测模块会使用TCP源端口和序列号的格式存储验证字符串。响应包(SYN+ACK)将包含目的端口和确认号的预期值。

int make_packet(
    void        *packetbuf,  // 包的缓冲区
    ipaddr_n_t  src_ip,      // 网络字节格式源IP
    ipaddr_n_t  dst_ip,      // 网络字节格式目的IP
    uint32_t    *validation, // 探测中的有效字符串
    int         probe_num    // 如果向每个主机发送多重探测,
                             // 该值为我们对于该主机
                             // 正在发送的探测数目
);

扫描模块也应该定义pcap_filtervalidate_packetprocess_packet。只有符合PCAP过滤器的包才会被扫描。举个例子,在一个TCP SYN扫描的情况下,我们只想要调查TCP SYN / ACK或RST TCP数据包,并利用类似tcp && tcp[13] & 4 != 0 || tcp[13] == 18的过滤方法。validate_packet函数将会被每个满足PCAP过滤条件的包调用。如果验证返回的值非零,将会调用process_packet函数,并使用fields定义的字段和包中的数据填充字段集。举个例子,如下代码为TCP synscan探测模块处理了一个数据包。

void synscan_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs)
{
    struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
    struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr
            + (sizeof(struct iphdr)));

    fs_add_uint64(fs, "sport", (uint64_t) ntohs(tcp->source));
    fs_add_uint64(fs, "dport", (uint64_t) ntohs(tcp->dest));
    fs_add_uint64(fs, "seqnum", (uint64_t) ntohl(tcp->seq));
    fs_add_uint64(fs, "acknum", (uint64_t) ntohl(tcp->ack_seq));
    fs_add_uint64(fs, "window", (uint64_t) ntohs(tcp->window));

    if (tcp->rst) { // RST packet
        fs_add_string(fs, "classification", (char*) "rst", 0);
        fs_add_uint64(fs, "success", 0);
    } else { // SYNACK packet
        fs_add_string(fs, "classification", (char*) "synack", 0);
        fs_add_uint64(fs, "success", 1);
    }
}

via: https://zmap.io/documentation.html

译者:martin2011qi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5860-1.html

Linux:互联网扫描器 ZMap 完全手册

初识 ZMap

ZMap被设计用来针对整个IPv4地址空间或其中的大部分实施综合扫描的工具。ZMap是研究者手中的利器,但在运行ZMap时,请注意,您很有可能正在以每秒140万个包的速度扫描整个IPv4地址空间 。我们建议用户即使在实施小范围扫描之前,也联系一下本地网络的管理员并参考我们列举的最佳扫描体验

默认情况下,ZMap会对于指定端口实施尽可能大速率的TCP SYN扫描。较为保守的情况下,对10,000个随机的地址的80端口以10Mbps的速度扫描,如下所示:

$ zmap --bandwidth=10M --target-port=80 --max-targets=10000 --output-file=results.csv

或者更加简洁地写成:

$ zmap -B 10M -p 80 -n 10000 -o results.csv

ZMap也可用于扫描特定子网或CIDR地址块。例如,仅扫描10.0.0.0/8和192.168.0.0/16的80端口,运行指令如下:

zmap -p 80 -o results.csv 10.0.0.0/8 192.168.0.0/16

如果扫描进行的顺利,ZMap会每秒输出类似以下内容的状态更新:

0% (1h51m left); send: 28777 562 Kp/s (560 Kp/s avg); recv: 1192 248 p/s (231 p/s avg); hits: 0.04%
0% (1h51m left); send: 34320 554 Kp/s (559 Kp/s avg); recv: 1442 249 p/s (234 p/s avg); hits: 0.04%
0% (1h50m left); send: 39676 535 Kp/s (555 Kp/s avg); recv: 1663 220 p/s (232 p/s avg); hits: 0.04%
0% (1h50m left); send: 45372 570 Kp/s (557 Kp/s avg); recv: 1890 226 p/s (232 p/s avg); hits: 0.04%

这些更新信息提供了扫描的即时状态并表示成:

完成进度% (剩余时间); send: 发出包的数量 即时速率 (平均发送速率); recv: 接收包的数量 接收率 (平均接收率); hits: 命中率

如果您不知道您所在网络能支持的扫描速率,您可能要尝试不同的扫描速率和带宽限制直到扫描效果开始下降,借此找出当前网络能够支持的最快速度。

默认情况下,ZMap会输出不同IP地址的列表(例如,根据SYN ACK数据包的情况),像下面这样。其输出结果还有几种附加的格式(如,JSON和Redis),可以用作生成程序可解析的扫描统计。 同样,可以指定附加的输出字段并使用输出过滤来过滤输出的结果。

115.237.116.119
23.9.117.80
207.118.204.141
217.120.143.111
50.195.22.82

我们强烈建议您使用黑名单文件,以排除预留的/未分配的IP地址空间(如,RFC1918 规定的私有地址、组播地址),以及网络中需要排除在您扫描之外的地址。默认情况下,ZMap将采用位于 /etc/zmap/blacklist.conf的这个简单的黑名单文件中所包含的预留和未分配地址。如果您需要某些特定设置,比如每次运行ZMap时的最大带宽或黑名单文件,您可以在文件/etc/zmap/zmap.conf中指定或使用自定义配置文件

如果您正试图解决扫描的相关问题,有几个选项可以帮助您调试。首先,您可以通过添加–dryrun实施预扫,以此来分析包可能会发送到网络的何处。此外,还可以通过设置’–verbosity=n`来更改日志详细程度

最佳扫描体验

我们为针对互联网进行扫描的研究者提供了一些建议,以此来引导养成良好的互联网合作氛围。

  • 密切协同本地的网络管理员,以减少风险和调查
  • 确认扫描不会使本地网络或上游供应商瘫痪
  • 在发起扫描的源地址的网页和DNS条目中申明你的扫描是善意的
  • 明确解释你的扫描中所有连接的目的和范围
  • 提供一个简单的退出扫描的方法并及时响应请求
  • 实施扫描时,不使用比研究对象需求更大的扫描范围或更快的扫描频率
  • 如果可以,将扫描流量分布到不同的时间或源地址上

即使不声明,使用扫描的研究者也应该避免利用漏洞或访问受保护的资源,并遵守其辖区内任何特殊的法律规定。

命令行参数

通用选项

这些选项是实施简单扫描时最常用的选项。我们注意到某些选项取决于所使用的探测模块输出模块(如,在实施ICMP Echo扫描时是不需要使用目的端口的)。

-p, –target-port=port

要扫描的目标TCP端口号(例如,443)

-o, –output-file=name

将结果写入该文件,使用代表输出到标准输出。

-b, –blacklist-file=path

文件中被排除的子网使用CIDR表示法(如192.168.0.0/16),一个一行。建议您使用此方法排除RFC 1918地址、组播地址、IANA预留空间等IANA专用地址。在conf/blacklist.example中提供了一个以此为目的示例黑名单文件。

扫描选项

-n, –max-targets=n

限制探测目标的数量。后面跟的可以是一个数字(例如’-n 1000),或可扫描地址空间的百分比(例如,-n 0.1%`,不包括黑名单)

-N, –max-results=n

收到多少结果后退出

-t, –max-runtime=secs

限制发送报文的时间

-r, –rate=pps

设置发包速率,以包/秒为单位

-B, –bandwidth=bps

以比特/秒设置传输速率(支持使用后缀G,M或K(如-B 10M就是速度10 mbps)的。设置会覆盖–rate

-c, –cooldown-time=secs

发送完成后等待多久继续接收回包(默认值= 8)

-e, –seed=n

地址排序种子。如果要用多个ZMap以相同的顺序扫描地址,那么就可以使用这个参数。

–shards=n

将扫描分片/区,使其可多个ZMap中执行(默认值= 1)。启用分片时,–seed参数是必需的。

–shard=n

选择扫描的分片(默认值= 0)。n的范围在[0,N),其中N为碎片的总数。启用分片时,–seed参数是必需的。

-T, –sender-threads=n

用于发送数据包的线程数(默认值= 1)

-P, –probes=n

发送到每个IP的探测数(默认值= 1)

-d, –dryrun

用标准输出打印出每个包,而不是将其发送(用于调试)

网络选项

-s, –source-port=port|range

发送数据包的源端口

-S, –source-ip=ip|range

发送数据包的源地址。可以仅仅是一个IP,也可以是一个范围(如,10.0.0.1-10.0.0.9)

-G, –gateway-mac=addr

数据包发送到的网关MAC地址(用以防止自动检测不工作的情况)

-i, –interface=name

使用的网络接口

探测选项

ZMap允许用户指定并添加自己所需要的探测模块。 探测模块的职责就是生成要发送的探测包,并处理主机回复的响应包。

–list-probe-modules

列出可用探测模块(如tcp_synscan)

-M, –probe-module=name

选择探测模块(默认值= tcp_synscan)

–probe-args=args

向模块传递参数

–list-output-fields

列出可用的输出模块

输出选项

ZMap允许用户指定和编写他们自己的输出模块。输出模块负责处理由探测模块返回的字段,并将它们输出给用户。用户可以指定输出的字段,并过滤相应字段。

–list-output-modules

列出可用输出模块(如tcp_synscan)

-O, –output-module=name

选择输出模块(默认值为csv)

–output-args=args

传递给输出模块的参数

-f, –output-fields=fields

输出的字段列表,以逗号分割

–output-filter

指定输出过滤器探测模块定义字段进行过滤

附加选项

-C, –config=filename

加载配置文件,可以指定其他路径。

-q, –quiet

不必每秒刷新输出

-g, –summary

在扫描结束后打印配置和结果汇总信息

-v, –verbosity=n

日志详细程度(0-5,默认值= 3)

-h, –help

打印帮助并退出

-V, –version

打印版本并退出

附加信息

TCP SYN 扫描

在执行TCP SYN扫描时,ZMap需要指定一个目标端口,也支持指定发起扫描的源端口范围。

-p, –target-port=port

扫描的TCP端口(例如 443)

-s, –source-port=port|range

发送扫描数据包的源端口(例如 40000-50000)

警示! ZMap基于Linux内核使用RST包来应答SYN/ACK包响应,以关闭扫描器打开的连接。ZMap是在Ethernet层完成包的发送的,这样做是为了减少跟踪打开的TCP连接和路由寻路带来的内核开销。因此,如果您有跟踪连接建立的防火墙规则,如类似于-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT的netfilter规则,将阻止SYN/ACK包到达内核。这不会妨碍到ZMap记录应答,但它会阻止RST包被送回,最终被扫描主机的连接会一直打开,直到超时后断开。我们强烈建议您在执行ZMap时,选择一组主机上未使用且防火墙允许访问的端口,加在-s后(如 -s ‘50000-60000’ )。

ICMP Echo 请求扫描

虽然在默认情况下ZMap执行的是TCP SYN扫描,但它也支持使用ICMP echo请求扫描。在这种扫描方式下ICMP echo请求包被发送到每个主机,并以收到ICMP应答包作为答复。实施ICMP扫描可以通过选择icmp_echoscan扫描模块来执行,如下:

$ zmap --probe-module=icmp_echoscan

UDP 数据报扫描

ZMap还额外支持UDP探测,它会发出任意UDP数据报给每个主机,并接收UDP或ICMP不可达的应答。ZMap可以通过使用–probe-args命令行选项来设置四种不同的UDP载荷。这些是:可在命令行设置可打印的ASCII 码的‘text’载荷和十六进制载荷的‘hex’,外部文件中包含载荷的‘file’,和通过动态字段生成的载荷的‘template’。为了得到UDP响应,请使用-f参数确保您指定的“data”字段处于输出范围。

下面的例子将发送两个字节’ST’,即PCAnwywhere的’status’请求,到UDP端口5632。

$ zmap -M udp -p 5632 --probe-args=text:ST -N 100 -f saddr,data -o -

下面的例子将发送字节“0X02”,即SQL Server的’client broadcast’请求,到UDP端口1434。

$ zmap -M udp -p 1434 --probe-args=hex:02 -N 100 -f saddr,data -o -

下面的例子将发送一个NetBIOS状态请求到UDP端口137。使用一个ZMap自带的载荷文件。

$ zmap -M udp -p 1434 --probe-args=file:netbios_137.pkt -N 100 -f saddr,data -o -

下面的例子将发送SIP的’OPTIONS’请求到UDP端口5060。使用附ZMap自带的模板文件。

$ zmap -M udp -p 1434 --probe-args=file:sip_options.tpl -N 100 -f saddr,data -o -

UDP载荷模板仍处于实验阶段。当您在更多的使用一个以上的发送线程(-T)时可能会遇到崩溃和一个明显的相比静态载荷性能降低的表现。模板仅仅是一个由一个或多个使用${}将字段说明封装成序列构成的载荷文件。某些协议,特别是SIP,需要载荷来反射包中的源和目的包。其他协议,如portmapper和DNS,每个请求包含的字段应该是随机的,或降低被Zamp扫描的多宿主系统的风险。

以下的载荷模板将发送SIP OPTIONS请求到每一个目的地:

OPTIONS sip:${RAND_ALPHA=8}@${DADDR} SIP/2.0
Via: SIP/2.0/UDP ${SADDR}:${SPORT};branch=${RAND_ALPHA=6}.${RAND_DIGIT=10};rport;alias
From: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT};tag=${RAND_DIGIT=8}
To: sip:${RAND_ALPHA=8}@${DADDR}
Call-ID: ${RAND_DIGIT=10}@${SADDR}
CSeq: 1 OPTIONS
Contact: sip:${RAND_ALPHA=8}@${SADDR}:${SPORT}
Content-Length: 0
Max-Forwards: 20
User-Agent: ${RAND_ALPHA=8}
Accept: text/plain

就像在上面的例子中展示的那样,注意每行行末以rn结尾,请求以rnrn结尾,大多数SIP实现都可以正确处理它。一个可以工作的例子放在ZMap的examples/udp-payloads目录下 (sip_options.tpl).

当前实现了下面的模板字段:

  • SADDR: 源IP地址的点分十进制格式
  • SADDR_N: 源IP地址的网络字节序格式
  • DADDR: 目的IP地址的点分十进制格式
  • DADDR_N: 目的IP地址的网络字节序格式
  • SPORT: 源端口的ascii格式
  • SPORT_N: 源端口的网络字节序格式
  • DPORT: 目的端口的ascii格式
  • DPORT_N: 目的端口的网络字节序格式
  • RAND_BYTE: 随机字节(0-255),长度由=(length) 参数决定
  • RAND_DIGIT: 随机数字0-9,长度由=(length) 参数决定
  • RAND_ALPHA: 随机大写字母A-Z,长度由=(length) 参数决定
  • RAND_ALPHANUM: 随机大写字母A-Z和随机数字0-9,长度由=(length) 参数决定

配置文件

ZMap支持使用配置文件来代替在命令行上指定所有要求的选项。配置中可以通过每行指定一个长名称的选项和对应的值来创建:

interface "eth1"
source-ip 1.1.1.4-1.1.1.8
gateway-mac b4:23:f9:28:fa:2d # upstream gateway
cooldown-time 300 # seconds
blacklist-file /etc/zmap/blacklist.conf
output-file ~/zmap-output
quiet
summary

然后ZMap就可以按照配置文件并指定一些必要的附加参数运行了:

$ zmap --config=~/.zmap.conf --target-port=443

详细

ZMap可以在屏幕上生成多种类型的输出。默认情况下,Zmap将每隔1秒打印出相似的基本进度信息。可以通过设置–quiet来禁用。

0:01 12%; send: 10000 done (15.1 Kp/s avg); recv: 144 143 p/s (141 p/s avg); hits: 1.44%

ZMap同样也可以根据扫描配置打印如下消息,可以通过’–verbosity`参数加以控制。

Aug 11 16:16:12.813 [INFO] zmap: started
Aug 11 16:16:12.817 [DEBUG] zmap: no interface provided. will use eth0
Aug 11 16:17:03.971 [DEBUG] cyclic: primitive root: 3489180582
Aug 11 16:17:03.971 [DEBUG] cyclic: starting point: 46588
Aug 11 16:17:03.975 [DEBUG] blacklist: 3717595507 addresses allowed to be scanned
Aug 11 16:17:03.975 [DEBUG] send: will send from 1 address on 28233 source ports
Aug 11 16:17:03.975 [DEBUG] send: using bandwidth 10000000 bits/s, rate set to 14880 pkt/s
Aug 11 16:17:03.985 [DEBUG] recv: thread started

ZMap还支持在扫描之后打印出一个的可grep的汇总信息,类似于下面这样,可以通过调用–summary来实现。

cnf target-port             443
cnf source-port-range-begin         32768
cnf source-port-range-end           61000
cnf source-addr-range-begin         1.1.1.4
cnf source-addr-range-end           1.1.1.8
cnf maximum-packets             4294967295
cnf maximum-runtime             0
cnf permutation-seed            0
cnf cooldown-period             300
cnf send-interface              eth1
cnf rate                    45000
env nprocessors             16
exc send-start-time             Fri Jan 18 01:47:35 2013
exc send-end-time               Sat Jan 19 00:47:07 2013
exc recv-start-time             Fri Jan 18 01:47:35 2013
exc recv-end-time               Sat Jan 19 00:52:07 2013
exc sent                    3722335150
exc blacklisted             572632145
exc first-scanned               1318129262
exc hit-rate                0.874102
exc synack-received-unique          32537000
exc synack-received-total           36689941
exc synack-cooldown-received-unique     193
exc synack-cooldown-received-total      1543
exc rst-received-unique         141901021
exc rst-received-total          166779002
adv source-port-secret          37952
adv permutation-gen             4215763218

结果输出

ZMap可以通过输出模块生成不同格式的结果。默认情况下,ZMap只支持csv的输出,但是可以通过编译支持redisjson 。可以使用输出过滤来过滤这些发送到输出模块上的结果。输出模块输出的字段由用户指定。默认情况如果没有指定输出文件,ZMap将以csv格式返回结果,而不会生成特定结果。也可以编写自己的输出模块;请参阅编写输出模块

-o, –output-file=p

输出写入文件地址

-O, –output-module=p

调用自定义输出模块

-f, –output-fields=p

以逗号分隔的输出的字段列表

–output-filter=filter

对给定的探测指定字段输出过滤

–list-output-modules

列出可用输出模块

–list-output-fields

列出给定的探测的可用输出字段

输出字段

除了IP地址之外,ZMap有很多字段。这些字段可以通过在给定探测模块上运行–list-output-fields来查看。

$ zmap --probe-module="tcp_synscan" --list-output-fields
saddr           string: 应答包中的源IP地址
saddr-raw          int: 网络字节格式的源IP地址
daddr           string: 应答包中的目的IP地址
daddr-raw          int: 网络字节格式的目的IP地址
ipid               int: 应答包中的IP识别号
ttl                int: 应答包中的ttl(存活时间)值
sport              int: TCP 源端口
dport              int: TCP 目的端口
seqnum             int: TCP 序列号
acknum             int: TCP Ack号
window             int: TCP 窗口
classification  string: 包类型
success            int: 是应答包成功
repeat             int: 是否是来自主机的重复响应
cooldown           int: 是否是在冷却时间内收到的响应
timestamp-str   string: 响应抵达时的时间戳使用ISO8601格式
timestamp-ts       int: 响应抵达时的时间戳使用UNIX纪元开始的秒数
timestamp-us       int: 时间戳的微秒部分(例如 从'timestamp-ts'的几微秒)

可以通过使用–output-fields=fields-f来选择选择输出字段,任意组合的输出字段可以被指定为逗号分隔的列表。例如:

$ zmap -p 80 -f "response,saddr,daddr,sport,seq,ack,in_cooldown,is_repeat,timestamp" -o output.csv

过滤输出

在传到输出模块之前,探测模块生成的结果可以先过滤。过滤是针对探测模块的输出字段的。过滤使用类似于SQL的简单过滤语法写成,通过ZMap的–output-filter选项来指定。输出过滤通常用于过滤掉重复的结果,或仅传输成功的响应到输出模块。

过滤表达式的形式为<字段名> <操作符> <值><值>的类型必须是一个字符串或一串无符号整数并且匹配<字段名>类型。对于整数比较有效的操作符是= !=, <, >, <=, >=。字符串比较的操作是=,!=。–list-output-fields可以打印那些可供探测模块选择的字段和类型,然后退出。

复合型的过滤操作,可以通过使用&&(逻辑与)和||(逻辑或)这样的运算符来组合出特殊的过滤操作。

示例

书写一则过滤仅显示成功的、不重复的应答

--output-filter="success = 1 && repeat = 0"

过滤出RST分类并且TTL大于10的包,或者SYNACK分类的包

--output-filter="(classification = rst && ttl > 10) || classification = synack"

CSV

csv模块将会生成以逗号分隔各个要求输出的字段的文件。例如,以下的指令将生成名为output.csv的CSV文件。

$ zmap -p 80 -f "response,saddr,daddr,sport,seq,ack,in_cooldown,is_repeat,timestamp" -o output.csv

#响应, 源地址, 目的地址, 源端口, 目的端口, 序列号, 应答, 是否是冷却模式, 是否重复, 时间戳
response, saddr, daddr, sport, dport, seq, ack, in_cooldown, is_repeat, timestamp
synack, 159.174.153.144, 10.0.0.9, 80, 40555, 3050964427, 3515084203, 0, 0,2013-08-15 18:55:47.681
rst, 141.209.175.1, 10.0.0.9, 80, 40136, 0, 3272553764, 0, 0,2013-08-15 18:55:47.683
rst, 72.36.213.231, 10.0.0.9, 80, 56642, 0, 2037447916, 0, 0,2013-08-15 18:55:47.691
rst, 148.8.49.150, 10.0.0.9, 80, 41672, 0, 1135824975, 0, 0,2013-08-15 18:55:47.692
rst, 50.165.166.206, 10.0.0.9, 80, 38858, 0, 535206863, 0, 0,2013-08-15 18:55:47.694
rst, 65.55.203.135, 10.0.0.9, 80, 50008, 0, 4071709905, 0, 0,2013-08-15 18:55:47.700
synack, 50.57.166.186, 10.0.0.9, 80, 60650, 2813653162, 993314545, 0, 0,2013-08-15 18:55:47.704
synack, 152.75.208.114, 10.0.0.9, 80, 52498, 460383682, 4040786862, 0, 0,2013-08-15 18:55:47.707
synack, 23.72.138.74, 10.0.0.9, 80, 33480, 810393698, 486476355, 0, 0,2013-08-15 18:55:47.710

Redis

Redis的输出模块允许地址被添加到一个Redis的队列,而不是保存到文件,允许ZMap将它与之后的处理工具结合使用。

注意! ZMap默认不会编译Redis功能。如果你从源码构建ZMap,可以在CMake的时候加上-DWITH_REDIS=ON来增加Redis支持。

JSON

JSON输出模块用起来类似于CSV模块,只是以JSON格式写入到文件。JSON文件能轻松地导入到其它可以读取JSON的程序中。

注意!,ZMap默认不会编译JSON功能。如果你从源码构建ZMap,可以在CMake的时候加上-DWITH_JSON=ON来增加JSON支持。

黑名单和白名单

ZMap同时支持对网络前缀做黑名单和白名单。如果ZMap不加黑名单和白名单参数,他将会扫描所有的IPv4地址(包括本地的,保留的以及组播地址)。如果指定了黑名单文件,那么在黑名单中的网络前缀将不再扫描;如果指定了白名单文件,只有那些网络前缀在白名单内的才会扫描。白名单和黑名单文件可以协同使用;黑名单优先于白名单(例如:如果您在白名单中指定了10.0.0.0/8并在黑名单中指定了10.1.0.0/16,那么10.1.0.0/16将不会扫描)。白名单和黑名单文件可以在命令行中指定,如下所示:

-b, –blacklist-file=path

文件用于记录黑名单子网,以CIDR(无类域间路由)的表示法,例如192.168.0.0/16

-w, –whitelist-file=path

文件用于记录限制扫描的子网,以CIDR的表示法,例如192.168.0.0/16

黑名单文件的每行都需要以CIDR的表示格式书写,一行单一的网络前缀。允许使用#加以备注。例如:

# IANA(英特网编号管理局)记录的用于特殊目的的IPv4地址
# http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
# 更新于2013-05-22

0.0.0.0/8           # RFC1122: 网络中的所有主机
10.0.0.0/8          # RFC1918: 私有地址
100.64.0.0/10       # RFC6598: 共享地址空间
127.0.0.0/8         # RFC1122: 回环地址
169.254.0.0/16      # RFC3927: 本地链路地址
172.16.0.0/12       # RFC1918: 私有地址
192.0.0.0/24        # RFC6890: IETF协议预留
192.0.2.0/24        # RFC5737: 测试地址1
192.88.99.0/24      # RFC3068: IPv6转换到IPv4的任播
192.168.0.0/16      # RFC1918: 私有地址
192.18.0.0/15       # RFC2544: 检测地址
198.51.100.0/24     # RFC5737: 测试地址2
203.0.113.0/24      # RFC5737: 测试地址3
240.0.0.0/4         # RFC1112: 预留地址
255.255.255.255/32  # RFC0919: 限制广播地址

# IANA记录的用于组播的地址空间
# http://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
# 更新于2013-06-25

224.0.0.0/4         # RFC5771: 组播/预留地址ed

如果您只是想扫描因特网中随机的一部分地址,使用抽样检出,来代替使用白名单和黑名单。

注意!ZMap默认设置使用/etc/zmap/blacklist.conf作为黑名单文件,其中包含有本地的地址空间和预留的IP空间。通过编辑/etc/zmap/zmap.conf可以改变默认的配置。

速度限制与抽样

默认情况下,ZMap将以您当前网卡所能支持的最快速度扫描。以我们对于常用硬件的经验,这通常是理论上Gbit以太网速度的95-98%,这可能比您的上游提供商可处理的速度还要快。ZMap是不会自动的根据您的上游提供商来调整发送速率的。您可能需要手动的调整发送速率来减少丢包和错误结果。

-r, –rate=pps

设置最大发送速率以包/秒为单位

-B, –bandwidth=bps

设置发送速率以比特/秒(支持G,M和K后缀)。这会覆盖–rate参数。

ZMap同样支持对IPv4地址空间进行指定最大目标数和/或最长运行时间的随机采样。由于每次对主机的扫描是通过随机排序生成的,限制扫描的主机个数为N就会随机抽选N个主机。命令选项如下:

-n, –max-targets=n

探测目标上限数量

-N, –max-results=n

结果上限数量(累积收到这么多结果后退出)

-t, –max-runtime=s

发送数据包时间长度上限(以秒为单位)

-s, –seed=n

种子用以选择地址的排列方式。使用不同ZMap执行扫描操作时将种子设成相同的值可以保证相同的扫描顺序。

举个例子,如果您想要多次扫描同样的一百万个互联网主机,您可以设定排序种子和扫描主机的上限数量,大致如下所示:

zmap -p 443 -s 3 -n 1000000 -o results

为了确定哪一百万主机将要被扫描,您可以执行预扫,只打印数据包而非发送,并非真的实施扫描。

zmap -p 443 -s 3 -n 1000000 --dryrun | grep daddr
    | awk -F'daddr: ' '{print $2}' | sed 's/ |.*//;'

发送多个数据包

ZMap支持向每个主机发送多个探测。增加这个数量既增加了扫描时间又增加了到达的主机数量。然而,我们发现,增加的扫描时间(每个额外扫描的增加近100%)远远大于到达的主机数量(每个额外扫描的增加近1%)。

-P, –probes=n

向每个IP发出的独立探测个数(默认值=1)

示例应用

ZMap专为向大量主机发起连接并寻找那些正确响应而设计。然而,我们意识到许多用户需要执行一些后续处理,如执行应用程序级别的握手。例如,用户在80端口实施TCP SYN扫描也许想要实施一个简单的GET请求,还有用户扫描443端口可能希望完成TLS握手。

Banner获取

我们收录了一个示例程序,banner-grab,伴随ZMap使用可以让用户从监听状态的TCP服务器上接收到消息。Banner-grab连接到提供的服务器上,发送一个可选的消息,然后打印出收到的第一个消息。这个工具可以用来获取banner,例如HTTP服务的回复的具体指令,telnet登陆提示,或SSH服务的字符串。

下面的例子寻找了1000个监听80端口的服务器,并向每个发送一个简单的GET请求,存储他们的64位编码响应至http-banners.out

$ zmap -p 80 -N 1000 -B 10M -o - | ./banner-grab-tcp -p 80 -c 500 -d ./http-req > out

如果想知道更多使用banner-grab的细节,可以参考examples/banner-grab中的README文件。

注意! ZMap和banner-grab(如例子中)同时运行可能会比较显著的影响对方的表现和精度。确保不让ZMap占满banner-grab-tcp的并发连接,不然banner-grab将会落后于标准输入的读入,导致阻塞ZMap的输出写入。我们推荐使用较慢扫描速率的ZMap,同时提升banner-grab-tcp的并发性至3000以内(注意 并发连接>1000需要您使用ulimit -SHn 100000ulimit -HHn 100000来增加每个进程的最大文件描述符数量)。当然,这些参数取决于您服务器的性能、连接成功率(hit-rate);我们鼓励开发者在运行大型扫描之前先进行小样本的试验。

建立套接字

我们也收录了另一种形式的banner-grab,就是forge-socket, 重复利用服务器发出的SYN-ACK,连接并最终取得banner。在banner-grab-tcp中,ZMap向每个服务器发送一个SYN,并监听服务器发回的带有SYN+ACK的应答。运行ZMap主机的内核接受应答后发送RST,这样就没有与该包关联活动连接。程序banner-grab必须在这之后创建一个新的TCP连接到从服务器获取数据。

在forge-socket中,我们利用内核中同名的模块,使我们可以创建任意参数的TCP连接。可以通过抑制内核的RST包,并重用SYN+ACK的参数取代该包而创建套接字,通过这个套接字收发数据和我们平时使用的连接套接字并没有什么不同。

要使用forge-socket,您需要forge-socket内核模块,从github上可以获得。您需要git clone git@github.com:ewust/forge_socket.git至ZMap源码根目录,然后cd进入forge_socket目录,运行make。以root身份运行insmod forge_socket.ko 来安装该内核模块。

您也需要告知内核不要发送RST包。一个简单的在全系统禁用RST包的方法是使用iptables。以root身份运行iptables -A OUTPUT -p tcp -m tcp –tcp-flgas RST,RST RST,RST -j DROP即可,当然您也可以加上一项–dport X将禁用局限于所扫描的端口(X)上。扫描完成后移除这项设置,以root身份运行iptables -D OUTPUT -p tcp -m tcp –tcp-flags RST,RST RST,RST -j DROP即可。

现在应该可以建立forge-socket的ZMap示例程序了。运行需要使用extended_fileZMap输出模块

$ zmap -p 80 -N 1000 -B 10M -O extended_file -o - |
    ./forge-socket -c 500 -d ./http-req > ./http-banners.out

详细内容可以参考examples/forge-socket目录下的README。


编写探测和输出模块

ZMap可以通过探测模块来扩展支持不同类型的扫描,通过输出模块增加不同类型的输出结果。注册过的探测和输出模块可以在命令行中列出:

–list-probe-modules

列出安装过的探测模块

–list-output-modules

列出安装过的输出模块

输出模块

ZMap的输出和输出后处理可以通过实现和注册扫描器的输出模块来扩展。输出模块在接收每一个应答包时都会收到一个回调。然而默认提供的模块仅提供简单的输出,这些模块同样支持更多的输出后处理(例如:重复跟踪或输出AS号码来代替IP地址)。

通过定义一个新的output_module结构来创建输出模块,并在output_modules.c中注册:

typedef struct output_module {
    const char          *name;           // 在命令行如何引用输出模块
    unsigned            update_interval; // 以秒为单位的更新间隔

    output_init_cb      init;            // 在扫描器初始化的时候调用
    output_update_cb    start;           // 在扫描器开始的时候调用
    output_update_cb    update;          // 每次更新间隔调用,秒为单位
    output_update_cb    close;           // 扫描终止后调用

    output_packet_cb    process_ip;      // 接收到应答时调用

    const char          *helptext;       // 会在--list-output-modules时打印在屏幕上

} output_module_t;

输出模块必须有名称,通过名称可以在命令行调用,并且通常会实现success_ip和常见的other_ip回调。process_ip的回调由每个收到并经由probe module过滤的应答包调用。应答是否被认定为成功并不确定(比如,它可以是一个TCP的RST)。这些回调必须定义匹配output_packet_cb定义的函数:

int (*output_packet_cb) (

    ipaddr_n_t    saddr,         // 网络字节格式的发起扫描主机IP地址
    ipaddr_n_t    daddr,         // 网络字节格式的目的IP地址

    const char*   response_type, // 发送模块的数据包分类

    int           is_repeat,     // {0: 主机的第一个应答, 1: 后续的应答}
    int           in_cooldown,   // {0: 非冷却状态, 1: 扫描器处于冷却中}

    const u_char* packet,        // 指向IP包的iphdr结构体的指针
    size_t        packet_len     // 包的长度,以字节为单位
);

输出模块还可以通过注册回调,执行在扫描初始化的时候(诸如打开输出文件的任务)、在扫描开始阶段(诸如记录黑名单的任务)、在扫描的常规间隔(诸如状态更新的任务)、在关闭的时候(诸如关掉所有打开的文件描述符)。提供的这些回调可以完整的访问扫描配置和当前状态:

int (*output_update_cb)(struct state_conf*, struct state_send*, struct state_recv*);

这些定义在output_modules.h中。在src/outputmodules/modulecsv.c中有可用示例。

探测模块

数据包由探测模块构造,它可以创建各种包和不同类型的响应。ZMap默认拥有两个扫描模块:tcp_synscanicmp_echoscan。默认情况下,ZMap使用tcp_synscan来发送TCP SYN包并对每个主机的响应分类,如打开时(收到SYN+ACK)或关闭时(收到RST)。ZMap允许开发者编写自己的ZMap探测模块,使用如下的API:

任何类型的扫描都必须通过开发和注册send_module_t结构中的回调来实现:

typedef struct probe_module {
    const char               *name;             // 如何在命令行调用扫描
    size_t                   packet_length;     // 探测包有多长(必须是静态的)

    const char               *pcap_filter;      // 对收到的响应实施PCAP过滤
    size_t                   pcap_snaplen;      // libpcap 捕获的最大字节数
    uint8_t                  port_args;         // 设为1,如果ZMap需要用户指定--target-port

    probe_global_init_cb     global_initialize; // 在扫描初始化会时被调用一次
    probe_thread_init_cb     thread_initialize; // 每个包缓存区的线程中被调用一次
    probe_make_packet_cb     make_packet;       // 每个主机更新包的时候被调用一次
    probe_validate_packet_cb validate_packet;   // 每收到一个包被调用一次,
                                                // 如果包无效返回0,
                                                // 非零则有效。

    probe_print_packet_cb    print_packet;      // 如果在预扫模式下被每个包都调用
    probe_classify_packet_cb process_packet;    // 由区分响应的接收器调用
    probe_close_cb           close;             // 扫描终止后被调用

    fielddef_t               *fields            // 该模块指定的字段的定义
    int                      numfields          // 字段的数量

} probe_module_t;

在扫描操作初始化时会调用一次global_initialize,可以用来实施一些必要的全局配置和初始化操作。然而,global_initialize并不能访问包缓冲区,那里是线程特定的。代替的,thread_initialize在每个发送线程初始化的时候被调用,提供对于缓冲区的访问,可以用来构建探测包和全局的源和目的值。此回调应用于构建主机不可知的包结构,甚至只有特定值(如:目的主机和校验和),需要随着每个主机更新。例如,以太网头部信息在交换时不会变更(减去校验和是由NIC硬件计算的)因此可以事先定义以减少扫描时间开销。

调用回调参数make_packet是为了让被扫描的主机允许探测模块更新主机指定的值,同时提供IP地址、一个非透明的验证字符串和探测数目(如下所示)。探测模块负责在探测中放置尽可能多的验证字符串,即便当服务器返回的应答为空时,探测模块也能验证它的当前状态。例如,针对TCP SYN扫描,tcp_synscan探测模块会使用TCP源端口和序列号的格式存储验证字符串。响应包(SYN+ACK)将包含目的端口和确认号的预期值。

int make_packet(
    void        *packetbuf,  // 包的缓冲区
    ipaddr_n_t  src_ip,      // 网络字节格式源IP
    ipaddr_n_t  dst_ip,      // 网络字节格式目的IP
    uint32_t    *validation, // 探测中的有效字符串
    int         probe_num    // 如果向每个主机发送多重探测,
                             // 该值为我们对于该主机
                             // 正在发送的探测数目
);

扫描模块也应该定义pcap_filtervalidate_packetprocess_packet。只有符合PCAP过滤器的包才会被扫描。举个例子,在一个TCP SYN扫描的情况下,我们只想要调查TCP SYN / ACK或RST TCP数据包,并利用类似tcp && tcp[13] & 4 != 0 || tcp[13] == 18的过滤方法。validate_packet函数将会被每个满足PCAP过滤条件的包调用。如果验证返回的值非零,将会调用process_packet函数,并使用fields定义的字段和包中的数据填充字段集。举个例子,如下代码为TCP synscan探测模块处理了一个数据包。

void synscan_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs)
{
    struct iphdr *ip_hdr = (struct iphdr *)&packet[sizeof(struct ethhdr)];
    struct tcphdr *tcp = (struct tcphdr*)((char *)ip_hdr
            + (sizeof(struct iphdr)));

    fs_add_uint64(fs, "sport", (uint64_t) ntohs(tcp->source));
    fs_add_uint64(fs, "dport", (uint64_t) ntohs(tcp->dest));
    fs_add_uint64(fs, "seqnum", (uint64_t) ntohl(tcp->seq));
    fs_add_uint64(fs, "acknum", (uint64_t) ntohl(tcp->ack_seq));
    fs_add_uint64(fs, "window", (uint64_t) ntohs(tcp->window));

    if (tcp->rst) { // RST packet
        fs_add_string(fs, "classification", (char*) "rst", 0);
        fs_add_uint64(fs, "success", 0);
    } else { // SYNACK packet
        fs_add_string(fs, "classification", (char*) "synack", 0);
        fs_add_uint64(fs, "success", 1);
    }
}

via: https://zmap.io/documentation.html

译者:martin2011qi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5860-1.html

Linux:LAMP 系统性能调优之内核调优措施

 

LAMP

LAMP的一些快速的内核调优措施 大多数 Linux 发布版都定义了适当的缓冲区和其他 Transmission Control  Protocol(TCP)参数。可以修改这些参数来分配更多的内存,从而改进网络性能。设置内核参数的方法是通过 proc 接口,也就是通过读写  /proc 中的值。幸运的是,sysctl 可以读取 /etc/sysctl.conf 中的值并根据需要填充  /proc,这样就能够更轻松地管理这些参数。清单 2 展示在互联网服务器上应用于 Internet 服务器的一些比较激进的网络设置。 清单 2. 包含较为激进的网络设置的 /etc/sysctl.conf

  • # Use TCP syncookies when needed  
  • net.ipv4.tcp_syncookies = 1  
  • # Enable TCP window scaling  
  • net.ipv4.tcp_window_scaling: = 1  
  • # Increase TCP max buffer size  
  • net.core.rmem_max = 16777216  
  • net.core.wmem_max = 16777216  
  • # Increase Linux autotuning TCP buffer limits  
  • net.ipv4.tcp_rmem = 4096 87380 16777216  
  • net.ipv4.tcp_wmem = 4096 65536 16777216  
  • # Increase number of ports available  
  • net.ipv4.ip_local_port_range = 1024 65000  

将这些设置添加到 /etc/sysctl.conf 的现有内容中。第一个设置启用 TCP SYN cookie。当从客户机发来新的 TCP  连接时,数据包设置了 SYN 位,服务器就为这个半开的连接创建一个条目,并用一个 SYN-ACK  数据包进行响应。在正常操作中,远程客户机用一个 ACK 数据包进行响应,这会使半开的连接转换为全开的。有一种称为 SYN 泛滥(SYN  flood) 的网络攻击,它使 ACK 数据包无法返回,导致服务器用光内存空间,无法处理到来的连接。SYN cookie  特性可以识别出这种情况,并使用一种优雅的方法保留队列中的空间(细节参见 参考资料  一节)。大多数系统都默认启用这个特性,但是确保配置这个特性更可靠。 启用 TCP 窗口伸缩使客户机能够以更高的速度下载数据。TCP 允许在未从远程端收到确认的情况下发送多个数据包,默认设置是最多 64 KB,在与延迟比较大的远程客户机进行通信时这个设置可能不够。窗口伸缩会在头中启用更多的位,从而增加窗口大小。 后面四个配置项增加 TCP 发送和接收缓冲区。这使应用程序可以更快地丢掉它的数据,从而为另一个请求服务。还可以强化远程客户机在服务器繁忙时发送数据的能力。 最后一个配置项增加可用的本地端口数量,这样就增加了可以同时服务的最大连接数量。 在下一次引导系统时,或者下一次运行 sysctl -p /etc/sysctl.conf 时,这些设置就会生效。 通过文章的描述和代码的分析,我们可以通过内核调优措施来对LAMP进行调优!

 

本文内容由 evremonder 提供

 

Linux:10 个你从未用过的 Linux 命令

这也许需要几年甚至是几十年,才能真正掌握 Linux shell 命令。这里有 10 个你从来没有听说或使用过的命令。他们在没有特定的顺序。我最喜欢的是 mkfifo。1、pgrep, 替代:

# ps -ef | egrep '^root ' | awk '{print $2}'
1
2
3
4
5
20
21
38

39

...

你还可以这样:

# pgrep -u root
1
2
3
4
5
20
21
38
39
...

2、pstree,在tree 格式中列出进程,当有webSphere或重任务应用时非常有用。

# pstree
init-+-acpid
|-atd
|-crond
|-cups-config-dae
|-cupsd
|-dbus-daemon-1
|-dhclient
|-events/0-+-aio/0
| |-kacpid
| |-kauditd
| |-kblockd/0
| |-khelper
| |-kmirrord
| `-2*[pdflush]
|-gpm
|-hald
|-khubd
|-2*[kjournald]
|-klogd
|-kseriod
|-ksoftirqd/0
|-kswapd0
|-login---bash
|-5*[mingetty]
|-portmap
|-rpc.idmapd
|-rpc.statd
|-2*[sendmail]
|-smartd
|-sshd---sshd---bash---pstree
|-syslogd
|-udevd
|-vsftpd
|-xfs
`-xinetd

3、bc 是个任意精度计算器语言,它可以Shell脚本执行平方根操作,expr 不支持平方根。

# ./sqrt
Usage: sqrt number
# ./sqrt 64
8
# ./sqrt 132112
363
# ./sqrt 1321121321
36347
Here is the script:
# cat sqrt
#!/bin/bash
if [ $# -ne 1 ]
then
echo 'Usage: sqrt number'
exit 1
else
echo -e "sqrt($1)\nquit\n" | bc -q -i
fi

4、split, 你需要将大的文件分解称若干小部分?split是你的命令,下面是将250MB文件分解为2M的块儿,所有开始于LF_前缀。

# ls -lh largefile
-rw-r--r-- 1 root root 251M Feb 19 10:27 largefile
# split -b 2m largefile LF_
# ls -lh LF_* | head -n 5
-rw-r--r-- 1 root root 2.0M Feb 19 10:29 LF_aa
-rw-r--r-- 1 root root 2.0M Feb 19 10:29 LF_ab
-rw-r--r-- 1 root root 2.0M Feb 19 10:29 LF_ac
-rw-r--r-- 1 root root 2.0M Feb 19 10:29 LF_ad
-rw-r--r-- 1 root root 2.0M Feb 19 10:29 LF_ae
# ls -lh LF_* | wc -l
126

5、nl 数字线,在没发现nl之前,一直用脚本来实现。

# head wireless.h
/*
* This file define a set of standard wireless extensions
*
* Version : 20 17.2.06
*
* Authors : Jean Tourrilhes - HPL
* Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
*/#ifndef _LINUX_WIRELESS_H
# nl wireless.h | head
1 /*
2 * This file define a set of standard wireless extensions
3 *
4 * Version : 20 17.2.06
5 *
6 * Authors : Jean Tourrilhes - HPL
7 * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
8 */9 #ifndef _LINUX_WIRELESS_H

6、mkfifo 是最酷的一个,你一定知道如何创建管道 输送grep的结果到LESS,可能甚至perl。但是你知道如何使2个命令通过1个命名管道沟通?看下图,创建管道,开始写到它。

https://dn-linuxcn.qbox.me/data/attachment/album/201107/07/1320125hjjonek5r2zekbf.png

然后读取它:

https://dn-linuxcn.qbox.me/data/attachment/album/201107/07/132013i8bz7azno61x1xbh.png

7、ldd, 想知道java链接到哪个Linux线程库?

# ldd /usr/java/jre1.5.0_11/bin/java
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00bd4000)
libdl.so.2 => /lib/libdl.so.2 (0x00b87000)
libc.so.6 => /lib/tls/libc.so.6 (0x00a5a000)
/lib/ld-linux.so.2 (0x00a3c000)

8、col, 想保存帮助页面为纯文本?

# PAGER=cat
# man less | col -b > less.txt

9、xmlwf, 需要知道一个XML文档或许是配置文件是否合理?

# curl -s 'http://bashcurescancer.com' > bcc.html
# xmlwf bcc.html
# perl -i -pe 's@@@g' bcc.html
# xmlwf bcc.html
bcc.html:104:2: mismatched tag

10、lsof 列出打开文件,你可以用它做很多很cool的事情,比如查找哪个接口是开放的?

# lsof | grep TCP
portmap 2587 rpc 4u IPv4 5544 TCP *:sunrpc (LISTEN)
rpc.statd 2606 root 6u IPv4 5585 TCP *:668 (LISTEN)
sshd 2788 root 3u IPv6 5991 TCP *:ssh (LISTEN)
sendmail 2843 root 4u IPv4 6160 TCP badhd:smtp (LISTEN)
vsftpd 9337 root 3u IPv4 34949 TCP *:ftp (LISTEN)
cupsd 16459 root 0u IPv4 41061 TCP badhd:ipp (LISTEN)
sshd 16892 root 3u IPv6 61003 TCP badhd.mshome.net:ssh->kontiki.mshome.net:4661 (ESTABLISHED)
Note: OpenBSD 101 pointed out that “lsof -i TCP” a better way to obtain this same information. Thanks!Or find the number of open files a user has. Very important for running big applications like Oracle, DB2, or WebSphere:
# lsof | grep ' root ' | awk '{print $NF}' | sort | uniq | wc -l
179

原文:http://bashcurescancer.com/10-linux-commands-youve-never-used.html

译文:http://www.oschina.net/news/19435/10-linux-commands-youve-never-used

Linux:Memcached真的过时了吗?

这两年Redis火得可以,Redis也常常被当作Memcached的挑战者被提到桌面上来。关于Redis与Memcached的比较更是比比皆是。然而,Redis真的在功能、性能以及内存使用效率上都超越了Memcached吗?

下面内容来自Redis作者在stackoverflow上的一个回答,对应的问题是《Is memcached a dinosaur in comparison to Redis?》(相比Redis,Memcached真的过时了吗?)

You should not care too much about performances. Redis is faster per core with small values, but memcached is able to use multiple cores with a single executable and TCP port without help from the client. Also memcached is faster with big values in the order of 100k. Redis recently improved a lot about big values (unstable branch) but still memcached is faster in this use case. The point here is: nor one or the other will likely going to be your bottleneck for the query-per-second they can deliver.

没有必要过多的关心性能,因为二者的性能都已经足够高了。由于Redis只使用单核,而Memcached可以使用多核,所以在比较上,平均每一个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,但是比起Memcached,还是稍有逊色。说了这么多,结论是,无论你使用哪一个,每秒处理请求的次数都不会成为瓶颈。(比如瓶颈可能会在网卡)

You should care about memory usage. For simple key-value pairs memcached is more memory efficient. If you use Redis hashes, Redis is more memory efficient. Depends on the use case.

如果要说内存使用效率,使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。当然,这和你的应用场景和数据特性有关。

You should care about persistence and replication, two features only available in Redis. Even if your goal is to build a cache it helps that after an upgrade or a reboot your data are still there.

如果你对数据持久化和数据同步有所要求,那么推荐你选择Redis,因为这两个特性Memcached都不具备。即使你只是希望在升级或者重启系统后缓存数据不会丢失,选择Redis也是明智的。

You should care about the kind of operations you need. In Redis there are a lot of complex operations, even just considering the caching use case, you often can do a lot more in a single operation, without requiring data to be processed client side (a lot of I/O is sometimes needed). This operations are often as fast as plain GET and SET. So if you don’t need just GEt/SET but more complex things Redis can help a lot (think at timeline caching).

当然,最后还得说到你的具体应用需求。Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果你需要缓存能够支持更复杂的结构和操作,那么Redis会是不错的选择。

来源:Is memcached a dinosaur in comparison to Redis?(其他人的回答同样值得一看)

VIA http://www.linuxde.net/2012/03/9007.html

Linux:用 CentOS 6 快速配置一台企业级 Web 代理服务器

  Web代理服务器让企业员工可以快速安全地浏览网络。Web代理服务器可以缓存内存,让用户之后对相同网页的请求由本地缓存来处理,这比多次返回网 站来得更快速。代理服务器还能扫描入站网络流量,查找有无恶意内容,并且保护最终用户远离病毒;它们还可以控制哪些用户访问什么样的网络内容。为了充分利 用所有这些功能,本文逐步介绍安装和配置一台简单Web代理服务器(带病毒过滤功能)的整个过程。

  一个完美的安全Web代理服务器包括下列组件:

  • Squid——主要的软件和代理服务。
  • ClamAV——检查入站内容的反病毒软件。
  • C-icap——采用互联网内容适配协议(ICAP)的服务,Squid需要该服务与其他服务进行联系。
  • SquidClamav——基于ClamAV的反病毒服务,Squid通过ICAP服务连接到该服务。

安装配置

  我们将在基本的CentOS 6平台上运行代理服务器,该平台上没有预先安装任何软件包组。如果是最基本的安装,你可以使用来自官方镜像页面的最小镜像。一旦我们安装了操作系统,就可以安装代理服务器的各组件。

  镜像下载:http://www.centos.org/modules/tinycontent/index.php?id=30

Squid

  Squid可以从官方的CentOS 6软件库获得。只要执行yum install squid,即可安装它。确保Squid随系统自动开启和关闭,为此借助命令chkconfig squid on,把它添加到默认的系统启动和关闭级别。

  默认情况下,Squid的主配置文件/etc/squid/squid.conf允许通过常见端口的来自本地网站的请求。去掉cache_dir ufs /var/spool/squid 100 16 256这一行的注释,那样代理服务器将文件缓存在磁盘上。这个命令的参数指示代理服务器使用默认的ufs存储格式。缓存目录是/var/spool /squid,它应该可以存储最多100MB的内容,16个一级子目录和256个次级子目录。考虑将缓存大小从100MB增加到1000MB,因为 100MB太低了,满足不了如今的浏览需求。

  在同一个文件中,在默认配置信息后面,添加下列几个命令:

icap_enable on
icap_send_client_ip on
icap_send_client_username on
icap_client_username_encode off
icap_client_username_header X-Authenticated-User
icap_preview_enable on
icap_preview_size 2048
icap_service service_req reqmod_precache bypass=1 icap://127.0.0.1:1344/squidclamav
adaptation_access service_req allow all
icap_service service_resp respmod_precache bypass=1 icap://127.0.0.1:1344/squidclamav
adaptation_access service_resp allow all

  这个基本配置指示Squid使用在本地主机上运行的SquidClamav ICAP服务,本地主机使用TCP端口1344。对非缓存内容而言,需要使用这项服务。你可以从官方的Squid说明文档,找到关于所有配置命令的更多信息。

ClamAV

  ClamAV并不存在于默认的CentOS 6软件库中,所以你要么从源代码安装,要么使用第三方软件库。我建议使用EPEL软件库,因为它让用户易于安装和维护。

  要将EPEL软件库安装到CentOS 6上,请运行命令rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release- 6-5.noarch.rpm。之后,要安装ClamAV,请执行yum install clamav clamav-db clamd。由于这是从EPEL软件库首次安装,你会看到关于其密钥的提醒;确认密钥正确后才能继续下一步。

  执行chkconfig clamd on,确保ClamAV后台守护进程clamd自动启动和终止。

  你可以设置最基本的ClamAV配置,只需编辑文件/etc/clamd.conf。你得至少移除显示Example的那一行,那样该服务就能启 动。你可能还考虑更改一些命令的默认值。比如说,可以定义使用ScanPE、ScanELF和ScanPDF来扫描哪些文件扩展名。为了提升性能,可以将 待扫描文件的默认最大值(MaxFileSize)由25MB改成其他值,或者更改每个文件的多少数据有待扫描(MaxScanSize)——100MB 是默认值。值越大,所需的资源就越多,代理服务器的速度也就越慢。

  ClamAV病毒特征数据库由一个名为freshclam的独立程序来更新。其配置文件是/etc/freshclam.conf。为了使用它,你同样得至少移除文件开头部分显示Example的那一行。大多数设置不用管,保持默认值就可以了。

  如果你执行没有参数的freshclam,病毒特征更新一次,程序退出。你可以将freshclam配置成一项计划任务(cron job),定期检查ClamAV更新版,或者可以在后台守护模式下启用它,只需运行freshclam -d -c 2,其中-d指明了后台守护模式,-c 2指明了每天更新几次——这个例子中每天两次。把这个命令添加到/etc/rc.local文件中,就可以确保下一次服务器重启时,它会启用。

  在/etc/freshclam.conf中可能需要更改的一项值得关注的设置是SafeBrowsing,它在默认情况下被设置成关闭。这个设置 指定了你是不是想使用谷歌的Safe Browsing(安全浏览)数据库,该数据库里面含有一份更新后的列表,收录了已知的恶意网站。你应该启用它,对性能只有一点影响,除非贵企业的最终用 户在使用已经采用该数据库的浏览器,比如Mozilla Firefox和谷歌Chrome。你只要指定SafeBrowsing yes,就可以开启它。

C-icap

  C-icap并不存在于默认的软件库或EPEL中,所以你得从其网站的源代码安装,对其进行解压缩,然后完成标准的配置、编译和安装这个过程。

  由于C-icap是从源代码自定义安装,并不得到chkconfig的支持。因而,为了让C-icap服务器在系统启动时自动开启,就用新的一行,将其二进制可执行代码/usr/local/bin/c-icap添加到底部的/etc/rc.local。

  你可以找到默认情况下在/usr/local/etc/c-icap.conf的C-icap配置文件。大多数默认选项不用管它。指定 ServerLog /var/log/icapserver.log,将服务器的活动记录到文件/var/log/icapserver.log中;我们以后要用到服务器的 日志,确保一切都在正常运行。

  你在检查配置时,要注意ModulesDir和ServicesDir这两个命令。默认情况下,两者都指向/usr/local/lib/c_icap。这个目录是你安装ICAP服务和模块(如SquidClamav)的地方。

SquidClamav

  你得从源代码安装SquidClamav,原因与C-icap一样。一旦你从其SourceForge网页下载它,对其进行解压缩,然后完成标准的配置、编译和安装这个过程。

  为了确保SquidClamav正确安装,要检查目录/usr/local/lib/c_icap。你应该会看到两个文件:squidclamav.la(libtool 库文件)和squidclamav.so(模块本身)。

  SquidClamav并不作为一项独立的服务来运行,所以没必要把它添加到默认的运行级别来实现自动启动。相反,它是通过C-icap服务器来访问的。

  SquidClamav的配置文件位于/etc/squidclamav.conf。这里,默认配置的大部分选项直接可以拿来用。要更改的其中一个 选项是redirect。最终用户试图下载病毒时,他们会被重定向至你在这里指定的URL。创建详细描述的一个页面,否则你这个管理员会接到大量投诉,反 映下载的内容莫名其妙地无法运行。

  为了创建重定向页面,可以使用脚本cgi-bin/clwarn.cgi,你可以在SqidClamav的源代码归档文件中找到它。只要将它上传至网站,指定redirect example.org/cgi-bin/clwarn.cgi即可。

测试代理服务器

  至此,你的代理服务器应该已安装完毕、合理配置。为了确保所有服务自动开启,重启服务器,然后开始测试。

  你开始测试时,确保可以通过TCP端口3128这个默认代理端口,连接到服务器的IP地址。你必须在默认的CentOS 6防火墙中允许连接到这个端口,除非按基本CentOS 6安装中建议的那样禁用了防火墙。

  一旦你确保了可以连接到这个端口,对浏览器进行同样详细的配置:至于HTTP代理地址,就使用服务器的IP地址;至于端口,使用端口3128。然后 开始浏览网络,看看代理服务器与未使用代理的浏览相比结果怎样。不妨模拟一下许多用户通常浏览的场景。你可能会发现,随着更多的用户开始使用代理服务器, 服务器的资源必须随之增加。

  在服务器端,监控下列日志:

  • Squid的日志——默认情况下,它在文件/var/log/squid/access.log中。你会在那里看到哪些用户的IP地址在提出什么样的请求。
  • C-icap服务器的日志——与/usr/local/etc/c-icap.conf中通过ServerLog之前配置的那样,它应该在/var/log/icapserver.log中。

  对你的代理服务器来说最重要的测试就是,试着下载病毒,看看结果如何。网上有众多资源介绍如何创建含有已知病毒特征的测试文件。一旦创建了这样一个文件,把它上传至某个地方,试着使用新建的代理服务器,用浏览器来下载它。如果一切运行正常,在C-icap服务器的日志中应该会看到这样的条目:

Wed Feb 22 01:03:57 2012, general, DEBUG squidclamav_end_of_data_handler: received from Clamd: stream: Eicar-Test-Signature FOUND
Wed Feb 22 01:03:57 2012, general, DEBUG squidclamav_end_of_data_handler: Virus redirection: http://example.org/cgi-bin/clwarn.cgi?url=http://the_url_of_your_test_virus_file: Eicar-Test-Signature FOUND.

进一步的改进

  如果到目前为止你已经做好了本文介绍的各个步骤,应该有一个带病毒防护功能的基本代理服务器了。你可以在此基础上继续改进、添加更多的功能。下面是针对你添加额外组件来加强用户安全的几个建议:

  • 使用安全DNS。这种DNS不仅可以阻止扩散恶意软件的域耗用资源,还能阻止成人网站,如果进行了相应配置的话。一项广受欢迎的安全DNS服务是诺顿DNS
  • 使用URL过滤(重定向器)。URL过滤器可与分门类别的域列表协同运行,可以根据用户拥有的许可权限,允许或禁止访问网站。这类过滤器经常用于阻止员工访问与工作无关的网站。可与Squid协同运行的一种广受欢迎的过滤器是SquidGuard。它是免费开源的,可以与随处可见的黑名单结合使用。

  要是由于某个原因,这款开源代理解决方案无法完全满足你的需要,可以研究一下主要的几款商用产品,比如SmoothWall,以便最好地满足贵企业的需要。

原文:http://olex.openlogic.com/wazi/2012/a-fast-and-secure-web-proxy-for-corporate-users/

译文:http://os.51cto.com/art/201204/327327.htm

Linux:10个工具让你的 shell 脚本更强大

很多人误以为shell脚本只能在命令行下使用。其实shell也可以调用一些GUI组件,例如菜单,警告框,进度条等等。你可以控制最终的输出,光标位置还有各种输出效果。下面我将介绍一些工具,帮助你创建强大的,互动的,用户友好的 Unix/Linux shell脚本。我在FreeBSD和Linux下测试过这些工具,不过其他UNIX系列的操作系统应该都支持的。 

1. notify-send 命令

这个命令可以让你通过通知进程发送一个桌面通知给用户。这可以用来向用户发送提示,或者显示一些信息而不用打断用户工作。你需要安装如下软件包: 

$ sudo apt-get install libnotify-bin

下面这个例子展示了如何从命令行向桌面发送一个简单的消息: 

notify-send "rsnapshot done :)" 

输出:  下面是一个复杂一点的例子: 

....
alert=18000
live=$(lynx --dump http://money.rediff.com/ | grep 'BSE LIVE' | awk '{ print $5}' | sed 's/,//g;s/\.[0-9]*//g')
[ $notify_counter -eq 0 ] && [ $live -ge $alert ] && { notify-send -t 5000 -u low -i   "BSE Sensex touched 18k";  notify_counter=1; }
...

输出:  这里的参数解释如下: 

  •  -t 5000:指定超时的时间,毫秒
  •  -u low:设置是否紧急
  •  -i gtk-dialog-info:通知图标,你可以指定图标 -i /path/to/your-icon.png

2. tput 命令

这个命令是用来设置终端特性的: 

  •   移动光标
  •   获得终端信息
  •   设置前景和背景色
  •   设置粗体模式
  •   设置反模式等等

举例: 

#!/bin/bash

# clear the screen
tput clear

# Move cursor to screen location X,Y (top left is 0,0)
tput cup 3 15

# Set a foreground colour using ANSI escape
tput setaf 3
echo "XYX Corp LTD."
tput sgr0

tput cup 5 17
# Set reverse video mode
tput rev
echo "M A I N - M E N U"
tput sgr0

tput cup 7 15
echo "1. User Management"

tput cup 8 15
echo "2. Service Management"

tput cup 9 15
echo "3. Process Management"

tput cup 10 15
echo "4. Backup"

# Set bold mode
tput bold
tput cup 12 15
read -p "Enter your choice [1-4] " choice

tput clear
tput sgr0
tput rc

输出:  

3. setleds 命令 

这个命令可以让你控制键盘灯,例如打开数字键盘灯: 

setleds -D +num

关闭数字键盘灯: 

setleds -D -num
  •   -caps: 清除大写灯
  •   +caps:打开大写灯
  •   -scroll:清除滚动锁
  •   +scroll:打开滚动锁

4. zenity 命令

这个命令可以显示GTK+的对话框,然后返回用户的输入。你可以用这个命令在脚本中显示信息,并要求用户输入信息。下面这段代码就是域名的whois查询: 

#!/bin/bash
# Get domain name
_zenity="/usr/bin/zenity"
_out="/tmp/whois.output.$$"
domain=$(${_zenity} --title  "Enter domain" \
                --entry --text "Enter the domain you would like to see whois info" )

if [ $? -eq 0 ]
then
  # Display a progress dialog while searching whois database
  whois $domain  | tee >(${_zenity} --width=200 --height=100 \
                      --title="whois" --progress \
                        --pulsate --text="Searching domain info..." \
                                    --auto-kill --auto-close \
                                    --percentage=10) >${_out}

  # Display back output
  ${_zenity} --width=800 --height=600  \
         --title "Whois info for $domain" \
         --text-info --filename="${_out}"
else
  ${_zenity} --error \
         --text="No input provided"
fi

输出: Fig.04: zenity in Action 

5. kdialog 命令 

这个命令和zenity很想,只不过它是为KDE/QT应用准备的。使用方法如下: 

kdialog --dontagain myscript:nofilemsg --msgbox "File: '~/.backup/config' not found."

输出  你可以查看 shell scription with KDE Dialogs 来获取更多信息 

6. Dialog 

这个命令可以在shell脚本中显示文本组件。它使用了curses和ncurses类库。示例代码: 

>#!/bin/bash
dialog --title "Delete file" \
--backtitle "Linux Shell Script Tutorial Example" \
--yesno "Are you sure you want to permanently delete \"/tmp/foo.txt\"?" 7 60

# Get exit status
# 0 means user hit [yes] button.
# 1 means user hit [no] button.
# 255 means user hit [Esc] key.
response=$?
case $response in
   0) echo "File deleted.";;
   1) echo "File not deleted.";;
   255) echo "[ESC] key pressed.";;
esac

 

7. logger 命令 

这个命令可以让你写入系统日志例如 /var/log/messages: 

logger "MySQL database backup failed."
tail -f /var/log/messages
logger -t mysqld -p daemon.error "Database Server failed"
tail -f /var/log/syslog

输出: Apr 20 00:11:45 vivek-desktop kernel: [38600.515354] CPU0: Temperature/speed normal Apr 20 00:12:20 vivek-desktop mysqld: Database Server failed 

8. setterm 命令 

这个命令可以设置中断的属性。下面的例子是强制屏幕全黑15分钟,并且60分钟后把显示器设为待机状态: 

setterm -blank 15 -powersave powerdown -powerdown 60

下面这段命令可以在中断显示加下划线的文字: 

setterm -underline on;
echo "Add Your Important Message Here"
setterm -underline off

或者你可以关闭光标: 

setterm -cursor off

9. smbclient:

向 MS-Windows 系统发送消息 smbclient可以和 SMB/CIFS服务器通信。它可以向MS-Windows系统的指定用户发送消息: 

smbclient -M WinXPPro <

或者 

echo "${Message}" | smbclient -M salesguy2

10. Bash Socket 编程 

你可以在bash中开启一个socket链接,并且传输数据。Bash有两个特殊的设备文件: 

  •   /dev/tcp/host/port - 如果hostname,和port是合法的话,bash会尝试开启一个TCP连接。
  •   /dev/udp/host/port - 如果hostname和port是合法的话,bash会开启一个UDP连接。

  你可以利用这个技术来测试一台主机的端口是否是开启的,而不需要使用nmap或者port扫描器: 

# find out if TCP port 25 open or not
(echo >/dev/tcp/localhost/25) &>/dev/null && echo "TCP port 25 open" || echo "TCP port 25 close"

你可以 使用循环来查找开着的端口: 

echo "Scanning TCP ports..."
for p in {1..1023}
do
  (echo >/dev/tcp/localhost/$p) >/dev/null 2>&1 && echo "$p open"
done

输出: Scanning TCP ports... 22 open 53 open 80 open 139 open 445 open 631 open 下面的这个例子让你的脚本扮演HTTP客户端: 

#!/bin/bash
exec 3<> /dev/tcp/${1:-www.cyberciti.biz}/80

printf "GET / HTTP/1.0\r\n" >&3
printf "Accept: text/html, text/plain\r\n" >&3
printf "Accept-Language: en\r\n" >&3
printf "User-Agent: nixCraft_BashScript v.%s\r\n" "${BASH_VERSION}"   >&3
printf "\r\n" >&3

while read LINE <&3
do
   # do something on $LINE
   # or send $LINE to grep or awk for grabbing data
   # or simply display back data with echo command
   echo $LINE
done

关于GUITools和Cronjob 

如果你使用cronjob来调用你的脚本的话,你要通过“ export DISPLAY=[user's machine]:0 ”命令来设置本地的 display/input 服务。例如调用 /home/vivek/scripts/monitor.stock.sh脚本,它使用了 zenity 工具: 

@hourly DISPLAY=:0.0 /home/vivek/scripts/monitor.stock.sh

所有的命令你都可以通过“man”来查询详细的使用方式。 

VIA http://www.oschina.net/question/28_39527

Linux:为重负网络优化 Nginx 和 Node.js

在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对。他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以获得很高的并发,不过,要是大家想在廉价硬件上做到每秒数千以上的请求,还是有一些工作要做的。

这篇文章假定读者们使用NginX的HttpProxyModule来为上游的node.js服务器充当反向代理。我们将介绍Ubuntu 10.04以上系统sysctl的调优,以及node.js应用与NginX的调优。当然,如果大家用的是Debian系统,也能达到同样的目标,只不过调优的方法有所不同而已。

网络调优

如果不先对Nginx和Node.js的底层传输机制有所了解,并进行针对性优化,可能对两者再细致的调优也会徒劳无功。一般情况下,Nginx通过TCP socket来连接客户端与上游应用。

我们的系统对TCP有许多门限值与限制,通过内核参数来设定。这些参数的默认值往往是为一般的用途而定的,并不能满足web服务器所需的高流量、短生命的要求。

这里列出了调优TCP可供候选的一些参数。为使它们生效,可以将它们放在/etc/sysctl.conf文件里,或者放入一个新配置文件,比如/etc/sysctl.d/99-tuning.conf,然后运行sysctl -p,让内核装载它们。我们是用sysctl-cookbook来干这个体力活。

需要注意的是,这里列出来的值是可以安全使用的,但还是建议大家研究一下每个参数的含义,以便根据自己的负荷、硬件和使用情况选择一个更加合适的值。

net.ipv4.ip_local_port_range='1024 65000'
net.ipv4.tcp_tw_reuse='1'
net.ipv4.tcp_fin_timeout='15'
net.core.netdev_max_backlog='4096'
net.core.rmem_max='16777216'
net.core.somaxconn='4096'
net.core.wmem_max='16777216'
net.ipv4.tcp_max_syn_backlog='20480'
net.ipv4.tcp_max_tw_buckets='400000'
net.ipv4.tcp_no_metrics_save='1'
net.ipv4.tcp_rmem='4096 87380 16777216'
net.ipv4.tcp_syn_retries='2'
net.ipv4.tcp_synack_retries='2'
net.ipv4.tcp_wmem='4096 65536 16777216'
vm.min_free_kbytes='65536'

重点说明其中几个重要的。

net.ipv4.ip_local_port_range

为了替上游的应用服务下游的客户端,NginX必须打开两条TCP连接,一条连接客户端,一条连接应用。在服务器收到很多连接时,系统的可用端口将很快被耗尽。通过修改net.ipv4.ip_local_port_range参数,可以将可用端口的范围改大。如果在/var/log/syslog中发现有这样的错误: “possible SYN flooding on port 80. Sending cookies”,即表明系统找不到可用端口。增大net.ipv4.ip_local_port_range参数可以减少这个错误。

net.ipv4.tcp_tw_reuse

当服务器需要在大量TCP连接之间切换时,会产生大量处于TIME_WAIT状态的连接。TIME_WAIT意味着连接本身是关闭的,但资源还没有释放。将net_ipv4_tcp_tw_reuse设置为1是让内核在安全时尽量回收连接,这比重新建立新连接要便宜得多。

net.ipv4.tcp_fin_timeout

这是处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。

如何检查连接状态

使用netstat:

netstat -tan | awk ‘{print $6}’ | sort | uniq -c

或使用ss:

ss -s

NginX

随着web服务器的负载逐渐升高,我们就会开始遭遇NginX的某些奇怪限制。连接被丢弃,内核不停报SYN flood。而这时,平均负荷和CPU使用率都很小,服务器明明是可以处理更多连接的状态,真令人沮丧。

经过调查,发现有非常多处于TIME_WAIT状态的连接。这是其中一个服务器的输出:

ss -s
Total: 388 (kernel 541)
TCP:   47461 (estab 311, closed 47135, orphaned 4, synrecv 0, timewait 47135/0), ports 33938

Transport Total     IP        IPv6
*          541       -         -
RAW        0         0         0
UDP        13        10        3
TCP        326       325       1
INET       339       335       4
FRAG       0         0         0

有47135个TIME_WAIT连接!而且,从ss可以看出,它们都是已经关闭的连接。这说明,服务器已经消耗了绝大部分可用端口,同时也暗示我们,服务器是为每个连接都分配了新端口。调优网络对这个问题有一点帮助,但是端口仍然不够用。

经过继续研究,我找到了一个关于上行连接keepalive指令的文档,它写道:

设置通往上游服务器的最大空闲保活连接数,这些连接会被保留在工作进程的缓存中。

有趣。理论上,这个设置是通过在缓存的连接上传递请求来尽可能减少连接的浪费。文档中还提到,我们应该把proxy_http_version设为”1.1″,并清除”Connection”头部。经过进一步的研究,我发现这是一种很好的想法,因为HTTP/1.1相比HTTP1.0,大大优化了TCP连接的使用率,而Nginx默认用的是HTTP/1.0。

按文档的建议修改后,我们的上行配置文件变成这样:

upstream backend_nodejs {
  server nodejs-3:5016 max_fails=0 fail_timeout=10s;
  server nodejs-4:5016 max_fails=0 fail_timeout=10s;
  server nodejs-5:5016 max_fails=0 fail_timeout=10s;
  server nodejs-6:5016 max_fails=0 fail_timeout=10s;
  keepalive 512;
}

我还按它的建议修改了server一节的proxy设置。同时,加了一个 p roxy_next_upstream来跳过故障的服务器,调整了客户端的 keepalive_timeout,并关闭访问日志。配置变成这样:

server {
  listen 80;
  server_name fast.gosquared.com;

  client_max_body_size 16M;
  keepalive_timeout 10;

  location / {
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    proxy_set_header   Connection "";
    proxy_http_version 1.1;
    proxy_pass http://backend_nodejs;
  }

  access_log off;
  error_log /dev/null crit;
}

采用新的配置后,我发现服务器们占用的socket 降低了90%。现在可以用少得多的连接来传输请求了。新的输出如下:

ss -s

Total: 558 (kernel 604)
TCP:   4675 (estab 485, closed 4183, orphaned 0, synrecv 0, timewait 4183/0), ports 2768

Transport Total     IP        IPv6
*          604       -         -
RAW        0         0         0
UDP        13        10        3
TCP        492       491       1
INET       505       501       4

Node.js

得益于事件驱动式设计可以异步处理I/O,Node.js开箱即可处理大量的连接和请求。虽然有其它一些调优手段,但这篇文章将主要关注node.js的进程方面。

Node是单线程的,不会自动使用多核。也就是说,应用不能自动获得服务器的全部能力。

实现Node进程的集群化

我们可以修改应用,让它fork多个线程,在同一个端口上接收数据,从而实现负载的跨越多核。Node有一个cluster模块,提供了实现这个目标所必需的所有工具,但要将它们加入应用中还需要很多体力活。如果你用的是express,eBay有一个叫cluster2的模块可以用。

防止上下文切换

当运行多个进程时,应该确保每个CPU核同一时间只忙于一个进程。一般来说,如果CPU有N个核,我们应该生成N-1个应用进程。这样可以确保每个进程都能得到合理的时间片,而剩下的一个核留给内核调度程序运行其它任务。我们还要确保服务器上基本不执行除Node.js外的其它任务,防止出现CPU的争用。

我们曾经犯过一个错误,在服务器上部署了两个node.js应用,然后每个应用都开了N-1个进程。结果,它们互相之间抢夺CPU,导致系统的负荷急升。虽然我们的服务器都是8核的机器,但仍然可以明显地感觉到由上下文切换引起的性能开销。上下文切换是指CPU为了执行其它任务而挂起当前任务的现象。在切换时,内核必须挂起当前进程的所有状态,然后装载和执行另一个进程。为了解决这个问题,我们减少了每个应用开启的进程数,让它们公平地分享CPU,结果系统负荷就降了下来:

为重负网络优化 Nginx 和 Node.js

请注意上图,看系统负荷(蓝线)是如何降到CPU核数(红线)以下的。在其它服务器上,我们也看到了同样的情况。既然总的工作量保持不变,那么上图中的性能改善只能归功于上下文切换的减少。

链接和参考

● 10 Vital Aspects of building a Node.JS application

● Using NginX to avoid node.js load

● Commands to analyse system socket usage

● TCP/IP setting reference

● Linux kernel tuning 

英文原文:Optimising NginX, Node.JS and networking for heavy workloads,编译:AlfredCheung

Linux:Linux TCP 系统参数配置

我们这里应用的是CentOS5.3,并内核使用的是2.6.18-128.el5PAE #1 SMP 。修改部分TCP ,有的是为了提高性能与负载,但是存在降低稳定性的风险。有的则是安全方面的配置,则有可能牺牲了性能。

1.TCP keepalive TCP连接保鲜设置

echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 15 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 5 > /proc/sys/net/ipv4/tcp_keepalive_probes

keepalive是TCP保鲜定时器。当网络两端建立了TCP连接之后,闲置idle(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器内核就会尝试向客户端发送侦测包,来判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。如果没有收到对方的回答(ack包),则会在tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对对方的ack,如果一直没有收到对方的ack,一共会尝试tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP连接。

2. syn cookies设置

echo 0 > /proc/sys/net/ipv4/tcp_syncookies

在CentOS5.3中,该选项默认值是1,即启用syn cookies功能。我们建议先关闭,直到确定受到syn flood攻击的时候再开启syn cookies功能,有效地防止syn flood攻击。也可以通过iptables规则拒绝syn flood攻击。

3.TCP  连接建立设置

echo 8192 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2 > /proc/sys/net/ipv4/tcp_syn_retries
echo 2 > /proc/sys/net/ipv4/tcp_synack_retries

tcp_max_syn_backlog  SYN队列的长度,时常称之为未建立连接队列。系统内核维护着这样的一个队列,用于容纳状态为SYN_RESC的TCP连接(half-open connection),即那些依然尚未得到客户端确认(ack)的TCP连接请求。加大该值,可以容纳更多的等待连接的网络连接数。

tcp_syn_retries  新建TCP连接请求,需要发送一个SYN包,该值决定内核需要尝试发送多少次syn连接请求才决定放弃建立连接。默认值是5. 对于高负责且通信良好的物理网络而言,调整为2

tcp_synack_retries  对于远端SYN连接请求,内核会发送SYN+ACK数据包来确认收到了上一个SYN连接请求包,然后等待远端的确认(ack数据包)。该值则指定了内核会向远端发送tcp_synack_retires次SYN+ACK数据包。默认设定值是5,可以调整为2

4. TCP 连接断开相关设置

echo 30 >  /proc/sys/net/ipv4/tcp_fin_timeout
echo 15000 > /proc/sys/net/ipv4/tcp_max_tw_buckets
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
echo 1 >  /proc/sys/net/ipv4/tcp_tw_recycle

tcp_fin_timeout 对于由本端主动断开连接的TCP连接,本端会主动发送一个FIN数据报,在收到远端ACK后,且并没有收到远端FIN包之前,该TCP连接的状态是FIN_WAIT_2状态,此时当远端关闭了应用,网络不可达(拔网张),程序不可断僵死等等,本端会一直保留状态为FIN_WAIT_2状态的TCP连接,该值tcp_fin_timeout则指定了状态为FIN_WAIT_2的TCP连接保存多长时间,一个FIN_WAIT_2的TCP连接最多占1.5k内存。系统默认值是60秒,可以将此值调整为30秒,甚至10秒。

tcp_max_tw_buckets 系统同时处理TIME_WAIT sockets数目。如果一旦TIME_WAIT tcp连接数超过了这个数目,系统会强制清除并且显示警告消息。设立该限制,主要是防止那些简单的DoS攻击,加大该值有可能消耗更多的内存资源。如果TIME_WAIT socket过多,则有可能耗尽内存资源。默认值是18w,可以将此值设置为5000~30000 tcp_tw_resue 是否可以使用TIME_WAIT tcp连接用于建立新的tcp连接。

tcp_tw_recycle 是否开启快带回收TIME_WAIT tcp连接的功能。

5. tcp 内存资源使用相参数设定

echo 16777216 > /proc/sys/net/core/rmem_max
echo 16777216 > /proc/sys/net/core/wmem_max
cat /proc/sys/net/ipv4/tcp_mem
echo “4096 65536 16777216″ > /proc/sys/net/ipv4/tcp_rmem
echo “4096 87380 16777216″ > /proc/sys/net/ipv4/tcp_wmem

rmem_max 定义了接收窗口可以使用的最大值,可以根据BDP值进行调节。

wmem_max 定义了发送窗口可以使用的最大值,可以根据BDP什值进行调整。

tcp_mem [low, pressure, high] TCP用这三个值来跟踪内存使用情况,来限定资源占用。通常情况下,在系统boot之时,内核会根据可用内存总数计算出这些值。如果出现了Out of socket memory,则可以试着修改这个参数。

1)low: 当TCP使用了低于该值的内存页面数时,TCP不会考滤释放内存。

2)pressure: 当TCP使用了超过该值的内存页面数量,TCP试图稳定其对内存的占用,进入pressure模式,直到内存消耗达于low值,退出该模式。

3)hight:允许所有tcp sockets用于排队缓冲数据报的内存页数。

tcp_rmem [min, default, max]

1)min 为每个TCP连接(tcp socket)预留用于接收缓冲的内存数量,即使在内存出现紧张情况下TCP socket都至少会有这么多数量的内存用于接收缓冲。

2)default 为TCP socket预留用于接收缓冲的内存数量,默认情况下该值影响其它协议使用的 rmem_default的值,所以有可能被rmem_default覆盖。

3)max 该值为每个tcp连接(tcp socket)用于接收缓冲的内存最大值。该值不会影响wmem_max的值,设置了选项参数 SO_SNDBUF则不受该值影响。

tcp_wmem [min, default, max] 如上(tcp_rmen)只不过用于发送缓存。

注:

1)可以通过sysctl -w 或者写入/etc/sysctl.conf永久保存

2)性能调优仅在于需要的时候进行调整,调整以后需要采集数据与基准测试数据进行比较。建议,不需要盲从地调整这些参数。

via http://www.linuxde.net/2013/05/13600.html

Linux:Linux 性能监测:Network

Linux:Linux 性能监测:Network
Linux:Linux 性能监测:Network

网络的监测是所有 Linux 子系统里面最复杂的,有太多的因素在里面,比如:延迟、阻塞、冲突、丢包等,更糟的是与 Linux 主机相连的路由器、交换机、无线信号都会影响到整体网络并且很难判断是因为 Linux 网络子系统的问题还是别的设备的问题,增加了监测和判断的复杂度。现在我们使用的所有网卡都称为自适应网卡,意思是说能根据网络上的不同网络设备导致的不同网络速度和工作模式进行自动调整。我们可以通过 ethtool 工具来查看网卡的配置和工作模式:

# /sbin/ethtool eth0
Settings for eth0:
	Supported ports: [ TP ]
	Supported link modes:   10baseT/Half 10baseT/Full
	                        100baseT/Half 100baseT/Full
	                        1000baseT/Half 1000baseT/Full
	Supports auto-negotiation: Yes
	Advertised link modes:  10baseT/Half 10baseT/Full
	                        100baseT/Half 100baseT/Full
	                        1000baseT/Half 1000baseT/Full
	Advertised auto-negotiation: Yes
	Speed: 100Mb/s
	Duplex: Full
	Port: Twisted Pair
	PHYAD: 1
	Transceiver: internal
	Auto-negotiation: on
	Supports Wake-on: g
	Wake-on: g
	Current message level: 0x000000ff (255)
	Link detected: yes

上面给出的例子说明网卡有 10baseT,100baseT 和 1000baseT 三种选择,目前正自适应为 100baseT(Speed: 100Mb/s)。可以通过 ethtool 工具强制网卡工作在 1000baseT 下:

# /sbin/ethtool -s eth0 speed 1000 duplex full autoneg off

iptraf

两台主机之间有网线(或无线)、路由器、交换机等设备,测试两台主机之间的网络性能的一个办法就是在这两个系统之间互发数据并统计结果,看看吞吐量、延迟、速率如何。iptraf 就是一个很好的查看本机网络吞吐量的好工具,支持文字图形界面,很直观。下面图片显示在 100 mbps 速率的网络下这个 Linux 系统的发送传输率有点慢,Outgoing rates 只有 66 mbps.

# iptraf -d eth0

linux system performance monitoring: network

 

netperf

netperf 运行在 client/server 模式下,比 iptraf 能更多样化的测试终端的吞吐量。先在服务器端启动 netserver:

# netserver
Starting netserver at port 12865
Starting netserver at hostname 0.0.0.0 port 12865 and family AF_UNSPEC

然后在客户端测试服务器,执行一次持续10秒的 TCP 测试:

# netperf -H 172.16.38.36 -l 10
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec

 87380  16384  16384    10.32      93.68

从以上输出可以看出,网络吞吐量在 94mbps 左右,对于 100mbps 的网络来说这个性能算的上很不错。上面的测试是在服务器和客户端位于同一个局域网,并且局域网是有线网的情况,你也可以试试不同结构、不同速率的网络,比如:网络之间中间多几个路由器、客户端在 wi-fi、VPN 等情况。

netperf 还可以通过建立一个 TCP 连接并顺序地发送数据包来测试每秒有多少 TCP 请求和响应。下面的输出显示在 TCP requests 使用 2K 大小,responses 使用 32K 的情况下处理速率为每秒243:

# netperf -t TCP_RR -H 172.16.38.36 -l 10 -- -r 2048,32768
TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Local /Remote
Socket Size   Request  Resp.   Elapsed  Trans.
Send   Recv   Size     Size    Time     Rate
bytes  Bytes  bytes    bytes   secs.    per sec

16384  87380  2048     32768   10.00     243.03
16384  87380

iperf

iperf 和 netperf 运行方式类似,也是 server/client 模式,先在服务器端启动 iperf:

# iperf -s -D
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
Running Iperf Server as a daemon
The Iperf daemon process ID : 5695

然后在客户端对服务器进行测试,客户端先连接到服务器端(172.16.38.36),并在30秒内每隔5秒对服务器和客户端之间的网络进行一次带宽测试和采样:

# iperf -c 172.16.38.36 -t 30 -i 5
------------------------------------------------------------
Client connecting to 172.16.38.36, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 172.16.39.100 port 49515 connected with 172.16.38.36 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0- 5.0 sec  58.8 MBytes  98.6 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  5.0-10.0 sec  55.0 MBytes  92.3 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 10.0-15.0 sec  55.1 MBytes  92.4 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 15.0-20.0 sec  55.9 MBytes  93.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 20.0-25.0 sec  55.4 MBytes  92.9 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 25.0-30.0 sec  55.3 MBytes  92.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.0 sec    335 MBytes  93.7 Mbits/sec

tcpdump 和 tcptrace

tcmdump 和 tcptrace 提供了一种更细致的分析方法,先用 tcpdump 按要求捕获数据包把结果输出到某一文件,然后再用 tcptrace 分析其文件格式。这个工具组合可以提供一些难以用其他工具发现的信息:

# /usr/sbin/tcpdump -w network.dmp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
511942 packets captured
511942 packets received by filter
0 packets dropped by kernel

# tcptrace network.dmp
1 arg remaining, starting with 'network.dmp'
Ostermann's tcptrace -- version 6.6.7 -- Thu Nov  4, 2004

511677 packets seen, 511487 TCP packets traced
elapsed wallclock time: 0:00:00.510291, 1002714 pkts/sec analyzed
trace file elapsed time: 0:02:35.836372
TCP connection info:
  1: zaber:54581 - boulder:111 (a2b)                   6>    5<  (complete)
  2: zaber:833 - boulder:32774 (c2d)                   6>    5<  (complete)
  3: zaber:pcanywherestat - 172.16.39.5:53086 (e2f)    2>    3<
  4: zaber:716 - boulder:2049 (g2h)                  347>  257<
  5: 172.16.39.100:58029 - zaber:12865 (i2j)           7>    5<  (complete)
  6: 172.16.39.100:47592 - zaber:36814 (k2l)        255380> 255378<  (reset)
  7: breakpoint:45510 - zaber:7012 (m2n)               9>    5<  (complete)
  8: zaber:35813 - boulder:111 (o2p)                   6>    5<  (complete)
  9: zaber:837 - boulder:32774 (q2r)                   6>    5<  (complete)
 10: breakpoint:45511 - zaber:7012 (s2t)               9>    5<  (complete)
 11: zaber:59362 - boulder:111 (u2v)                   6>    5<  (complete)
 12: zaber:841 - boulder:32774 (w2x)                   6>    5<  (complete)
 13: breakpoint:45512 - zaber:7012 (y2z)               9>    5<  (complete)

tcptrace 功能很强大,还可以通过过滤和布尔表达式来找出有问题的连接,比如,找出转播大于100 segments 的连接:

# tcptrace -f'rexmit_segs>100' network.dmp

如果发现连接 #10 有问题,可以查看关于这个连接的其他信息:

# tcptrace -o10 network.dmp

下面的命令使用 tcptrace 的 slice 模式,程序自动在当前目录创建了一个 slice.dat 文件,这个文件包含了每隔15秒的转播信息:

# tcptrace -xslice network.dmp

# cat slice.dat
date                segs    bytes  rexsegs rexbytes      new   active
--------------- -------- -------- -------- -------- -------- --------
16:58:50.244708    85055  4513418        0        0        6        6
16:59:05.244708   110921  5882896        0        0        0        2
16:59:20.244708   126107  6697827        0        0        1        3
16:59:35.244708   151719  8043597        0        0        0        2
16:59:50.244708    37296  1980557        0        0        0        3
17:00:05.244708       67     8828        0        0        2        3
17:00:20.244708      149    22053        0        0        1        2
17:00:35.244708       30     4080        0        0        0        1
17:00:50.244708       39     5688        0        0        0        1
17:01:05.244708       67     8828        0        0        2        3
17:01:11.081080       37     4121        0        0        1        3

 

来源:http://www.vpsee.com/2009/11/linux-system-performance-monitoring-network/