#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <time.h>
#include <sys/stat.h>
#include <libiptc/libiptc.h>
#include <arpa/inet.h>
#include <errno.h>

#define IP_LENGTH 16
const char *denied = "denied";
const char *file_name = "/var/log/named/security.log";
//const char *file_name = "/tmp/test.log";
uint32_t *banned_ips;
uint32_t *banlist;


struct Unique_Ips{
	//char ip[IP_LENGTH];
	uint32_t ip;
	uint32_t times;
};




//static int insert_rule (const char *table, const char *chain, unsigned int src, int inverted_src, unsigned int dest, int inverted_dst, const char *target){
static int insert_rule (const char *table, const char *chain, unsigned int src, int inverted_src, const char *target){
	struct{
		struct ipt_entry entry;
		struct xt_standard_target target;
	}entry;
	struct xtc_handle *h;
	int ret = 1;

	h = iptc_init (table);
	if(!h){
		printf("iptc error!\n");
		//fprintf (stderr, "Could not init IPTC library: %s\n", iptc_strerror (errno));
		goto out;
	}
	memset (&entry, 0, sizeof (entry));

	/* target */
	entry.target.target.u.user.target_size = XT_ALIGN (sizeof (struct xt_standard_target));
	strncpy(entry.target.target.u.user.name, target, sizeof (entry.target.target.u.user.name));
	/* entry */
	entry.entry.target_offset = sizeof (struct ipt_entry);
	entry.entry.next_offset = entry.entry.target_offset + entry.target.target.u.user.target_size;
	if(src){
		entry.entry.ip.src.s_addr  = src;
		entry.entry.ip.smsk.s_addr = 0xFFFFFFFF;
		if(inverted_src)
			entry.entry.ip.invflags |= IPT_INV_SRCIP;
	}
/*
	if(dest){
		entry.entry.ip.dst.s_addr  = dest;
		entry.entry.ip.dmsk.s_addr = 0xFFFFFFFF;
		if(inverted_dst)
			entry.entry.ip.invflags |= IPT_INV_DSTIP;
	}
*/
	if(!iptc_append_entry (chain, (struct ipt_entry *) &entry, h)){
		printf("iptc error!\n");
		//fprintf (stderr, "Could not insert a rule in iptables (table %s): %s\n", table, iptc_strerror (errno));
		goto out;
	}
	if(!iptc_commit (h)){
		printf("iptc error!\n");
		//fprintf (stderr, "Could not commit changes in iptables (table %s): %s\n", table, iptc_strerror (errno));
		goto out;
	}
	ret = 0;
	out:
	if(h)
		iptc_free(h);
	return ret;
}

/*
int main (int argc, char **argv)
{
  unsigned int a, b;
 
  inet_pton (AF_INET, "1.2.3.4", &a);
  inet_pton (AF_INET, "4.3.2.1", &b);
 
  insert_rule ("filter",
               "INPUT",
               a,
               0,
               b,
               1,
               "DROP");
  return 0;
}
*/









int Is_Denied(char *linestring){
	uint8_t num1 = 0;
	const uint8_t denied_length = 6;
	while(linestring[num1] != '\0')
		num1++;
	num1--;
	return strncmp(denied, (const char *)(&linestring[num1-denied_length]), denied_length);
}

void Grab_Ip(char *linestring, uint32_t *ip){
//void Grab_Ip(char *linestring, char *ip){
	uint8_t num1 = 0;
	uint8_t tmp = 0;
	char cur_ip[IP_LENGTH];
	while(linestring[num1] != '\0' && linestring[num1] != '#')
		num1++;

	if(linestring[num1] == '\0'){
		printf("malformed line 1\n");
		exit(1);
	}
	while(linestring[num1-tmp] != ' ')
		tmp++;
	tmp--;
	//printf("%s\n", &linestring[num1-tmp]);
	(void)memset(cur_ip, '\0', IP_LENGTH);
	(void)memcpy(cur_ip, (const void *)(&linestring[num1-tmp]), tmp);
	(void)inet_pton(AF_INET, (const char *)cur_ip, (void *)ip);
	//(void)memset(ip, '\0', IP_LENGTH);
	//(void)memcpy(ip, (const void *)(&linestring[num1-tmp]), tmp);
}

