19

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.

4
  • 1
    well, I can't test this right now but if you have multiple lines you could do | tr -d '\n' or grep -C 3 to get some lines before and after
    – barlop
    Jun 10, 2014 at 11:50
  • @barlop, grep -C sort of works, but unreliable, as I never know how many lines up the header will be, and I will not see the lines below the match. The tr command trancates all the output to 1 line, so its a bit too much. Jun 10, 2014 at 14:29
  • The following wouldn't be grep, but tcpdump can match strings by hex which is essentially grep without any regex. You can specify an offset. I have this jotted down in a file (done with windump but I that's just a windows version of tcpdump so assume tcpdump) tcpdump -nXr zfile "tcp[32:4] = 0x47455420"
    – barlop
    Jun 10, 2014 at 14:39
  • related: How to process/pipe TCPDUMPs output in realtime
    – bain
    Dec 19, 2019 at 11:56

6 Answers 6

16

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.

2
  • 1
    Thanks, but data is still presented at multiply lines - wherever the webpage has newlines in it. I have problem associating the header (and rest of data) with grepped output. Jun 10, 2014 at 11:52
  • I just realized why the tool is called awkward Nov 15, 2015 at 23:32
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
2
  • 1
    Would like to use ngrep, but there is no such tool - it is an appliance... Jun 10, 2014 at 14:30
  • ngrep is awesome. I was searching for hours which host is generating HTTP traffic to my host. With single sudo ngrep "GET .." found answer in minute. Sep 28, 2016 at 13:56
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.

1
  • 2
    Yes, but it will not contain the content of the packet.
    – RalfFriedl
    May 31, 2019 at 20:36
1

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."

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .