#!/usr/bin/perl
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2013 Alexander Marx <amarx@ipfire.org>                        #
#                                                                             #
# 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 3 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, see <http://www.gnu.org/licenses/>.       #
#                                                                             #
###############################################################################
#                                                                             #
# This script converts old portforwarding rules from old Firewall             #
# to the new one. This is a 3-step process.                                   #
# STEP1: read old config and normalize settings                               #
# STEP2: create new rules from old ones                                       #
# STEP3: check if rule already exists, when not, put it into                  #
#        /var/ipfire/firewall/config                                          #
###############################################################################
require '/var/ipfire/general-functions.pl';
my @values=();
my @built_rules=();
my %nat=();
my $portfwconfig 	= "${General::swroot}/portfw/config";
my $confignat 		= "${General::swroot}/firewall/config";
my ($key,$flag,$prot,$ipfireport,$target,$targetport,$active,$alias,$source,$remark);
my ($key1,$flag1,$prot1,$ipfireport1,$target1,$targetport1,$active1,$alias1,$source1,$remark1);
my $count=0;
my $jump;

if (! -e "$portfwconfig") {
        print "Config file for portforward not found. Exiting!\n";
        exit(1);
}

if (! -s "$portfwconfig") {
        print "Empty portforward configuration file. Nothing to do. Exiting...\n";
        exit(0);
}

