I'll not rewrite this, since it already resolved the problem, which cause me write this snippet code. If you have change/fix something, an email is very appreciated.
If you need this, it's a headache.
This is also useful for sniff password or email(with arpspoof), :-).
#!/usr/bin/perl -w
#
# Author: jiangzuoyan@gmail.com
# 2008-07-22
#
# parse http get/send through
# tcpdump -S -lnx -s 40960 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
#
# this is buggy.
use Getopt::Long;
use warnings;
use strict;
#open (STDIN,"/usr/sbin/tcpdump -lnx -s 40960 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'|");
my ($srchost, $dsthost, $seqstart, $seqend, $ack, $packet);
# packet = {srchost: dsthost:, seqstart:, seqend:, ack:}
my @packets;
sub add_packet {
return unless $_[5] && length($_[5]) && $_[0] && length($_[0]);
my @tmp = @_;
$packets[@packets] = \@tmp;
#print "add packet (" , join(",", @_[0..4]) , "), lidx=", $#packets, "\n";
}
sub is_following {
my ($a, $b) = (shift, shift); #@_;
return ($$a[0] eq $$b[0]) &&
($$a[1] eq $$b[1]) &&
($$a[4] eq $$b[4]) &&
($$a[3] eq $$b[2]);
}
sub compare_packet() {
my ($a, $b) = (shift, shift);
my ($ret, $idx) = 0;
for ($idx = 0; !$ret && $idx < 5; ++$idx) {
$ret = $$a[$idx] cmp $$b[$idx];
}
return $ret;
}
sub print_packets {
return unless @packets;
my $idx = 0;
my ($srchost, $dsthost, $seqstart, $seqend, $ack, $packet) = @{$packets[$idx]};
for ($idx = 1; $idx < @packets; ++$idx) {
#print "check is_following (", join(",", @{$packets[$idx-1]}[0..4]), ") , (", join(",", @{$packets[$idx]}[0..4]), ")\n";
if (&is_following($packets[$idx-1], $packets[$idx])) {
$packet .= $packets[$idx][5];
$seqend = $packets[$idx][3];
} else {
#print $idx, " is not following...\n";
while ($packet && length($packet)) {
$packet = &print_packet($srchost, $dsthost, $seqstart, $seqend, $ack, $packet);
}
($srchost, $dsthost, $seqstart, $seqend, $ack, $packet) = @{$packets[$idx]};
}
}
while ($packet && length($packet)) {
$packet = &print_packet($srchost, $dsthost, $seqstart, $seqend, $ack, $packet);
}
}
sub print_packet{
#print "on print packet, (", join(",", @_[0..4]), ")\n";
my ($srchost, $dsthost, $seqstart, $seqend, $ack, $packet) = @_;
return unless $packet && $srchost && $dsthost;
print "##FROM-TO:$srchost -> $dsthost $seqstart,$seqend ack $ack\n";
my $hp = index($packet, "\r\n\r\n");
if ($hp != -1) {
my $header = substr($packet, 0, $hp);
print "##GOT HEAD\n", $header, "\n\n";
my ($clen) = $header =~ /[\r\n]Content-Length: +([0-9]+)\s/;
$clen = 0 unless $clen;
my $data;
if ($clen) {
$data = substr($packet, $hp + 4, $clen);
$packet = substr($packet, $hp + 4 + $clen);
} else {
$data = substr($packet, $hp+4);
$packet = "";
}
if ($header =~ /[\r\n]Content-Encoding: +gzip\s/) {
print "##got gzip content len=$clen\n";
open(GZIP, "| gunzip");
print GZIP $data;
close(GZIP);
} elsif($header =~ /[\r\n]Content-Type: image\//) {
print "##got a image ....\n";
} else {
print "##got plain content len=$clen\n";
print $data;
}
} else {
print "##UNFOUND HEADER PACKET\n";
print $packet;
$packet = "";
}
print "\n##EFROM-TO:$srchost -> $dsthost\n";
return $packet;
}
binmode STDOUT;
while (<>) {
if (/^\S/) {
&add_packet($srchost, $dsthost, $seqstart, $seqend, $ack, $packet);
($srchost, $dsthost, $seqstart, $seqend, $ack)
= /(\d+(?:\.\d+){4})\s+>\s+(\d+(?:\.\d+){4}):[^0-9]+([0-9]+):([0-9]+)\([0-9]+\) ack ([0-9]+)/;
$packet = "";
} else {
next if /\s+0x00[012]0:\s+/;
s/^(\s+0x[0-9a-f]+:\s+[0-9a-f\s]{0,40}).*$/$1/;
s/^(\s+0x0030:\s+)(?:[0-9a-f]{4}\s+){1,2}/$1/;
s/^\s+0x[0-9a-f]+:\s+//;
s/\s*$//;
s/([0-9a-f]{2})\s?/chr(hex($1))/eg;
$packet .= $_;
}
}
@packets = sort {&compare_packet($a, $b) } @packets;
&print_packets();