botho has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to write a PERL script to decode/convert tcpdump (ethereal, etc.) files to a human readable (ascii) form so that I can parse out the specific info I need. Searching the net hasn't been rewarding. I realize this is a pretty open-ended request but any help would be appreciated.

Replies are listed 'Best First'.
Re: converting tcpdump files
by BrowserUk (Pope) on Apr 30, 2003 at 19:09 UTC

    Isn't there a -d option on your version of tcpdump?

    From the manpage

    -d Dump the compiled packet-matching code in a human readable form to sta +ndard output and stop.

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.

      The -d option does something different than what botho is asking; it doesn't display the captured data in a different format, it displays the capture program that it writes.

      The 'capture filter' in tcpdump works by parsing the filter string during startup, and then writing an optimized machine-language filter subroutine which is called for each packet. The -d option shows that subroutine, in assembler language, which is 'human' compared to the raw machine language that -dd or -ddd would show.

      For example, if I want to capture only TCP packets, ignoring all UDP, ICMP, and non-IP packets, I would use tcpdump tcp . Adding -d and running it, I get:

Re: converting tcpdump files
by hacker (Priest) on May 01, 2003 at 11:48 UTC
    This works, assuming you redirect your tcpdump output to a file. Run with your output file as STDIN to this snippet. You could probably use IO::File here as well:
    use strict; open (DUMP, "|cat -v"); select(DUMP); $| = 1; while (<>) { if (/^\s/) { chop; s/\s//g; while ($_) { my $hex; ($hex, $_) = /^(..)(.*)$/; my $byte = hex($hex); print pack("c", $byte); } } else { print "\n", "-"x74, "\n\n"; } } close(DUMP);

    Here's another, which runs tcpdump directly:

    use strict; my ($pkt, $client, $host); my $lim = shift || 999999999; my $tcpd = "/usr/sbin/tcpdump"; my $tcpargs = "-lnx -s 1024 dst host|"; $|=1; open (STDIN, "$tcpd $tcpargs"); while (<>) { if (/^\S/) { last unless $lim--; while ($pkt=~/(.+).+/g) { print "$client -> $host\t$&\n"; } ($client, $host, $pkt) = (); # All on one line please ($client, $host) = /(\d+\.\d+\.\d+\.\d+).+ > (\d+\.\d+\.\d+\.\d+)/ if /P \d+:\d+\((\d+)\)/ && $1 > 0; } next unless $client && $host; s/\s+//; s/([0-9a-f]{2})\s?/chr(hex($1))/eg; tr/\x1F-\x7E\r\n//cd; $pkt .= $_; }

    Here's one using Net::Pcap and Net::RawIP. I leave the decoding of the packet stream up to you..

    use strict; use Net::Pcap; use Net::RawIP; my $errstr; my $count = 0; my $dev = Net::Pcap::lookupdev(\$errstr); my $pcap = Net::Pcap::open_live($dev, 1024, 1, 0, \$errstr); Net::Pcap::loop($pcap, -1, \&check_tcp, "abc"); Net::Pcap::close($pcap); sub check_tcp { my ($user, $hdr, $pkt) = @_; # Add your error checking here print "Saw snap of len hdr->{len} $hdr->{caplen} \n"; $count++; }
      Thanks to everyone for some great ideas that I will pursue. Part of my challenge is that I will be getting the dumps after the fact (tcpdump, ethereal, and other sniffers) so I can't really pipe a live capture in the format I want. Thanks again!
        tethereal is designed to be run on (pre-captured) binary capture files, too.


Re: converting tcpdump files
by traveler (Parson) on Apr 30, 2003 at 21:11 UTC
    If you have ethereal, you probably have tethereal (both are free and both are provided with the *nix and Win32 ethereal distros; I think MacOS, too, but don't have a copy of that handy). tethereal is "text-based ethereal"; it prints the packets as specified in its args.

    HTH, --traveler

Re: converting tcpdump files
by Limbic~Region (Chancellor) on Apr 30, 2003 at 23:12 UTC
    Have you tried Net::Pcap? Here is a blurb from the docs:

    "a system-independent interface for user-level packet capture. libpcap provides a portable framework for low-level network monitoring. Applications include network statistics collection, security monitoring, network debugging, etc."

    I know it isn't tcpdump, but I am pretty sure that it contains almost all the same information.

    Cheers - L~R

Re: converting tcpdump files
by LameNerd (Hermit) on Apr 30, 2003 at 17:27 UTC
    Have you tried using pack or unpack?
    perldoc -f pack