8

Problem description:

I want to print only the source and destination address from a tcpdump[1].

Have one working solution, but believe it could be improved a lot. An example that captures 5 packets, just as an example of what I'm looking for:

tcpdump -i eth1 -n -c 5 ip | \
cut -d" " -f3,5 | \
sed -e 's/^\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\..* \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*$/\1 > \2/'

Question:

Can this be done in any easier way? Performance is also an issue here.

[1] A part of a test if the snort home_net is correctly defined, or if we see traffic not defined in the home_net.


Solution:

Ok, thanks to everyone who have replied to this one. There have been two concerns related to the answers, one is the compatibility across different linux-versions and the second one is speed.

Here is the results on the speed test I did. First the grep-version:

time tcpdump -l -r test.dmp -n ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo >/dev/null

real    0m5.625s
user    0m0.513s
sys     0m4.305s

Then the sed-version:

time tcpdump -n -r test.dmp ip | sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)

real    0m0.491s
user    0m0.496s
sys     0m0.020s

And the fastest one, the awk-version:

time tcpdump -l -r test.dmp -n ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)

real    0m0.093s
user    0m0.111s
sys     0m0.013s

Unfortunately I have not been able to test how compatible they are, but the awk needs gnu awk to work due to the gensub function. Anyway, all three solutions works on the two platforms I have tested them on. :)

Eigir
  • 1,969
  • 2
  • 14
  • 19

4 Answers4

9

Here's one way using GNU awk:

tcpdump -i eth1 -n -c 5 ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }'
Steve
  • 51,466
  • 13
  • 89
  • 103
  • Did not work out of the box. Had to install gawk. But then it was about 3 times faster than the sed-version. :) The question then is how compatible it is across different systems... – Eigir Nov 21 '12 at 13:28
  • I had faced some trouble while using gensub on centos. regex containing {} gave me a lot of trouble to me... – anishsane Nov 21 '12 at 13:52
  • regarding speed: if you want to capture only 5 packets, then speed should not bother much. I mean, main bottleneck would be tcpdump, rather than sed. Try dumping tcpdump output to a file & then running awk vs sed on it. – anishsane Nov 21 '12 at 13:53
  • Yes, I don't think other `awk`'s, like `BSD/OSX awk` etc, support the `gensub()` function, unfortunately. – Steve Nov 21 '12 at 13:53
  • 1
    Speed: The 5 packet limitation is just to test the command. The speed test was done on about 100k packets (read from a pcap file). :) – Eigir Nov 23 '12 at 11:48
2

Try this:

 tcpdump -i eth1 -n -c 5 ip 2>/dev/null | sed -r 's/.* ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).* > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1 > \2/'

If running from a .sh script, remember to escape \1 & \2 as required.

anishsane
  • 20,270
  • 5
  • 40
  • 73
  • Ah, sending stderr to /dev/null is something I forgot. And using + instead of \{1,3\} saves a lot of typing (and makes it more readable). Thanks. :) – Eigir Nov 21 '12 at 13:06
  • with `-r` you would not require `\` before { & }, I think... but `{1,3}` is more restricting/precise. – anishsane Nov 21 '12 at 13:51
1

Warning You have to use unbuffered ou line-buffered output to monitor the output of another command like tcpdump.

But you command seem correct.

To simplify, you could:

tcpdump -i eth1 -n -c 5 ip | 
  sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'

Notice the u switch usefull without -c 5 at tcpdump

tcpdump -ni eth1 ip | 
  sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
1

& here is a grep only solution:

tcpdump -l -i eth1 -n -c 5 ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo

Note -l, in case you don't want to limit the number of packets using -c.

anishsane
  • 20,270
  • 5
  • 40
  • 73
  • Tcpdump uses `getopt()`, not `getopt_long()`, so it doesn't have options such as `--line-buffered`. It *does* have a `-l` option, which is (in effect) line-buffered (it's actually "flush at the end of each packet"; that was done because, on Windows, "line-buffered" standard I/O writes one character at a time). –  Nov 22 '12 at 18:49
  • ^^ sorry, yes you are right. `--line-buffered` is grep option. – anishsane Nov 23 '12 at 04:48
  • I like the grep version. Have to check how compatible it is, and do a small speed test up against the awk and the sed solutions. The -c 5 is only to limit the number of packets when testing the command line. :) – Eigir Nov 23 '12 at 11:53
  • I thought, grep should be fast, only because it is probably light-weight compared to awk/sed. but 2*grep _may be_ costly. Let me know the perf result :-) Compatibility wise: I have tested it, wirks well. – anishsane Nov 23 '12 at 12:42
  • On another note: Make sure that tcpdump itself is not the bottleneck, while doing the perf test. Perhaps, you should dump the output to a logfile, & then cat that same file for testing awk vs sed vs grep. – anishsane Nov 23 '12 at 12:46