#!/usr/bin/perl

use Getopt::Std;
use threads;
use strict;
use warnings;
use Time::HiRes;

my $nb_threads = $ARGV[0];
my $nb_requests_per_thread = $ARGV[1];
my $message = $ARGV[2];
my $cmd = undef;


die "Radius calls: please specify the number of threads and the number of requests per thread on the command line" if (!($nb_threads && $nb_requests_per_thread));

print "about to launch $nb_threads threads sending each $nb_requests_per_thread radius calls...\n";

# worker launcher
my @threads;
my $start = [ Time::HiRes::gettimeofday( ) ];
for (my $i = 0; $i<$nb_threads; $i++) {

  # create the thread
  push @threads, threads->create( \&radius_requests, $i);
}

# wait for everyone
foreach my $thread (@threads) {
  $thread->join();
}

my $elapsed = Time::HiRes::tv_interval( $start );
print "time: $elapsed \n";
my $tran_per_secoand= $nb_threads*$nb_requests_per_thread/$elapsed;
print "transactions per second: $tran_per_secoand \n";


sub radius_requests {

  my ($tid) = @_;
  my $fun_factor = int(rand(10000));
  my $fake_mac_for_thread = sprintf("%04x", $fun_factor % 65536);

  for(my $i=0; $i<$nb_requests_per_thread; $i++) {
  
    my $fake_client_mac = sprintf("%04x", $i % 65536); # generates fake last 4 digit of a MAC address based on $i
    my $fake_nas_port = ($fun_factor + $i) % 65536;

#    print "thread $tid connection #$i: about to launch radius call with mac aabb.$fake_mac_for_thread.$fake_client_mac NAS-Port: $fake_nas_port\n";
    
#    my $cmd = "echo \"User-Name = aabb$fake_mac_for_thread$fake_client_mac, Calling-Station-Id = aabb.$fake_mac_for_thread.$fake_client_mac, Wavion=\\\"ssid=Inverse-Invite\\\", NAS-Port-Type = Wireless-802.11, NAS-Port = $fake_nas_port\" | radclient 192.168.1.5 auth testing123 2>&1";
    
    if ( $message eq "acct" )
    {
        $cmd  = "echo \"Packet-Type=4,Packet-Dst-Port=1813,Acct-Session-Id = \"4D2BB8AC-00000098\"," .
                "Acct-Status-Type = Interim-Update,User-Name = aabb$fake_mac_for_thread$fake_client_mac," .  
                "NAS-Port = $fake_nas_port, Calling-Station-Id = aabb$fake_mac_for_thread$fake_client_mac," .  
                "NAS-Port-Type = Wireless-802.11, NAS-Port = $fake_nas_port,Acct-Session-Time = 11, Acct-Input-Packets = 15" . 
                "Acct-Output-Packets = 3, Acct-Input-Octets = 1407, Acct-Output-Octets = 467\" | radclient 192.168.1.5 auto testing123 2>&1";
    }
    elsif ( $message eq  "auth" )
    {
        $cmd  = "./eapol_test -a 192.168.1.5 -c peap-mschapv2.conf -s testing123 2>&1"        
    }
    elsif ( $message eq "acct-start" )
    {
        $cmd  = "echo \"Packet-Type=4,Packet-Dst-Port=1813,Acct-Session-Id = \"4D2BB8AC-00000098\"," .
                "Acct-Status-Type=Start,Acct-Authentic=RADIUS,User-Name=aabb$fake_mac_for_thread$fake_client_mac," .  
                "NAS-Port = $fake_nas_port, NAS-Port-Type=Wireless-802.11," .  
                "Calling-Station-Id = aabb$fake_mac_for_thread$fake_client_mac, Connect-Info = \"CONNECT 48Mbps 802.11b\" \" | radclient 192.168.1.5 auto testing123 2>&1";       
    }

    elsif ($message eq "acct-stop" )
    {
        $cmd  = "echo \"Packet-Type=4,Packet-Dst-Port=1813,Acct-Session-Id = \"4D2BB8AC-00000098\"," .
                "Acct-Status-Type=Stop,Acct-Authentic=RADIUS, User-Name= abb$fake_mac_for_thread$fake_client_mac," .  
                "NAS-Port = $fake_nas_port, Calling-Station-Id = aabb$fake_mac_for_thread$fake_client_mac," .  
                "NAS-Port-Type=Wireless-802.11, NAS-Port = $fake_nas_port, ,Acct-Session-Time = 30, Acct-Input-Packets = 25" . 
                "Acct-Output-Packets = 7, Acct-Input-Octets = 3407, Acct-Output-Octets = 867," . 
                "Acct-Terminate-Cause = User-Request \" | radclient 192.168.1.5 auto testing123 2>&1";      
    }

    eval {
      my $result = `$cmd`;
      if ($? != 0 || $result =~ /no response/) {
        print ("warning thread $tid connection #$i: something went wrong with the radius call. cmd: $cmd / result: $result");
      }
    };
    if ($@) {
      print ("warning thread $tid connection #$i mac aabb.ccdd.$fake_client_mac NOT successful: $@\n");
      next;
    }

  }
}

=head1 AUTHOR

Olivier Bilodeau <obilodeau@inverse.ca>

=head1 COPYRIGHT

Copyright (C) 2009,2010 Inverse inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
USA.

=cut

