Bash 将tcpdump输出写入压缩的/gzip文件

Bash 将tcpdump输出写入压缩的/gzip文件,bash,debian,gzip,tcpdump,Bash,Debian,Gzip,Tcpdump,我想将tcpdump的文本输出写入压缩文件 首先,我尝试了最明显的方法: # tcpdump -l -i eth0 | gzip -c > test.gz tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes ^C63 packets capture

我想将tcpdump的文本输出写入压缩文件

首先,我尝试了最明显的方法:

# tcpdump -l -i eth0 | gzip -c > test.gz
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C63 packets captured
244 packets received by filter
0 packets dropped by kernel
4 packets dropped by interface

# file test.gz
test.gz: empty
# 
然后我为Debian 9 Stretch找到了以下解决方案:

这适用于Debian 9 Stretch,但不适用于Debian 8 Jessie:

两个问题:

“显而易见的解决方案”有什么问题? 如何在Debian Jessie中捕获和压缩tcpdump输出?显而易见的解决方案在那里也不起作用 谢谢

发生了什么事 要解释此处发生的情况:

Ctrl+C向整个进程组发送一个SIGINT。这意味着它不仅终止tcpdump,还终止gzip。您尝试的变通方法是通过将内容移动到后台进程,从而从同一进程组中移出来避免这种情况。 默认情况下,只有当输出到TTY时,才会对标准输出进行行缓冲;当输出到FIFO时,它是块缓冲的,只有当有足够大的块可用时,才能从左侧进程写入数据,从而提高效率。在许多情况下,您可以使用stdbuf-oL或类似的工具来禁用它。然而 gzip就其性质而言,不能完全无缓冲地运行。这是因为基于块的压缩算法需要将数据收集到块中;批量分析该内容&C 因此,如果gzip和tcpdump同时终止,这意味着无法保证tcpdump能够在gzip自身退出同时接收的信号之前,刷新其输出缓冲区,然后让gzip读取、压缩和写入刷新的数据

解决问题 请注意,包含Interactive一词的标题下的代码段是用于交互用途的

Bash的可靠交互式解决方案 作为surefire解决方案,请将gzip完全移出带外,这样当您在tcpdump命令上按ctrl+c时,它就不容易被发送信号:

适用于任何POSIX Shell的可靠交互式解决方案 同样的事情,但稍长一点,不依赖流程替代:

mkfifo test.fifo                            # create a named FIFO
gzip -c <test.fifo >test.gz & gzip_pid="$!" # start gzip, reading from that named FIFO
tcpdump -l -i eth0 >test.fifo               # start tcpdump, writing to that named FIFO
rm test.fifo                                # delete the FIFO when done
wait "$gzip_pid"                            # ...and wait for gzip to exit
发生了什么事 要解释此处发生的情况:

Ctrl+C向整个进程组发送一个SIGINT。这意味着它不仅终止tcpdump,还终止gzip。您尝试的变通方法是通过将内容移动到后台进程,从而从同一进程组中移出来避免这种情况。 默认情况下,只有当输出到TTY时,才会对标准输出进行行缓冲;当输出到FIFO时,它是块缓冲的,只有当有足够大的块可用时,才能从左侧进程写入数据,从而提高效率。在许多情况下,您可以使用stdbuf-oL或类似的工具来禁用它。然而 gzip就其性质而言,不能完全无缓冲地运行。这是因为基于块的压缩算法需要将数据收集到块中;批量分析该内容&C 因此,如果gzip和tcpdump同时终止,这意味着无法保证tcpdump能够在gzip自身退出同时接收的信号之前,刷新其输出缓冲区,然后让gzip读取、压缩和写入刷新的数据

解决问题 请注意,包含Interactive一词的标题下的代码段是用于交互用途的

Bash的可靠交互式解决方案 作为surefire解决方案,请将gzip完全移出带外,这样当您在tcpdump命令上按ctrl+c时,它就不容易被发送信号:

适用于任何POSIX Shell的可靠交互式解决方案 同样的事情,但稍长一点,不依赖流程替代:

mkfifo test.fifo                            # create a named FIFO
gzip -c <test.fifo >test.gz & gzip_pid="$!" # start gzip, reading from that named FIFO
tcpdump -l -i eth0 >test.fifo               # start tcpdump, writing to that named FIFO
rm test.fifo                                # delete the FIFO when done
wait "$gzip_pid"                            # ...and wait for gzip to exit
从回答中,我非常感谢他!:

Ctrl+C向整个进程组发送一个SIGINT。这意味着它不仅终止tcpdump,还终止gzip。您尝试的变通方法是通过将内容移动到后台进程,从而从同一进程组中移出来避免这种情况

由于他认为gzip只在一个完整的32k块被压缩时才写入输出文件是正确的,所以我在一个终端中启动了“显而易见的解决方案”

$ tcpdump -l -i eth0 | gzip -c > test.gz
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
1926 packets captured
1938 packets received by filter
0 packets dropped by kernel
$ 
并从第二个终端终止tcpdump:

$ killall -INT tcpdump
$
在后台tcpdump-l-i eth0 | gzip-c>test.gz&中启动“显而易见的解决方案”,将允许从同一终端杀死tcpdump。

从回答中感谢他!:

Ctrl+C向整个进程组发送一个SIGINT。这意味着它不仅终止tcpdump,还终止gzip。您尝试的变通方法是通过将内容移动到后台进程,从而从同一进程组中移出来避免这种情况

由于他认为gzip只在一个完整的32k块被压缩时才写入输出文件是正确的,所以我在一个终端中启动了“显而易见的解决方案”

$ tcpdump -l -i eth0 | gzip -c > test.gz
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
1926 packets captured
1938 packets received by filter
0 packets dropped by kernel
$ 
并从第二个终端终止tcpdump:

$ killall -INT tcpdump
$
在后台tcpdump-l-i eth0 | gzip-c>test.gz中启动“显而易见的解决方案”,将允许从同一终端终止tcpdump。

显而易见的解决方案是在管道中有足够的内容流动的情况下工作的。如果您只想捕获几行,或者需要在按下ctrl+c时捕获所有内容,那么。。。是的,你有问题。然而,当需要内联gzip时,通常不会捕获非常少量的内容。顺便说一句,对于额外的妄想症,您可以将我的答案中的tcpdump更改为stdbuf-oL tcpdump,告诉glibc在每行之后刷新tcpdump的输出。但是,不应该需要,因为SIGINT是可捕获的,因此允许程序自己进行最终刷新。如果SIGKILL发生关机,您将需要它,然而…顺便说一句,可能是有用的补充阅读。谢谢您的解释。我刚刚核实过。gzip仅在压缩完整的32k块时写入文件。由于我最初的tcpdump输出包含许多类似的行,因此需要相当长的时间才能达到32k。显而易见的解决方案是,通过管道传输的内容足够多。如果您只想捕获几行,或者需要在按下ctrl+c时捕获所有内容,那么。。。是的,你有问题。然而,当需要内联gzip时,通常不会捕获非常少量的内容。顺便说一句,对于额外的妄想症,您可以将我的答案中的tcpdump更改为stdbuf-oL tcpdump,告诉glibc在每行之后刷新tcpdump的输出。但是,不应该需要,因为SIGINT是可捕获的,因此允许程序自己进行最终刷新。如果SIGKILL发生关机,您将需要它,然而…顺便说一句,可能是有用的补充阅读。谢谢您的解释。我刚刚核实过。gzip仅在压缩完整的32k块时写入文件。由于我最初的tcpdump输出包含许多类似的行,因此需要相当长的时间才能达到32k。
$ killall -INT tcpdump
$