#!perl # tdg # TcpDump Grapher # # Jeffrey Semke # Pittsburgh Supercomputing Center # November 1998 # plot ack numbers and seq numbers from tcpdump hex files sub match { my $src = shift(@_); my $dst = shift(@_); my $sender = shift(@_); my $acker = shift(@_); if (((index $src, $sender) >=0) && ((index $dst, $acker) >=0)) { return 1; } return 0; } if (($#ARGV < 2 ) || ($#ARGV > 4)) { print STDERR "Usage: $0 tcpdump-text-file sender acker [sack] [rwin] | xgraph"; exit(-1); } $input_file = $ARGV[0]; $sender = $ARGV[1]; $acker = $ARGV[2]; $sack = 0; $rwin = 0; $rscale = 0; $last_ack = $last_rwin = 0; GETARGS: for ($i = 3; $i <= $#ARGV; $i++) { if ($ARGV[$i] eq 'sack') { $sack = 1; next GETARGS; } if ($ARGV[$i] eq 'rwin') { $rwin = 1; next GETARGS; } die "Invalid paramater: $ARGV[$i]\n"; } if (!open(DUMPFILE, $input_file)) { die "Can't open file: $input_file\n"; } $title = substr($input_file, rindex($input_file, "/")+1); print "Markers: 1\n"; print "YLowLimit: 0\n"; print "XLowLimit: 0\n"; print "XUnitText: Time (s)\n"; print "YUnitText: Number\n"; print "Device: Postscript\n"; print "Disposition: To Device\n"; print "NoLines: 1\n"; print "FileOrDev: moon\n"; print "TitleText: $title\n"; # data packets print "\n\"sequence\n"; while () { if (/\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):\s+\S+\s+\d+:(\d+)/) { my $minutes = $1; my $time = $2; my $src = $3; my $dst = $4; my $seq = $5; if (!defined($first_min)) { $first_min = $minutes; } if (match($src, $dst, $sender, $acker)) { $time = $time + 60*($minutes - $first_min); print "$time $seq\n"; } } } # acks seek(DUMPFILE, 0, 0); print "\n\"ack\n"; while () { if (/\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):\s+\S+\s+ack\s+(\d+)\s+win\s+(\d+)/ || /\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):\s+\S+\s+\d+:\d+\(\d+\)\s+ack\s+(\d+)\s+win\s+(\d+)/) { my $minutes = $1; my $time = $2; my $src = $3; my $dst = $4; my $ack = $5; my $rwin = $6; if (match($src, $dst, $acker, $sender)) { if (($ack != $last_ack) || (/sack/) || ($rwin <= $last_rwin)) { $time = $time + 60*($minutes - $first_min); print "$time $ack\n"; } $last_ack = $ack; $last_rwin = $rwin; } } } # receiver window if ($rwin == 1) { seek(DUMPFILE, 0, 0); print "\n\"rwin\n"; while () { if (/wscale\s+(\d+)/) { my $pend_rscale = $1; if (/\d+:\d+:[\d.]+\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):/) { my $src = $1; my $dst = $2; if (match($src, $dst, $acker, $sender)) { $rscale = $pend_rscale; } } } elsif (/\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):\s+\S+\s+ack\s+(\d+)\s+win\s+(\d+)/) { my $minutes = $1; my $time = $2; my $src = $3; my $dst = $4; my $ack = $5; my $adv = $6; if (match($src, $dst, $acker, $sender)) { my $advertisement = $adv * (2 ** $rscale) + $ack; $time = $time + 60*($minutes - $first_min); print "$time $advertisement\n"; } } } } # SACKs if ($sack == 1) { # start of SACK block seek(DUMPFILE, 0, 0); print "\n\"SACK start\n"; while () { if (! /sackOK/ && /sack\s+(.+)[,>]/) { my $blocks = $1; if (/\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):/) { my $minutes = $1; my $time = $2; my $src = $3; my $dst = $4; if (match($src, $dst, $acker, $sender)) { while ($blocks =~ /(\d+)[:@]\d+/) { my $start = $1; my $printtime = $time + 60*($minutes - $first_min); $blocks = $'; print "$printtime $start\n"; } } } } } # end of SACK block seek (DUMPFILE, 0, 0); print "\n\"SACK end\n"; while () { if (! /sackOK/ && /sack\s+(.+)[,>]/) { my $blocks = $1; if (/\d+:(\d+):([\d.]+)\s+([\w\d-.]+)\s+>\s+([\w\d-.]+):/) { my $minutes = $1; my $time = $2; my $src = $3; my $dst = $4; if (match($src, $dst, $acker, $sender)) { while ($blocks =~ /\d+[:@](\d+)/) { my $end = $1; my $printtime = $time + 60*($minutes - $first_min); $blocks = $'; print "$printtime $end\n"; } } } } } }