"pfBlockerAfrica", "Antartica" => "pfBlockerAntartica", "Asia" => "pfBlockerAsia", "Europe" => "pfBlockerEurope", "North America" => "pfBlockerNorthAmerica", "Oceania" => "pfBlockerOceania", "South America" => "pfBlockerSouthAmerica", "Top Spammers" => "pfBlockerTopSpammers"); #create rules vars and arrays $new_aliases=array(); $new_aliases_list=array(); $permit_inbound=array(); $permit_outbound=array(); $deny_inbound=array(); $deny_outbound=array(); $aliases_list=array(); #check if pfblocker is enabled or not. $deny_action_inbound=($pfblocker_config['inbound_deny_action']!= ""?$pfblocker_config['inbound_deny_action']:"block"); $deny_action_outbound=($pfblocker_config['outbound_deny_action']!= ""?$pfblocker_config['outbound_deny_action']:"reject"); $base_rule= array( "id" => "", "tag"=> "", "tagged"=> "", "max"=> "", "max-src-nodes"=>"", "max-src-conn"=> "", "max-src-states"=>"", "statetimeout"=>"", "statetype"=>"keep state", "os"=> ""); ############################################# # Assign Countries # ############################################# foreach ($continents as $continent => $pfb_alias){ ${$continent}=""; if (is_array($config['installedpackages']['pfblocker'.strtolower(preg_replace('/ /','',$continent))]['config'])){ $continent_config=$config['installedpackages']['pfblocker'.strtolower(preg_replace('/ /','',$continent))]['config'][0]; if ($continent_config['action'] != 'Disabled' && $continent_config['action'] != '' && $pfblocker_enable == "on"){ foreach (explode(",", $continent_config['countries']) as $iso){ #var_dump ($iso); if ($iso <> "" && file_exists($pfbdir.'/'.$iso.'.txt')){ ${$continent} .= file_get_contents($pfbdir.'/'.$iso.'.txt'); } } if($continent_config['countries'] != "" && $pfblocker_enable == "on"){ #write alias files file_put_contents($pfb_alias_dir.'/'.$pfb_alias.'.txt',${$continent},LOCK_EX); file_put_contents($pfsense_alias_dir.'/'.$pfb_alias.'.txt',${$continent}, LOCK_EX); #Create alias config $new_aliases_list[]=$pfb_alias; $new_aliases[]=array( "name"=> $pfb_alias, "url"=> $web_local.'?pfb='.$pfb_alias, "updatefreq"=> "32", "address"=>"", "descr"=> "pfBlocker country list", "type"=> "urltable", "detail"=> "DO NOT EDIT THIS ALIAS"); #Create rule if action permits switch($continent_config['action']){ case "Deny_Both": case "Deny_Outbound": $rule = $base_rule; $rule["type"] = $deny_action_outbound; $rule["descr"]= "$pfb_alias auto rule"; $rule["source"]=array("any"=>""); $rule["destination"]= array("address"=> $pfb_alias); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $deny_outbound[]=$rule; if ($continent_config['action'] != "Deny_Both") break; case "Deny_Inbound": $rule = $base_rule; $rule["type"] = $deny_action_inbound; $rule["descr"]= "$pfb_alias auto rule"; $rule["source"]= array("address"=> $pfb_alias); $rule["destination"]=array("any"=>""); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $deny_inbound[]=$rule; break; case "Permit_Both": case "Permit_Outbound": $rule = $base_rule; $rule["type"] = "pass"; $rule["descr"]= "$pfb_alias auto rule"; $rule["source"]=array("any"=>""); $rule["destination"]= array("address"=> $pfb_alias); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $permit_outbound[]=$rule; if ($continent_config['action'] != "Permit_Both") break; case "Permit_Inbound": $rule = $base_rule; $rule["type"] = "pass"; $rule["descr"]= "$pfb_alias auto rule"; $rule["source"]= array("address"=> $pfb_alias); $rule["destination"]=array("any"=>""); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $permit_inbound[]=$rule; break; } } } else{ #unlink continent list if any unlink_if_exists($pfb_alias_dir.'/'.$pfb_alias.'.txt'); } } #mark pfctl aliastable for cleanup if (!in_array($pfb_alias, $aliases_list)){ $aliases_list[]=$pfb_alias; } } ############################################# # Assign lists # ############################################# #print "
";
		if($config['installedpackages']['pfblockerlists']['config'] != ""){
			foreach($config['installedpackages']['pfblockerlists']['config'] as $list){
				$alias="pfBlocker".preg_replace("/\W/","",$list['aliasname']);
				#print $list['aliasname'].$list['action']." ".$alias." ".$row['url']."
"; if ($alias != "pfBlocker" && $list['action'] != "" && $list['action'] != 'Disabled' && $pfblocker_enable == "on"){ #remove empty lists files if any if (is_array($list['row'])){ foreach ($list['row'] as $row){ #print $list['aliasname'].$list['action'].$list['cron']." ".$alias." ".$row['url']."$update_local
"; if ($row['url'] != ""){ $md5_url = md5($row['url']); if (file_exists($pfbdir."/".$md5_url.".txt")){ ${$alias}.= file_get_contents($pfbdir.'/'.$md5_url.'.txt'); } else{ if ($row['format'] == "gz"){ $url_list= gzfile($row['url']); } else{ $url_list= file($row['url']); } #extract range lists $new_file=""; if (is_array($url_list)){ foreach ($url_list as $line){ # Network range 192.168.0.0-192.168.0.254 if (preg_match("/(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)/",$line,$matches)){ $a_cidr = ip_range_to_subnet_array($matches[1],$matches[2]); if (is_array($a_cidr)) { foreach ($a_cidr as $cidr) { ${$alias}.= $cidr."\n"; $new_file.= $cidr."\n"; } } } # CIDR format 192.168.0.0/16 else if (preg_match("/(\d+\.\d+\.\d+\.\d+\/\d+)/",$line,$matches)){ ${$alias}.= $matches[1]."\n"; $new_file.= $matches[1]."\n"; } # Single ip addresses else if (preg_match("/(\d+\.\d+\.\d+\.\d+)\s+/",$line,$matches)){ ${$alias}.= $matches[1]."/32\n"; $new_file.= $matches[1]."/32\n"; } } } if ($new_file != ""){ file_put_contents($pfbdir.'/'.$md5_url.'.txt',$new_file, LOCK_EX); } } } } } #check custom network list if (pfb_text_area_decode($list['custom']) != ""){ ${$alias}.=pfb_text_area_decode($list['custom'])."\n"; } #save alias file if not empty if (${$alias} == ""){ unlink_if_exists($pfb_alias_dir.'/'.$alias.'.txt'); } else{ file_put_contents($pfb_alias_dir.'/'.$alias.'.txt',${$alias}, LOCK_EX); file_put_contents($pfsense_alias_dir.'/'.$alias.'.txt',${$alias}, LOCK_EX); #create alias $new_aliases_list[]=$alias; $new_aliases[]=array( "name"=> $alias, "url"=> $web_local.'?pfb='.$alias, "updatefreq"=> "32", "address"=>"", "descr"=> "pfBlocker user list", "type"=> "urltable", "detail"=> "DO NOT EDIT THIS ALIAS"); #Create rule if action permits switch($list['action']){ case "Deny_Both": case "Deny_Outbound": $rule = $base_rule; $rule["type"] = $deny_action_outbound; $rule["descr"]= "$alias auto rule"; $rule["source"]=array("any"=>""); $rule["destination"]= array("address"=> $alias); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $deny_outbound[]=$rule; if ($list['action'] != "Deny_Both") break; case "Deny_Inbound": $rule = $base_rule; $rule["type"] = $deny_action_inbound; $rule["descr"]= "$alias auto rule"; $rule["source"]= array("address"=> $alias); $rule["destination"]=array("any"=>""); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $deny_inbound[]=$rule; break; case "Permit_Both": case "Permit_Outbound": $rule = $base_rule; $rule["type"] = "pass"; $rule["descr"]= "$alias auto rule"; $rule["source"]=array("any"=>""); $rule["destination"]= array("address"=> $alias); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $permit_outbound[]=$rule; if ($list['action'] != "Permit_Both") break; case "Permit_Inbound": $rule = $base_rule; $rule["type"] = "pass"; $rule["descr"]= "$alias auto rule"; $rule["source"]= array("address"=> $alias); $rule["destination"]=array("any"=>""); if ($pfblocker_config['enable_log']){ $rule["log"]=""; } $permit_inbound[]=$rule; break; } } #mark pfctl aliastable for cleanup if (!in_array($alias, $aliases_list)){ $aliases_list[]=$alias; } } else{ #unlink previous pfblocker alias list if any unlink_if_exists($pfb_alias_dir.'/'.$alias.'.txt'); } } } #update pfsense alias table if (is_array($config['aliases']['alias'])){ $aliases=$config['aliases']['alias']; foreach($aliases as $cbalias){ if (preg_match("/pfBlocker/",$cbalias['name'])){ #mark pfctl aliastable for cleaning if (!in_array($cbalias['name'], $aliases_list)){ $aliases_list[]=$cbalias['name']; #mark aliastable for cleaning } #remove previous aliastable file if alias is not defined any more if (!in_array($cbalias['name'], $new_aliases_list)){ unlink_if_exists("/var/db/aliastables/".$cbalias['name'].".txt"); } } else{ $new_aliases[]= $cbalias; if (file_exists($pfb_alias_dir.'/'.$alias.'.txt') && $message ==""){ preg_match("/(\d+)/",exec("/usr/bin/wc -l ".$pfb_alias_dir.'/'.$alias.'.txt'),$matches); } if (($matches[1] * 2.1)>= $table_limit ){ #alias table too large $message= $alias .' alias table is too large. Reduce networks in list or increase "Firewall Maximum Table Entries" value to at least '. (int)($matches[1] * 2.1) .' in "system - advanced - Firewall/NAT".'; } } } } #apply new alias table to xml if ($message == ""){ $config['aliases']['alias']=$new_aliases; } #exit; ############################################# # Assign rules # ############################################# #print "
";
		#var_dump($permit_inbound);
		#var_dump($permit_outbound);
		#var_dump($deny_inbound);
		#var_dump($deny_outbound);			
		#var_dump($pfblocker_config['inbound_interface']);
		#print count($deny_inbound) .count($deny_inbound);
		# Inbound filter options
		$inbound_interfaces = explode(",",$pfblocker_config['inbound_interface']);
		if (count($deny_inbound) > 0 || count($permit_inbound) > 0){
			if($pfblocker_config['inbound_interface'] == ""){
				$message="Unable to apply rules.Inbound Interface option not configured.";
			}
			if (in_array("lo0",$inbound_interfaces)){
				$message="Floating rules are not implemented in pfBlocker yet, choose Inbound Interface other than loopback or change action to Alias only.";
			}
		}
		
		# Outbound filter options
		$outbound_interfaces = explode(",",$pfblocker_config['outbound_interface']);
		if (count($deny_outbound) > 0 || count($permit_outbound) > 0){
			if($pfblocker_config['outbound_interface'] == ""){
				$message="Unable to apply rules.Outbound Interface option not configured.";
			}
			if (in_array("lo0",$outbound_interfaces)){
				$message="Floating rules are not implemented in pfBlocker yet, choose Outbound Interface other than loopback or change action to Alias only.";
			}
		}
		
		if ($message == ""){
			$rules=$config['filter']['rule'];
			$new_rules=array();
			$interfaces_processed=array();
			# The rules in the config come in priority order, 
			# but the interface to which each rule applies can be all mixed up in the list.
			# e.g. some WAN rules, then some LAN rules, then some floating rules, then more
			# LAN rules, some OPT1 rules, some more LAN rules and so on.
			# So we have to allow for this, and only add pfBlocker rules the first time an 
			# interface is found in the rules list.
			foreach ($rules as $rule){
				# If this next rule is for a non-blank interface, different from any interface already processed,
				# then add any needed pfblocker rules to the interface. This puts pfblocker rules at the
				# top of the list for each interface, after any built-in rules (e.g. anti-lockout)
				$found_new_interface = TRUE;
				foreach ($interfaces_processed as $processed_interface){
					if ($processed_interface == $rule['interface']){
						$found_new_interface = FALSE;
					}
				}
				if (($rule['interface'] != "") && ($found_new_interface)){
					$interfaces_processed[] = $rule['interface'];
					#apply pfblocker rules if enabled
				
					#Inbound
					foreach ($inbound_interfaces as $inbound_interface){
						if ($inbound_interface==$rule['interface']){
							#permit rules
							if (is_array($permit_inbound)){
								foreach ($permit_inbound as $cb_rules){
									$cb_rules['interface']=$rule['interface'];
									$new_rules[]=$cb_rules;
								}
							}
							#deny rules
							if (is_array($deny_inbound)){
								foreach ($deny_inbound as $cb_rules){
									$cb_rules['interface']=$rule['interface'];
									$new_rules[]=$cb_rules;
								}
							}
						}
					}
					#Outbound
					foreach ($outbound_interfaces as $outbound_interface){
						if ($outbound_interface==$rule['interface']){
							#permit rules
							if (is_array($permit_outbound)){
								foreach ($permit_outbound as $cb_rules){
									$cb_rules['interface']=$rule['interface'];
									$new_rules[]=$cb_rules;	
								}
							}
							#deny rules
							if (is_array($deny_outbound)){
								foreach ($deny_outbound as $cb_rules){
									$cb_rules['interface']=$rule['interface'];
									$new_rules[]=$cb_rules;	
								}
							}
						}
					}
				}
				#include all rules that are not from pfBlocker
				if (!preg_match("/pfBlocker.*rule/",$rule['descr']) && ($rule['interface'] != "" || $rule['floating']=="yes")){
					$new_rules[]=$rule;
				}
			}
			$config['filter']['rule']=$new_rules;
		}	
	
		if ($message == ""){
			#check cron
			$cron_found=0;
			$cron_cmd="/usr/local/bin/php -q /usr/local/www/pfblocker.php cron";
			if (is_array($config['cron']['item'])){
				$new_cron=array();
				foreach($config['cron']['item'] as $cron){
					if (preg_match("/usr.local.www.pfblocker.php cron/",$cron["command"])){
						#fix 0.1.4.6 missing php path
						if($cron["command"]==$cron_cmd && $pfblocker_enable == "on"){
							$new_cron['item'][]=$cron;
							$cron_found=1;
						}
					}
					else{
						$new_cron['item'][]=$cron;
					}
				}
				if ($cron_found == 0){
					if($pfblocker_enable == "on"){
						$new_cron['item'][]=array(	"minute" =>	"0",
										"hour"	 =>	"*",
										"mday" 	 =>	"*",
										"month"  =>	"*",
										"wday"	 =>	"*",
										"who"	 =>	"root",
										"command"=>	$cron_cmd);
					}
					$config['cron']=$new_cron;
				}
			}
		
			# to be removed in final version
			$aliases_list[]="pfBlockerInbound";	#remove previous version lists
			$aliases_list[]="pfBlockerOutbound";	#remove previous version lists
			$aliases_list[]="pfBlockerWL";		#remove previous version lists
			#exit;
			#update pfctrl tables
			foreach ($aliases_list as $table){
				exec("/sbin/pfctl -t " . escapeshellarg($table) . " -T kill 2>&1", $result_pfb);
			}

			#uncheck donation and credits check box
			$config['installedpackages']['pfblocker']['config'][0]['donation']="";
			$config['installedpackages']['pfblocker']['config'][0]['credits']="";
			#write config
			write_config();

			#update cron
			if ($cron_found == 0){
				configure_cron();
			}
		
			#load filter file after editing
			filter_configure();

			#sync config
			pfblocker_sync_on_changes();
		}
		else{
			log_error("[pfBlocker] ".$message);
			file_notice("pfBlocker", $message, "pfblocker rule apply", "");
		}
		conf_mount_ro();
	}

function pfblocker_validate_input($post, &$input_errors) {
	global $config;
	foreach ($post as $key => $value) {
		if (empty($value))
			continue;
		if($key == "message_size_limit" && !is_numeric($value))
			$input_errors[] = "Message size limit must be numeric.";
		if($key == "process_limit" && !is_numeric($value))
			$input_errors[] = "Process limit must be numeric.";	
		if($key == "freq" && (!preg_match("/^\d+(h|m|d)$/",$value) || $value == 0))
			$input_errors[] = "A valid number with a time reference is required for the field 'Frequency'";
		if (substr($key, 0, 2) == "dc" && !is_hostname($value))
			$input_errors[] = "{$value} is not a valid host name.";
		if (substr($key, 0, 6) == "domain" && is_numeric(substr($key, 6))) {
			if (!is_domain($value))
				$input_errors[] = "{$value} is not a valid domain name.";
		} else if (substr($key, 0, 12) == "mailserverip" && is_numeric(substr($key, 12))) {
			if (empty($post['domain' . substr($key, 12)]))
				$input_errors[] = "Domain for {$value} cannot be blank.";
			if (!is_ipaddr($value) && !is_hostname($value))
				$input_errors[] = "{$value} is not a valid IP address or host name.";
		}
	}
}

function pfblocker_php_install_command() {
	include_once '/usr/local/www/pfblocker.php';
	pfblocker_get_countries();
	sync_package_pfblocker();
}

function pfblocker_php_deinstall_command() {
	global $config;
	$config['installedpackages']['pfblocker']['config'][0]['enable_cb']="";
	write_config();
	sync_package_pfblocker();
}

/* Uses XMLRPC to synchronize the changes to a remote node */
function pfblocker_sync_on_changes() {
	global $config, $g;
	log_error("[pfblocker] pfblocker_xmlrpc_sync.php is starting.");
	$synconchanges = $config['installedpackages']['pfblockersync']['config'][0]['synconchanges'];	
	if(!$synconchanges) 
		return;
	foreach ($config['installedpackages']['pfblockersync']['config'] as $rs ){
		foreach($rs['row'] as $sh){
			$sync_to_ip = $sh['ipaddress'];
			$password   = $sh['password'];
			if($password && $sync_to_ip){
				pfblocker_do_xmlrpc_sync($sync_to_ip, $password);
			}
		}
	}
	log_error("[pfblocker] pfblocker_xmlrpc_sync.php is ending.");
}

/* Do the actual XMLRPC sync */
function pfblocker_do_xmlrpc_sync($sync_to_ip, $password) {
	global $config, $g;

	if(!$password)
		return;

	if(!$sync_to_ip)
		return;

	$xmlrpc_sync_neighbor = $sync_to_ip;
	if($config['system']['webgui']['protocol'] != "") {
		$synchronizetoip = $config['system']['webgui']['protocol'];
		$synchronizetoip .= "://";
	}
	$port = $config['system']['webgui']['port'];
	/* if port is empty lets rely on the protocol selection */
	if($port == "") {
		if($config['system']['webgui']['protocol'] == "http"){
			$port = "80";
		}
		else{ 
			$port = "443";
		}
	}
	$synchronizetoip .= $sync_to_ip;

	/* xml will hold the sections to sync */
	$xml = array();
	$xml['pfblocker'] = $config['installedpackages']['pfblocker'];
	$xml['pfblockerlists'] = $config['installedpackages']['pfblockerlists'];
	$xml['pfblockertopspammers'] = $config['installedpackages']['pfblockertopspammers'];
	$xml['pfblockerafrica'] = $config['installedpackages']['pfblockerafrica'];
	$xml['pfblockerantartica'] = $config['installedpackages']['pfblockerantartica'];
	$xml['pfblockerasia'] = $config['installedpackages']['pfblockerasia'];
	$xml['pfblockereurope'] = $config['installedpackages']['pfblockereurope'];
	$xml['pfblockernorthamerica'] = $config['installedpackages']['pfblockernorthamerica'];
	$xml['pfblockeroceania'] = $config['installedpackages']['pfblockeroceania'];
	$xml['pfblockersouthamerica'] = $config['installedpackages']['pfblockersouthamerica'];
	/* assemble xmlrpc payload */
	$params = array(
		XML_RPC_encode($password),
		XML_RPC_encode($xml)
	);

	/* set a few variables needed for sync code borrowed from filter.inc */
	$url = $synchronizetoip;
	log_error("Beginning pfblocker XMLRPC sync to {$url}:{$port}.");
	$method = 'pfsense.merge_installedpackages_section_xmlrpc';
	$msg = new XML_RPC_Message($method, $params);
	$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
	$cli->setCredentials('admin', $password);
	if($g['debug']){
		$cli->setDebug(1);
	}
	/* send our XMLRPC message and timeout after 250 seconds */
	$resp = $cli->send($msg, "250");
	if(!$resp) {
		$error = "A communications error occurred while attempting pfblocker XMLRPC sync with {$url}:{$port}.";
		log_error($error);
		file_notice("sync_settings", $error, "pfblocker Settings Sync", "");
	} elseif($resp->faultCode()) {
		$cli->setDebug(1);
		$resp = $cli->send($msg, "250");
		$error = "An error code was received while attempting pfblocker XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
		log_error($error);
		file_notice("sync_settings", $error, "pfblocker Settings Sync", "");
	} else {
		log_error("pfblocker XMLRPC sync successfully completed with {$url}:{$port}.");
	}
	
	/* tell pfblocker to reload our settings on the destionation sync host. */
	$method = 'pfsense.exec_php';
	$execcmd  = "require_once('/usr/local/pkg/pfblocker.inc');\n";
	$execcmd .= "sync_package_pfblocker();";
	
	/* assemble xmlrpc payload */
	$params = array(
		XML_RPC_encode($password),
		XML_RPC_encode($execcmd)
	);

	log_error("pfblocker XMLRPC reload data {$url}:{$port}.");
	$msg = new XML_RPC_Message($method, $params);
	$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
	$cli->setCredentials('admin', $password);
	$resp = $cli->send($msg, "250");
	if(!$resp) {
		$error = "A communications error occurred while attempting pfblocker XMLRPC sync with {$url}:{$port} (exec_php).";
		log_error($error);
		file_notice("sync_settings", $error, "pfblocker Settings Sync", "");
	} elseif($resp->faultCode()) {
		$cli->setDebug(1);
		$resp = $cli->send($msg, "250");
		$error = "An error code was received while attempting pfblocker XMLRPC exec with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
		log_error($error);
		file_notice("sync_settings", $error, "pfblocker Settings Sync", "");
	} else {
		log_error("pfblocker XMLRPC reload data success with {$url}:{$port} (exec_php).");
	}

}

?>