<?php
/*********************************************************************************
* ACFW ADVANCE CREWCOMM FIREWALL
* ==============================
* WRITTEN BY JOSE MARI REYES
* HISTORY:
* 01-14-2019		VERSION 1.0
* 01-15-2019	    UPDATE CODE FIX BUG V1.1
* 01-31-2019		SUPPORT FOR MULTI PORT
* 02-28-2019		SUPPORT DOMAIN NAME
* 03-26-2019		FORWARDING SUPPORTED - BETA
* 05-20-2019		MODIFIED FOR API CONFIG
* 06-24-2019		FIXED FORWARDING 
* 07-22-2019		FORWARDING IS NOW ON /etc/smsg/fwdsmsg FILE
* 09-16-2019		added root path to apiconfig 
* --------------------------------------------------------------------------------------------------
* tom modified |	Moved Global to function to static class, conflicts when file is being included somewhere
* 10-02-2019 - |	removed bin-bash introducing whitespace when file is included
* 			   |    Removed Ending PHP tag so that FILE may not create white space when included by other files
* 			 
* 10-24-2019		ICMP IS DEPRECATED.  11 IS NOW TCP+UDP PROTOCOL			 
* 01-07-2020		SOURCE AND DESTINATION FIELD NOW SUPPORT BOOLEAN (!) FUNCTION			 
* 01-14-2020		APICONFIG IS NOW THE UNIVERSAL NETWORK CONFIGURATION			 
* 			 
********************************************************************************/
//added by tom causes errors when including multiple files
if(!defined('SMSG_IS_INCLUDED')){
	include ('/www/cgi-bin/apiconfig');	
}

define('ADV_FIREWALL_SAVE', "/etc/smsg/advcfw.dat");  //save file for the instruction
define('ADV_PORTFWD_SAVE', "/etc/smsg/advportfwd.dat"); //save to port forwarding file
define('FIREWALL_FILE', "/etc/smsg/firesmsg");
define('FORWARD_FILE', "/etc/smsg/fwdsmsg");
define ("INPUT", "delegate_input");
define ("FORWARD", "delegate_forward");
define ("OUTPUT", "delegate_output");

/*
	Encapsulate all variable on a static class accessible to all
	Removing GLOBAL so that it will not class with other variables outside file
*/
class GlobalConfig{
	public static $OP_IA 			= array("0" => "-I", "1" => "-A");  
	public static $OP_CH 			= array("00" => INPUT, "01" => FORWARD, "10" => OUTPUT);
	public static $OP_PT 			= array("00" => "", "01" => "-p tcp", "10" => "-p udp", "11" => "TCP+UDP");
	public static $OP_SD 			= array("0" => "--dport", "1" => "--sport");
	public static $OP_JJ 			= array("00" => "-j ACCEPT", "01" => "-j DROP", "10" => "-j REJECT", "11" => "RAW");
	public static $OP_FWD_PROTO 	= array("00" => "tcp", "01" => "udp");
}

echo "<pre>";

$rules = "";

if (isset($_REQUEST['rules']))
{
	$rules = $_REQUEST['rules'];
	proc_adv_firewall($rules, 0);
}

if (isset($_REQUEST['read']))
{
	proc_adv_firewall("dummy", 1);
}
	

if (isset($_REQUEST['forward']))
{
	$forward = $_REQUEST['forward'];
	proc_adv_forwarding($forward);
}





function proc_adv_firewall($rules, $read = 0, $append = 0)
{
	$cmd_filter = "\n";

	if (strlen($rules) < 1) return 0;
	


	if ($read == 0)
	{
		$op = trim($rules, ";");
		file_put_contents(ADV_FIREWALL_SAVE, $op);
	}
	
	$op = @file_get_contents(ADV_FIREWALL_SAVE);
	if ($op === false) {echo "NA"; exit;}
		
		
	$data = explode(";", $op);
		
	for ($i = 0; $i < count($data); $i++)
	{
		//echo $data[$i] . "\n";		
		$tmp  = explode("|", $data[$i]); 
		//print_r($tmp);
		$op   = $tmp[0];
		$src  = $tmp[1];
		$dest = $tmp[2];
		$port = $tmp[3];
			
		//echo "send to process: $op $src $dest $port\n";
			
		$cmd_filter .= ident_op($op, $src, $dest, $port) . "\n";
	}

	if ($append == 1) 
		file_put_contents(FIREWALL_FILE, $cmd_filter, FILE_APPEND);
	else
	  	file_put_contents(FIREWALL_FILE, $cmd_filter); 
				
}



