Записать вывод tcpdump в сжатый / gziped файл - PullRequest
0 голосов
/ 23 мая 2018

Я хочу записать текстовый вывод 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
# 

Два вопроса:

  1. Что не так с«очевидное решение»?
  2. Как записать и сжать вывод tcpdump в Debian Jessie?(Очевидное решение там тоже не работает)

Спасибо!

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

От Ответ Чарльза Даффи (большое ему спасибо!):

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 с того же терминала.

0 голосов
/ 23 мая 2018

Что случилось

Чтобы объяснить, что здесь происходит:

  • Ctrl + C отправляет SIGINT на вся группа процессов .Это означает, что он не только завершает tcpdump, но также завершает gzip.(Временные решения, которые вы пытались избежать, пытаются избежать этого путем перемещения содержимого в фоновые процессы и, следовательно, из одной и той же группы процессов).
  • stdout по умолчанию буферизуется в строке только в том случае, если вывод выполняется в TTY;когда выходные данные передаются в FIFO, они буферизуются в блоке, что позволяет повысить эффективность путем записи данных из левого процесса только при наличии достаточно большого фрагмента.В многих ситуациях вы можете просто использовать stdbuf -oL или подобное, чтобы отключить это.Однако ...
  • gzip по своей природе не может работать полностью без буферизации.Это потому, что алгоритмы сжатия на основе блоков должны собирать данные, в общем, блоки ;анализировать этот контент навалом;& c.

Итак, если gzip и tcpdump завершены одновременно, это означает, что нет никакой гарантии, что tcpdump действительно сможет очистить свой выходной буфер, а затем gzip прочитайте, сожмите и запишите эти очищенные данные , прежде чем gzip сам выйдет из сигнала, который он получил одновременно.


Исправление проблемы

Обратите внимание, что фрагменты кода под заголовками, содержащими слово "Интерактивный", предназначены для интерактивного использования .


Надежный интерактивный обходной путь (для Bash)

Как верное решение, переместите gzip полностью вне диапазона, чтобы он не был склонен к отправке SIGINT при нажатии ctrl + c на команде tcpdump:

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.

Надежный интерактивный обходной путь (для любой оболочки POSIX)

То же самое, но немного дольше и не зависит от замены процесса:

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, так что вы можете определить, чтоВ эфире обнаружена ошибка.


Надежный сценарий обходного решения (для любой оболочки POSIX)

Если мы запускаем скрипт, то целесообразно настроить обработчик сигнала, чтобы мыможет обрабатывать 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"
...