22

I am trying to troubleshoot an issue where I only have tcpdump available on an appliance. I want to use tcpdump to filter web traffic, and only display traffic containing certain strings.

I do the following:

tcpdump -nei eth0 -X | grep "something interesting"

The output is a hexview with 16 bytes pr line. I cannot grep this data, as the data is presented on multiple lines.

Is there a way for tcpdump to present the captured data on a single line? This would make it possible to use grep to find interesting packets.

Dog eat cat world
  • 366
  • 1
  • 4
  • 14

6 Answers6

18

For those like you who cannot use ngrep, here's how to use awk to make the tcpdump output of packet contents grepable.

First some sample output as provided by tcpdump -x, in order to present the task ahead:

$ tcpdump -xr dump.pcap 2>/dev/null
12:04:59.590664 IP 10.17.14.93.51009 > 239.194.1.9.51009: UDP, length 370
        0x0000:  4500 018e 0000 4000 fa11 7625 0a11 0e5d
        0x0010:  efc2 0109 c741 c741 017a 6f28 1120 2020
        0x0020:  3337 3030 3039 3031 3835 3635 3430 3130
...

And this is the copy-and-pastable awk script you can pipe the output to

awk '{ if (match($0, /^[0-9]/, _)) { printf (NR == 1 ? "%s " : "\n%s "), $0; fflush() } else { sub(/^\s+0x[0-9a-z]+:\s+/, " "); gsub(" ", ""); printf "%s", $0 } } END { print ""; fflush() }'

in order to get the following, grepable output

12:04:59.590664 IP 10.17.14.93.51009 > 239.194.1.9.51009: UDP, length 370 4500018e00004000fa1176250a...
12:04:59.590798 IP 10.17.14.113.51011 > 239.194.1.11.51011: UDP, length 370 4500018e00004000fa11760f...
...

Below is a commented version of above script:

awk '{
    # if this is a header line
    if (match($0, /^[0-9]/, _)) {
        # print the header, but:
    # except for the first line,
    # we need to insert a newline,
    # as the preceding data lines will
    # have been stripped of theirs

    # we also append a space to
    # separate header info from the
    # data that will get appended
    printf (NR == 1 ? "%s " : "\n%s "), $0
    # enforce line-buffering
    fflush()
}
# otherwise it is a data line
else {
    # remove the data address
    sub(/^\s+0x[0-9a-z]+:\s+/, " ");
    # remove all spaces
    gsub(" ", "");
    # print w/o newline
    printf "%s", $0 
}

} END { # print final newline, as # the preceding data lines will # have been stripped of theirs print "" # enforce line-buffering fflush() }'

8

From the tcpdump manpage:

-A      Print each packet (minus its link level header) in ASCII.  Handy
        for capturing web pages.

Make sure you also use the -s 0 option to make sure the entire packet is displayed.

Flup
  • 3,675
  • 24
  • 27
3

You may want to have a look at ngrep command:

ngrep -W single -d eth0 'regex to match' 'port 80'

Where:

  • -W single specifies single line formatting
  • regex to match means to only dump packets containing certain string.
  • 'port 80' is a pcap filter to only sniff packets from or to port 80
LatinSuD
  • 1,296
2

tcpdump -nei eth0 -l | grep "something interesting"

man 1 tcpdump: "-l Make stdout line buffered. Useful if you want to see the data while capturing it."

sjas
  • 451
1

The reason your output is hex is the -X flag. Try:

tcpdump -ni eth1 | grep something_interesting

You will get dumped readable output right to the cli.

Worthwelle
  • 4,816
DaveA
  • 11
0

I couldn't get the awk script to do what I wanted and ngrep would not work on an Ethernet over USB, so I wrote a small C program to join the lines output by tcpdump so they are grepable. It's at https://gitlab.com/dargaud/TcpDumpJoin

dargaud
  • 341