#!/usr/bin/perl # $Id: fix-rh61-pcap.pl,v 1.3 2000/09/03 21:31:52 sra Exp $ # Some clever hacker decided to add a few fields to the pcap data # structure used by tcpdump, tcptrace, tcpshow, etc on RedHat Linux # 6.1 (and possibly other versions, I haven't checked). Very nice, but # this totally breaks portability of pcap files between Red Hat Linux # 6.1 and other operating systems (eg, FreeBSD) or other pcap-using # tools that were compiled with a normal version of libpcap instead of # the mutant RH version. Sigh. Presumably whoever did this couldn't # care less, but for the rest of us it can be a real pain to spend a # lot of time setting up a complicated network test then discover # afterwards that the resulting capture file is unreadable by any of # the analysis tools one intended to use. Hence this script to # convert from the mutant RH format to the standard format. # # Reference: pcap.h, pcap format version 2.4. On Red Hat Linux 6.1, # the full pathname of the file is /usr/include/pcap/pcap.h; if it's # not there in your Linux distribution, try "locate pcap.h". # # Along with his or her other sins, the bozo responsible for this # lossage neglected to modify the pcap version identifier, so you # can't tell whether a particular pcap file is the mutant version or # not except by watching your tools explode. Grrr. # # This program is hereby explictly placed in the public domain as # Beer-Ware. If we meet some day and you think this program is worth # it, you can buy me a beer. Your mileage may vary. We decline # responsibilities, all shapes, all sizes, all colors. If this # program breaks, you get to keep both pieces. $debug = 0; $pcap_magic = 0xa1b2c3d4; $pcap_version_major = 2; $pcap_version_minor = 4; $pcap_file_header_format = "LSSlLLL"; $pcap_file_header_length = 24; $pcap_pkthdr_std_format = "LLLL"; $pcap_pkthdr_std_length = 16; $pcap_pkthdr_rh_format = $pcap_pkthdr_std_format . "iSC"; $pcap_pkthdr_rh_length = $pcap_pkthdr_std_length + 8; # For the moment I'm only handling the RH -> standard conversion, # because that's the only one that's of any use to me. If I ever # bother to figure out what to put in the extra RH goop and have some # reason to care, I'll write the inverse conversion too. Feel free to # write it yourself and send it back to me. die("Couldn't read PCAP file header: $!") unless (sysread(STDIN, $header, $pcap_file_header_length) == $pcap_file_header_length); ($h_magic, $h_version_major, $h_version_minor, $h_thiszone, $h_sigfigs, $h_snaplen, $h_linktype) = unpack($pcap_file_header_format, $header); printf(STDERR ">> header: magic %08x, version %u.%u, thiszone %u, sigfigs %u, snaplen %u, linktype %u\n", $h_magic, $h_version_major, $h_version_minor, $h_thiszone, $h_sigfigs, $h_snaplen, $h_linktype) if ($debug); die("Bad PCAP magic number (%08x)", $h_magic) unless ($h_magic == $pcap_magic); die("Don't know how to handle PCAP version %u.%u", $h_version_major, $h_version_minor) unless ($h_version_major == $pcap_version_major && $h_version_minor == $pcap_version_minor); die("Couldn't write PCAP file header: $!") unless (syswrite(STDOUT, $header, $pcap_file_header_length) == $pcap_file_header_length); $n = 1; while (($i = sysread(STDIN, $pkthdr, $pcap_pkthdr_rh_length)) != 0) { die("Couldn't read packet header $n: $!") unless (defined($i)); die("Wrong size for packet header $n: $i") unless ($i == $pcap_pkthdr_rh_length); ($p_ts_sec, $p_ts_usec, $p_caplen, $p_len, $p_ifindex, $p_protocol, $p_pkt_type) = unpack($pcap_pkthdr_rh_format, $pkthdr); printf(STDERR ">> packet #%u: ts %06u.%06u, caplen %u, len %u\n", $n, $p_ts_sec, $p_ts_usec, $p_caplen, $p_len) if ($debug); printf(STDERR ">> discarding: ifindex %d, protocol %x, pkt_type %x\n", $p_ifindex, $p_protocol, $p_pkt_type) if ($debug); die("Couldn't write packet header $n: $!") unless (syswrite(STDOUT, $pkthdr, $pcap_pkthdr_std_length) == $pcap_pkthdr_std_length); die("Couldn't read packet buffer $n: $!") unless (defined(($i = sysread(STDIN, $pktbuf, $p_caplen)))); die("Wrong size for packet buffer $n: $i") unless ($i == $p_caplen); die("Couldn't write packet buffer $n: $!") unless (syswrite(STDOUT, $pktbuf, $p_caplen) == $p_caplen); $n++; } exit 0;