#!/usr/bin/perl -w
# bmc@shmoo.com
# license: perl artistic, same as NetPacket, since I c&p some of netpacket to fix a bug in the IP checksum calculations.
use strict;
use warnings;
use Net::Pcap;
use NetPacket::Ethernet qw(ETH_TYPE_IP);
use NetPacket::IP qw(:flags);
use NetPacket::TCP;
use NetPacket::UDP;
use NetPacket::ICMP;
my $err;
die "$0 \n" if (scalar(@ARGV) != 2);
my ($input, $output) = @ARGV;
my $in = Net::Pcap::open_offline($input, \$err) || die "Cant open input file: $err";
my $type = Net::Pcap::datalink_val_to_description(Net::Pcap::datalink($in));
if ($type ne 'Ethernet') {
die "This tool is only useful for ethernet. sorry\n";
}
my $out = Net::Pcap::dump_open($in, $output) || die Net::Pcap::geterr($in);
Net::Pcap::loop($in, -1, \&process, '');
Net::Pcap::close($in);
Net::Pcap::dump_close($out);
sub process {
my ($data, $hdr, $pkt) = @_;
my $eth = NetPacket::Ethernet->decode($pkt);
if ($eth->{'type'} eq ETH_TYPE_IP) {
my $ip = NetPacket::IP->decode($eth->{data});
if ($ip->{'foffset'} == 0 && $ip->{'flags'} != 1) {
if ($ip->{proto} == 6) { # TCP
my $tcp = NetPacket::TCP->decode($ip->{'data'});
$ip->{data} = $tcp->encode($ip);
} elsif ($ip->{proto} == 17) { # UDP
my $udp = NetPacket::UDP->decode($ip->{'data'});
$ip->{data} = $udp->encode($ip);
} elsif ($ip->{proto} == 1) { # ICMP
my $icmp = NetPacket::ICMP->decode($ip->{'data'});
$ip->{data} = $icmp->encode($ip);
} else {
$ip->{data} = $ip->{data}; # cheak hack
}
}
my $new = substr($pkt, 0, 14) . my_encode($ip);
Net::Pcap::dump($out, $hdr, $new);
} else {
Net::Pcap::dump($out, $hdr, $pkt);
}
}
# because NetPacket::IP is broken...
sub my_encode {
my ($self) = @_;
# adjust the length of the packet
$self->{len} = ($self->{hlen} * 4) + length($self->{data});
my $tmp = $self->{hlen} & 0x0f;
$tmp = $tmp | (($self->{ver} << 4) & 0xf0);
my $offset = $self->{flags} << 13;
$offset = $offset | (($self->{foffset} >> 3) & 0x1fff);
# convert the src and dst ip
my $src_ip = gethostbyname($self->{src_ip});
my $dest_ip = gethostbyname($self->{dest_ip});
# construct header to calculate the checksum
my $hdr = pack('CCnnnCCna4a4a*', $tmp, $self->{tos},$self->{len},
$self->{id}, $offset, $self->{ttl}, $self->{proto},
0, $src_ip, $dest_ip, $self->{options});
$self->{cksum} = NetPacket::htons(NetPacket::in_cksum($hdr));
my $packet = pack('CCnnnCCna4a4a*a*', $tmp, $self->{tos},$self->{len},
$self->{id}, $offset, $self->{ttl}, $self->{proto},
$self->{cksum}, $src_ip, $dest_ip, $self->{options},
$self->{data});
return($packet);
}