tcpdump - 如何检查数据包的速率?

tcpdump - 如何检查数据包的速率?

我正在使用这个脚本来检查传入数据包的速率,如果速率达到 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

这将按时间列进行过滤,并删除微秒部分,并按接收时间分组。

输出:

列:# packetsreceived 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为更大的值,例如2550更多)更好,因为它减少了启动开销引入的错误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输出中提取第一个和最后一个数据包时间戳,并使用它们来确定数据包速率

对于这种技术,我们需要做一些事情:

  1. 首先,请始终使用-l(破折号小写 L,而不是破折号 1)标志tcpdump来制作 stdout 输出行缓冲这样,您将在脚本运行时看到它定期更新。如果不使用此标志,tcpdump如果输出很短,您将只能在命令的最后看到一次输出;如果输出很长,您将在每次 stdout 缓冲区完全填满时看到大量的定期块。
  2. 将输出通过管道传输到tee以下位置:A)将其保存到文件中,然后可以从中提取时间戳B)将其打印到标准输出,以便您可以实时看到它。

这是“一行代码”。请注意,该time部分是可选的。它只是在最后打印出总时间,我认为这很好。再次更新值num_packets和命令以满足您的需要。您可以使用的tcpdump最小值为。num_packets2这种技术具有很高的精确度,因此您不是需要使用较大的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"

再次,根据您的需要修改这两行(如下所示),记住以下几点:

  1. 对于tcpdump线,请务必保留-l| tee tcpdump.txt,如上所述。
  2. 此外,使用-twithtcpdump意味着“不在每个转储行上打印时间戳”,如果使用,将导致该技术不是因为它依赖于这些时间戳,所以无法工作。但是,上面的选项 1 仍然可以正常工作。
  3. 如果您正在使用嵌入式 Linux 板,请考虑以下事项:
    1. 它可能具有大多数只读的文件系统,在这种情况下,您需要强制将输出tee放入文件系统可写部分的文件中,例如,也许不仅仅是/var/log/tcpdump.txt在您当前的目录中。 /tmp/tcpdump.txttcpdump.txt
      1. 如果默认情况下文件系统的任何部分都不可写,那么您可能需要先卸载它并将其重新挂载为可读写 ( 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 /
        
    2. 您的嵌入式 Linux 主板可能不是sudo命令,在这种情况下,您需要直接 ssh 或以 root 身份登录到主板,并sudotcpdump上面的命令中删除该单词。
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

示例完整命令和实际数据的输出。请注意,当使用 缓冲输出时-lstderr输出(例如指示捕获、接收和丢弃了多少个数据包的行)会意外地与其余输出混合在一起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带有 的标志tcpdumpman tcpdump则表示它意味着:

-t     Don't print a timestamp on each dump line.

因此,如果使用该标志,选项 2 显然不起作用,因为它依赖于这些时间戳。但是,选项 1 仍然可以正常工作!

如果出现任何其他场景或可能的tcpdump命令,而这些命令无法与选项 2 很好地配合使用,则可以使用选项 1,它始终有效。但是,只要可能,请使用选项 2,因为它会产生更加准确和精确输出!

参考

  1. 为了帮助我提出我的正则表达式grephttps://regex101.com/

相关内容