437 lines
16 KiB
PHP
Executable File
437 lines
16 KiB
PHP
Executable File
#!/usr/local/bin/php -f
|
|
<?php
|
|
/*
|
|
filter.inc
|
|
Copyright (C) 2004-2006 Scott Ullrich
|
|
Copyright (C) 2005 Bill Marquette
|
|
Copyright (C) 2006 Peter Allgeyer
|
|
Copyright (C) 2008 Ermal Luci
|
|
All rights reserved.
|
|
|
|
originally part of m0n0wall (http://m0n0.ch/wall)
|
|
Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
require_once("globals.inc");
|
|
require_once("config.inc");
|
|
require_once("functions.inc");
|
|
require_once("filter.inc");
|
|
require_once("shaper.inc");
|
|
require_once("xmlrpc.inc");
|
|
require_once("interfaces.inc");
|
|
|
|
/*
|
|
* backup_vip_config_section($section): returns as an xml file string of
|
|
* the configuration section
|
|
*/
|
|
function backup_vip_config_section() {
|
|
global $config;
|
|
|
|
if (!is_array($config['virtualip']['vip']))
|
|
return;
|
|
$temp = array();
|
|
$temp['vip'] = array();
|
|
foreach($config['virtualip']['vip'] as $section) {
|
|
if (($section['mode'] == 'proxyarp' || $section['mode'] == 'ipalias') && !(strpos($section['interface'], '_vip') || strpos($section['interface'], 'lo0')))
|
|
continue;
|
|
if ($section['advskew'] <> "") {
|
|
$section_val = intval($section['advskew']);
|
|
$section_val=$section_val+100;
|
|
if ($section_val > 254)
|
|
$section_val = 254;
|
|
$section['advskew'] = $section_val;
|
|
}
|
|
if ($section['advbase'] <> "") {
|
|
$section_val = intval($section['advbase']);
|
|
if ($section_val > 254)
|
|
$section_val = 254;
|
|
$section['advbase'] = $section_val;
|
|
}
|
|
$temp['vip'][] = $section;
|
|
}
|
|
return $temp;
|
|
}
|
|
|
|
function remove_special_characters($string) {
|
|
$match_array = "";
|
|
preg_match_all("/[a-zA-Z0-9\_\-]+/",$string,$match_array);
|
|
$string = "";
|
|
foreach ($match_array[0] as $ma) {
|
|
if ($string <> "")
|
|
$string .= " ";
|
|
$string .= $ma;
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
function carp_check_version($url, $username, $password, $port = 80, $method = 'pfsense.host_firmware_version') {
|
|
global $config, $g;
|
|
|
|
if(file_exists("{$g['varrun_path']}/booting") || $g['booting'])
|
|
return;
|
|
|
|
$params = array(
|
|
XML_RPC_encode($password)
|
|
);
|
|
|
|
$numberofruns = 0;
|
|
while ($numberofruns < 2) {
|
|
$msg = new XML_RPC_Message($method, $params);
|
|
$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
|
|
$cli->setCredentials($username, $password);
|
|
if($numberofruns > 0)
|
|
$cli->setDebug(1);
|
|
/* send our XMLRPC message and timeout after 240 seconds */
|
|
$resp = $cli->send($msg, "240");
|
|
if(!is_object($resp)) {
|
|
$error = "A communications error occurred while attempting XMLRPC sync with username {$username} {$url}:{$port}.";
|
|
} elseif($resp->faultCode()) {
|
|
$error = "An error code was received while attempting XMLRPC sync with username {$username} {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
|
|
} else {
|
|
$parsed_response = XML_RPC_decode($resp->value());
|
|
if(!is_array($parsed_response)) {
|
|
if (trim($parsed_response) == "Authentication failed") {
|
|
$error = "An authentication failure occurred while trying to access {$url}:{$port} ({$method}).";
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
exit;
|
|
}
|
|
} else {
|
|
if (!isset($parsed_response['config_version']) ||
|
|
$parsed_response['config_version'] < $config['version']) {
|
|
update_filter_reload_status("The other member is on older configuration version of {$g['product_name']}. Sync will not be done to prevent problems!");
|
|
log_error("The other member is on older configuration version of {$g['product_name']}. Sync will not be done to prevent problems!");
|
|
return false;
|
|
} else
|
|
return true;
|
|
}
|
|
}
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
$numberofruns++;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function carp_sync_xml($url, $username, $password, $sections, $port = 80, $method = 'pfsense.restore_config_section') {
|
|
global $config, $g;
|
|
|
|
if(file_exists("{$g['varrun_path']}/booting") || $g['booting'])
|
|
return;
|
|
|
|
update_filter_reload_status("Syncing CARP data to {$url}");
|
|
|
|
/* make a copy of config */
|
|
$config_copy = $config;
|
|
|
|
/* strip out nosync items */
|
|
if (is_array($config_copy['nat']['outbound']['rule'])) {
|
|
$rulescnt = count($config_copy['nat']['outbound']['rule']);
|
|
for ($x = 0; $x < $rulescnt; $x++) {
|
|
$config_copy['nat']['outbound']['rule'][$x]['descr'] = remove_special_characters($config_copy['nat']['outbound']['rule'][$x]['descr']);
|
|
if (isset ($config_copy['nat']['outbound']['rule'][$x]['nosync']))
|
|
unset ($config_copy['nat']['outbound']['rule'][$x]);
|
|
}
|
|
}
|
|
if (is_array($config_copy['nat']['rule'])) {
|
|
$natcnt = count($config_copy['nat']['rule']);
|
|
for ($x = 0; $x < $natcnt; $x++) {
|
|
$config_copy['nat']['rule'][$x]['descr'] = remove_special_characters($config_copy['nat']['rule'][$x]['descr']);
|
|
if (isset ($config_copy['nat']['rule'][$x]['nosync']))
|
|
unset ($config_copy['nat']['rule'][$x]);
|
|
}
|
|
}
|
|
if (is_array($config_copy['filter']['rule'])) {
|
|
$filtercnt = count($config_copy['filter']['rule']);
|
|
for ($x = 0; $x < $filtercnt; $x++) {
|
|
$config_copy['filter']['rule'][$x]['descr'] = remove_special_characters($config_copy['filter']['rule'][$x]['descr']);
|
|
if (isset ($config_copy['filter']['rule'][$x]['nosync']))
|
|
unset ($config_copy['filter']['rule'][$x]);
|
|
}
|
|
}
|
|
if (is_array($config_copy['aliases']['alias'])) {
|
|
$aliascnt = count($config_copy['aliases']['alias']);
|
|
for ($x = 0; $x < $aliascnt; $x++) {
|
|
$config_copy['aliases']['alias'][$x]['descr'] = remove_special_characters($config_copy['aliases']['alias'][$x]['descr']);
|
|
if (isset ($config_copy['aliases']['alias'][$x]['nosync']))
|
|
unset ($config_copy['aliases']['alias'][$x]);
|
|
}
|
|
}
|
|
if (is_array($config_copy['dnsmasq']['hosts'])) {
|
|
$dnscnt = count($config_copy['dnsmasq']['hosts']);
|
|
for ($x = 0; $x < $dnscnt; $x++) {
|
|
$config_copy['dnsmasq']['hosts'][$x]['descr'] = remove_special_characters($config_copy['dnsmasq']['hosts'][$x]['descr']);
|
|
if (isset ($config_copy['dnsmasq']['hosts'][$x]['nosync']))
|
|
unset ($config_copy['dnsmasq']['hosts'][$x]);
|
|
}
|
|
}
|
|
if (is_array($config_copy['ipsec']['tunnel'])) {
|
|
$ipseccnt = count($config_copy['ipsec']['tunnel']);
|
|
for ($x = 0; $x < $ipseccnt; $x++) {
|
|
$config_copy['ipsec']['tunnel'][$x]['descr'] = remove_special_characters($config_copy['ipsec']['tunnel'][$x]['descr']);
|
|
if (isset ($config_copy['ipsec']['tunnel'][$x]['nosync']))
|
|
unset ($config_copy['ipsec']['tunnel'][$x]);
|
|
}
|
|
}
|
|
|
|
if (is_array($config_copy['dhcpd'])) {
|
|
foreach($config_copy['dhcpd'] as $dhcpif => $dhcpifconf) {
|
|
if($dhcpifconf['failover_peerip'] <> "") {
|
|
$int = guess_interface_from_ip($dhcpifconf['failover_peerip']);
|
|
$intip = find_interface_ip($int);
|
|
$config_copy['dhcpd'][$dhcpif]['failover_peerip'] = $intip;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($sections as $section) {
|
|
/* we can't use array_intersect_key()
|
|
* due to the vip 'special case'
|
|
*/
|
|
switch ($section) {
|
|
case 'virtualip':
|
|
$xml[$section] = backup_vip_config_section();
|
|
break;
|
|
case 'user':
|
|
$xml['system'][$section] = $config_copy['system'][$section];
|
|
$xml['system']['nextuid'] = $config_copy['system']['nextuid'];
|
|
break;
|
|
case 'group':
|
|
$xml['system'][$section] = $config_copy['system'][$section];
|
|
$xml['system']['nextgid'] = $config_copy['system']['nextgid'];
|
|
break;
|
|
case 'authserver':
|
|
$xml['system'][$section] = $config_copy['system'][$section];
|
|
default:
|
|
$xml[$section] = $config_copy[$section];
|
|
}
|
|
}
|
|
|
|
$params = array(
|
|
XML_RPC_encode($password),
|
|
XML_RPC_encode($xml)
|
|
);
|
|
|
|
$numberofruns = 0;
|
|
while ($numberofruns < 2) {
|
|
log_error("Beginning XMLRPC sync to {$url}:{$port}.");
|
|
$msg = new XML_RPC_Message($method, $params);
|
|
$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
|
|
$cli->setCredentials($username, $password);
|
|
if($numberofruns > 0)
|
|
$cli->setDebug(1);
|
|
/* send our XMLRPC message and timeout after 240 seconds */
|
|
$resp = $cli->send($msg, "240");
|
|
if(!is_object($resp)) {
|
|
$error = "A communications error occurred while attempting XMLRPC sync with username {$username} {$url}:{$port}.";
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
} elseif($resp->faultCode()) {
|
|
$error = "An error code was received while attempting XMLRPC sync with username {$username} {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
} else {
|
|
$parsed_response = XML_RPC_decode($resp->value());
|
|
if(!is_array($parsed_response) && trim($parsed_response) == "Authentication failed") {
|
|
$error = "An authentication failure occurred while trying to access {$url}:{$port} ($method).";
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
exit;
|
|
} else {
|
|
log_error("XMLRPC sync successfully completed with {$url}:{$port}.");
|
|
update_filter_reload_status("XMLRPC sync successfully completed with {$url}:{$port}.");
|
|
}
|
|
$numberofruns = 3;
|
|
}
|
|
$numberofruns++;
|
|
}
|
|
}
|
|
|
|
global $g;
|
|
if (file_exists("{$g['varrun_path']}/booting") || $g['booting'])
|
|
return;
|
|
|
|
if (is_array($config['hasync'])) {
|
|
update_filter_reload_status("Building high availability sync information");
|
|
$hasync = $config['hasync'];
|
|
|
|
if (empty($hasync['synchronizetoip'])) {
|
|
/* this gets hit on every filter sync on the secondary, a log here creates a lot of log spam and I never saw it actually log anything useful */
|
|
exit;
|
|
}
|
|
|
|
/*
|
|
* XXX: The way we're finding the port right now is really suboptimal -
|
|
* we can't assume that the other machine is setup identically.
|
|
*/
|
|
if (!empty($config['system']['webgui']['protocol'])) {
|
|
$synchronizetoip = $config['system']['webgui']['protocol'];
|
|
$synchronizetoip .= "://";
|
|
}
|
|
|
|
/* if port is empty lets rely on the protocol selection */
|
|
$port = $config['system']['webgui']['port'];
|
|
if (empty($port)) {
|
|
if ($config['system']['webgui']['protocol'] == "http")
|
|
$port = "80";
|
|
else
|
|
$port = "443";
|
|
}
|
|
|
|
if(is_ipaddrv6($hasync['synchronizetoip']))
|
|
$hasync['synchronizetoip'] = "[{$hasync['synchronizetoip']}]";
|
|
$synchronizetoip .= $hasync['synchronizetoip'];
|
|
if ($hasync['synchronizerules'] != "") {
|
|
if (!is_array($config['filter']))
|
|
$config['filter'] = array();
|
|
$sections[] = 'filter';
|
|
}
|
|
if ($hasync['synchronizenat'] != "") {
|
|
if (!is_array($config['nat']))
|
|
$config['nat'] = array();
|
|
$sections[] = 'nat';
|
|
}
|
|
if ($hasync['synchronizealiases'] != "") {
|
|
if (!is_array($config['aliases']))
|
|
$config['aliases'] = array();
|
|
$sections[] = 'aliases';
|
|
}
|
|
if ($hasync['synchronizedhcpd'] != "" and is_array($config['dhcpd']))
|
|
$sections[] = 'dhcpd';
|
|
if ($hasync['synchronizewol'] != "") {
|
|
if (!is_array($config['wol']))
|
|
$config['wol'] = array();
|
|
$sections[] = 'wol';
|
|
}
|
|
if ($hasync['synchronizetrafficshaper'] != "" and is_array($config['shaper']))
|
|
$sections[] = 'shaper';
|
|
if ($hasync['synchronizetrafficshaperlimiter'] != "" and is_array($config['dnshaper']))
|
|
$sections[] = 'dnshaper';
|
|
if ($hasync['synchronizetrafficshaperlayer7'] != "" and is_array($config['l7shaper']))
|
|
$sections[] = 'l7shaper';
|
|
if ($hasync['synchronizestaticroutes'] != "") {
|
|
if (!is_array($config['staticroutes']))
|
|
$config['staticroutes'] = array();
|
|
if (!is_array($config['staticroutes']['route']))
|
|
$config['staticroutes']['route'] = array();
|
|
$sections[] = 'staticroutes';
|
|
if (!is_array($config['gateways']))
|
|
$config['gateways'] = array();
|
|
$sections[] = 'gateways';
|
|
}
|
|
if ($hasync['synchronizevirtualip'] != "") {
|
|
if (!is_array($config['virtualip']))
|
|
$config['virtualip'] = array();
|
|
$sections[] = 'virtualip';
|
|
}
|
|
if ($hasync['synchronizelb'] != "") {
|
|
if (!is_array($config['load_balancer']))
|
|
$config['load_balancer'] = array();
|
|
$sections[] = 'load_balancer';
|
|
}
|
|
if ($hasync['synchronizeipsec'] != "") {
|
|
if (!is_array($config['ipsec']))
|
|
$config['ipsec'] = array();
|
|
$sections[] = 'ipsec';
|
|
}
|
|
if ($hasync['synchronizeopenvpn'] != "") {
|
|
if (!is_array($config['openvpn']))
|
|
$config['openvpn'] = array();
|
|
$sections[] = 'openvpn';
|
|
}
|
|
if ($hasync['synchronizecerts'] != "" || $hasync['synchronizeopenvpn'] != "") {
|
|
if (!is_array($config['cert']))
|
|
$config['cert'] = array();
|
|
$sections[] = 'cert';
|
|
|
|
if (!is_array($config['ca']))
|
|
$config['ca'] = array();
|
|
$sections[] = 'ca';
|
|
|
|
if (!is_array($config['crl']))
|
|
$config['crl'] = array();
|
|
$sections[] = 'crl';
|
|
}
|
|
if ($hasync['synchronizeusers'] != "") {
|
|
$sections[] = 'user';
|
|
$sections[] = 'group';
|
|
}
|
|
if ($hasync['synchronizeauthservers'] != "") {
|
|
$sections[] = 'authserver';
|
|
}
|
|
if ($hasync['synchronizednsforwarder'] != "" and is_array($config['dnsmasq']))
|
|
$sections[] = 'dnsmasq';
|
|
if ($hasync['synchronizeschedules'] != "" || $hasync['synchronizerules'] != "") {
|
|
if (!is_array($config['schedules']))
|
|
$config['schedules'] = array();
|
|
$sections[] = 'schedules';
|
|
}
|
|
if ($hasync['synchronizecaptiveportal'] != "" and is_array($config['captiveportal']))
|
|
$sections[] = 'captiveportal';
|
|
if ($hasync['synchronizecaptiveportal'] != "" and is_array($config['vouchers']))
|
|
$sections[] = 'vouchers';
|
|
|
|
if (count($sections) <= 0) {
|
|
log_error("Nothing has been configured to be synched. Skipping....");
|
|
exit;
|
|
}
|
|
|
|
if (empty($hasync['username']))
|
|
$username = "admin";
|
|
else
|
|
$username = $hasync['username'];
|
|
|
|
if (!carp_check_version($synchronizetoip, $username, $hasync['password'], $port))
|
|
exit;
|
|
|
|
update_filter_reload_status("Signaling CARP reload signal...");
|
|
carp_sync_xml($synchronizetoip, $username, $hasync['password'], $sections, $port);
|
|
$cli = new XML_RPC_Client('/xmlrpc.php', $synchronizetoip, $port);
|
|
$params = array(
|
|
XML_RPC_encode($hasync['password'])
|
|
);
|
|
|
|
$msg = new XML_RPC_Message('pfsense.filter_configure', $params);
|
|
$cli->setCredentials($username, $hasync['password']);
|
|
$resp = $cli->send($msg, "900");
|
|
|
|
if (!is_object($resp)) {
|
|
$error = "A communications error occurred while attempting Filter sync with username {$username} {$synchronizetoip}:{$port}.";
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
} elseif($resp->faultCode()) {
|
|
$error = "An error code was received while attempting Filter sync with username {$username} {$synchronizetoip}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
|
|
log_error($error);
|
|
file_notice("sync_settings", $error, "Settings Sync", "");
|
|
} else {
|
|
log_error("Filter sync successfully completed with {$synchronizetoip}:{$port}.");
|
|
$numberofruns = 3;
|
|
}
|
|
}
|
|
|
|
?>
|