我想将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)
的以下解决方案:
# 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
^C150 packets captured
160 packets received by filter
0 packets dropped by kernel
# file test.gz
test.gz: gzip compressed data, last modified: Wed May 23 12:56:16 2018, from Unix
#
这适用于Debian 9 (Stretch)
但不适用于Debian 8 (Jessie)
:
# 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
tcpdump: Unable to write output: Broken pipe
#
两个问题:
谢谢!
答案 0 :(得分:2)
解释这里发生的事情:
tcpdump
,但也会终止gzip
。 (您尝试的变通方法是通过将内容移动到后台进程中来避免这种情况,因此不会出现在同一进程组中。)stdbuf -oL
或类似方法来禁用此功能。然而... gzip
本质上无法完全无缓冲地运行。这是因为基于块的压缩算法需要将数据收集到块中;分析批量内容; &安培; C。因此,如果gzip
和tcpdump
同时终止,则表示无法保证tcpdump
实际上能够刷新其输出缓冲区,< em>然后gzip
读取,压缩和写入刷新的数据,然后gzip
本身退出同时收到的信号。
请注意,代码片段包含单词&#34; Interactive&#34;用于交互式使用。
作为一个万无一失的解决方案,将gzip
完全移出带外,因此当您在tcpdump
命令上按ctrl + c时,不会发送SIGINT:
exec 3> >(gzip -c >test.gz) # Make FD 3 point to gzip
tcpdump -l -i eth0 >&3 # run tcpdump **AS A SEPARATE COMMAND** writing to that fd
exec 3>&- # later, after you cancelled tcpdump, close the FD.
同样的事情,但稍微长一点并且不依赖于流程替换:
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
请注意,wait
将具有gzip进程的退出状态,因此您可以确定是否遇到错误。
如果我们正在运行脚本,那么设置信号处理程序是合适的,这样我们就可以明确地处理SIGINT(仅通过杀死 tcpdump):
#!/bin/sh
[ "$#" -gt 0 ] || {
echo "Usage: ${0##*/} file.tcpdump.gz [tcpdump-args]" >&2
echo " Example: ${0##*/} foo.tcpdump.gz -l -i eth0" >&2
exit 1
}
outfile=$1; shift
fifo=test-$$.fifo # for real code, put this in a unique temporary directory
trap '[ -n "$tcpdump_pid" ] && kill "$tcpdump_pid"' INT
trap 'rm -f -- "$fifo"' EXIT
rm -f -- "$fifo"; mkfifo "$fifo" || exit
gzip -c >"$outfile" <"$fifo" & gzip_pid=$!
# avoid trying to run tcpdump if gzip obviously failed to start
{ [ -n "$gzip_pid" ] && [ "$gzip_pid" -gt 0 ] && kill -0 "$gzip_pid"; } || exit 1
tcpdump "$@" >"$fifo" & tcpdump_pid=$!
# return exit status of tcpdump if it fails, or gzip if tcpdump succeeds
wait "$tcpdump_pid" || wait "$gzip_pid"
答案 1 :(得分:1)
从Charles Duffy's回答(非常感谢他!):
Ctrl + C 将SIGINT发送到整个流程组。这意味着它不仅会终止
tcpdump
,还会终止gzip
。 (您尝试的变通方法是通过将内容移动到后台进程中来避免这种情况,因此不会出现在同一进程组中。)
因为gzip
仅在压缩完整32k block
时才写出输出文件是对的,所以我在一个终端中启动了“明显的解决方案”......
$ 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。