if(! -d "/var/log/converters"){ mkdir("/var/log/converters");}
open(FILE, $portfwconfig) or die 'Unable to open config file.';
my @current = <FILE>;
close(FILE);
open (LOG, ">/var/log/converters/portfw-convert.log") or die $!;
open(ALIAS, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
my @alias = <ALIAS>;
close(ALIAS);
&get_config;
&build_rules;
&write_rules;
sub get_config
{
	my $baseipfireport;
	my $basesource;
	print LOG "STEP 1:   Get config from old portforward\n#########################################\n";
	foreach my $line (@current){
		my $u=$count+1;
		($key,$flag,$prot,$ipfireport,$target,$targetport,$active,$alias,$source,$remark) = split(",",$line);
		($key1,$flag1,$prot1,$ipfireport1,$target1,$targetport1,$active1,$alias1,$source1,$remark1) = split(",",$current[$u]);
		if ($key == $key1 && $flag == '0'){
			$baseipfireport = $ipfireport;
		}
		if ($key == $key1 && $flag1 == '1'){
			$count++;
			next;
		}
		my $now=localtime;
		chomp($remark);
		print LOG "$now   processing-> KEY: $key FLAG: $flag PROT: $prot FIREPORT: $baseipfireport TARGET: $target TGTPORT: $targetport ACTIVE: $active ALIAS: $alias SOURCE: $source REM: $remark Doublerule: $jump\n";
		push (@values,$prot.",".$baseipfireport.",".$target.",".$targetport.",".$active.",".$alias.",".$source.",".$remark);
		$count++;
	}
}
sub build_rules
{
	print LOG "\nSTEP 2: Convert old portforwardrules in a useable format\n########################################################\n";
	my $src;
	my $src1;
	my $ipfireip;
	my $count=0;
	my $stop;
	#build rules for new firewall
	foreach my $line (@values){
		chomp ($line);
		($prot,$ipfireport,$target,$targetport,$active,$alias,$source,$remark)=split(",",$line);
		$count++;
		#get sourcepart
		if($source eq '0.0.0.0/0'){
			$src  = 'std_net_src';
			$src1 = 'ALL';
		}else{
			$src  = 'src_addr';
			my ($a,$b) = split("/",$source);
			if ($b != ''){
				$b = &General::iporsubtocidr($b);
			}else{
				$b = "32";
			}
			$src1 = $a."/".$b;
		}
		#get ipfire ip
		if($alias eq '0.0.0.0' || $alias eq '0'){
			$alias='Default IP';
		}else{
			foreach my $ali (@alias){
				my ($alias_ip,$alias_active,$alias_name) = split (",",$ali);
				if($alias eq $alias_ip){
					chomp($alias_name);
					$alias=$alias_name;
				}
			}
		}
		$active = uc $active;
		$prot   = uc $prot;
		chomp($remark);
		push (@built_rules,"ACCEPT,FORWARDFW,$active,$src,$src1,tgt_addr,$target/32,,$prot,,TGT_PORT,$targetport,$remark,00:00,00:00,ON,$alias,$ipfireport,dnat");
		my $now=localtime;
		print LOG "$now    Converted-> KEY: $count ACCEPT,FORWARDFW,$active,$src,$src1,tgt_addr,$target/32,*,$prot,,TGT_PORT,$targetport,$remark,00:00,00:00,ON,$alias,$ipfireport,dnat\n";
	}
}
sub write_rules
{
	my $skip='';
	my $id;
	print LOG "\nSTEP 3: Create DNAT rules in new firewall\n#########################################\n";
	&General::readhasharray($confignat,\%nat);
	foreach my $line (@built_rules){
		$skip='';
		my ($action,$chain,$active,$src,$src1,$tgt,$tgt1,$dummy,$prot,$dummy,$tgt_port,$tgt_port1,$remark,$from,$to,$use_port,$alias,$ipfireport,$dnat) = split (",",$line);
		foreach my $key (sort keys %nat){
			if ($line eq "$nat{$key}[0],$nat{$key}[1],$nat{$key}[2],$nat{$key}[3],$nat{$key}[4],$nat{$key}[5],$nat{$key}[6],$nat{$key}[7],$nat{$key}[8],$nat{$key}[11],$nat{$key}[14],$nat{$key}[15],$nat{$key}[16],$nat{$key}[26],$nat{$key}[27],$nat{$key}[28],$nat{$key}[29],$nat{$key}[30],$nat{$key}[31]"){
				my $now=localtime;
				print LOG "$now         SKIP->  Rule  $nat{$key}[0],$nat{$key}[1],$nat{$key}[2],$nat{$key}[3],$nat{$key}[4],$nat{$key}[5],$nat{$key}[6],$nat{$key}[7],$nat{$key}[8],$nat{$key}[11],$nat{$key}[14],$nat{$key}[15],$nat{$key}[16],$nat{$key}[26],$nat{$key}[27],$nat{$key}[28],$nat{$key}[29],$nat{$key}[30],$nat{$key}[31] ->EXISTS\n";
				$skip='1';
			}
		}
		if ($skip ne '1'){
			if ( $prot eq 'GRE'){
				$tgt_port='';
				$tgt_port1='';
				$use_port='';
				$ipfireport='';
				$use_prot='';
			}
			$id = &General::findhasharraykey(\%nat);
			$nat{$id}[0]  = $action;
			$nat{$id}[1]  = $chain;
			$nat{$id}[2]  = $active;
			$nat{$id}[3]  = $src;
			$nat{$id}[4]  = $src1;
			$nat{$id}[5]  = $tgt;
			$nat{$id}[6]  = $tgt1;
			$nat{$id}[7]  = $dummy;
			$nat{$id}[8]  = $prot;
			$nat{$id}[11] = $use_port;
			$nat{$id}[14] = $tgt_port;
			$nat{$id}[15] = $tgt_port1;
			$nat{$id}[16] = $remark;
			$nat{$id}[26] = $from;
			$nat{$id}[27] = $to;
			$nat{$id}[28] = $use_port;
			$nat{$id}[29] = $alias;
			$nat{$id}[30] = $ipfireport;
			$nat{$id}[31] = $dnat;
			my $now=localtime;
			print LOG "$now     NEW RULE->  Rule  $nat{$id}[0],$nat{$id}[1],$nat{$id}[2],$nat{$id}[3],$nat{$id}[4],$nat{$id}[5],$nat{$id}[6],$nat{$id}[11],$nat{$id}[12],$nat{$id}[13],$nat{$id}[14],$nat{$id}[15],$nat{$id}[16],$nat{$id}[26],$nat{$id}[27],$nat{$id}[28],$nat{$id}[29],$nat{$id}[30],$nat{$id}[31]\n";
		}
	}
	&General::writehasharray($confignat,\%nat);
}
close (LOG);
