我正在使用这个脚本来检查传入数据包的速率,如果速率达到 5mbps 或更高,就会触发该脚本。然后将数据包记录到 tcpdump 文件中。
interface=eth0
dumpdir=/tmp/
while /bin/true; do
pkt_old=`grep $interface: /proc/net/dev | cut -d : -f2 | awk '{ print $2 }'`
sleep 1
pkt_new=`grep $interface: /proc/net/dev | cut -d : -f2 | awk '{ print $2 }'`
pkt=$(( $pkt_new - $pkt_old ))
echo -ne "\r$pkt packets/s\033[0K"
if [ $pkt -gt 5000 ]; then
echo -e "\n`date` Under attack, dumping packets."
tcpdump -n -s0 -c 2000 -w $dumpdir/dump.`date +"%Y%m%d-%H%M%S"`.cap
echo "`date` Packets dumped, sleeping now."
sleep 300
fi
done
输出类似于捕获了 2000 个数据包。过滤器接收了 XXX 个数据包,内核丢弃了 XXX-(减)2000 个数据包。
现在我想知道的是,输出文件实际上不会告诉我攻击的速率,比如它是 300mbps 还是什么?那么过滤器每秒接收的 XXX 个数据包是多少?如果不是,我该如何检查,因为我的端口有时会饱和。
更新:
我使用一个程序通过上述脚本从捕获的文件中捕获统计信息。 以下是我得到的结果:
root@$:/tmp/dumps# capinfos dump.20130621-174506.cap
File name: dump.20130621-174506.cap
File type: Wireshark/tcpdump/... - libpcap
File encapsulation: Linux cooked-mode capture
Number of packets: 2000
File size: 2065933 bytes
Data size: 2033909 bytes
Capture duration: 43 seconds
Start time: Fri Jun 21 17:45:06 2013
End time: Fri Jun 21 17:45:49 2013
Data byte rate: 46968.49 bytes/sec
Data bit rate: 375747.94 bits/sec
Average packet size: 1016.95 bytes
Average packet rate: 46.19 packets/sec
我认为攻击可能只持续了 15-20 秒,而捕获的信息持续了 43 秒,因此这里的数据比特率可能是从这个总时间中平均得出的。如果有人可以编辑上面的原始脚本,而不是捕获 2000 个数据包并丢弃其余数据包,在达到阈值时捕获所有数据包,持续时间为 5 秒,这可能会有所帮助。
更新:
按照上述方法更改脚本后,我发现文件似乎已损坏,因为我在 Wireshark 中看到它说“捕获文件似乎在数据包中间被截断了”。以下是 capinfos 的输出:
capinfos: An error occurred after reading 3085 packets from `"dump.20130710-215413.cap": Less data was read than was expected.
第二次尝试时,只有当我在脚本控制台中按下 Ctrl+C 时才能够读取该文件:
capinfos dump.20130710-215413.cap
File name: dump.20130710-215413.cap
File type: Wireshark/tcpdump/... - libpcap
File encapsulation: Linux cooked-mode capture
Number of packets: 18136
File size: 2600821 bytes
Data size: 2310621 bytes
Capture duration: 591 seconds
Start time: Wed Jul 10 21:54:13 2013
End time: Wed Jul 10 22:04:04 2013
Data byte rate: 3909.73 bytes/sec
Data bit rate: 31277.83 bits/sec
Average packet size: 127.41 bytes
Average packet rate: 30.69 packets/sec
注意捕获持续时间为 591 秒。我相信“sleep 300”在这里与此有关,因为我看到了控制台输出。此输出带有“-c 2000”选项:
./Log.sh
10275 packets/s
Wed Jul 10 12:41:31 MSD 2013 Under attack, dumping packets.
tcpdump: listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
2000 packets captured
100012 packets received by filter
98003 packets dropped by kernel
Wed Jul 10 12:42:34 MSD 2013 Packets dumped, sleeping now.
现在这是使用“sleep 5”修改脚本后的输出:
./Log.sh
24103 packets/s
Wed Jul 10 21:54:13 MSD 2013 Under attack, dumping packets.
tcpdump: listening on venet0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
Wed Jul 10 21:54:18 MSD 2013 Packets dumped, sleeping now.
1620 packets/sroot@nl:~# 18136 packets captured
1850288 packets received by filter
1832106 packets dropped by kernel
^C
注意,我按下了 Ctrl+C 来中断睡眠功能,我猜这使得读取文件成为可能。
答案1
首都信息网是您正在寻找的:
$ capinfos ddos.cap
File name: ddos.cap
File type: Wireshark/tcpdump/... - libpcap
File encapsulation: Ethernet
Packet size limit: file hdr: 65535 bytes
Number of packets: 1000000
File size: 189073212 bytes
Data size: 173073188 bytes
Capture duration: 2 seconds
Start time: Fri Jul 5 16:35:04 2013
End time: Fri Jul 5 16:35:07 2013
Data byte rate: 69839025.27 bytes/sec
Data bit rate: 558712202.18 bits/sec
Average packet size: 173.07 bytes
Average packet rate: 403523.08 packets/sec
SHA1: 34d758e6445061855ca4397729098f469f411fe3
RIPEMD160: 14f430231fc2962cd86ddb8edb8daf75a5d07af8
MD5: 5893809fb02d1a20997629a9a501842b
Strict time order: False
注意数据比特率。
这里可能会有帮助的是,如果有人可以编辑上面的原始脚本,而不是捕获 2000 个数据包并丢弃其余数据包,而是在达到阈值时捕获所有数据包,持续时间为 5 秒。
这个怎么样:
tcpdump -n -s0 -w $dumpdir/dump.`date +"%Y%m%d-%H%M%S"`.cap &
sleep 5 && pkill -HUP -f /usr/sbin/tcpdump
答案2
计算每秒的数据包数量:
tcpdump -tttt -r dump.pcap | awk '{ print $2 }' | cut --delimiter='.' --fields=1 | uniq -c
这将按时间列进行过滤,并删除微秒部分,并按接收时间分组。
输出:
列:# packets
,received at time
1 21:12:35
3 21:12:39
567 21:12:40
答案3
如何使用tcpdump
纳秒分辨率时间戳测量数据包速率(频率)
摘要:
对于下面显示的两个选项,更新num_packets
值和tcpdump
命令就是全部,在这些“单行”命令 blob 中:
选项1:
这总是有效并且非常好:
num_packets="25"; \
time_start_sec="$(date +"%s.%N")"; \
time sudo tcpdump -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)"; \
time_end_sec="$(date +"%s.%N")"; \
dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
packet_rate_hz="$(bc <<< "scale=20; $num_packets / $dt_sec")"; \
printf "\n%s%.3f\n\n" "packet_rate_hz = " "$packet_rate_hz"
选项 2 [最佳]:
这适用于大多数(如果不是全部)tcpdump
命令,不是包括-t
标志,并且好多了!:
num_packets="10"; \
time sudo tcpdump -l -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)" \
| tee tcpdump.txt; \
time_start_sec="$(grep -o \
'[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
"tcpdump.txt" \
| head -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
time_end_sec="$(grep -o \
'[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
"tcpdump.txt" \
| tail -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
packet_rate_hz="$(bc <<< "scale=20; ($num_packets-1) / $dt_sec")"; \
printf "\n%s%.4f\n\n" "packet_rate_hz = " "$packet_rate_hz"
选项 1:使用纳秒级精度的时间戳手动计时整个过程date
这没问题。我只需告诉tcpdump
抓取一定数量的数据包,对整个过程进行计时,然后计算数据包速率:
num_packets="25"; \
time_start_sec="$(date +"%s.%N")"; \
time sudo tcpdump -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)"; \
time_end_sec="$(date +"%s.%N")"; \
dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
packet_rate_hz="$(bc <<< "scale=20; $num_packets / $dt_sec")"; \
printf "\n%s%.3f\n\n" "packet_rate_hz = " "$packet_rate_hz"
这是一条 bash“单行代码”。一次性复制并粘贴整个代码块。务必先将变量更新num_packets
为要捕获的数据包数量,然后更新行tcpdump
以仅过滤您感兴趣的数据包。换句话说,根据您的需要修改以下两行:
num_packets="25"; \
time sudo tcpdump -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)"; \
它将在最后打印出数据包速率,如下所示(其中真实数据包速率为 10.00 Hz):
packet_rate_hz = 9.418
请注意,由于tcpdump
启动时会产生一些开销,显示的计算频率(本例中为 9.698 Hz)偏低了一点。我知道它的实际频率是 10.00 Hz(是的,精度大于 2 个零),因为我编写了发送数据包的代码,并使用了精确的计时来执行此操作——请参阅我的答案定时该代码的一部分:如何使用软实时调度程序和纳秒延迟在 Linux 中轻松以任意频率(例如:高达 10 KHz~100 KHz)运行高分辨率、高精度周期循环
因此,对于选项 1,使用更大的数据包数(设置num_packets
为更大的值,例如25
或50
更多)更好,因为它减少了启动开销引入的错误tcpdump
,我们将其包含在我们的时间安排中,但不想这样做。
真实数据的完整命令和输出示例:
$ num_packets="25"; \
> time_start_sec="$(date +"%s.%N")"; \
> time sudo tcpdump -i any -c "$num_packets" \
> "(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)"; \
> time_end_sec="$(date +"%s.%N")"; \
> dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
> packet_rate_hz="$(bc <<< "scale=20; $num_packets / $dt_sec")"; \
> printf "\n%s%.3f\n" "packet_rate_hz = " "$packet_rate_hz"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:58:36.181547 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.281798 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.381547 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.481842 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.581581 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.681724 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.781734 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.881735 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:36.981637 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.081633 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.181585 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.281661 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.381456 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.481732 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.581709 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.681696 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.781710 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.881603 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:37.981751 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.081860 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.181669 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.281727 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.381457 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.481574 IP localhost.40000 > localhost.40001: UDP, length 44
11:58:38.581724 IP localhost.40000 > localhost.40001: UDP, length 44
25 packets captured
50 packets received by filter
0 packets dropped by kernel
real 0m2.651s
user 0m0.016s
sys 0m0.017s
packet_rate_hz = 9.418
选项 2 [最佳——尽可能使用此方法!]:从tcpdump
输出中提取第一个和最后一个数据包时间戳,并使用它们来确定数据包速率
对于这种技术,我们需要做一些事情:
- 首先,请始终使用
-l
(破折号小写 L,而不是破折号 1)标志tcpdump
来制作 stdout 输出行缓冲这样,您将在脚本运行时看到它定期更新。如果不使用此标志,tcpdump
如果输出很短,您将只能在命令的最后看到一次输出;如果输出很长,您将在每次 stdout 缓冲区完全填满时看到大量的定期块。 - 将输出通过管道传输到
tee
以下位置:A)将其保存到文件中,然后可以从中提取时间戳和B)将其打印到标准输出,以便您可以实时看到它。
这是“一行代码”。请注意,该time
部分是可选的。它只是在最后打印出总时间,我认为这很好。再次更新值num_packets
和命令以满足您的需要。您可以使用的tcpdump
最小值为。num_packets
2
这种技术具有很高的精确度,因此您不是需要使用较大的num_packets
值才能使其正常工作。收集尽可能少的2
数据包会产生良好的结果,而10
收集数据包会产生出色的结果。
num_packets="10"; \
time sudo tcpdump -l -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)" \
| tee tcpdump.txt; \
time_start_sec="$(grep -o \
'[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
"tcpdump.txt" \
| head -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
time_end_sec="$(grep -o \
'[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
"tcpdump.txt" \
| tail -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
packet_rate_hz="$(bc <<< "scale=20; ($num_packets-1) / $dt_sec")"; \
printf "\n%s%.4f\n\n" "packet_rate_hz = " "$packet_rate_hz"
再次,根据您的需要修改这两行(如下所示),记住以下几点:
- 对于
tcpdump
线,请务必保留-l
和| tee tcpdump.txt
,如上所述。 - 此外,使用
-t
withtcpdump
意味着“不在每个转储行上打印时间戳”,如果使用,将导致该技术不是因为它依赖于这些时间戳,所以无法工作。但是,上面的选项 1 仍然可以正常工作。 - 如果您正在使用嵌入式 Linux 板,请考虑以下事项:
- 它可能具有大多数只读的文件系统,在这种情况下,您需要强制将输出
tee
放入文件系统可写部分的文件中,例如,也许不仅仅是/var/log/tcpdump.txt
在您当前的目录中。/tmp/tcpdump.txt
tcpdump.txt
- 如果默认情况下文件系统的任何部分都不可写,那么您可能需要先卸载它并将其重新挂载为可读写 (
rw
),如下所示。然后,运行tcpdump
上述命令。完成后,您可以将其重新挂载为只读 (ro
),如下所示:# Remount your root dir (/) as read-writable (rw) mount -o remount,rw / # Remount your root dir (/) as read-only (ro) mount -o remount,ro /
- 如果默认情况下文件系统的任何部分都不可写,那么您可能需要先卸载它并将其重新挂载为可读写 (
- 您的嵌入式 Linux 主板可能不是有
sudo
命令,在这种情况下,您需要直接 ssh 或以 root 身份登录到主板,并sudo
从tcpdump
上面的命令中删除该单词。
- 它可能具有大多数只读的文件系统,在这种情况下,您需要强制将输出
num_packets="10"; \
time sudo tcpdump -l -i any -c "$num_packets" \
"(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)" \
| tee tcpdump.txt; \
最后打印的示例数据包速率(其中真实数据包速率为 10.00 Hz):
packet_rate_hz = 10.0003
示例完整命令和实际数据的输出。请注意,当使用 缓冲输出时-l
,stderr
输出(例如指示捕获、接收和丢弃了多少个数据包的行)会意外地与其余输出混合在一起stdout
。没关系。这不是理想的情况,但我们对此无能为力。所以,这是正常的。
$ num_packets="10"; \
> time sudo tcpdump -l -i any -c "$num_packets" \
> "(src 127.0.0.1 and port 40000) and (dst 127.0.0.1 and port 40001)" \
> | tee tcpdump.txt; \
> time_start_sec="$(grep -o \
> '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
> "tcpdump.txt" \
> | head -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
> time_end_sec="$(grep -o \
> '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]*' \
> "tcpdump.txt" \
> | tail -n 1 | grep -o '[0-9][0-9]\.[0-9]*')"; \
> dt_sec="$(bc <<< "scale=20; $time_end_sec - $time_start_sec")"; \
> packet_rate_hz="$(bc <<< "scale=20; ($num_packets-1) / $dt_sec")"; \
> printf "\n%s%.4f\n\n" "packet_rate_hz = " "$packet_rate_hz"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:59:35.481669 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:35.581440 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:35.681468 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:35.781661 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:35.881649 IP localhost.40000 > localhost.40001: UDP, length 44
10 packets captured
28 packets received by filter
0 packets dropped by kernel
11:59:35.981540 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:36.081669 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:36.181423 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:36.281595 IP localhost.40000 > localhost.40001: UDP, length 44
11:59:36.381638 IP localhost.40000 > localhost.40001: UDP, length 44
real 0m1.098s
user 0m0.021s
sys 0m0.009s
packet_rate_hz = 10.0003
选项 1 与选项 2
如果上述选项 2 更好并且产生更好的结果,我们为什么还要使用选项 1?
好吧,如果你曾经使用-t
带有 的标志tcpdump
,man tcpdump
则表示它意味着:
-t Don't print a timestamp on each dump line.
因此,如果使用该标志,选项 2 显然不起作用,因为它依赖于这些时间戳。但是,选项 1 仍然可以正常工作!
如果出现任何其他场景或可能的tcpdump
命令,而这些命令无法与选项 2 很好地配合使用,则可以使用选项 1,它始终有效。但是,只要可能,请使用选项 2,因为它会产生更加准确和精确输出!
参考
- 为了帮助我提出我的正则表达式
grep
:https://regex101.com/