/***************************************************************************
 *   Copyright (C) 2005 by Christian Hubinger   *
 *   e9806056@student.tuwien.ac.at   *
 *                                                                         *
 *   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, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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 General Public License for more details.                          *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/
#include "iptchecker.h"


extern "C" {
#include <getopt.h>
#include <sys/errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include <netdb.h>
#include "libiptc/libiptc.h"
#include "iptables.h"
}


/* Here begins some of the code taken from iptables-save.c **************** */
#define IP_PARTS_NATIVE(n)      \
 (unsigned int)((n)>>24)&0xFF,   \
 (unsigned int)((n)>>16)&0xFF,   \
 (unsigned int)((n)>>8)&0xFF,    \
 (unsigned int)((n)&0xFF)



IPTChecker::IPTChecker()
{
}


IPTChecker::~IPTChecker()
{
}

int IPTChecker::numChainsInTable( char *tablename ) {
	int foundChain = 0;
	iptc_handle_t h;
	const char *chain = NULL;

	h = iptc_init(tablename);
	if (!h) {
     	printf("Can't initialize IPT Handle for table %s : %s\n", tablename, iptc_strerror(errno));
		return -1;
	}
	
 	for (chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h))  {
       	foundChain++;
  	}
	printf("Table %s Num: %d\n", tablename, foundChain );
	return foundChain;
}


int IPTChecker::numRulesInChain( char *tablename, char *chain ) {
	int foundRule = 0;
	iptc_handle_t h;
  	const struct ipt_entry *e;
	const char *ch = NULL;

	h = iptc_init(tablename);
	if (!h) {
     	printf("Can't initialize IPT Handle for table %s : %s\n", tablename, iptc_strerror(errno));
		return -1;
	}
	
 	if ( iptc_is_chain( chain, h ) == 0 ) {
		printf("Error Chain: %s Not Found in table: %s\n", chain, tablename );
		return -1;
	}	
	for (ch = iptc_first_chain(&h); ch; ch = iptc_next_chain(&h))  {
		if ( strcmp( ch, chain ) == 0 ) {
			int found = 0;
			for (e = iptc_first_rule(ch, &h); e && found == 0; e = iptc_next_rule(e, &h))  {
				foundRule++;
			}
			printf("Table: %s Chain: %s Num Rules: %d\n", tablename, chain, foundRule );
			return foundRule;
		}
   	}
	return -1;
}
TQStringList IPTChecker::getRuleProperties( char * table, char *chain, int ruleIndex ) {
	TQStringList list;
	int numRules = 0;
	int found = 0;
	iptc_handle_t h;
  	const struct ipt_entry *rule = 0;
	const struct ipt_entry *my_rule = 0;
	const char *ch = NULL;

	h = iptc_init(table);
	if (!h) {
     	printf("Can't initialize IPT Handle for table %s : %s\n", table, iptc_strerror(errno));
		return list;
	}
	
 	if ( iptc_is_chain( chain, h ) == 0 ) {
		printf("Error Chain: %s Not Found in table: %s\n", chain, table );
		return list;
	}	
	int foundChain = 0;
	for (ch = iptc_first_chain(&h); ch && foundChain == 0; ch = iptc_next_chain(&h))  {
		if ( strcmp( ch, chain ) == 0 ) {
			foundChain = 1;
			for (rule = iptc_first_rule(ch, &h); rule && found == 0; rule = iptc_next_rule(rule, &h))  {
				if ( numRules == ruleIndex ) {
					my_rule = rule;
					found = 1;
				}	
				numRules++;
			}
		}
   	}
	if ( my_rule ) {
		const char *target_name;
		/* Print target name */	
		target_name = iptc_get_target( my_rule, &h );
		if ( target_name && (*target_name != '\0') ) {
			
			list << TQString("%1").arg(target_name);
		}
		

		/* Print targinfo part */
/*		struct ipt_entry_target *t;
		t = ipt_get_target( (struct ipt_entry *) my_rule );
		if ( t ) {
			list << "Found Target:";
			list <<  t->u.user.name;
		}

		if ( t->u.user.name ) {
			list << TQString("TARGET2:%1").arg(t->u.user.name);
			
			struct iptables_target *target = find_target( target_name, TRY_LOAD );
			
			if ( ! target ) {
				list << "Can't find library for target `%s'\n" << t->u.user.name;
				return list;
			}
			
			if (target->save) {
				target->save(&my_rule->ip, t);
			} else {
				// If the target size is greater than ipt_entry_target
				// there is something to be saved, we just don't know
				// how to print it 
				if (t->u.target_size != sizeof(struct ipt_entry_target)) {
					fprintf(stderr, "Target `%s' is missing "
						"save function\n",
					t->u.user.name);
					return list;
				} 
			}
		}*/
	} else {
		list << "ERROR";
	}
	return list;
}

TQStringList IPTChecker::getChainsInTable( char * table ) {
	TQStringList list;
	int foundRule = 0;
	iptc_handle_t h;
  	const struct ipt_entry *e;
	const char *chain = NULL;

	h = iptc_init(table);
	if (!h) {
     	printf("Can't initialize IPT Handle for table %s : %s\n", table, iptc_strerror(errno));
		return list;
	}
	
 	
	for ( chain = iptc_first_chain(&h); chain; chain = iptc_next_chain(&h) )  {
       	list << chain;
  	}
	return list;
}


TQString IPTChecker::getChainPolicy( char * table, char *chain ) {
	TQString policy = "";
	iptc_handle_t h;
  	const struct ipt_entry *e;
	const char *ch = NULL;

	h = iptc_init(table);
	if (!h) {
     	printf("Can't initialize IPT Handle for table %s : %s\n", table, iptc_strerror(errno));
		return "";
	}
	
 	
	for ( ch = iptc_first_chain(&h); ch; ch = iptc_next_chain(&h) )  {
		if ( strcmp( ch, chain ) == 0 ) {
			
		if ( iptc_builtin(chain, h) ) {
				struct ipt_counters count;
				policy = iptc_get_policy(chain, &count, &h);
				
/*				printf("%s ",
				       iptc_get_policy(chain, &count, &h));
				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);*/
			} else {
// 				printf("- [0:0]\n");
			}

		}
  	}
	return policy;
}
