testapp.pl


#!/usr/bin/perl -w
# ---------------------------------------------------------
# testapp.pl (v 0.2): captures and dump packets;
# based on Loris Degioanni's TestApp program in C
# (see the Packet Capture Driver Developer's Pack).
# This simple example shows how to capture raw packets
# to the network using Win32::NetPacket.
# This program is free software; you can redistribute it
# and/or modify it under the same terms as Perl itself.
# (c) 2003-2006 J-L Morel jlmorel@cpan.org
# ---------------------------------------------------------

use strict;
use Win32::Console::ANSI;
use Win32::NetPacket qw/ :ndis GetAdapterNames  /;
use Term::ReadKey;
$|++;

use constant SizeOfInt => 4;    # for word alignment

# select the adapter
my %desc;
my @adpts = GetAdapterNames( \%desc );
@adpts > 0 or die "No adapter installed !\n";
my $i = 1;
if ( @adpts > 1 ) {
  print "Adapters installed:\n\n";
  print $i++, " - $desc{$_}\n    $_\n" foreach @adpts;
  do {
    print "\nSelect the number of the adapter to open : ";
    $i = <STDIN>;
    chomp $i;
  } until ( $i =~ /^(\d)+$/ and 0 < $i and $i <= @adpts );
}

# open the selected adapter
my $nic = Win32::NetPacket->new(
  adapter_name       => $adpts[ $i - 1 ],
  driver_buffer_size => 512 * 1024,         # 512 kbytes kernel buffer
  read_timeout       => 1000,               # 1s timeout
) or die $@;

$nic->SetHwFilter(NDIS_PACKET_TYPE_PROMISCUOUS); # set nic in promiscuous mode

# print infos
my ( $name, $description, $type, $speed, $ip, $mask, $mac ) = $nic->GetInfo();
$description ||= $desc{$name};
$ip          ||= '?.?.?.?';
$mask        ||= '?.?.?.?';
$mac = join '-', unpack 'A2' x 6, $mac;
print "Listening $name\n($description)\nMAC: $mac IP: $ip Mask: $mask\n";
print "** press [enter] to terminate\n";

# set user's buffer
my $Buff;
$nic->SetUserBuffer( $Buff, 128 * 1024 );

# main capture loop
my $BytesReceived;
while ( !ReadKey(-1) ) {    # press (enter) to terminate
  $BytesReceived = $nic->ReceivePacket();    # capture the packets
  printPackets();                            # print the packets
}

printf "\n\n%d packets received,\n%d packets lost.\n", $nic->GetStats;

# ------ printPackets routine

sub printPackets {
  my $nic    = shift;
  my $offset = 0;
  while ( $offset < $BytesReceived ) {
    my ( $tv_sec, $tv_usec, $caplen, $datalen, $hdrlen ) = unpack 'llIIS',
      substr $Buff, $offset;
    printf "\nPacket length, captured portion: %ld, %ld\n", $datalen, $caplen;
    $offset += $hdrlen;
    my $data = substr $Buff, $offset, $datalen;    # extract the datagram
    my $i = 0;
    do {
      local $, = ' ';
      my $lg = substr $data, $i, 16;
      printf "%.8X : ", $i;
      $i += 16;
      print unpack( 'H2' x 16, $lg ), '  ' x ( 16 - length $lg );
      $lg =~ s/[\x00-\x1F\x95\xFF]/./g;
      print " $lg\n";
    } until $i >= $datalen;

    # Packet word alignment
    $offset
      = ( ( $offset + $caplen ) + ( SizeOfInt - 1 ) ) & ~( SizeOfInt - 1 );
  }
}