function is_hex($hex_code) {
	return @preg_match("/^[a-f0-9]{2,}$/i", $hex_code) && !(strlen($hex_code) & 1);
}



function proc_adv_forwarding($rules, $read = 0)
{

	$cmd_filter = "";

	if (strlen($rules) < 1) return 0;
	
	if ($read == 0)
	{
		$op = trim($rules, ";");
		file_put_contents(ADV_PORTFWD_SAVE, $op);
	}
	
	$op = @file_get_contents(ADV_PORTFWD_SAVE);
	if ($op === false) {echo "NA"; exit;}
		
		
	$data = explode(";", $op);
		
	for ($i = 0; $i < count($data); $i++)
	{
		//echo $data[$i] . "\n";		
		$tmp  = explode("|", $data[$i]); 
		//print_r($tmp);
		
		$op   		= $tmp[0];
		$from_port  = $tmp[1];
		$dest_ip 	= $tmp[2];
		$dest_port 	= $tmp[3];
			
		//echo "send to process: $op $src $dest $port\n";
		$cmd_filter .= forwarding_op($op, $from_port, $dest_ip, $dest_port) . "\n";
	}

	file_put_contents(FORWARD_FILE, $cmd_filter);
				
}




function forwarding_op($op, $from_port, $dest_ip, $dest_port)
{

	/*
	IF=eth1
	PORT_FROM=8080
	PORT_TO=80
	DEST=10.32.25.2
	iptables -w -t nat -A PREROUTING -i $IF -p tcp --dport $PORT_FROM -j DNAT --to $DEST:$PORT_TO
	iptables -w -t nat -A POSTROUTING -p tcp -d $DEST --dport $PORT_TO -j MASQUERADE
	*/
	$OP_FWD_PROTO = GlobalConfig::$OP_FWD_PROTO;

	$cmd 			= "";
	$if 			= WAN_ETH;
	$v				= h2b($op);
	$dest_ip 		= hex2ip($dest_ip);
	$from_port 		= hexdec($from_port);
	$dest_port 		= hexdec($dest_port);
	
	
	$opt = $v[0] . $v[1];  //operation
	
	//protocol
	$proto = "";
	$proto = $v[2] . $v[3];
	 
	$proto = $OP_FWD_PROTO[$proto];
	
		
	if ($opt == '00')  
	{
		$cmd  = "iptables -w -t nat -A PREROUTING -i $if -p $proto --dport $from_port -j DNAT --to $dest_ip:$dest_port\n";
		$cmd .= "iptables -w -t nat -A POSTROUTING -p $proto -d $dest_ip --dport $dest_port -j MASQUERADE\n";
	}
 
  	return $cmd; 
}


