#include <pcap.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>		
#include <arpa/inet.h>	
#include <netinet/if_ether.h>
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <libnet.h>
#include <sys/stat.h>
#include <sys/types.h>

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

/**********************/
/* Callback functions */
/**********************/
void callback_dnsid(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
	dns_packet datas;
	unsigned short dns_id;
	unsigned short flags;
	unsigned short question_type;
	u_char *temp;
	int i = 0;
	FILE *output;

	datas = (dns_packet) &packet[42];		/* Point our structure at the beginning of the DNS packet (UDP datas) */
	dns_id = htons(datas->dns_id);
	flags  = htons(datas->flags);
		
	temp = datas->datas;
	while( (*(temp+i) != '\0') && (i < 1024) )	/* 1024 : Only for security reason... forged dns packets, that's why we don't use strlen here */
		i++;
	i++;						/* We don't need the null byte */
	
	/* Let's see question type */
	question_type = temp[ i + 1 ];

	/* Types of queries [ From DNS RFC ] :			*/
	/* 0001		A					*/
	/* 000c		PTR					*/
	if( (question_type == 0x0001) && (flags == 0x0100) )
	{

#ifdef DEBUG
		printf("DNS REQUEST A received : Question type : %.4lx\n", (unsigned long) question_type); 
#endif
		if(args != NULL)
		{
			/* File name specified... Store result in a file */
			/* TODO: IF THE FILE EXISTS : Check if it's valid (contain DNS IDs -> check_file_IDs), and append it */
			/* FIXME: Check if the file isn't a link (sym or not) */	
						
			if((output = fopen(args, "a")) == NULL)
			{
				fprintf(stderr, "** Error : Can't open %s.\n", args);
				exit(EXIT_FAILURE);
			}
			/* And then, write it! ;) */
			fprintf(output, "%u\n", dns_id);
			fclose(output);
			/* Give a visual output too */
			printf("%u\n", dns_id);	
		}	
		else
		{
			printf("%u\n", dns_id);
		}
	}
}


/****************************/
/* Packet capture functions */
/****************************/
/* Grab dns queries on "device" from "srchost" and run the callback function (spoofing) for "hostdst" IP
 * If device == NULL, then use pcap_lookupdev
 * If srchost == NULL, then grab EVERY UDP DNS PAQUETS (promisc) */
int grab_dns_IDs(char *device, char *srchost, char *file)
{
	char *filter = malloc(MAX_FILTER_LONG * sizeof(char));
	char *dev;
	char errbuf[PCAP_ERRBUF_SIZE];
	pcap_t *descr;
	bpf_u_int32 maskp;	/* subnet mask			*/
	bpf_u_int32 netp;	/* ip				*/
	struct bpf_program fp;	/* hold compiled program 	*/

	if(filter == NULL)
		err_mem();

	sprintf(filter, "udp and dst port 53 and src host %s", srchost);
#ifdef DEBUG
	printf("\t\tFilter = %s\n\t\tSRChost = %s", filter, srchost);
#endif

	if(device == NULL)	/* Let's use interface of our choice! */
		dev = pcap_lookupdev(errbuf);
	else
		dev = device;

	if(dev == NULL)
	{
#ifdef DEBUG
		printf("\t\tdev = NULL\n");
#endif
		fprintf(stderr, "%s\n", errbuf);
		exit(EXIT_FAILURE);
	}
#ifdef DEBUG
	printf("\t\tUsing interface %s\n", dev);
#endif
	pcap_lookupnet(dev, &netp, &maskp, errbuf);	/* Get conf for this interface */
	if ((descr = pcap_open_live(dev, BUFSIZ, PROMISC_MODE, -1, errbuf)) == NULL)
	{
		fprintf(stderr, "%s\n", errbuf);
		exit(EXIT_FAILURE);
	}
#ifdef DEBUG
	if(PROMISC_MODE > 0)
		printf("\t\tPromisc mode enabled\n");
	else
		printf("\t\tPromisc mode disabled\n");
#endif
	if(pcap_compile(descr, &fp, filter, 0, netp) == -1)
	{
		fprintf(stderr, "** Error with pcap_compile\n");
	}

	if(pcap_setfilter(descr, &fp) == -1)
	{
		fprintf(stderr, "** Error with filter\n");
		exit(EXIT_FAILURE);
	}
	/* TODO: Replace with pcap_next and a loop structure */
	if(file == NULL)
		pcap_loop(descr, -1, callback_dnsid, NULL);
	else
		pcap_loop(descr, -1, callback_dnsid, file);

	free(filter);
	return (EXIT_SUCCESS);
}


/******************************************************/
/* Function that check if a file contain corrects IDs */
/******************************************************/
int check_file_IDs(char *path)
{
	/* Just open, and read every line to check if it's correct or not 	*/
	/* Return positive if the file format is correct. < 0 else 		*/
	FILE *input;
	int supposed_id;

	input = fopen(path, "r");

	while(!feof(input))
	{
		fscanf(input, "%d\n", &supposed_id);
		printf("%d\n", supposed_id);
		if( (supposed_id < 0) || (supposed_id > 65635) )
		{	
			printf("Wrong file format\n");
			fclose(input);
			return (EXIT_FAILURE);
		}
	}
	return (EXIT_SUCCESS);
}
