#!/usr/bin/env perl use strict; use warnings; use MIME::Base64; use Env qw(QUERY_STRING DOCUMENT_ROOT); sub url_decode { my $str = shift; $str =~ s/%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;; return $str; } sub print_pcap_header { my $out = shift; # pcap magic_number print $out pack ( 'L', 0xa1b2c3d4 ); # pcap version_major print $out pack ( 'S', 0x2 ); # pcap version_minor print $out pack ( 'S', 0x4 ); # pcap thiszone print $out pack ( 'l', 0x0 ); # pcap sigfigs print $out pack ( 'L', 0x0 ); # pcap snaplen print $out pack ( 'L', 0xffff ); # pcap network print $out pack ( 'L', 0x1 ); } sub print_packet { my ( $out, $packet ) = @_; # ts_sec print $out pack ( 'L', $packet->{'time'} ); # ts_usec print $out pack ( 'L', 0x0 ); my $pkt_data = decode_base64 ( url_decode ( $packet->{'content'} )); my $hex = unpack ( 'H*', $pkt_data ); my @pairs = $hex =~ /([a-fA-F0-9]{2})/g; # If this is not an IP packet, trust what the client has told you as packet length if (( $pairs[0] ne '45' && $pairs[1] ne '00' ) || ( @pairs < 5 )) { # incl_len print $out pack ( 'L', $packet->{'length'} + 12 ); # orig_len print $out pack ( 'L', $packet->{'length'} + 12 ); } else { # Otherwise, the length of the packet is the one specified in the IP header my $length = hex ( $pairs[2].$pairs[3] ); # If the lengths differ (IP length and actual length of the stream received), pad # the end of the packet with some 0's so that its length matches the one # specified in the IP header if ( $length > ( length ( $hex ) / 2 )) { my $pad_size = $length - ( length ( $hex ) / 2 ); $hex .= '00' for ( 0..$pad_size-1 ); $pkt_data = pack ( 'H*', $hex ); } # Add the length of a pseudo-ethernet header $length += 14; # incl_len print $out pack ( 'L', $length ); # orig_len print $out pack ( 'L', $length ); } # pseudo ethernet header print $out pack ( 'H*', 0 x24 ); # ethernet type (IP) print $out pack ( 'S', 0x8 ); # packet content print $out $pkt_data; } $QUERY_STRING =~ /packets=([0-9]+)/; my $packets_num = $1; my %packets = (); for ( my $i=0; $i < $packets_num; $i++ ) { $QUERY_STRING =~ /packet_len$i=([0-9]+)/; my $length = $1; $QUERY_STRING =~ /time$i=([0-9]+)/; my $time = $1; $QUERY_STRING =~ /packet$i=(.+?)(&|$)/; my $content = $1; $packets{$i} = { 'length' => $length, 'time' => $time, 'content' => $content }; } print "Content-Type: application/pcap\n\n"; # open my $out, "> $DOCUMENT_ROOT/out.pcap"; open my $out, ">&STDOUT"; binmode $out; print_pcap_header $out; for ( my $i=0; $i < $packets_num; $i++ ) { print_packet $out, $packets{$i}; } close $out; # print "Content-Type: text/html\\n\\n"; # print "\\n";