int Already_Denied(uint32_t *cur_ip, struct Unique_Ips *unique_ips, uint32_t ip_count){
	uint32_t num1 = 0;
	//uint32_t times = 0;
	while(num1 < ip_count){
		if(*cur_ip == unique_ips[num1].ip){
		//if(strncmp((const char *)cur_ip, (const char *)&(unique_ips[num1].ip), IP_LENGTH) == 0){
			unique_ips[num1].times++;
			return 1;
		}
		num1++;
	}
	return 0;
}

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

void Init_Banlist(void){
	FILE *fp;
	//const char *file_name = "/var/log/named/security.log";
	//const char *denied = "denied";
	char linestring[384];
	//uint32_t linenum = 0;
	//char cur_ip[IP_LENGTH];
	uint32_t cur_ip;
	struct Unique_Ips *unique_ips;
	//struct Unique_Ips tmp_unique_ip;
	uint32_t ip_count = 1;
	//uint32_t tmp1 = 0;
	uint32_t num1 = 0;
	//19-Sep-2018 07:48:25.243 client @0x7f9fc01ba2d0 23.161.0.30#12426 (access-board.gov): query (cache) 'access-board.gov/ANY/IN' denied

	//open log file
	if( (fp = fopen(file_name, "r")) == NULL){
		fprintf( stderr, "Error opening %s\n", file_name );
		exit( 1 );
	}
	unique_ips = (struct Unique_Ips *)malloc(ip_count * sizeof(struct Unique_Ips));

	//grab first "denied" line
	while(fgets(linestring, sizeof(linestring), fp) != NULL){
		if(Is_Denied(linestring) == 0){
			Grab_Ip(linestring, &cur_ip);
			unique_ips[ip_count-1].ip = cur_ip;
			//(void)memcpy(unique_ips[ip_count-1].ip, cur_ip, IP_LENGTH);
			unique_ips[ip_count-1].times = 1;
			break;
		}
	}

	//do the rest
	while(fgets(linestring, sizeof(linestring), fp) != NULL){
		if(Is_Denied(linestring) == 0){
			Grab_Ip(linestring, &cur_ip);
			//unique_ips[num1].times+
			if(Already_Denied(&cur_ip, unique_ips, ip_count) == 0){
				ip_count++;
				unique_ips = (struct Unique_Ips *)realloc(unique_ips, ip_count * sizeof(struct Unique_Ips));
				unique_ips[ip_count-1].ip = cur_ip;
				//(void)memcpy(unique_ips[ip_count-1].ip, cur_ip, IP_LENGTH);
				unique_ips[ip_count-1].times = 1;
			}
		}
	}
	fclose(fp);
	printf("%d unique denied ips detected in logfile\n", ip_count);

	system("iptables -F");

	//banned_ips = (uint32_t *)malloc(sizeof(uint32_t));
	for(num1=0; num1<ip_count; num1++){
//		printf("ip: %s denied: %d\n", unique_ips[num1].ip, unique_ips[num1].times);

		if(unique_ips[num1].times>3){
			
			(void)insert_rule("filter", "INPUT", unique_ips[num1].ip, 0, "DROP");
			//(void)insert_rule("filter", "INPUT", unique_ips[num1].ip, 0, unique_ips[num1].ip, 1, "DROP");
			//(void)memset(linestring, '\0', sizeof(linestring));
			//(void)sprintf(linestring, "iptables -A INPUT -s %u -j DROP", unique_ips[num1].ip);
			//system("iptables -F");
			//system((const char *)linestring);
		}
	}
	//fclose(fp);
	//banned_ips = (struct Unique_Ips *)malloc(ip_count * sizeof(struct Unique_Ips));

	free(unique_ips);

	//return 0;
}


int File_Modified(void) {
	struct stat attr;
	static time_t st_mtime_backup = 0;

	if(stat(file_name, &attr) != 0){
		printf("stat error!\n");
	}
	//st_mtime_backup = attr.st_mtime;

	//printf("Last modified time: %lu %lu\n", st_mtime_backup, attr.st_mtime);
	//printf("Last modified time: %s", ctime(&attr.st_mtime));
	//st_mtime_backup = attr.st_mtime;
	if(st_mtime_backup != attr.st_mtime){
		st_mtime_backup = attr.st_mtime;
		return 1;
	}else{
		//st_mtime_backup = attr.st_mtime;
		return 0;
	}
}

int main(int argc, char **argv){
	//uint32_t *banlist;
//system("iptables -F");
//	Init_Banlist();
	while(1){
		if(File_Modified() == 1){
Init_Banlist();
//			Main_Loop();
		}
//return 0;
		sleep(1);

	}

	//while(Main_Loop()){
	//	sleep(1);
	//}
	return 0;
}

