//
// C++ Implementation: kmfiptablesscriptgenerator
//
// Description: 
//
//
// Author: Christian Hubinger <chubinger@gmail.com>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
// License: GPL
//
#include "kmfiptablesscriptgenerator.h"

// QT includes
#include <qptrlist.h>
#include <qstringlist.h>
#include <qmultilineedit.h>
#include <qtextstream.h>
#include <qtabwidget.h>

// KDE includes
#include <kdebug.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kfiledialog.h>
#include <ktempfile.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>
#include <kapplication.h>

// Project includes
#include "../../version.h"
#include "../../core/kmfgenericdoc.h"
#include "../../core/kmfiptdoc.h"
#include "../../core/kmfnetzone.h"
#include "../../core/kmfnethost.h"
#include "../../core/kmfprotocol.h"
#include "../../core/iptable.h"
#include "../../core/iptchain.h"
#include "../../core/iptrule.h"
#include "../../core/iptruleoption.h"
#include "../../core/kmferror.h"
#include "../../core/kmferrorhandler.h"
#include "../../core/kmfconfig.h"
#include "../../kmfwidgets/kmflistview.h"




KMFIPTablesScriptGenerator::KMFIPTablesScriptGenerator()
{
}


KMFIPTablesScriptGenerator::~KMFIPTablesScriptGenerator()
{
}

const QString& KMFIPTablesScriptGenerator::compile( KMFIPTDoc* doc ) {
	m_iptDoc = doc;
	QString script;
	QTextOStream ts( &script );
	ts << printScriptHeader() << endl;
	ts << printScriptStartFunction() << endl;
	ts << printScriptStopFunction() << endl;
	ts << printScriptExecLogic() << endl;
	return *(new QString( script ) );
}



