aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfig/snort/snort.inc459
1 files changed, 305 insertions, 154 deletions
diff --git a/config/snort/snort.inc b/config/snort/snort.inc
index 44dd133e..f1f5ad9b 100755
--- a/config/snort/snort.inc
+++ b/config/snort/snort.inc
@@ -42,14 +42,12 @@ require_once("filter.inc");
// Snort GUI needs some extra PHP memory space to manipulate large rules arrays
ini_set("memory_limit", "192M");
-// Explicitly declare these as global so they work through function call includes
-global $snort_rules_file, $snort_version, $emerging_threats_version, $snort_rules_upd_log;
-global $all_rules, $flowbit_rules_file, $snort_enforcing_rules_file, $rebuild_rules, $is_postinstall;
-global $snort_community_rules_filename, $snort_community_rules_url, $emergingthreats_filename;
+// Explicitly declare this as global so it works through function call includes
+global $rebuild_rules;
/* package version */
-$snort_version = "2.9.4.1";
-$pfSense_snort_version = "2.5.8";
+$snort_version = "2.9.4.6";
+$pfSense_snort_version = "2.5.9";
$snort_package_version = "Snort {$snort_version} pkg v. {$pfSense_snort_version}";
// Define SNORTDIR and SNORTLIBDIR constants according to FreeBSD version (PBI support or no PBI)
@@ -67,24 +65,20 @@ else {
define("SNORTLIBDIR", "/usr/local/lib/snort");
}
+/* Define some useful constants for Snort */
define("SNORTLOGDIR", "/var/log/snort");
-
-/* Important file definitions */
-$snort_rules_file = "snortrules-snapshot-2941.tar.gz";
-$emerging_threats_version = "2.9.0";
-$emergingthreats_filename = "emerging.rules.tar.gz";
-$snort_community_rules_url = "https://s3.amazonaws.com/snort-org/www/rules/community/";
-$snort_community_rules_filename = "community-rules.tar.gz";
-$flowbit_rules_file = "flowbit-required.rules";
-$snort_enforcing_rules_file = "snort.rules";
-$snort_rules_upd_log = SNORTLOGDIR;
-$snort_rules_upd_log .= "/snort_rules_update.log";
-
-/* Rebuild Rules Flag -- if "on", rebuild enforcing rules and flowbit-rules files */
-$rebuild_rules = "off";
-
-/* Post-install Flag -- normally "false" except during post-install of package */
-$is_postinstall = false;
+define("VRT_DNLD_FILENAME", "snortrules-snapshot-2946.tar.gz");
+define("VRT_DNLD_URL", "https://www.snort.org/reg-rules/");
+define("ET_VERSION", "2.9.0");
+define("ET_DNLD_FILENAME", "emerging.rules.tar.gz");
+define("GPLV2_DNLD_FILENAME", "community-rules.tar.gz");
+define("GPLV2_DNLD_URL", "https://s3.amazonaws.com/snort-org/www/rules/community/");
+define("FLOWBITS_FILENAME", "flowbit-required.rules");
+define("ENFORCING_RULES_FILENAME", "snort.rules");
+define("RULES_UPD_LOGFILE", SNORTLOGDIR . "/snort_rules_update.log");
+
+/* Rebuild Rules Flag -- if "true", rebuild enforcing rules and flowbit-rules files */
+$rebuild_rules = false;
if (!is_array($config['installedpackages']['snortglobal']))
$config['installedpackages']['snortglobal'] = array();
@@ -107,19 +101,6 @@ function snort_get_blocked_ips() {
return $blocked_ips_array;
}
-function snort_get_rule_part($source, $beginning, $ending, $start_pos) {
-
- $beginning_pos = strpos($source, $beginning, $start_pos);
- if (!$beginning_pos)
- return false;
- $middle_pos = $beginning_pos + strlen($beginning);
- $source = substr($source, $middle_pos);
- $ending_pos = strpos($source, $ending, 0);
- if (!$ending_pos)
- return false;
- return substr($source, 0, $ending_pos);
-}
-
function snort_generate_id() {
global $config;
@@ -136,7 +117,7 @@ function snort_generate_id() {
return $snort_uuid;
}
-function snort_load_suppress_sigs($snortcfg) {
+function snort_load_suppress_sigs($snortcfg, $track_by=false) {
global $config;
@@ -144,7 +125,17 @@ function snort_load_suppress_sigs($snortcfg) {
/* This function loads the GEN_ID and SIG_ID for all the */
/* suppressed alert entries from the Suppression List of */
/* the passed Snort interface. The results are returned */
- /* in an array with GEN_ID and SIG_ID as the keys. */
+ /* in an array with GEN_ID and SIG_ID as the primary */
+ /* keys. Any "track by_src" or "track by_dst" entries */
+ /* in the Suppression List are tacked on as additional */
+ /* keys in the array along with the IP address in either */
+ /* IPv4 or IPv6 format when $track_by is passed as true. */
+ /* */
+ /* Sample returned array: */
+ /* $suppress[1][2069] = "suppress" */
+ /* $suppress[1][2070]['by_src']['10.1.1.5'] = "suppress" */
+ /* $suppress[1][2070]['by_dst']['10.1.1.6'] = "suppress" */
+ /* */
/**********************************************************/
$suppress = array();
@@ -169,12 +160,35 @@ function snort_load_suppress_sigs($snortcfg) {
// Skip any comment lines
if (preg_match('/^\s*#/', $line))
continue;
- if (preg_match('/gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+)/i', $line, $matches)) {
+ /* See if entry suppresses GID:SID for all hosts */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+)\s*$/i', $line, $matches)) {
$genid = $matches[1];
$sigid = $matches[2];
if (!empty($genid) && !empty($sigid))
$suppress[$genid][$sigid] = "suppress";
}
+
+ /* Get "track by IP" entries if requested */
+ if ($track_by) {
+ /* See if entry suppresses only by SRC or DST IPv4 address */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s*$/i', $line, $matches)) {
+ $genid = $matches[1];
+ $sigid = $matches[2];
+ $whichip = trim($matches[3]);
+ $ip = $matches[4];
+ if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip))
+ $suppress[$genid][$sigid][$whichip][$ip] = "suppress";
+ }
+ /* See if entry suppresses only by SRC or DST IPv6 address */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*([0-9a-f\.:]+)\s*$/i', $line, $matches)) {
+ $genid = $matches[1];
+ $sigid = $matches[2];
+ $whichip = trim($matches[3]);
+ $ip = trim($matches[4]);
+ if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip))
+ $suppress[$genid][$sigid][$whichip][$ip] = "suppress";
+ }
+ }
}
unset($tmp);
}
@@ -205,8 +219,13 @@ function snort_find_list($find_name, $type = 'whitelist') {
/* func builds custom whitelists and the HOME_NET variable */
function snort_build_list($snortcfg, $listname = "", $whitelist = false) {
- global $config, $g;
- global $aliastable, $filterdns;
+
+ /***********************************************************/
+ /* The default is to build a HOME_NET variable unless */
+ /* '$whitelist' is set to 'true' when calling. */
+ /***********************************************************/
+
+ global $config, $g, $aliastable, $filterdns;
$home_net = array();
if ($listname == 'default' || empty($listname)) {
@@ -233,35 +252,56 @@ function snort_build_list($snortcfg, $listname = "", $whitelist = false) {
/********************************************************************/
/* Always put the interface running Snort in HOME_NET and whitelist */
/* unless it's the WAN. WAN options are handled further down. */
+ /* If the user specifically chose not to include LOCAL_NETS in the */
+ /* WHITELIST, then do not include the Snort interface subnet in the */
+ /* WHITELIST. We do include the actual LAN interface IP for Snort, */
+ /* though, to prevent locking out the firewall itself. */
/********************************************************************/
$snortip = get_interface_ip($snortcfg['interface']);
- if (is_ipaddr($snortip)) {
- if ($snortcfg['interface'] <> "wan") {
- $sn = get_interface_subnet($snortcfg['interface']);
- $ip = gen_subnet($snortip, $sn) . "/{$sn}";
- if (!in_array($ip, $home_net))
- $home_net[] = $ip;
+ if (!$whitelist || $localnet == 'yes' || empty($localnet)) {
+ if (is_ipaddr($snortip)) {
+ if ($snortcfg['interface'] <> "wan") {
+ $sn = get_interface_subnet($snortcfg['interface']);
+ $ip = gen_subnet($snortip, $sn) . "/{$sn}";
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+ }
+ else {
+ if (is_ipaddr($snortip)) {
+ if (!in_array($snortip, $home_net))
+ $home_net[] = $snortip;
}
}
+ /* Handle IPv6 if available (2.1 and higher) */
if (function_exists('get_interface_ipv6')) {
$snortip = get_interface_ipv6($snortcfg['interface']);
- if (is_ipaddrv6($snortip)) {
- if ($snortcfg['interface'] <> "wan") {
- $sn = get_interface_subnetv6($snortcfg['interface']);
- $ip = gen_subnetv6($snortip, $sn). "/{$sn}";
- if (!in_array($ip, $home_net))
- $home_net[] = $ip;
+ if (!$whitelist || $localnet == 'yes' || empty($localnet)) {
+ if (is_ipaddrv6($snortip)) {
+ if ($snortcfg['interface'] <> "wan") {
+ $sn = get_interface_subnetv6($snortcfg['interface']);
+ $ip = gen_subnetv6($snortip, $sn). "/{$sn}";
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+ }
+ else {
+ if (is_ipaddrv6($snortip)) {
+ if (!in_array($snortip, $home_net))
+ $home_net[] = $snortip;
}
}
}
- if ($localnet == 'yes') {
+ if (!$whitelist || $localnet == 'yes' || empty($localnet)) {
/*************************************************************************/
/* Iterate through the interface list and write out whitelist items and */
/* also compile a HOME_NET list of all the local interfaces for snort. */
/* Skip the WAN interface as we do not typically want that whole subnet */
- /* whitelisted (just the interface IP itself). */
+ /* whitelisted (just the i/f IP itself which was handled earlier). */
/*************************************************************************/
$int_array = get_configured_interface_list();
foreach ($int_array as $int) {
@@ -433,17 +473,22 @@ function snort_start($snortcfg, $if_real) {
}
/**************************************************************/
-/* This function sends a SIGHUP to the Snort instance on the */
-/* passed interface to cause Snort to reload and parse the */
-/* running configuration without stopping packet processing. */
-/* It also executes the reload as a background process and */
-/* returns control immediately to the caller. */
+/* This function sends the passed SIGNAL to the Snort */
+/* instance on the passed interface to cause Snort to reload */
+/* and parse the running configuration without stopping */
+/* packet processing. It also executes the reload as a */
+/* background process and returns control immediately to the */
+/* caller. */
+/* */
+/* $signal = SIGHUP (default) parses and reloads config. */
+/* SIGURG updates Host Attribute Table. */
/**************************************************************/
-function snort_reload_config($snortcfg, $if_real) {
+function snort_reload_config($snortcfg, $signal="SIGHUP") {
global $config, $g;
$snortdir = SNORTDIR;
$snort_uuid = $snortcfg['uuid'];
+ $if_real = snort_get_real_interface($snortcfg['interface']);
/******************************************************/
/* Only send the SIGHUP if Snort is running and we */
@@ -451,7 +496,7 @@ function snort_reload_config($snortcfg, $if_real) {
/******************************************************/
if (file_exists("{$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid") && isvalidpid("{$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid")) {
log_error("[Snort] Snort RELOAD CONFIG for {$snortcfg['descr']}({$if_real})...");
- exec("/bin/pkill -SIGHUP -F {$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid 2>&1 &");
+ exec("/bin/pkill -{$signal} -F {$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid 2>&1 &");
}
}
@@ -539,15 +584,14 @@ function snort_post_delete_logs($snort_uuid = 0) {
}
function snort_postinstall() {
- global $config, $g, $snort_rules_file, $emerging_threats_version;
- global $snort_version, $rebuild_rules, $is_postinstall;
+ global $config, $g, $rebuild_rules, $pkg_interface, $snort_gui_include;
$snortdir = SNORTDIR;
$snortlibdir = SNORTLIBDIR;
$rcdir = RCFILEPREFIX;
/* Set flag for post-install in progress */
- $is_postinstall = true;
+ $g['snort_postinstall'] = true;
/* cleanup default files */
@rename("{$snortdir}/snort.conf-sample", "{$snortdir}/snort.conf");
@@ -586,11 +630,13 @@ function snort_postinstall() {
update_output_window(gettext("Please wait... rebuilding installation with saved settings..."));
log_error(gettext("[Snort] Downloading and updating configured rule types..."));
update_output_window(gettext("Please wait... downloading and updating configured rule types..."));
+ if ($pkg_interface <> "console")
+ $snort_gui_include = true;
@include_once("/usr/local/pkg/snort/snort_check_for_rule_updates.php");
update_status(gettext("Generating snort.conf configuration file from saved settings..."));
- $rebuild_rules = "on";
+ $rebuild_rules = true;
sync_snort_package_config();
- $rebuild_rules = "off";
+ $rebuild_rules = false;
update_output_window(gettext("Finished rebuilding files..."));
log_error(gettext("[Snort] Finished rebuilding installation from saved settings..."));
@@ -605,7 +651,7 @@ function snort_postinstall() {
}
/* Done with post-install, so clear flag */
- $is_postinstall = false;
+ unset($g['snort_postinstall']);
log_error(gettext("[Snort] Package post-installation tasks completed..."));
}
@@ -779,44 +825,63 @@ function snort_rules_up_install_cron($should_install) {
$x++;
}
$snort_rules_up_info_ck = $config['installedpackages']['snortglobal']['autorulesupdate7'];
+
+ /* See if a customized start time has been set for rule file updates */
+ if (!empty($config['installedpackages']['snortglobal']['rule_update_starttime']))
+ $snort_rules_upd_time = $config['installedpackages']['snortglobal']['rule_update_starttime'];
+ else
+ $snort_rules_upd_time = "00:03";
+
if ($snort_rules_up_info_ck == "6h_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "*/6";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $hour = intval(substr($snort_rules_upd_time, 0, 2));
+ $snort_rules_up_hr = strval($hour);
+ for ($i=0; $i<3; $i++) {
+ $hour += 6;
+ if ($hour > 24)
+ $hour -= 24;
+ $snort_rules_up_hr .= "," . strval($hour);
+ }
$snort_rules_up_mday = "*";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
}
if ($snort_rules_up_info_ck == "12h_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "*/12";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $hour = intval(substr($snort_rules_upd_time, 0, 2));
+ $snort_rules_up_hr = strval($hour) . ",";
+ $hour += 12;
+ if ($hour > 24)
+ $hour -= 24;
+ $snort_rules_up_hr .= strval($hour);
$snort_rules_up_mday = "*";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
}
if ($snort_rules_up_info_ck == "1d_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "0";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $snort_rules_up_hr = intval(substr($snort_rules_upd_time, 0, 2));
$snort_rules_up_mday = "*/1";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
}
if ($snort_rules_up_info_ck == "4d_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "0";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $snort_rules_up_hr = intval(substr($snort_rules_upd_time, 0, 2));
$snort_rules_up_mday = "*/4";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
}
if ($snort_rules_up_info_ck == "7d_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "0";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $snort_rules_up_hr = intval(substr($snort_rules_upd_time, 0, 2));
$snort_rules_up_mday = "*/7";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
}
if ($snort_rules_up_info_ck == "28d_up") {
- $snort_rules_up_min = "3";
- $snort_rules_up_hr = "0";
+ $snort_rules_up_min = intval(substr($snort_rules_upd_time, -2));
+ $snort_rules_up_hr = intval(substr($snort_rules_upd_time, 0, 2));
$snort_rules_up_mday = "*/28";
$snort_rules_up_month = "*";
$snort_rules_up_wday = "*";
@@ -847,8 +912,8 @@ function snort_rules_up_install_cron($should_install) {
/* Only run when all ifaces needed to sync. Expects filesystem rw */
function sync_snort_package_config() {
- global $config, $g, $flowbit_rules_file, $snort_enforcing_rules_file;
- global $snort_version, $rebuild_rules, $is_postinstall;
+ global $config, $g;
+ global $rebuild_rules;
$snortdir = SNORTDIR;
$rcdir = RCFILEPREFIX;
@@ -890,7 +955,7 @@ function sync_snort_package_config() {
configure_cron();
/* Do not attempt package sync if reinstalling package or booting */
- if (!$is_postinstall && !$g['booting'])
+ if (!$g['snort_postinstall'] && !$g['booting'])
snort_sync_on_changes();
conf_mount_ro();
@@ -1372,7 +1437,7 @@ function snort_get_set_flowbits($rules_map) {
return $set_flowbits;
}
-function snort_find_flowbit_required_rules($all_rules, $unchecked_flowbits) {
+function snort_find_flowbit_required_rules($rules, $unchecked_flowbits) {
/********************************************************/
/* This function finds all rules that must be enabled */
@@ -1382,7 +1447,7 @@ function snort_find_flowbit_required_rules($all_rules, $unchecked_flowbits) {
/********************************************************/
$required_flowbits_rules = array();
- foreach ($all_rules as $k1 => $rule) {
+ foreach ($rules as $k1 => $rule) {
if (!is_array($rule))
continue;
foreach ($rule as $k2 => $rule2) {
@@ -1420,7 +1485,7 @@ function snort_find_flowbit_required_rules($all_rules, $unchecked_flowbits) {
return $required_flowbits_rules;
}
-function snort_resolve_flowbits($active_rules) {
+function snort_resolve_flowbits($rules, $active_rules) {
/******************************************************/
/* This function auto-resolves flowbit requirements */
@@ -1435,16 +1500,14 @@ function snort_resolve_flowbits($active_rules) {
/* interface to resolve flowbit */
/* dependencies for. */
/* */
- /* NOTE: this function assumes the global variable */
- /* $all_rules is populated with all the rules */
- /* currently downloaded. */
+ /* $rules --> Rules Map array containing */
+ /* all the available rules. */
/******************************************************/
- global $all_rules;
$snortdir = SNORTDIR;
/* Check $all_rules array to be sure it is filled. */
- if (empty($all_rules)) {
+ if (empty($rules)) {
log_error(gettext("[Snort] WARNING: Flowbit resolution not done - no rules in {$snortdir}/rules/ ..."));
return array();
}
@@ -1463,7 +1526,7 @@ function snort_resolve_flowbits($active_rules) {
/* Now find all the needed "set flowbit" rules from */
/* the master list of all rules. */
- $required_rules = snort_find_flowbit_required_rules($all_rules, $delta_flowbits);
+ $required_rules = snort_find_flowbit_required_rules($rules, $delta_flowbits);
/* Cleanup and release memory we no longer need. */
unset($delta_flowbits);
@@ -1477,9 +1540,16 @@ function snort_write_flowbit_rules_file($flowbit_rules, $rule_file) {
/* This function takes an array of rules in the */
/* rules_map format and writes them to the file */
/* given. */
+ /* */
+ /* $flowbit_rules --> array of flowbit-required */
+ /* rules. */
+ /* */
+ /* $rule_file --> filename to write the */
+ /* flowbit-required rules */
+ /* to. */
/************************************************/
- global $flowbit_rules_file;
+ $flowbit_rules_file = FLOWBITS_FILENAME;
/* See if we were passed a directory or full */
/* filename to write the rules to, and adjust */
@@ -1511,39 +1581,37 @@ function snort_write_flowbit_rules_file($flowbit_rules, $rule_file) {
}
}
-function snort_load_vrt_policy($policy, $load_rules_map=true) {
+function snort_load_vrt_policy($policy, $all_rules=null) {
/************************************************/
/* This function returns an array of all rules */
/* marked with the passed in $policy metadata. */
/* */
- /* $policy --> desired VRT security policy */
- /* 1. connectivity */
- /* 2. balanced */
- /* 3. security */
+ /* $policy --> desired VRT security policy */
+ /* 1. connectivity */
+ /* 2. balanced */
+ /* 3. security */
/* */
- /* $load_rules --> load a local copy of all */
- /* the rules if true. If */
- /* false, assume the global */
- /* $all_rules array is valid. */
+ /* $all_rules --> optional Rules Map array of */
+ /* rules to scan for policy. */
+ /* If not provided, then an */
+ /* array will be created. */
/************************************************/
- global $all_rules;
$snortdir = SNORTDIR;
$vrt_policy_rules = array();
- /* Refresh the map of all the rules if flag */
- /* is set. */
- if ($load_rules_map) {
+ /* Load a map of all the VRT rules if we were */
+ /* not passed a pre-loaded one to use. */
+ if (is_null($all_rules)) {
/* Since only Snort VRT rules have IPS Policy metadata, */
/* limit our search to just those files. */
$snort_vrt_files = glob("{$snortdir}/rules/snort_*.rules");
- $all_rules = array();
$all_rules = snort_load_rules_map($snort_vrt_files);
}
- /* Now walk the rules list and find all those that are defined */
- /* defined as active for the chosen security policy. */
+ /* Now walk the rules list and find all those that are */
+ /* defined as active for the chosen security policy. */
foreach ($all_rules as $k1 => $arulem) {
foreach ($arulem as $k2 => $arulem2) {
if (strripos($arulem2['rule'], "policy {$policy}-ips") !== false) {
@@ -1567,11 +1635,6 @@ function snort_load_vrt_policy($policy, $load_rules_map=true) {
/* Release memory we no longer need. */
unset($arulem, $arulem2);
- /* If we loaded the ALL_RULES map, */
- /* then release the global memory. */
- if ($load_rules_map == true)
- unset($GLOBALS['all_rules']);
-
/* Return all the rules that match the policy. */
return $vrt_policy_rules;
}
@@ -1582,11 +1645,15 @@ function snort_write_enforcing_rules_file($rule_map, $rule_path) {
/* This function takes a rules map array of */
/* the rules chosen for the active rule set */
/* and writes them out to the passed path. */
+ /* */
+ /* $rule_map --> Rules Map array of rules to */
+ /* write to disk. */
+ /* */
+ /* $rule_path --> filename or directory where */
+ /* rules file will be written. */
/************************************************/
- global $snort_enforcing_rules_file;
-
- $rule_file = "/{$snort_enforcing_rules_file}";
+ $rule_file = "/" . ENFORCING_RULES_FILENAME;
/* See if we were passed a directory or full */
/* filename to write the rules to, and adjust */
@@ -1968,12 +2035,13 @@ EOD;
function snort_deinstall() {
- global $config, $g, $snort_rules_upd_log;
+ global $config, $g;
$snortdir = SNORTDIR;
$snortlibdir = SNORTLIBDIR;
$snortlogdir = SNORTLOGDIR;
$rcdir = RCFILEPREFIX;
+ $snort_rules_upd_log = RULES_UPD_LOGFILE;
log_error(gettext("[Snort] Snort package uninstall in progress..."));
@@ -2060,13 +2128,28 @@ function snort_deinstall() {
function snort_prepare_rule_files($snortcfg, $snortcfgdir) {
- global $snort_enforcing_rules_file, $flowbit_rules_file, $rebuild_rules, $all_rules;
+ /***********************************************************/
+ /* This function builds a new set of enforcing rules for */
+ /* Snort and writes them to disk. */
+ /* */
+ /* $snortcfg --> pointer to applicable section of */
+ /* config.xml containing settings for */
+ /* the interface. */
+ /* */
+ /* $snortcfgdir --> pointer to physical directory on */
+ /* disk where Snort configuration is */
+ /* to be written. */
+ /***********************************************************/
+
+ global $rebuild_rules;
$snortdir = SNORTDIR;
+ $flowbit_rules_file = FLOWBITS_FILENAME;
+ $snort_enforcing_rules_file = ENFORCING_RULES_FILENAME;
$no_rules_defined = true;
/* If there is no reason to rebuild the rules, exit to save time. */
- if ($rebuild_rules == "off")
+ if (!$rebuild_rules)
return;
/* Log a message for rules rebuild in progress */
@@ -2076,10 +2159,10 @@ function snort_prepare_rule_files($snortcfg, $snortcfgdir) {
if (!empty($snortcfg['rulesets']) || $snortcfg['ips_policy_enable'] == 'on') {
$enabled_rules = array();
$enabled_files = array();
+ $all_rules = array();
$no_rules_defined = false;
/* Load up all the rules into a Rules Map array. */
- $all_rules = array();
$all_rules = snort_load_rules_map("{$snortdir}/rules/");
/* Create an array with the filenames of the enabled */
@@ -2119,7 +2202,7 @@ function snort_prepare_rule_files($snortcfg, $snortcfgdir) {
/* Check if a pre-defined Snort VRT policy is selected. If so, */
/* add all the VRT policy rules to our enforcing rule set. */
if (!empty($snortcfg['ips_policy'])) {
- $policy_rules = snort_load_vrt_policy($snortcfg['ips_policy'], false);
+ $policy_rules = snort_load_vrt_policy($snortcfg['ips_policy'], $all_rules);
foreach ($policy_rules as $k1 => $policy) {
foreach ($policy as $k2 => $p) {
if (!is_array($enabled_rules[$k1]))
@@ -2151,7 +2234,7 @@ function snort_prepare_rule_files($snortcfg, $snortcfgdir) {
/* If auto-flowbit resolution is enabled, generate the dependent flowbits rules file. */
if ($snortcfg['autoflowbitrules'] == 'on') {
log_error('[Snort] Enabling any flowbit-required rules for: ' . snort_get_friendly_interface($snortcfg['interface']) . '...');
- $fbits = snort_resolve_flowbits($enabled_rules);
+ $fbits = snort_resolve_flowbits($all_rules, $enabled_rules);
/* Check for and disable any flowbit-required rules dependent upon */
/* disabled preprocessors if this option is enabled for the interface. */
@@ -2164,8 +2247,6 @@ function snort_prepare_rule_files($snortcfg, $snortcfgdir) {
} else
/* Just put an empty file to always have the file present */
snort_write_flowbit_rules_file(array(), "{$snortcfgdir}/rules/{$flowbit_rules_file}");
-
- unset($GLOBALS['all_rules']);
} else {
snort_write_enforcing_rules_file(array(), "{$snortcfgdir}/rules/{$snort_enforcing_rules_file}");
snort_write_flowbit_rules_file(array(), "{$snortcfgdir}/rules/{$flowbit_rules_file}");
@@ -2197,10 +2278,16 @@ function snort_filter_preproc_rules($snortcfg, &$active_rules, $persist_log = fa
/* non-enabled preprocessors are disabled to stop */
/* start-up errors from unknown rule options. */
/* */
- /* $snortcfg -> config parameters array for */
- /* the interface */
- /* $active_rules -> rules_map array of enabled */
- /* rules for the interface */
+ /* $snortcfg --> config parameters array for */
+ /* the interface. */
+ /* */
+ /* $active_rules --> rules_map array of enabled */
+ /* rules for the interface. */
+ /* */
+ /* $persist_log --> flag indicating if new log */
+ /* file should be created or */
+ /* the existing one appended */
+ /* to. */
/* */
/* NOTE: This feature must be enabled in the GUI */
/* by the user. Use of this feature can */
@@ -2350,11 +2437,13 @@ function snort_filter_preproc_rules($snortcfg, &$active_rules, $persist_log = fa
function snort_generate_conf($snortcfg) {
- global $config, $g, $flowbit_rules_file, $snort_enforcing_rules_file, $rebuild_rules;
+ global $config, $g, $rebuild_rules;
$snortdir = SNORTDIR;
$snortlibdir = SNORTLIBDIR;
$snortlogdir = SNORTLOGDIR;
+ $flowbit_rules_file = FLOWBITS_FILENAME;
+ $snort_enforcing_rules_file = ENFORCING_RULES_FILENAME;
if (!is_array($config['installedpackages']['snortglobal']['rule']))
return;
@@ -2432,7 +2521,7 @@ function snort_generate_conf($snortcfg) {
$pfkill = "";
if ($snortcfg['blockoffenderskill'] == "on")
$pfkill = "kill";
- $spoink_wlist = snort_build_list($snortcfg, $snortcfg['whitelistname']);
+ $spoink_wlist = snort_build_list($snortcfg, $snortcfg['whitelistname'], true);
/* write whitelist */
@file_put_contents("{$snortcfgdir}/{$snortcfg['whitelistname']}", implode("\n", $spoink_wlist));
$spoink_type = "output alert_pf: {$snortcfgdir}/{$snortcfg['whitelistname']},snort2c,{$snortcfg['blockoffendersip']},{$pfkill}";
@@ -2878,6 +2967,15 @@ EOD;
if ($snortcfg['cksumcheck'] == 'on')
$cksumcheck = "none";
+ /* Pull in user-configurable detection config options */
+ $cfg_detect_settings = "search-method {$snort_performance} max-pattern-len 20 max_queue_events 5";
+ if ($snortcfg['fpm_split_any_any'] == "on")
+ $cfg_detect_settings .= " split-any-any";
+ if ($snortcfg['fpm_search_optimize'] == "on")
+ $cfg_detect_settings .= " search-optimize";
+ if ($snortcfg['fpm_no_stream_inserts'] == "on")
+ $cfg_detect_settings .= " no_stream_inserts";
+
/* Pull in user-configurable options for Frag3 preprocessor settings */
$frag3_disabled = "";
if ($snortcfg['frag3_detection'] == "off")
@@ -2901,6 +2999,13 @@ EOD;
if (!empty($snortcfg['frag3_policy']))
$frag3_policy = "policy {$snortcfg['frag3_policy']}";
+ /* Grab any user-customized value for Protocol Aware Flushing (PAF) max PDUs */
+ $paf_max_pdu_config = "config paf_max: ";
+ if (empty($snortcfg['max_paf']) || $snortcfg['max_paf'] == "0")
+ $paf_max_pdu_config .= "0";
+ else
+ $paf_max_pdu_config .= $snortcfg['max_paf'];
+
/* Pull in user-configurable options for Stream5 preprocessor settings */
$stream5_reassembly = "";
if ($snortcfg['stream5_reassembly'] == "off")
@@ -2948,7 +3053,19 @@ EOD;
if (!empty($snortcfg['stream5_icmp_timeout']))
$stream5_icmp_timeout = "timeout {$snortcfg['stream5_icmp_timeout']}";
- /* build snort configuration file */
+ /* Check for and configure Host Attribute Table if enabled */
+ $host_attrib_config = "";
+ if ($snortcfg['host_attribute_table'] == "on" && !empty($snortcfg['host_attribute_data'])) {
+ file_put_contents("{$snortcfgdir}/host_attributes", base64_decode($snortcfg['host_attribute_data']));
+ $host_attrib_config = "# Host Attribute Table #\n";
+ $host_attrib_config .= "attribute_table filename {$snortcfgdir}/host_attributes\n";
+ if (!empty($snortcfg['max_attribute_hosts']))
+ $host_attrib_config .= "config max_attribute_hosts: {$snortcfg['max_attribute_hosts']}\n";
+ if (!empty($snortcfg['max_attribute_services_per_host']))
+ $host_attrib_config .= "config max_attribute_services_per_host: {$snortcfg['max_attribute_services_per_host']}";
+ }
+
+ /* Finally, build the Snort configuration file */
$snort_conf_text = <<<EOD
# snort configuration file
@@ -2968,6 +3085,9 @@ var PREPROC_RULE_PATH {$snortcfgdir}/preproc_rules
# Define Server Ports #
{$portvardef}
+# Configure quiet startup mode #
+config quiet
+
# Configure the snort decoder #
config checksum_mode: {$cksumcheck}
config disable_decode_alerts
@@ -2986,15 +3106,15 @@ config pcre_match_limit: 3500
config pcre_match_limit_recursion: 1500
# Configure the detection engine #
-config detection: search-method {$snort_performance} search-optimize max-pattern-len 20 max_queue_events 5
+config detection: {$cfg_detect_settings}
config event_queue: max_queue 8 log 5 order_events content_length
# Configure to show year in timestamps
config show_year
-# Configure protocol aware flushing #
-# For more information see README.stream5 #
-config paf_max: 16000
+# Configure protocol aware flushing #
+# For more information see README.stream5 #
+{$paf_max_pdu_config}
#Configure dynamically loaded libraries
dynamicpreprocessor directory {$snort_dirs['dynamicpreprocessor']}
@@ -3002,11 +3122,12 @@ dynamicengine directory {$snort_dirs['dynamicengine']}
dynamicdetection directory {$snort_dirs['dynamicrules']}
# Inline packet normalization. For more information, see README.normalize
-preprocessor normalize_ip4
-preprocessor normalize_tcp: ips ecn stream
-preprocessor normalize_icmp4
-preprocessor normalize_ip6
-preprocessor normalize_icmp6
+# Disabled since we do not use "inline" mode with pfSense
+# preprocessor normalize_ip4
+# preprocessor normalize_tcp: ips ecn stream
+# preprocessor normalize_icmp4
+# preprocessor normalize_ip6
+# preprocessor normalize_icmp6
# Flow and stream #
preprocessor frag3_global: {$frag3_memcap}, {$frag3_max_frags}{$frag3_disabled}
@@ -3019,6 +3140,8 @@ preprocessor stream5_icmp: {$stream5_icmp_timeout}
{$snort_preprocessors}
+{$host_attrib_config}
+
# Snort Output Logs #
output alert_csv: alert timestamp,sig_generator,sig_id,sig_rev,msg,proto,src,srcport,dst,dstport,id,classification,priority
{$alertsystemlog_type}
@@ -3052,10 +3175,10 @@ EOD;
/* Uses XMLRPC to synchronize the changes to a remote node */
function snort_sync_on_changes() {
- global $config, $g, $is_postinstall;
+ global $config, $g;
/* Do not attempt a package sync while booting up or installing package */
- if ($g['booting'] || $is_postinstall)
+ if ($g['booting'] || $g['snort_postinstall'])
return;
if (is_array($config['installedpackages']['snortsync']['config'])){
@@ -3117,10 +3240,10 @@ function snort_sync_on_changes() {
/* Do the actual XMLRPC sync */
function snort_do_xmlrpc_sync($syncdownloadrules, $sync_to_ip, $username, $password, $synctimeout, $syncstartsnort) {
- global $config, $g, $is_postinstall;
+ global $config, $g;
/* Do not attempt a package sync while booting up or installing package */
- if ($g['booting'] || $is_postinstall)
+ if ($g['booting'] || $g['snort_postinstall'])
return;
if(!$username || !$password || !$sync_to_ip) {
@@ -3192,28 +3315,35 @@ function snort_do_xmlrpc_sync($syncdownloadrules, $sync_to_ip, $username, $passw
$snortstart .= "else {log_error(gettext(\"[snort] XMLRPC pkg sync: Snort is running...\"));\n}\n";
}
- /* Build a series of commands for the secondary host to execute that will load the new settings. */
- $execcmd = <<<EOD
+ /* Build a series of commands as a PHP file for the secondary host to execute to load the new settings. */
+ $snort_sync_cmd = <<<EOD
+ <?php
require_once("/usr/local/pkg/snort/snort.inc");
require_once("service-utils.inc");
- global \$g, \$rebuild_rules, \$snort_gui_include, \$is_postinstall, \$pkg_interface;
+ global \$g, \$rebuild_rules, \$snort_gui_include, \$pkg_interface;
\$orig_pkg_interface = \$pkg_interface;
- \$is_postinstall = true;
+ \$g["snort_postinstall"] = true;
+ \$g["snort_sync_in_progress"] = true;
\$snort_gui_include = false;
\$pkg_interface = "console";
{$downloadrulescmd}
- \$is_postinstall = false;
- log_error(gettext("[snort] XMLRPC pkg sync: Generating snort.conf file using Master Host's settings..."));
- \$rebuild_rules = "on";
+ unset(\$g["snort_postinstall"]);
+ log_error(gettext("[snort] XMLRPC pkg sync: Generating snort.conf file using Master Host settings..."));
+ \$rebuild_rules = true;
sync_snort_package_config();
- \$rebuild_rules = "off";
+ \$rebuild_rules = false;
{$snortstart}
log_error(gettext("[snort] XMLRPC pkg sync process on this host is complete..."));
\$pkg_interface = \$orig_pkg_interface;
+ unset(\$g["snort_sync_in_progress"]);
return true;
+ ?>
EOD;
+ /* First, have the target host write the commands to a PHP file in the /tmp directory */
+ $execcmd = "file_put_contents('/tmp/snort_sync_cmds.php', '{$snort_sync_cmd}');";
+
/* assemble xmlrpc payload */
$method = 'pfsense.exec_php';
$params = array(
@@ -3221,7 +3351,7 @@ EOD;
XML_RPC_encode($execcmd)
);
- log_error("[snort] Snort XMLRPC sending reload configuration cmd to {$url}:{$port}.");
+ log_error("[snort] Snort XMLRPC sending reload configuration cmd set as a file to {$url}:{$port}.");
$msg = new XML_RPC_Message($method, $params);
$cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
$cli->setCredentials($username, $password);
@@ -3237,6 +3367,27 @@ EOD;
} else {
log_error("[snort] Snort pkg XMLRPC reload configuration success with {$url}:{$port} (pfsense.exec_php).");
}
+
+ /* Now assemble a command to execute the previously sent PHP file in the background */
+ $execcmd = "exec(\"/usr/local/bin/php -f '/tmp/snort_sync_cmds.php' > /dev/null 2>&1 &\");";
+ $params2 = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+ log_error("[snort] Snort XMLRPC sending {$url}:{$port} cmd to execute configuration reload.");
+ $msg2 = new XML_RPC_Message($method, $params2);
+ $resp = $cli->send($msg2, $synctimeout);
+ if(!$resp) {
+ $error = "A communications error occurred while attempting snort XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("sync_settings", $error, "snort Settings Sync", "");
+ } elseif($resp->faultCode()) {
+ $error = "An error code was received while attempting snort XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "snort Settings Sync", "");
+ } else {
+ log_error("[snort] Snort pkg XMLRPC reload configuration success with {$url}:{$port} (pfsense.exec_php).");
+ }
}
?>