/* ***********************IMPORTANT *********************************************
 *  Copyright (C) 2004-2007 Thierry Lagarde <tlagarde@users.sourceforge.net>
 *  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.
 *
 *
 *                      ********************
 *
 *
 *  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 Library General Public License for more details.
 *
 *
 *                      ********************
 *
 *
 * You are highly encouraged to send your changes to <tlagarde@users.sourceforge.net>
 * for possible incorporation into the main distribution.
 * By sending these changes to <tlagarde@users.sourceforge.net>,
 * it is assumed that you are offering <tlagarde@users.sourceforge.net>
 * the unlimited, non-exclusive right to reuse, modify, and relicense the code.
 *
 *
 *                      ********************
 *
 *  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.
 **************************************************************************************/
#include <errno.h>
#include "Thread_Detect.h"
#include "Reseau.h"
#include "Debug.h"
#include "Sous_Reseau_Autorise.h"
#include "Liste_Equipement.h"
#include "Scan_Port.h"
#include "Scan_Equipement.h"
#include "Scan_Signature.h"
#include "Com/Initialisation_Com.h"
#include "Semaphore.h"
#include "Info.h"
#include "Thread.h"
#include "Macro.h"
#include "Liste_Sous_Reseau.h"
#include "Ip_Dynamic.h"
#ifdef         __WINDOWS_ENABLE
#include <pcap.h>
#include <remote-ext.h>
#endif

void Start_Scan_Plage(){
	unsigned char Ma_Plage[4 + 1];
	
	Scanne_Liste_Sous_Reseau_Restaurer (Nb_Sous_Reseau ());
	if (Nb_Sous_Reseau () == 0) {
		memcpy (&Ma_Plage, &Mon_Adresse_Ip, IP_ADDR_LEN);
		Ma_Plage[3] = 0;
		if (Recherche_Index_Sous_Reseau (Ma_Plage) == -1)
			Ajout_Sous_Reseau (Ma_Plage, TRUE);
	}
}

void Boucle_Scan (void)
{
	struct Struct_Liste_Equipement *Equipement = NULL;
#ifdef __LOG_ENABLE
	struct struct_Cle_Privee *Donnee_Cle = NULL;	
#endif
	gint      Num;

#ifdef __LOG_ENABLE
	Create_Log(CATEG_BOUCLE_SCAN,NULL,NULL,TRUE);
#endif
	Num = Nb_Machine_Dans_La_Liste;
	while (1) {
#ifndef         __WINDOWS_ENABLE
		Attendre_Semaphore (&Semaphore_Nouveau_Equipement);
		Attendre_Semaphore (&Semaphore_Thread_Scan);
#else
		Attendre_Semaphore (Semaphore_Nouveau_Equipement);
		Attendre_Semaphore (Semaphore_Thread_Scan);
#endif
		Retour_Pointeur_Equipement (&Equipement,Num);
		demmarrage_Thread (&Scanne_Equipement, (gpointer *) Equipement); 
		Num++;
	}
}