const QString& KMFIPTablesScriptGenerator::printScriptExecLogic() {
	QString script;
	QTextOStream ts( &script );
	ts <<
	"IPT=\"" + KMFConfig::iPTPath() + "\"\n"
	"MOD=\"" + KMFConfig::modprobePath() + "\"\n"
	"status=\"0\"\n"
	"verbose=\"0\"\n"
	"action=\"$1\"\n"

	"if [ \"$1\" = \"-v\" ]; then\n  "
	"  verbose=\"1\"\n"
	"fi\n\n"
	"if [ \"$1\" = \"--verbose\" ]; then\n  "
	"  verbose=\"1\"\n"
	"fi\n\n"

	"if [ \"$verbose\" = \"1\" ]; then\n  "
	"  if [ \"$2\" = \"\" ]; then\n"
	"    echo \"Usage: sh kmyfirewall.sh [-v|--verbose] { start | stop | restart }\"\n"
	"    exit 1\n"
	"  fi\n"
	"action=\"$2\"\n"
	"fi\n\n"

	"case $action in\n"
	"  start)\n"
	"  stopFirewall\n"
	"  startFirewall\n"
	"  ;;\n"
	"  stop)\n"
	"  stopFirewall\n"
	"  ;;\n"
	"  restart)\n"
	"  stopFirewall\n"
	"  startFirewall\n"
	"  ;;\n"
	"  *)\n"
	"  echo \"Invalid action!\nUsage: sh kmyfirewall.sh [-v|--verbose] { start | stop | restart }\"\n"
	"  ;;\n"
	"  esac\n\n"

	"if [ \"$status\" = \"1\" ]; then\n"
	"  exit 1\n"
	"else\n"
	"  exit 0\n"
	"fi\n" << endl;
	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptStartFunction() {
	QString script;
	QTextOStream ts( &script );

	ts << "startFirewall() {\n"
	"\necho -n \"Starting iptables (created by KMyFirewall)...       \"";
	if ( m_iptDoc->useModules() ) {
		ts << printScriptModuleLoad() << endl;
	}
	ts << "#  Define all custom chains" << endl;
	ts << printScriptDebug( "Create custom chains...       ", false) << endl;
	if ( m_iptDoc->useFilter() ) {
		ts << printScriptTableChainDefinition(  m_iptDoc->table( "filter"  ) ) << endl;
	}
	if ( m_iptDoc->useNat() ) {
		ts << printScriptTableChainDefinition(  m_iptDoc->table( "nat"  ) ) << endl;
	}
	if ( m_iptDoc->useMangle() ) {
		ts << printScriptTableChainDefinition(  m_iptDoc->table( "mangle"  ) ) << endl;
	}

	ts << printScriptDebug( "  Done." ) << endl;
	ts << "\n#  Rules:" << endl;
	if ( m_iptDoc->useFilter() ) {
		ts << printScriptTableRules( m_iptDoc->table( "filter" ) ) << endl;
	}
	if ( m_iptDoc->useNat() ) {
		ts << printScriptTableRules( m_iptDoc->table( "nat" ) ) << endl;
	}
	if ( m_iptDoc->useMangle() ) {
		ts << printScriptTableRules( m_iptDoc->table( "mangle" ) ) << endl;
	}

	if ( m_iptDoc->useIPFwd() ) {
		ts << "\n"<< printScriptDebug( "Enable IP Forwarding.                ", false ) << endl;
		ts << "echo 1 > /proc/sys/net/ipv4/ip_forward" << endl;
		ts << printScriptDebug( "Done." ) << endl;
	} else {
		ts << printScriptDebug( "Disable IP Forwarding.              ", false ) << endl;
		ts << "echo 0 > /proc/sys/net/ipv4/ip_forward" << endl;
		ts << printScriptDebug( "Done.") << endl;
	}

	if ( m_iptDoc->useRPFilter() ) {

		ts << "\n" << printScriptDebug( "Enable Reverse Path Filtering      ", false ) << endl;
		ts << "for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do" << endl;
		ts << "echo 2 > $i " << endl;
		ts << "done" << endl;
		ts <<  printScriptDebug( "Done." ) << endl;
	} else {
		ts << printScriptDebug( "Disable Reverse Path Filtering       ", false ) << endl;
		ts << "for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do" << endl;
		ts << "echo 0 > $i " << endl;
		ts << "done" << endl;
		ts << printScriptDebug( "Done." ) << endl;
	}

	if ( m_iptDoc->useMartians() ) {
		ts << "\n" << printScriptDebug( "Enable log_martians (logging).             ", false ) << endl;
		ts << "for i in /proc/sys/net/ipv4/conf/*/log_martians ; do" << endl;
		ts << "echo 1 > $i " << endl;
		ts << "done" << endl;
		ts << printScriptDebug( "Done." ) << endl;
	} else {
		ts << printScriptDebug( "Disable log_martians (logging).           ", false ) << endl;
		ts << "for i in /proc/sys/net/ipv4/conf/*/log_martians ; do" << endl;
		ts << "echo 0 > $i " << endl;
		ts << "done" << endl;
		ts << printScriptDebug( "Done." ) << endl;
	}

	if ( m_iptDoc->useSynCookies() ) {
		ts << "\n" <<  printScriptDebug( "Enable Syn Cookies.          ", false ) << endl;
		ts << "echo 1 > /proc/sys/net/ipv4/tcp_syncookies" << endl;
		ts << printScriptDebug( "Done." )<< endl;
	} else {
		ts <<  printScriptDebug( "Disable Syn Cookies.          ", false ) << endl;
		ts << "echo 0 > /proc/sys/net/ipv4/tcp_syncookies" << endl;
		ts << printScriptDebug( "Done." ) << endl;
	}
	ts << "echo Done." << endl;
	ts << "}" << endl;

	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptStopFunction() {
	QString script;
	QTextOStream ts( &script );
	ts << "stopFirewall() {\n"
	"  echo -n \"Clearing iptables (created by KMyFirewall)...       \"\n" << endl;
	if ( m_iptDoc->useFilter() ) {
		ts << "  $IPT -t filter -F || status=\"1\"\n"
		"  $IPT -t filter -X || status=\"1\"\n"
		"  $IPT -t filter -P INPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t filter -P OUTPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t filter -P FORWARD ACCEPT || status=\"1\"\n"<< endl;
	}
	if ( m_iptDoc->useNat() ) {
		ts << "  $IPT -t nat -F || status=\"1\"\n"
		"  $IPT -t nat -X || status=\"1\"\n"
		"  $IPT -t nat -P OUTPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t nat -P PREROUTING ACCEPT || status=\"1\"\n"
		"  $IPT -t nat -P POSTROUTING ACCEPT || status=\"1\"\n"<< endl;
	}
	if ( m_iptDoc->useMangle() ) {
		ts << "  $IPT -t mangle -F || status=\"1\"\n"
		"  $IPT -t mangle -X || status=\"1\"\n"
		"  $IPT -t mangle -P INPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t mangle -P OUTPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t mangle -P OUTPUT ACCEPT || status=\"1\"\n"
		"  $IPT -t mangle -P PREROUTING ACCEPT || status=\"1\"\n"
		"  $IPT -t mangle -P POSTROUTING ACCEPT || status=\"1\"\n" << endl;
	}
	ts << "  echo \"Done.\"\n" << endl;
	ts << "}" << endl;
	return *(new QString( script ) );
}


const QString& KMFIPTablesScriptGenerator::printScriptDebug( const QString& msg, bool newLine ) {
	QString script;
	QTextOStream ts( &script );
	ts << "if [ \"$verbose\" = \"1\" ]; then\n" ;
	ts << "echo " ;
	if ( ! newLine )
		ts << "-n " ;
	ts << "\"" + msg +"\"\n";
	ts << "fi\n" << endl;
	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptTableChainDefinition( IPTable *tbl ) {
	QString script;
	QTextOStream ts( &script );
	for ( uint i = 0;i < tbl->chains().count();i++ ) {
		IPTChain* c = tbl->chains().at( i );
		if ( !c->isBuildIn() ) {
			ts << "\n#  Create Chain: " + c->name() << endl;
			QString s2 = c->createIPTablesChainDefinition();
			if ( !s2.isEmpty() ) {
				ts << s2 << " || { status=\"1\"; echo \"Setting up Chain: " + c->name() + " FAILED !!!\"; exit 1; }\n";
			}
		}
	}
	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptTableRules( IPTable *tbl ) {
	QString script;
	QTextOStream ts( &script );
	ts << printScriptDebug(  "Settup Rules in Table " + tbl->name().upper() + ":" ) << "\n" << endl;
	for ( uint i = 0;i < tbl->chains().count();i++ ) {
		IPTChain* c = tbl->chains().at( i );
		ts << "\n#  Define Rules for Chain: " + c->name() << endl ;
		ts << printScriptDebug( "Create Rules for Chain: " + c->name() ) + "                    " << endl;
		QPtrList<QStringList> rules = c->createIPTablesChainRules();
		QStringList* curr_rule;
		QString rule_name;
		for ( curr_rule = rules.first(); curr_rule; curr_rule = rules.next() ) {
			rule_name = *curr_rule->at( 0 );
			QString s = *curr_rule->at( 1 );
			if ( !s.isEmpty() ) {
				ts << s << " || { status=\"1\"; echo \" Setting up Rule: " + rule_name + " FAILED! \"; exit 1; }\n" << endl;
			}
		}
	}
	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptModuleLoad() {
	QString script;
	QTextOStream ts( &script );
	ts << "\n";
	ts << printScriptDebug( "\nLoading needed modules...          ", false ) << endl;
	ts <<
	"$MOD ip_tables \n"
	"$MOD ip_conntrack \n"
	"$MOD ipt_LOG \n"
	"$MOD ipt_limit \n"
	"$MOD ipt_state \n"
	"$MOD ip_conntrack_ftp\n"
	"$MOD ip_conntrack_irc\n"
	<< endl;
	if ( m_iptDoc->useFilter() ) {
		ts << "$MOD iptable_filter" << endl;
	}
	if ( m_iptDoc->useNat() ) {
		ts << "$MOD iptable_nat" << endl;

	}
	if ( m_iptDoc->useMangle() ) {
		ts << "$MOD iptable_mangle" << endl;
	}
	ts << printScriptDebug( "Done.") << endl;
	return *(new QString( script ) );
}

const QString& KMFIPTablesScriptGenerator::printScriptHeader() {
	QString script;
	QTextOStream ts( &script );
	QString version = KMYFIREWALL_VERSION;
	QString copyright_string = COPYRIGHT_STRING;
	QString maintainer = MAINTAINER;
	QString license = LICENSE;
	ts <<
	"#!/bin/sh\n"
	"#\n"
	"# " + copyright_string + "\n"
	"# PLease reprt bugs to: " + maintainer + "\n"
	"#\n"
	"# " + license + "\n"
	"#\n"
	"# KMyFirewall v" + version + "\n"
	"# This is an automatic generated file DO NOT EDIT\n"
	"#\n" << endl;
	return *(new QString( script ) );
}