function ident_op($opx, $source, $destination, $port)
{
	$OP_IA = GlobalConfig::$OP_IA;
	$OP_CH = GlobalConfig::$OP_CH;
	$OP_PT = GlobalConfig::$OP_PT;
	$OP_SD = GlobalConfig::$OP_SD;
	$OP_JJ = GlobalConfig::$OP_JJ;

    
	$op = h2b($opx);
	
	//INSERT OR APPENED
	$loc = $op[0];
	$loc = $OP_IA[ $loc ] . "";
	
	//CHAIN
	$chain = $op[1] . $op[2];
	$chain = $OP_CH[ $chain ] . "";

    //TARGET
	$target = $op[6] . $op[7];
	$target = $OP_JJ[$target];

    //RAW
	if ($target == "RAW"){
		$cmd = "$loc $chain $source"; 
		return "iptables -w $cmd\n";
	}


	//PROTOCOL
	$proto = $op[3] . $op[4];
	$proto = $OP_PT[$proto];
	
	
	if ($proto != "")
	{
		if ($port != "0") //port not set to zero
		{
			$sd = $op[5];
			$sd =  $OP_SD[$sd];
			echo "::::$port\n";
			if (strpos($port, ":") != 0) //port range
			{
				$pr = explode(":", $port);
				$prt = "-m multiport $sd ";
				$prt .= hexdec($pr[0]) . ":" . hexdec($pr[1]);
				$sdport = $prt;
			}
			elseif (strpos($port, ",") != 0) //port list
			{
				//echo ">>>$port\n";
				$pr = explode(",", $port);
				$prt = "-m multiport $sd ";
				
				for ($i = 0; $i < count($pr); $i++)
				{
					//echo "---->" . $pr[$i] . "\n"; 
					$prt .= hexdec($pr[$i]) . ",";
				}
				$prt = trim($prt, ",");
				$sdport = $prt;
			}
			else
			{
				$prt = hexdec($port);
				$sdport = "$sd $prt";
			}	
			
			
		}	
	}
	
	
	
	//SOURCE AND DESTINATION
	$ipsrc  = "";
	$ipdest = "";
	
	if ($source != "0")
	{
		if (strpos($source, '!') === false) $ipsrc = "-s "; else  $ipsrc = "! -s ";
	   	
		$source = ltrim($source, '!');  
		
		if ($source == "B") 
	   		$ipsrc .= get_business_lan();
	   	elseif ($source == "C") 
	   		$ipsrc .= get_crew_lan();
		elseif (is_hex($source) == false)
			$ipsrc .= $source;
	   	else
	   	{	
	   		$ipsrc .= hex2ip($source);
	   	}	   
	}
	
	if ($destination != "0")
	{
		if (strpos($destination, '!') === false) $ipdest = "-d "; else  $ipdest = "! -d ";
			
		$destination = ltrim($destination, '!');  
		
	   	if ($destination == "B") 
	   		$ipdest .= get_business_lan();
	   	elseif ($destination == "C") 
	   		$ipdest .= get_crew_lan();
		elseif (is_hex($destination) == false)
			$ipdest .= $destination;
	   	else
	   	{
	   		$ipdest .= hex2ip($destination);
	   	}
	} 
	
	
	//COMPOSE RULE
	
	$cmd = "$loc $chain "; 
	$cmd .= ((strlen($ipsrc) > 0) ? "$ipsrc " : "");
	$cmd .= ((strlen($ipdest) > 0) ? "$ipdest " : "");
	
	$cmd .= "$proto $sdport $target";
	

	//modify cmd if proto is TCP+UDP or 00
	if (strcmp($proto, "TCP+UDP") == 0)
	{
		$tmp_tcp = str_replace("TCP+UDP", "-p tcp", $cmd);
		$tmp_udp = str_replace("TCP+UDP", "-p udp", $cmd);
		
		$cmd = "iptables -w " . $tmp_tcp . "\niptables -w " . $tmp_udp;	
	}
	else
		$cmd = "iptables -w $cmd";
		
	echo "\nCMD=$cmd\n";	
    	return $cmd;


}




function hex2ip($hex)
{
	$tmp = $hex[0] . $hex[1];
	$ip = hexdec($tmp) . ".";
	
	$tmp = $hex[2] . $hex[3];
	$ip .= hexdec($tmp) . ".";
	
	$tmp = $hex[4] . $hex[5];
	$ip .= hexdec($tmp) . ".";
	
	$tmp = $hex[6] . $hex[7];
	$ip .= hexdec($tmp);
	
	if (strlen($hex) > 8)  $ip .= substr($hex, 8);
	
	return $ip;
}


function h2b($hex, $n = 8) 
{
	$dec = hexdec($hex);
    return str_pad(decbin($dec), $n, "0", STR_PAD_LEFT);
}


function get_business_lan()
{
	$ip  = "";
        $net = "";

	$iface = BUS_IFACE;

    $ip = shell_exec("ifconfig $iface | awk '/inet addr:/ { sub(/addr:/, \"\", $2); print $2 }'");

    $ip = explode('.', $ip);

    $net = $ip[0] . "." . $ip[1] . "." . $ip[2] . ".0/24";

    return $net;

}

function get_crew_lan()
{
	return get_tun0_ip_net();
}


function get_tun0_ip_net()
{
	$ip  = "";
	$net = "";
	
	$ip = shell_exec("ifconfig tun0 | awk '/inet addr:/ { sub(/addr:/, \"\", $2); print $2 }'");
	
	$ip = explode('.', $ip);
	
	$net = $ip[0] . "." . $ip[1] . "." . $ip[2] . ".0/24";

	return $net;	
}
 