void Thread_Detect (void)
{
	struct Struct_Liste_Equipement *Equipement = NULL, *Equipement_GateWay = NULL;
#ifdef __LOG_ENABLE
	struct struct_Cle_Privee *Donnee_Cle = NULL;	
#endif
#ifndef         __WINDOWS_ENABLE
	struct struct_trame Packet_struct,*Packet = NULL;
#else
	struct struct_trame *Packet = NULL;
#endif
	struct timeval timev;
	unsigned char ID_Equipement[MAC_ADDR_LEN + IP_ADDR_LEN + 1];
	unsigned char Ip_Adresse_Bouclage[IP_ADDR_LEN + 1];
	unsigned char *ID_Equipement_Marquer = NULL;
	unsigned short Port_Source, Taille_Ip, Port_Destination, Icmp_Id;
	unsigned char Type_ICMP, Code_ICMP;
	unsigned int Ip_MonNum;
	struct sockaddr sock;
	gchar     *Ping_Time = NULL,*Utilisateur = NULL;
	gint      Socket, n_read, Index_Equipement, Type_Trame,nb_Seconde,nb_usec,Etat_Equipement;
	gboolean  Machine_Local,Arret_NBNS,INFO_NBNS, Equipement_Detecter, Port_Ouvert, Port_Fermer, GateWay_Detecter;

	
	Ip_Adresse_Bouclage[0] = 127;
	Ip_Adresse_Bouclage[1] = 0;
	Ip_Adresse_Bouclage[2] = 0;
	Ip_Adresse_Bouclage[3] = 1;
	Ip_Adresse_Bouclage[4] = 0;
	
	if (Nb_Machine_Dans_La_Liste==0)	
		Scan_Machine_Local_Fait = FALSE; 
	else
		Scan_Machine_Local_Fait = TRUE; 

#ifdef __LOG_ENABLE
	Create_Log(CATEG_THREAD_DETECT,NULL,NULL,TRUE);
#endif
	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Thread Detect  pid(%d)", getpid ());
	strcpy (sock.sa_data, Info_Demarrage.Interface);
	sock.sa_family = AF_INET;
#ifndef         __WINDOWS_ENABLE
	Packet = &Packet_struct;
	if ((Socket = socket_control (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
		debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "%s\nSocket ouvert[%d]  Thread[%d][%d]\n Nb equipement (%d)", strerror (errno), Nb_Socket_Ouverte, Info_Demarrage.Nb_Thread_Max, Info_Demarrage.Nb_Thread_Max - Valeur_Semaphore (&Semaphore_Thread_Scan), g_list_length (GList_Equipement));
#else
	pcap_t    * captureHandle = NULL;
    struct pcap_pkthdr* packetHeader = NULL;
    const  u_char *     packetData = NULL;
	char errbuf[PCAP_ERRBUF_SIZE];
	int res;
	 

	captureHandle = pcap_open(Info_Demarrage.nom , 65535, PCAP_OPENFLAG_PROMISCUOUS, 1, NULL, errbuf);
    if( captureHandle == NULL)
        debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__,"pcap_open(): %s\n", errbuf);

#endif
	
	while (1) {
		INFO_NBNS = FALSE;
		Arret_NBNS = FALSE;
		Equipement_Detecter = FALSE;
		Port_Ouvert = FALSE;
		Port_Fermer = FALSE;
		Utilisateur = NULL;
		GateWay_Detecter = FALSE;
#ifndef         __WINDOWS_ENABLE
		n_read = recvfrom (Socket, Packet, sizeof (struct struct_trame)-sizeof(int), 0, NULL, 0);
#else
		res = pcap_next_ex(captureHandle, &packetHeader, &packetData);
		if(res==0)
            continue; 
		n_read = packetHeader->len;
		Packet = (struct struct_trame *) packetData;
#endif
		Type_Trame = 0;
		memcpy (&ID_Equipement, Packet->Source_MAC, MAC_ADDR_LEN);
		switch (htons (Packet->Proto)) {
		    case TRAME_IP:
			    if ((Packet->Datagramme[0] >> 4) == IP_VERSION4) {
				    memcpy (&ID_Equipement[MAC_ADDR_LEN], &Packet->Datagramme[12], IP_ADDR_LEN);
					Equipement_Detecter = TRUE; 
				    switch (Packet->Datagramme[9]) {
					case TCP:
						Type_Trame = TCP;
						Taille_Ip = (Packet->Datagramme[0] & 0x0F) << 2;
						memcpy (&Port_Source, &Packet->Datagramme[Taille_Ip], 2);
						Port_Source = htons (Port_Source);
						memcpy (&Port_Destination, &Packet->Datagramme[Taille_Ip + 2], 2);
						Port_Destination = htons (Port_Destination);
						switch (Packet->Datagramme[Taille_Ip + 13]) {
						    case 0x14:
						    case 0x1C:
						    case 0x15:
							    Port_Fermer = TRUE;
							    break;
						    case 0x12:
							    Port_Ouvert = TRUE;
							    break;
						    case 0x02:
							   
							   
							    if ((memcmp (&Packet->Datagramme[12], &Packet->Datagramme[16], IP_ADDR_LEN) == 0) 
									&& (memcmp (Packet->Dest_MAC, Mon_Adresse_MAC, MAC_ADDR_LEN) == 0) 
									&&  (memcmp (Packet->Source_MAC, Mon_Adresse_MAC, MAC_ADDR_LEN) != 0)) {
									GateWay_Detecter = TRUE;
							    }
							    break;
						}
						break;
					case UDP:
						Type_Trame = UDP;
					
						if ((Packet->Dest_MAC[3] == 255) && (Packet->Dest_MAC[4] == 255) && (Packet->Dest_MAC[5] == 255) 
							&& (Packet->Datagramme[22] == 0) && (Packet->Datagramme[23] == NBNS)) {
							INFO_NBNS = TRUE;
							if ((Packet->Datagramme[30] == 0x30) && (Packet->Datagramme[31] == 0x10) && (Packet->Datagramme[71] == 0x41) && (Packet->Datagramme[72] == 0x41))
								Arret_NBNS = TRUE;
						
							if ((Packet->Datagramme[30] == 0x28) && (Packet->Datagramme[31] == 0x10) && (Packet->Datagramme[71] == 0x41) && (Packet->Datagramme[72] == 0x44))
								Utilisateur = get_nbns_name(&Packet->Datagramme[40]);
						}
						if ( (Packet->Dest_MAC[3] == 255) && (Packet->Dest_MAC[4] == 255) && (Packet->Dest_MAC[5] == 255)
							&& (Packet->Datagramme[9] == UDP) 
							&& (Packet->Datagramme[22] == 0) && (Packet->Datagramme[23] == BROWSE)) {
					    	if (Packet->Datagramme[196] == MASTER_ANNONCE) {
							   
						    }
						    if (Packet->Datagramme[196] == HOST_ANNONCE) {
							   
					    	}	
				    	}
						break;
					case ICMP:
						Type_Trame = ICMP;
						Taille_Ip = (Packet->Datagramme[0] & 0x0F) << 2;
						Type_ICMP = Packet->Datagramme[Taille_Ip];
						Code_ICMP = Packet->Datagramme[Taille_Ip + 1];
						memcpy (&Icmp_Id, &Packet->Datagramme[Taille_Ip + 4], 2);
						Icmp_Id = htons (Icmp_Id);
						break;
				    }
			    }
			    break;
		    case TRAME_ARP:
			    Type_Trame = TRAME_ARP;
			    memcpy (&ID_Equipement[MAC_ADDR_LEN], &Packet->Datagramme[14], IP_ADDR_LEN);
				Equipement_Detecter = TRUE;
			    break;
		}
	
		if (memcmp (&ID_Equipement[6], Ip_Adresse_Bouclage, IP_ADDR_LEN) == 0)
			continue;			
		
	
		if (!Equipement_Detecter)
			continue;
		
		Machine_Local = (memcmp (&ID_Equipement[6], Mon_Adresse_Ip, IP_ADDR_LEN) == 0);
	
		if ((!Scan_Machine_Local_Fait) && (!Machine_Local))
			continue;
		
	
		if ((Scan_Machine_Local_Fait) && (Machine_Local) ){
			if (GateWay_Detecter) {
			   	
			   
			   
		    
		    
		    	Equipement_GateWay = Recherche_MAC_Gateway (ID_Equipement);
		    	if (Equipement_GateWay != NULL) {
			    	if ((Port_Source == Equipement_GateWay->Port_Source_Test_GateWay)
					    && (Port_Destination == Equipement_GateWay->Port_Destination_Test_GateWay)) {
				    	debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "GateWay %d %d %d %d", Port_Source, Port_Destination, Equipement_GateWay->Port_Source_Test_GateWay, Equipement_GateWay->Port_Destination_Test_GateWay);
				    	Equipement_GateWay->GateWay = TRUE;
			    	}
		    	}
		    	else
				    debug_printf (D_WARN, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Gateway non retrouvé : [%d.%d.%d.%d]", ID_Equipement[6], ID_Equipement[7], ID_Equipement[8], ID_Equipement[9]);
			}
			continue;			
		}

		if (!((ID_Equipement[0] == 0) && (ID_Equipement[1] == 0) && (ID_Equipement[2] == 0) && (ID_Equipement[3] == 0))) {
		
			if (Recherche_Si_Sous_Reseau_Autoriser (&ID_Equipement[MAC_ADDR_LEN])) {
			
			
				Etat_Equipement = Recherche_Equipement(ID_Equipement,&Equipement);
			
				
			
				switch (Etat_Equipement) {
  					case EQUIPEMENT_UNKNOWN:
					
					    if (memcmp (ID_Equipement, Mon_Adresse_MAC, MAC_ADDR_LEN) != 0) {
						    if (htons (Packet->Proto) == TRAME_ARP) {
							   
								debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Equipement détecté pris en compte : [%d.%d.%d.%d]", ID_Equipement[6], ID_Equipement[7], ID_Equipement[8], ID_Equipement[9]);
							   
							   
							   
							    if (Info_Demarrage.Ip_Dynamic)
									Recherche_Equipement_Perte_Ip (ID_Equipement);
							   
							   
							    switch (Marque_Equipement_Avec_Meme_Adresse_MAC (ID_Equipement)) {
								case DEJA_EN_COURS_CHANGE_IP:
								
									break;
								case EQUIPEMENT_MARQUER_CHANGE_IP:
								
								
									MALLOC(ID_Equipement_Marquer,sizeof (unsigned char) * (MAC_ADDR_LEN + IP_ADDR_LEN + 1));
									memcpy (ID_Equipement_Marquer, ID_Equipement, MAC_ADDR_LEN + IP_ADDR_LEN + 1);
									demmarrage_Thread (&Traite_Equipement_Marquer_Ip_Change, (gpointer *) ID_Equipement_Marquer);
									break;
								case AUCUN_EQUIPEMENT_MARQUER_CHANGE_IP:
								
									Equipement = Ajout_Equipement (ID_Equipement);
									break;
								default:
									debug_printf (D_ERRO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Retour inconnu");
							    }
						    }
						    else
								Envoie_Arp (&ID_Equipement[6], 1, 1, FALSE);
					    }
					    else {
						   
						    if (memcmp (&ID_Equipement[6], Mon_Adresse_Ip, IP_ADDR_LEN) == 0) {
							    Equipement = Ajout_Equipement (ID_Equipement);
						    }
					    }
					    break;
				    case EQUIPEMENT_NO_IP:
					   
					
					    Recherche_Equipement_Perte_Ip (ID_Equipement);
					    Ip_Equipement_Retrouver (ID_Equipement);
					    break;
				    default:
					
					   
					    if (INFO_NBNS) { 
							if (Arret_NBNS)
						    	Equipement_Arreter (Equipement);
					    	if (Utilisateur)
								Change_Name_Netbios(Equipement,Utilisateur);
						}
					    else {
						    Reception_Donnee_Equipement_Connu (Equipement);
						    switch (Type_Trame) {
							case TCP:
								if (!(Traitement_ScanOS_TCP (Equipement, Packet, n_read, Taille_Ip, Port_Source, Port_Destination))) {
								
									memcpy (&Ip_MonNum, &Packet->Datagramme[Taille_Ip + 8], 4);
									if (Port_Fermer) {
										Modifie_Etat_Port_Equipement (Equipement, Port_Source,Port_Destination, FERMER,Ip_MonNum,Packet->Datagramme[Taille_Ip + 13]);
									}
									if (Port_Ouvert) {
										Modifie_Etat_Port_Equipement (Equipement, Port_Source,Port_Destination, OUVERT,Ip_MonNum,Packet->Datagramme[Taille_Ip + 13]);
									}
								}
								break;
							case ICMP:
								Traitement_Port_UDP_Fermer (Equipement, Packet, n_read, Taille_Ip, Type_ICMP, Code_ICMP);
								if (!(Traitement_ScanOS_ICMP (Equipement, Packet, n_read, Taille_Ip, Type_ICMP, Code_ICMP))) {
								
								}
								if ((Equipement->Scan_Signature) && (Type_ICMP == 5) && (Code_ICMP == 1) && (memcmp (&Packet->Datagramme[Taille_Ip + 4], Mon_Adresse_Ip, IP_ADDR_LEN) == 0)) {
									debug_printf (D_INFO, __FILE__, __PRETTY_FUNCTION__, __LINE__, "Routage %s", Equipement->Adresse_Ip_Char);
									Equipement->Routage_Activer = TRUE;
								}
								break;
						    }
					    }
				}
			}
		}
	}
}
