diff options
Diffstat (limited to 'config/suricata')
49 files changed, 7480 insertions, 1104 deletions
diff --git a/config/suricata/disablesid-sample.conf b/config/suricata/disablesid-sample.conf new file mode 100644 index 00000000..026f4d94 --- /dev/null +++ b/config/suricata/disablesid-sample.conf @@ -0,0 +1,43 @@ +# example disablesid.conf + +# Example of modifying state for individual rules +# 1:1034,1:9837,1:1270,1:3390,1:710,1:1249,3:13010 + +# Example of modifying state for rule ranges +# 1:220-1:3264,3:13010-3:13013 + +# Comments are allowed in this file, and can also be on the same line +# As the modify state syntax, as long as it is a trailing comment +# 1:1011 # I Disabled this rule because I could! + +# Example of modifying state for MS and cve rules, note the use of the : +# in cve. This will modify MS09-008, cve 2009-0233, bugtraq 21301, +# and all MS00 and all cve 2000 related sids! These support regular expression +# matching only after you have specified what you are looking for, i.e. +# MS00-<regex> or cve:<regex>, the first section CANNOT contain a regular +# expression (MS\d{2}-\d+) will NOT work, use the pcre: keyword (below) +# for this. +# MS09-008,cve:2009-0233,bugtraq:21301,MS00-\d+,cve:2000-\d+ + +# Example of using the pcre: keyword to modify rulestate. the pcre keyword +# allows for full use of regular expression syntax, you do not need to designate +# with / and all pcre searches are treated as case insensitive. For more information +# about regular expression syntax: http://www.regular-expressions.info/ +# The following example modifies state for all MS07 through MS10 +# pcre:MS(0[7-9]|10)-\d+ +# pcre:"Joomla" + +# Example of modifying state for specific categories entirely. +# "snort_" limits to Snort VRT rules, "emerging-" limits to +# Emerging Threats Open rules, "etpro-" limits to ET-PRO rules. +# "shellcode" with no prefix would match in any vendor set. +# snort_web-iis,emerging-shellcode,etpro-imap,shellcode + +# Any of the above values can be on a single line or multiple lines, when +# on a single line they simply need to be separated by a , +# 1:9837,1:220-1:3264,3:13010-3:13013,pcre:MS(0[0-7])-\d+,MS09-008,cve:2009-0233 + +# The modifications in this file are for sample/example purposes only and +# should not actively be used, you need to modify this file to fit your +# environment. + diff --git a/config/suricata/enablesid-sample.conf b/config/suricata/enablesid-sample.conf new file mode 100644 index 00000000..4cccc5dd --- /dev/null +++ b/config/suricata/enablesid-sample.conf @@ -0,0 +1,39 @@ +# example enablesid.conf + +# Example of modifying state for individual rules +# 1:1034,1:9837,1:1270,1:3390,1:710,1:1249,3:13010 + +# Example of modifying state for rule ranges +# 1:220-1:3264,3:13010-3:13013 + +# Comments are allowed in this file, and can also be on the same line +# As the modify state syntax, as long as it is a trailing comment +# 1:1011 # I Disabled this rule because I could! + +# Example of modifying state for MS and cve rules, note the use of the : +# in cve. This will modify MS09-008, cve 2009-0233, bugtraq 21301, +# and all MS00 and all cve 2000 related sids! These support regular expression +# matching only after you have specified what you are looking for, i.e. +# MS00-<regex> or cve:<regex>, the first section CANNOT contain a regular +# expression (MS\d{2}-\d+) will NOT work, use the pcre: keyword (below) +# for this. +# MS09-008,cve:2009-0233,bugtraq:21301,MS00-\d+,cve:2000-\d+ + +# Example of using the pcre: keyword to modify rulestate. the pcre keyword +# allows for full use of regular expression syntax, you do not need to designate +# with / and all pcre searches are treated as case insensitive. For more information +# about regular expression syntax: http://www.regular-expressions.info/ +# The following example modifies state for all MS07 through MS10 +# pcre:MS(0[7-9]|10)-\d+ +# pcre:"Joomla" + +# Example of modifying state for specific categories entirely. +# "snort_" limits to Snort VRT rules, "emerging-" limits to +# Emerging Threats Open rules, "etpro-" limits to ET-PRO rules. +# "shellcode" with no prefix would match in any vendor set. +# snort_web-iis,emerging-shellcode,etpro-imap,shellcode + +# Any of the above values can be on a single line or multiple lines, when +# on a single line they simply need to be separated by a , +# 1:9837,1:220-1:3264,3:13010-3:13013,pcre:MS(0[0-7])-\d+,MS09-008,cve:2009-0233 + diff --git a/config/suricata/modifysid-sample.conf b/config/suricata/modifysid-sample.conf new file mode 100644 index 00000000..d59f84ba --- /dev/null +++ b/config/suricata/modifysid-sample.conf @@ -0,0 +1,23 @@ +# example modifysid.conf +# +# formatting is simple +# <sid or sid list> "what I'm replacing" "what I'm replacing it with" +# +# Note that this will only work with GID:1 rules, simply because modifying +# GID:3 SO stub rules would not actually affect the rule. +# +# If you are attempting to change rulestate (enable,disable) from here +# then you are doing it wrong. Do this from within the respective +# rulestate modification configuration files. + +# the following applies to sid 10010 only and represents what would normally +# be s/to_client/from_server/ +# 10010 "to_client" "from_server" + +# the following would replace HTTP_PORTS with HTTPS_PORTS for ALL GID:1 +# rules +# "HTTP_PORTS" "HTTPS_PORTS" + +# multiple sids can be specified as noted below: +# 302,429,1821 "\$EXTERNAL_NET" "\$HOME_NET" + diff --git a/config/suricata/suricata.inc b/config/suricata/suricata.inc index c767f2d0..66c1e799 100644 --- a/config/suricata/suricata.inc +++ b/config/suricata/suricata.inc @@ -44,37 +44,12 @@ require_once("services.inc"); require_once("service-utils.inc"); require_once("pkg-utils.inc"); require_once("filter.inc"); +require("/usr/local/pkg/suricata/suricata_defs.inc"); global $g, $config; -if (!is_array($config['installedpackages']['suricata'])) - $config['installedpackages']['suricata'] = array(); - -/* Get installed package version for display */ -$suricata_package_version = "Suricata {$config['installedpackages']['package'][get_pkg_id("suricata")]['version']}"; - -// Define the installed package version -define('SURICATA_PKG_VER', $suricata_package_version); - -// Define the name of the pf table used for IP blocks -define('SURICATA_PF_TABLE', 'snort2c'); - -// Create some other useful defines -define('SURICATADIR', '/usr/pbi/suricata-' . php_uname("m") . '/etc/suricata/'); -define('SURICATALOGDIR', '/var/log/suricata/'); -define('RULES_UPD_LOGFILE', SURICATALOGDIR . 'suricata_rules_update.log'); -define('ENFORCING_RULES_FILENAME', 'suricata.rules'); -define('FLOWBITS_FILENAME', 'flowbit-required.rules'); - -// Rule set download filenames and prefixes -define('ET_DNLD_FILENAME', 'emerging.rules.tar.gz'); -define('ETPRO_DNLD_FILENAME', 'etpro.rules.tar.gz'); -define('VRT_DNLD_FILENAME', 'snortrules-snapshot-edge.tar.gz'); -define('GPLV2_DNLD_FILENAME', 'community-rules.tar.gz'); -define('VRT_FILE_PREFIX', 'snort_'); -define('GPL_FILE_PREFIX', 'GPLv2_'); -define('ET_OPEN_FILE_PREFIX', 'emerging-'); -define('ET_PRO_FILE_PREFIX', 'etpro-'); +// Suricata GUI needs some extra PHP memory space to manipulate large rules arrays +ini_set("memory_limit", "256M"); function suricata_generate_id() { global $config; @@ -130,10 +105,11 @@ function suricata_barnyard_start($suricatacfg, $if_real) { $suricata_uuid = $suricatacfg['uuid']; $suricatadir = SURICATADIR . "suricata_{$suricata_uuid}_{$if_real}"; $suricatalogdir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}"; + $suricatabindir = SURICATA_PBI_BINDIR; if ($suricatacfg['barnyard_enable'] == 'on') { log_error("[Suricata] Barnyard2 START for {$suricatacfg['descr']}({$if_real})..."); - mwexec_bg("/usr/local/bin/barnyard2 -r {$suricata_uuid} -f unified2.alert --pid-path {$g['varrun_path']} --nolock-pidfile -c {$suricatadir}/barnyard2.conf -d {$suricatalogdir} -D -q"); + mwexec_bg("{$suricatabindir}barnyard2 -r {$suricata_uuid} -f unified2.alert --pid-path {$g['varrun_path']} --nolock-pidfile -c {$suricatadir}/barnyard2.conf -d {$suricatalogdir} -D -q"); } } @@ -142,10 +118,11 @@ function suricata_start($suricatacfg, $if_real) { $suricatadir = SURICATADIR; $suricata_uuid = $suricatacfg['uuid']; + $suricatabindir = SURICATA_PBI_BINDIR; if ($suricatacfg['enable'] == 'on') { log_error("[Suricata] Suricata START for {$suricatacfg['descr']}({$if_real})..."); - mwexec_bg("/usr/local/bin/suricata -i {$if_real} -D -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/suricata.yaml --pidfile {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid"); + mwexec_bg("{$suricatabindir}suricata -i {$if_real} -D -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/suricata.yaml --pidfile {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid"); } else return; @@ -154,6 +131,61 @@ function suricata_start($suricatacfg, $if_real) { suricata_barnyard_start($suricatacfg, $if_real); } +function suricata_start_all_interfaces($background=FALSE) { + + /*************************************************************/ + /* This function starts all configured and enabled Suricata */ + /* interfaces. */ + /*************************************************************/ + + global $g, $config; + + /* do nothing if no Suricata interfaces active */ + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + + foreach ($config['installedpackages']['suricata']['rule'] as $suricatacfg) { + if ($suricatacfg['enable'] != 'on') + continue; + suricata_start($suricatacfg, get_real_interface($suricatacfg['interface'])); + } +} + +function suricata_stop_all_interfaces() { + + /*************************************************************/ + /* This function stops all configured Suricata interfaces. */ + /*************************************************************/ + + global $g, $config; + + /* do nothing if no Suricata interfaces active */ + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + + foreach ($config['installedpackages']['suricata']['rule'] as $suricatacfg) { + suricata_stop($suricatacfg, get_real_interface($suricatacfg['interface'])); + } +} + +function suricata_restart_all_interfaces() { + + /*************************************************************/ + /* This function stops all configured Suricata interfaces */ + /* and restarts enabled Suricata interfaces. */ + /*************************************************************/ + + global $g, $config; + + /* do nothing if no Suricata interfaces active */ + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + + suricata_stop_all_interfaces(); + sleep(2); + suricata_start_all_interfaces(TRUE); +} + function suricata_reload_config($suricatacfg, $signal="USR2") { /**************************************************************/ @@ -178,7 +210,6 @@ function suricata_reload_config($suricatacfg, $signal="USR2") { /******************************************************/ if (isvalidpid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid")) { log_error("[Suricata] Suricata LIVE RULE RELOAD initiated for {$suricatacfg['descr']} ({$if_real})..."); -// sigkillbypid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid", $signal); mwexec_bg("/bin/pkill -{$signal} -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid"); } } @@ -207,7 +238,6 @@ function suricata_barnyard_reload_config($suricatacfg, $signal="HUP") { /******************************************************/ if (isvalidpid("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid")) { log_error("[Suricata] Barnyard2 CONFIG RELOAD initiated for {$suricatacfg['descr']} ({$if_real})..."); -// sigkillbypid("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid", $signal); mwexec_bg("/bin/pkill -{$signal} -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid"); } } @@ -250,7 +280,7 @@ function suricata_find_list($find_name, $type = 'passlist') { return array(); } -function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { +function suricata_build_list($suricatacfg, $listname = "", $passlist = false, $externallist = false) { /***********************************************************/ /* The default is to build a HOME_NET variable unless */ @@ -260,9 +290,10 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { global $config, $g, $aliastable, $filterdns; $home_net = array(); - if ($listname == 'default' || empty($listname)) { + if (!$externallist && ($listname == 'default' || empty($listname))) { $localnet = 'yes'; $wanip = 'yes'; $wangw = 'yes'; $wandns = 'yes'; $vips = 'yes'; $vpns = 'yes'; - } else { + } + else { $list = suricata_find_list($listname); if (empty($list)) return $list; @@ -276,21 +307,25 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { $home_net = explode(" ", trim(filter_expand_alias($list['address']))); } - // Always add loopback to HOME_NET and passlist (ftphelper) - if (!in_array("127.0.0.1", $home_net)) - $home_net[] = "127.0.0.1"; + // Always add loopback to HOME_NET and passlist + if (!$externallist) { + if (!in_array("127.0.0.1/32", $home_net)) + $home_net[] = "127.0.0.1/32"; + if (!in_array("::1/128", $home_net)) + $home_net[] = "::1/128"; + } /********************************************************************/ /* Always put the interface running Suricata in HOME_NET and */ - /* whitelist unless it's the WAN. WAN options are handled further */ + /* pass list unless it's the WAN. WAN options are handled further */ /* down. If the user specifically chose not to include LOCAL_NETS */ /* in the PASS LIST, then do not include the Suricata interface */ /* subnet in the PASS LIST. We do include the actual LAN interface */ /* IP for Suricata, though, to prevent locking out the firewall. */ /********************************************************************/ $suricataip = get_interface_ip($suricatacfg['interface']); - if (!$whitelist || $localnet == 'yes' || empty($localnet)) { - if (is_ipaddr($suricataip)) { + if (($externallist && $localnet == 'yes') || (!$externallist && (!$passlist || $localnet == 'yes' || empty($localnet)))) { + if (is_ipaddrv4($suricataip)) { if ($suricatacfg['interface'] <> "wan") { $sn = get_interface_subnet($suricatacfg['interface']); $ip = gen_subnet($suricataip, $sn) . "/{$sn}"; @@ -299,15 +334,19 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { } } } - else { - if (is_ipaddr($suricataip)) { - if (!in_array($suricataip, $home_net)) - $home_net[] = $suricataip; + elseif (!$externallist && $localnet != 'yes') { + if (is_ipaddrv4($suricataip)) { + if (!in_array($suricataip . "/32", $home_net)) + $home_net[] = $suricataip . "/32"; } } + // Grab the IPv6 address if we have one assigned $suricataip = get_interface_ipv6($suricatacfg['interface']); - if (!$whitelist || $localnet == 'yes' || empty($localnet)) { + // Trim off the interface designation (e.g., %em1) if present + if (strpos($suricataip, "%") !== FALSE) + $suricataip = substr($suricataip, 0, strpos($suricataip, "%")); + if (($externallist && $localnet == 'yes') || (!$externallist && (!$passlist || $localnet == 'yes' || empty($localnet)))) { if (is_ipaddrv6($suricataip)) { if ($suricatacfg['interface'] <> "wan") { $sn = get_interface_subnetv6($suricatacfg['interface']); @@ -317,14 +356,24 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { } } } - else { + elseif (!$externallist && $localnet != 'yes') { if (is_ipaddrv6($suricataip)) { - if (!in_array($suricataip, $home_net)) - $home_net[] = $suricataip; + if (!in_array($suricataip . "/128", $home_net)) + $home_net[] = $suricataip . "/128"; } } - if (!$whitelist || $localnet == 'yes' || empty($localnet)) { + // Add link-local address if user included locally-attached networks + $suricataip = get_interface_linklocal($suricatacfg['interface']); + if (!empty($suricataip) && $localnet == 'yes') { + // Trim off the interface designation (e.g., %em1) if present + if (strpos($suricataip, "%") !== FALSE) + $suricataip = substr($suricataip, 0, strpos($suricataip, "%")); + if (!in_array($suricataip . "/128", $home_net)) + $home_net[] = $suricataip . "/128"; + } + + if (($$externallist && $localnet == 'yes') || (!$externallist && (!$passlist || $localnet == 'yes' || empty($localnet)))) { /*************************************************************************/ /* Iterate through the interface list and write out pass list items and */ /* also compile a HOME_NET list of all local interfaces for suricata. */ @@ -336,58 +385,89 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { if ($int == "wan") continue; $subnet = get_interface_ip($int); - if (is_ipaddr($subnet)) { + if (is_ipaddrv4($subnet)) { $sn = get_interface_subnet($int); $ip = gen_subnet($subnet, $sn) . "/{$sn}"; if (!in_array($ip, $home_net)) $home_net[] = $ip; } - if ($int == "wan") - continue; + $subnet = get_interface_ipv6($int); + // Trim off the interface designation (e.g., %em1) if present + if (strpos($subnet, "%") !== FALSE) + $subnet = substr($subnet, 0, strpos($subnet, "%")); if (is_ipaddrv6($subnet)) { $sn = get_interface_subnetv6($int); $ip = gen_subnetv6($subnet, $sn). "/{$sn}"; if (!in_array($ip, $home_net)) $home_net[] = $ip; } + + // Add link-local address + $suricataip = get_interface_linklocal($int); + if (!empty($suricataip)) { + // Trim off the interface designation (e.g., %em1) if present + if (strpos($suricataip, "%") !== FALSE) + $suricataip = substr($suricataip, 0, strpos($suricataip, "%")); + if (!in_array($suricataip . "/128", $home_net)) + $home_net[] = $suricataip . "/128"; + } } } if ($wanip == 'yes') { $ip = get_interface_ip("wan"); - if (is_ipaddr($ip)) { - if (!in_array($ip, $home_net)) - $home_net[] = $ip; + if (is_ipaddrv4($ip)) { + if (!in_array($ip . "/32", $home_net)) + $home_net[] = $ip . "/32"; } $ip = get_interface_ipv6("wan"); + // Trim off the interface designation (e.g., %em1) if present + if (strpos($ip, "%") !== FALSE) + $ip = substr($ip, 0, strpos($ip, "%")); if (is_ipaddrv6($ip)) { - if (!in_array($ip, $home_net)) - $home_net[] = $ip; + if (!in_array($ip . "/128", $home_net)) + $home_net[] = $ip . "/128"; + } + // Explicitly grab the WAN Link-Local address + $ip = get_interface_linklocal("wan"); + if (!empty($ip)) { + // Trim off the interface designation (e.g., %em1) if present + if (strpos($ip, "%") !== FALSE) + $ip = substr($ip, 0, strpos($ip, "%")); + if (!in_array($ip . "/128", $home_net)) + $home_net[] = $ip . "/128"; } } if ($wangw == 'yes') { // Grab the default gateway if set $default_gw = exec("/sbin/route -n get default |grep 'gateway:' | /usr/bin/awk '{ print $2 }'"); - if (is_ipaddr($default_gw) && !in_array($default_gw, $home_net)) - $home_net[] = $default_gw; - if (is_ipaddrv6($default_gw) && !in_array($default_gw, $home_net)) - $home_net[] = $default_gw; + if (is_ipaddrv4($default_gw) && !in_array($default_gw . "/32", $home_net)) + $home_net[] = $default_gw . "/32"; + if (is_ipaddrv6($default_gw) && !in_array($default_gw . "/128", $home_net)) + $home_net[] = $default_gw . "/128"; // Get any other interface gateway and put in $HOME_NET if not there already $gw = get_interface_gateway($suricatacfg['interface']); - if (is_ipaddr($gw) && !in_array($gw, $home_net)) - $home_net[] = $gw; + if (is_ipaddrv4($gw) && !in_array($gw . "/32", $home_net)) + $home_net[] = $gw . "/32"; $gw = get_interface_gateway_v6($suricatacfg['interface']); - if (is_ipaddrv6($gw) && !in_array($gw, $home_net)) - $home_net[] = $gw; + // Trim off the interface designation (e.g., %em1) if present + if (strpos($gw, "%") !== FALSE) + $gw = substr($gw, 0, strpos($gw, "%")); + if (is_ipaddrv6($gw) && !in_array($gw . "/128", $home_net)) + $home_net[] = $gw . "/128"; } if ($wandns == 'yes') { - // Add DNS server for WAN interface to whitelist + // Add DNS server for WAN interface to Pass List $dns_servers = get_dns_servers(); foreach ($dns_servers as $dns) { + if (is_ipaddrv4($dns)) + $dns .= "/32"; + elseif (is_ipaddrv6($dns)) + $dns .= "/128"; if ($dns && !in_array($dns, $home_net)) $home_net[] = $dns; } @@ -405,7 +485,7 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { } } - // grab a list of vpns and whitelist if user desires + // Grab a list of vpns enabled - these come back as CIDR mask networks if ($vpns == 'yes') { $vpns_list = filter_get_vpns_list(); if (!empty($vpns_list)) { @@ -435,10 +515,61 @@ function suricata_build_list($suricatacfg, $listname = "", $passlist = false) { return $valresult; } +function suricata_cron_job_exists($crontask, $match_time=FALSE, $minute="0", $hour="*", $monthday="*", $month="*", $weekday="*", $who="root") { + + /************************************************************ + * This function iterates the cron[] array in the config * + * to determine if the passed $crontask entry exists. It * + * returns TRUE if the $crontask already exists, or FALSE * + * if there is no match. * + * * + * The $match_time flag, when set, causes a test of the * + * configured task execution times along with the task * + * when checking for a match. * + * * + * We use this to prevent unneccessary config writes if * + * the $crontask already exists. * + ************************************************************/ + + global $config, $g; + + if (!is_array($config['cron'])) + $config['cron'] = array(); + if (!is_array($config['cron']['item'])) + $config['cron']['item'] = array(); + + foreach($config['cron']['item'] as $item) { + if(strpos($item['command'], $crontask) !== FALSE) { + if ($match_time) { + if ($item['minute'] != $minute) + return FALSE; + if ($item['hour'] != $hour) + return FALSE; + if ($item['mday'] != $monthday) + return FALSE; + if ($item['month'] != $month) + return FALSE; + if ($item['wday'] != $weekday) + return FALSE; + if ($item['who'] != $who) + return FALSE; + } + return TRUE; + } + } + return FALSE; +} + function suricata_rules_up_install_cron($should_install=true) { global $config, $g; - $command = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/www/suricata/suricata_check_for_rule_updates.php"; + // If called with FALSE as argument, then we're removing + // the existing job. + if ($should_install == FALSE) { + if (suricata_cron_job_exists("suricata_check_for_rule_updates.php", FALSE)) + install_cron_job("suricata_check_for_rule_updates.php", false); + return; + } // Get auto-rule update parameter from configuration $suricata_rules_up_info_ck = $config['installedpackages']['suricata']['config'][0]['autoruleupdate']; @@ -504,12 +635,32 @@ function suricata_rules_up_install_cron($should_install=true) { $suricata_rules_up_wday = "*"; } - // System call to manage the cron job. - install_cron_job($command, $should_install, $suricata_rules_up_min, $suricata_rules_up_hr, $suricata_rules_up_mday, $suricata_rules_up_month, $suricata_rules_up_wday, "root"); + // Construct the basic cron command task + $command = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_check_for_rule_updates.php"; + + // If there are no changes in the cron job command string from the existing job, then exit + if (suricata_cron_job_exists($command, TRUE, $suricata_rules_up_min, $suricata_rules_up_hr, $suricata_rules_up_mday, $suricata_rules_up_month, $suricata_rules_up_wday, "root")) + return; + + // Else install the new or updated cron job + if ($should_install) + install_cron_job($command, $should_install, $suricata_rules_up_min, $suricata_rules_up_hr, $suricata_rules_up_mday, $suricata_rules_up_month, $suricata_rules_up_wday, "root"); } function suricata_loglimit_install_cron($should_install=true) { + // See if simply removing existing "loglimit" job for Suricata + if ($should_install == FALSE) { + if (suricata_cron_job_exists("suricata/suricata_check_cron_misc.inc", FALSE)) + install_cron_job("suricata_check_cron_misc.inc", false); + return; + } + + // If there are no changes in the cron job command string from the existing job, then exit. + if ($should_install && suricata_cron_job_exists("/usr/local/pkg/suricata/suricata_check_cron_misc.inc", TRUE, "*/5")) + return; + + // Else install the new or updated cron job install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_check_cron_misc.inc", $should_install, "*/5"); } @@ -517,6 +668,13 @@ function suricata_rm_blocked_install_cron($should_install) { global $config, $g; $suri_pf_table = SURICATA_PF_TABLE; + // See if simply removing existing "expiretable" job for Suricata + if ($should_install == FALSE) { + if (suricata_cron_job_exists("{$suri_pf_table}", FALSE)) + install_cron_job("{$suri_pf_table}", false); + return; + } + $suricata_rm_blocked_info_ck = $config['installedpackages']['suricata']['config'][0]['rm_blocked']; if ($suricata_rm_blocked_info_ck == "15m_b") { @@ -600,13 +758,15 @@ function suricata_rm_blocked_install_cron($should_install) { $suricata_rm_blocked_expire = "2419200"; } - // First, remove any existing cron task for "rm_blocked" hosts - install_cron_job("pfctl -t {$suri_pf_table} -T expire" , false); + // Construct the basic cron command task + $command = "/usr/bin/nice -n20 /sbin/pfctl -q -t {$suri_pf_table} -T expire {$suricata_rm_blocked_expire}"; - // Now add or update the cron task for "rm_blocked" hosts - // if enabled. + // If there are no changes in the cron job command string from the existing job, then exit. + if (suricata_cron_job_exists($command, TRUE, $suricata_rm_blocked_min, $suricata_rm_blocked_hr, $suricata_rm_blocked_mday, $suricata_rm_blocked_month, $suricata_rm_blocked_wday, "root")) + return; + + // Else install the new or updated cron job if ($should_install) { - $command = "/usr/bin/nice -n20 /sbin/pfctl -t {$suri_pf_table} -T expire {$suricata_rm_blocked_expire}"; install_cron_job($command, $should_install, $suricata_rm_blocked_min, $suricata_rm_blocked_hr, $suricata_rm_blocked_mday, $suricata_rm_blocked_month, $suricata_rm_blocked_wday, "root"); } } @@ -617,46 +777,39 @@ function sync_suricata_package_config() { $suricatadir = SURICATADIR; $rcdir = RCFILEPREFIX; - conf_mount_rw(); - // Do not start config build if there are no Suricata-configured interfaces - if (!is_array($config['installedpackages']['suricata']) || !is_array($config['installedpackages']['suricata']['rule'])) { - @unlink("{$rcdir}/suricata.sh"); - conf_mount_ro(); + if (!is_array($config['installedpackages']['suricata']['rule']) || count($config['installedpackages']['suricata']['rule']) < 1) return; - } $suricataconf = $config['installedpackages']['suricata']['rule']; foreach ($suricataconf as $value) { - $if_real = get_real_interface($value['interface']); + /* Skip configuration of any disabled interface */ + if ($value['enable'] != 'on') + continue; // create a suricata.yaml file for interface suricata_generate_yaml($value); // create barnyard2.conf file for interface if ($value['barnyard_enable'] == 'on') - suricata_generate_barnyard2_conf($value, $if_real); + suricata_generate_barnyard2_conf($value, get_real_interface($value['interface'])); } // create suricata bootup file suricata.sh suricata_create_rc(); - $suricataglob = $config['installedpackages']['suricata']['config'][0]; // setup the log directory size check job if enabled suricata_loglimit_install_cron(true); + // setup the suricata rules update job if enabled suricata_rules_up_install_cron($config['installedpackages']['suricata']['config'][0]['autoruleupdate'] != "never_up" ? true : false); + // set the suricata blocked hosts time suricata_rm_blocked_install_cron($config['installedpackages']['suricata']['config'][0]['rm_blocked'] != "never_b" ? true : false); - write_config(); - configure_cron(); - // Do not attempt package sync if reinstalling package or booting -// if (!$g['suricata_postinstall'] && !$g['booting']) -// suricata_sync_on_changes(); - - conf_mount_ro(); + if (!isset($g['suricata_postinstall']) && !$g['booting']) + suricata_sync_on_changes(); } function suricata_load_suppress_sigs($suricatacfg, $track_by=false) { @@ -791,19 +944,19 @@ function suricata_post_delete_logs($suricata_uuid = 0) { // Keep most recent file unset($filelist[count($filelist) - 1]); foreach ($filelist as $file) - @unlink($file); + unlink_if_exists($file); /* Clean-up Barnyard2 archived files if any exist */ $filelist = glob("{$suricata_log_dir}/barnyard2/archive/unified2.alert.*"); foreach ($filelist as $file) - @unlink($file); + unlink_if_exists($file); /* Clean-up packet capture files if any exist */ $filelist = glob("{$suricata_log_dir}/log.pcap.*"); // Keep most recent file unset($filelist[count($filelist) - 1]); foreach ($filelist as $file) - @unlink($file); + unlink_if_exists($file); unset($filelist); } } @@ -933,7 +1086,7 @@ function suricata_build_sid_msg_map($rules_path, $sid_file) { natcasesort($sidMap); // Now print the result to the supplied file - @file_put_contents($sid_file, "#v2\n# sid-msg.map file auto-generated by Snort.\n\n"); + @file_put_contents($sid_file, "#v2\n# sid-msg.map file auto-generated by Suricata.\n\n"); @file_put_contents($sid_file, array_values($sidMap), FILE_APPEND); } @@ -1047,11 +1200,11 @@ function suricata_load_rules_map($rules_path) { if (empty($rules_path)) return $map_ref; - /*************************************************************** + /************************************************************************************ * Read all the rules into the map array. * The structure of the map array is: * - * map[gid][sid]['rule']['category']['disabled']['flowbits'] + * map[gid][sid]['rule']['category']['action']['disabled']['managed']['flowbits'] * * where: * gid = Generator ID from rule, or 1 if general text @@ -1062,9 +1215,11 @@ function suricata_load_rules_map($rules_path) { * action = alert, drop, reject or pass * disabled = 1 if rule is disabled (commented out), 0 if * rule is enabled + * managed = 1 if rule is auto-managed by SID MGMT process, + * 0 if not auto-managed * flowbits = Array of applicable flowbits if rule contains * flowbits options - ***************************************************************/ + ************************************************************************************/ // First check if we were passed a directory, a single file // or an array of filenames to read. Set our $rule_files @@ -1537,6 +1692,854 @@ function suricata_load_vrt_policy($policy, $all_rules=null) { return $vrt_policy_rules; } +function suricata_parse_sidconf_file($sidconf_file) { + + /**********************************************/ + /* This function loads and processes the file */ + /* specified by '$sidconf_file'. The file is */ + /* assumed to contain valid instructions for */ + /* matching rule SIDs as supported by the */ + /* Oinkmaster and PulledPork utilities. */ + /* */ + /* $sidconf_file ==> full path and name of */ + /* file to process */ + /* */ + /* Returns ==> an array containing */ + /* SID modifier tokens */ + /**********************************************/ + + $buf = ""; + $sid_mods = array(); + + $fd = fopen("{$sidconf_file}", "r"); + if ($fd == FALSE) { + log_error("[Suricata] Failed to open SID MGMT file '{$sidconf_file}' for processing."); + return $sid_mods; + } + + // Read and parse the conf file line-by-line + while (($buf = fgets($fd)) !== FALSE) { + $line = array(); + + // Skip any lines that may be just spaces. + if (trim($buf, " \r\n") == "") + continue; + + // Skip line with leading "#" since it's a comment + if (preg_match('/^\s*#/', $buf)) + continue; + + // Trim off any trailing comment + $line = explode("#", $buf); + + // Trim leading and trailing spaces plus newline and any carriage returns + $buf = trim($line[0], ' \r\n'); + + // Now split the SID mod arguments at the commas, if more than one + // per line, and add to our $sid_mods array. + $line = explode(",", $buf); + foreach ($line as $ent) + $sid_mods[] = trim($ent); + } + + // Close the file, release unneeded memory and return + // the array of SID mod tokens parsed from the file. + fclose($fd); + unset($line, $buf); + return $sid_mods; +} + +function suricata_sid_mgmt_auto_categories($suricatacfg, $log_results = FALSE) { + + /****************************************************/ + /* This function parses any auto-SID conf files */ + /* configured for the interface and returns an */ + /* array of rule categories adjusted from the */ + /* ['enabled_rulesets'] element in the config for */ + /* the interface in accordance with the contents */ + /* of the SID Mgmt conf files. */ + /* */ + /* The returned array shows which files should be */ + /* removed and which should be added to the list */ + /* used when building the enforcing ruleset. */ + /* */ + /* $suricatacfg ==> pointer to interface */ + /* configuration info */ + /* $log_results ==> [optional] log results to */ + /* 'sid_changes.log' in the */ + /* interface directory in */ + /* /var/log/suricata when TRUE */ + /* */ + /* Returns ==> array of category file names */ + /* for the interface. The keys */ + /* are category file names and */ + /* the corresponding values show */ + /* if the file should be added */ + /* or removed from the enabled */ + /* rulesets list. */ + /* */ + /* Example - */ + /* $changes[file] = 'enabled' */ + /* */ + /****************************************************/ + + global $config; + $suricata_sidmods_dir = SURICATA_SID_MODS_PATH; + $sid_mods = array(); + $enables = array(); + $disables = array(); + + // Check if auto-mgmt of SIDs is enabled, exit if not + if ($config['installedpackages']['suricata']['config'][0]['auto_manage_sids'] != 'on') + return array(); + if (empty($suricatacfg['disable_sid_file']) && empty($suricatacfg['enable_sid_file'])) + return array(); + + // Configure the interface's logging subdirectory if log results is enabled + if ($log_results == TRUE) + $log_file = SURICATALOGDIR . $suricatalogdir . "suricata_" . get_real_interface($suricatacfg['interface']) . "{$suricatacfg['uuid']}/sid_changes.log"; + else + $log_file = NULL; + + // Get the list of currently enabled categories for the interface + if (!empty($suricatacfg['rulesets'])) + $enabled_cats = explode("||", $suricatacfg['rulesets']); + + if ($log_results == TRUE) { + error_log(gettext("********************************************************\n"), 3, $log_file); + error_log(gettext("Starting auto RULE CATEGORY management for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) ."\n"), 3, $log_file); + error_log(gettext("Start Time: " . date("Y-m-d H:i:s") . "\n"), 3, $log_file); + } + + switch ($suricatacfg['sid_state_order']) { + case "disable_enable": + if (!empty($suricatacfg['disable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing disable_sid file: {$suricatacfg['disable_sid_file']}\n"), 3, $log_file); + + // Attempt to open the 'disable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'disable_sid_file' \"{$suricatacfg['disable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) + error_log(gettext("Unable to open disable_sid file \"{$suricatacfg['disable_sid_file']}\".\n"), 3, $log_file); + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}"); + + if (!empty($sid_mods)) + $disables = suricata_get_auto_category_mods($enabled_cats, $sid_mods, "disable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['disable_sid_file']}\".\n"), 3, $log_file); + } + } + if (!empty($suricatacfg['enable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing enable_sid file: {$suricatacfg['enable_sid_file']}\n"), 3, $log_file); + + // Attempt to open the 'enable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'enable_sid_file' \"{$suricatacfg['enable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) + error_log(gettext("Unable to open enable_sid file \"{$suricatacfg['enable_sid_file']}\".\n"), 3, $log_file); + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}"); + + if (!empty($sid_mods)) + $enables = suricata_get_auto_category_mods($enabled_cats, $sid_mods, "enable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['enable_sid_file']}\".\n"), 3, $log_file); + } + } + break; + + case "enable_disable": + if (!empty($suricatacfg['enable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing enable_sid file: {$suricatacfg['enable_sid_file']}\n"), 3, $log_file); + + // Attempt to open the 'enable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'enable_sid_file' \"{$suricatacfg['enable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) + error_log(gettext("Unable to open enable_sid file \"{$suricatacfg['enable_sid_file']}\".\n"), 3, $log_file); + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}"); + + if (!empty($sid_mods)) + $enables = suricata_get_auto_category_mods($enabled_cats, $sid_mods, "enable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['enable_sid_file']}\".\n"), 3, $log_file); + } + } + if (!empty($suricatacfg['disable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing disable_sid file: {$suricatacfg['disable_sid_file']}\n"), 3, $log_file); + + // Attempt to open the 'disable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'disable_sid_file' \"{$suricatacfg['disable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) + error_log(gettext("Unable to open disable_sid file \"{$suricatacfg['disable_sid_file']}\".\n"), 3, $log_file); + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}"); + + if (!empty($sid_mods)) + $disables = suricata_get_auto_category_mods($enabled_cats, $sid_mods, "disable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['disable_sid_file']}\".\n"), 3, $log_file); + } + } + break; + + default: + log_error(gettext("[Suricata] Unrecognized 'sid_state_order' value. Skipping auto CATEGORY mgmt step for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) { + error_log(gettext("ERROR: unrecognized 'sid_state_order' value. Skipping auto CATEGORY mgmt step for ") . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']). ".\n", 3, $log_file); + } + } + + if ($log_results == TRUE) { + error_log(gettext("End Time: " . date("Y-m-d H:i:s") . "\n"), 3, $log_file); + error_log(gettext("********************************************************\n\n"), 3, $log_file); + } + + // Return the required rule category modifications as an array; + return array_merge($enables, $disables); +} + +function suricata_get_auto_category_mods($categories, $sid_mods, $action, $log_results = FALSE, $log_file = NULL) { + + /****************************************************/ + /* This function parses the provided SID mod tokens */ + /* in $sid_mods and returns an array of category */ + /* files that must be added ('enabled') or removed */ + /* ('disabled') from the provided $categories list */ + /* of enabled rule categories as determined by the */ + /* content of the SID Mgmt tokens in $sid_mods. */ + /* */ + /* The returned array shows which files should be */ + /* removed and which should be added to the list */ + /* used when building the enforcing ruleset. */ + /* */ + /* $categories ==> array of currently enabled */ + /* ruleset categories */ + /* $sid_mods ==> array of SID modification */ + /* tokens */ + /* $action ==> modification action for */ + /* matching category targets: */ + /* 'enable' or 'disable' */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename of log */ + /* file to write to */ + /* */ + /* Returns ==> array of category file names */ + /* for the interface. The keys */ + /* are category file names and */ + /* the corresponding values show */ + /* if the file should be added */ + /* or removed from the enabled */ + /* rulesets list. */ + /* */ + /* Example - */ + /* $changes[file] = 'enabled' */ + /* */ + /****************************************************/ + + $suricatadir = SURICATADIR; + $all_cats = array(); + $changes = array(); + $counter = 0; + $matchcount = 0; + + // Get a list of all possible categories by loading all rules files + foreach (array( VRT_FILE_PREFIX, ET_OPEN_FILE_PREFIX, ET_PRO_FILE_PREFIX, GPL_FILE_PREFIX ) as $prefix) { + $files = glob("{$suricatadir}rules/{$prefix}*.rules"); + foreach ($files as $file) + $all_cats[] = basename($file); + } + + // Walk the SID mod tokens and decode looking for rule + // category enable/disable changes. + foreach ($sid_mods as $tok) { + $matches = array(); + // Test the SID token for a GID:SID range and skip if true + if (preg_match('/^(\d+):(\d+)-\1:(\d+)/', $tok)) + continue; + // Test the token for a single GID:SID and skip if true + elseif (preg_match('/^(\d+):(\d+)$/', $tok)) + continue; + // Test the token for the PCRE: keyword and skip if true + elseif (preg_match('/(^pcre\:)(.+)/i', $tok)) + continue; + // Test the token for the MS reference keyword and skip if true + elseif (preg_match('/^MS\d+-.+/i', $tok)) + continue; + // Test the token for other keywords delimited with a colon and skip if true + elseif (preg_match('/^[a-xA-X]+\:.+/', $tok)) + continue; + // Test the SID token for a rule category name. Anything that + // failed to match above is considered a potential category name. + elseif (preg_match('/[a-xA-X]+(-|\w).*/', $tok, $matches)) { + $counter++; + $regex = "/" . preg_quote(trim($matches[0]), '/') . "/i"; + // Search through the $all_cats array for any matches to the regex + $matches = preg_grep($regex, $all_cats); + + // See if any matches are in the $categories array + foreach ($matches as $cat) { + switch ($action) { + case 'enable': + if (!isset($changes[$cat])) { + $changes[$cat] = 'enabled'; + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext(" Enabled rule category: {$cat}\n"), 3, $log_file); + $matchcount++; + } + break; + + case 'disable': + if (!isset($changes[$cat])) { + $changes[$cat] = 'disabled'; + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext(" Disabled rule category: {$cat}\n"), 3, $log_file); + $matchcount++; + } + break; + + default: + break; + } + } + } + else { + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext("WARNING: unrecognized token '{$tok}' encountered while processing an automatic SID MGMT file.\n"), 3, $log_file); + } + } + + if ($log_results == TRUE && !empty($log_file)) { + error_log(gettext(" Parsed {$counter} potential Rule Categories to match from the list of tokens.\n"), 3, $log_file); + error_log(gettext(" " . ucfirst($action) . "d {$matchcount} matching Rule Categories.\n"), 3, $log_file); + } + + // Release memory no longer needed + unset($all_cats, $matches); + + // Return array of rule category file changes + return $changes; +} + +function suricata_modify_sid_state(&$rule_map, $sid_mods, $action, $log_results = FALSE, $log_file = NULL) { + + /**********************************************/ + /* This function walks the provided array of */ + /* SID modification tokens and locates the */ + /* target SID or SIDs in the $rule_map array. */ + /* It then performs the change specified by */ + /* $action on the target SID or SIDs. */ + /* */ + /* $rule_map ==> reference to array of */ + /* current rules */ + /* $sid_mods ==> array of SID modification */ + /* tokens */ + /* $action ==> modification action for */ + /* matching SID targets: */ + /* 'enable' or 'disable' */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename */ + /* of log file to write to */ + /* */ + /* On Return ==> $rule_map array modified */ + /* by changing state for */ + /* matching SIDs. */ + /* */ + /* Returns a two-dimension */ + /* array of matching GID:SID */ + /* pairs. */ + /**********************************************/ + + $sids = array(); + + // If no rules in $rule_map or mods in $sid_mods, + // then nothing to do. + if (empty($rule_map) || empty($sid_mods)) + return $sids; + + // Validate the action keyword as we only accept + // 'enable' and 'disable' as valid. + switch ($action) { + + case "enable": + break; + + case "disable": + break; + + default: + log_error(gettext("[Suricata] Error - unknown action '{$action}' supplied to suricata_modify_sid_state() function...no SIDs modified.")); + return $sids; + } + + // Walk the SID mod tokens and decode each one + foreach ($sid_mods as $tok) { + $matches = array(); + // Test the SID token for a GID:SID range + if (preg_match('/^(\d+):(\d+)-\1:(\d+)/', $tok, $matches)) { + // It was a range, so find all the intervening SIDs + $gid = trim($matches[1]); + $lsid = trim($matches[2]); + $usid = trim($matches[3]); + $sids[$gid][$lsid] = $action; + while ($lsid < $usid) { + $lsid++; + $sids[$gid][$lsid] = $action; + } + } + // Test the SID token for a single GID:SID + elseif (preg_match('/^(\d+):(\d+)$/', $tok, $matches)) { + // It's a single GID:SID, so grab it + $sids[$matches[1]][$matches[2]] = $action; + } + // Test the SID token for the PCRE: keyword + elseif (preg_match('/(^pcre\:)(.+)/i', $tok, $matches)) { + $regex = '/' . preg_quote($matches[2], '/') . '/i'; + + // Now search through the $rule_map in the 'rule' + // element for any matches to the regex and get + // the GID:SID. + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (preg_match($regex, $v['rule'])) { + $sids[$k1][$k2] = $action; + } + } + } + } + // Test the SID token for the MS reference keyword + elseif (preg_match('/^MS\d+-.+/i', $tok, $matches)) { + $regex = "/" . preg_quote($matches[0], '/') . "/i"; + + // Now search through the $rule_map in the 'rule' + // element for any matches to the regex and get + // the GID:SID. + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (preg_match($regex, $v['rule'])) { + $sids[$k1][$k2] = $action; + } + } + } + } + // Test the SID token for other keywords delimited with a colon + elseif (preg_match('/^[a-xA-X]+\:.+/', $tok, $matches)) { + $regex = "/" . str_replace(':', ",", preg_quote($matches[0], '/')) . "/i"; + + // Now search through the $rule_map in the 'rule' + // element for any matches to the regex and get + // the GID:SID. + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (preg_match($regex, $v['rule'])) { + $sids[$k1][$k2] = $action; + } + } + } + } + // Test the SID token for a rule category name. Anything that + // failed to match above is considered a potential category name. + elseif (preg_match('/[a-xA-X]+(-|\w).*/', $tok, $matches)) { + $regex = "/" . preg_quote(trim($matches[0]), '/') . "/i"; + // Now search through the $rule_map in the 'category' + // element for any matches to the regex and get + // the GID:SID. + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (preg_match($regex, $v['category'] . ".rules")) { + $sids[$k1][$k2] = $action; + } + } + } + } + else { + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext("WARNING: unrecognized token '{$tok}' encountered while processing an automatic SID MGMT file.\n"), 3, $log_file); + } + } + + // Change state of all the matching GID:SID pairs we found + // above in the $rule_map array passed to us. + $modcount = $changecount = 0; + $counter = count($sids, COUNT_RECURSIVE) - count($sids); + + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext(" Parsed {$counter} potential SIDs to match from the provided list of tokens.\n"), 3, $log_file); + + foreach (array_keys($sids) as $k1) { + foreach (array_keys($sids[$k1]) as $k2) { + if (isset($rule_map[$k1][$k2])) { + if ($action == 'enable' && $rule_map[$k1][$k2]['disabled'] == 1) { + $rule_map[$k1][$k2]['rule'] = ltrim($rule_map[$k1][$k2]['rule'], " \t#"); + $rule_map[$k1][$k2]['disabled'] = 0; + $rule_map[$k1][$k2]['managed'] = 1; + $changecount++; + $modcount++; + } + elseif ($action == 'disable' && $rule_map[$k1][$k2]['disabled'] == 0) { + $rule_map[$k1][$k2]['rule'] = "# " . $rule_map[$k1][$k2]['rule']; + $rule_map[$k1][$k2]['disabled'] = 1; + $rule_map[$k1][$k2]['managed'] = 1; + $changecount++; + $modcount++; + } + } + } + } + + if ($log_results == TRUE && !empty($log_file)) { + error_log(gettext(" Found {$modcount} matching SIDs in the active rules.\n"), 3, $log_file); + error_log(gettext(" Changed state for {$changecount} SIDs to '{$action}d'.\n"), 3, $log_file); + } + + // Return the array of matching SIDs + return $sids; +} + +function suricata_modify_sid_content(&$rule_map, $sid_mods, $log_results = FALSE, $log_file = NULL) { + + /************************************************/ + /* This function walks the provided array of */ + /* SID modification tokens and locates the */ + /* target SID or SIDs in the $rule_map array. */ + /* It then modifies the content of the target */ + /* SID or SIDs. Modifications are only valid */ + /* for normal GID=1 text rules. */ + /* */ + /* $rule_map ==> reference to array of */ + /* current rules */ + /* $sid_mods ==> array of SID modification */ + /* tokens */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename */ + /* of log file to write to */ + /* */ + /* On Return ==> $rule_map array modified */ + /* by changing content for */ + /* matching SIDs. */ + /* */ + /* Returns a two-dimension */ + /* array of matching */ + /* GID:SID pairs. */ + /************************************************/ + + $sids = array(); + $tokencounter = $modcount = $modifiedcount = 0; + + // If no rules in $rule_map or mods in $sid_mods, + // then nothing to do. + if (empty($rule_map) || empty($sid_mods)) + return $sids; + + // Walk the SID mod tokens and decode each one + foreach ($sid_mods as $tok) { + $matches = array(); + if (preg_match('/([\d+|,|\*]*)\s+"(.+)"\s+"(.*)"/', $tok, $matches)) { + $tokencounter++; + $sidlist = explode(",", $matches[1]); + $from = '/' . preg_quote($matches[2], '/') . '/'; + $to = $matches[3]; + $count = 0; + + // Now walk the provided rule map and make the modifications + if ($matches[1] == "*") { + // If wildcard '*' provided for SID, then check them all + foreach ($rule_map[1] as $rulem) { + foreach ($rulem as $k2 => $v) { + $modcount++; + $rule_map[1][$k2]['rule'] = preg_replace($from, $to, $v['rule'], -1, $count); + if ($count > 0) { + $rule_map[1][$k2]['managed'] = 1; + $sids[1][$k2] = 'modify'; + $modifiedcount++; + } + } + } + } + else { + // Otherwise just check the provided SIDs + foreach ($sidlist as $sid) { + if (isset($rule_map[1][$sid])) { + $modcount++; + $rule_map[1][$sid]['rule'] = preg_replace($from, $to, $rule_map[1][$sid]['rule'], -1, $count); + if ($count > 0) { + $rule_map[1][$sid]['managed'] = 1; + $sids[1][$sid] = 'modify'; + $modifiedcount++; + } + } + } + } + } + else { + if ($log_results == TRUE && !empty($log_file)) + error_log(gettext("WARNING: unrecognized token '{$tok}' encountered while processing an automatic SID MGMT file.\n"), 3, $log_file); + } + } + + if ($log_results == TRUE && !empty($log_file)) { + error_log(gettext(" Parsed {$tokencounter} potential SIDs to match from the provided list of tokens.\n"), 3, $log_file); + error_log(gettext(" Found {$modcount} matching SIDs in the active rules.\n"), 3, $log_file); + error_log(gettext(" Modified rule text for {$modifiedcount} SIDs.\n"), 3, $log_file); + } + + // Return the array of matching SIDs + return $sids; +} + +function suricata_process_enablesid(&$rule_map, $suricatacfg, $log_results = FALSE, $log_file = NULL) { + + /**********************************************/ + /* This function loads and processes the file */ + /* specified by 'enable_sid_file' for the */ + /* interface. The file is assumed to be a */ + /* valid enablesid.conf file containing */ + /* instructions for enabling matching rule */ + /* SIDs. */ + /* */ + /* $rule_map ==> reference to array of */ + /* current rules */ + /* $suricatacfg ==> interface config params */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename */ + /* of log file to write to */ + /* */ + /* On Return ==> suitably modified */ + /* $rule_map array */ + /**********************************************/ + + $suricata_sidmods_dir = SURICATA_SID_MODS_PATH; + $suricatalogdir = SURICATALOGDIR; + $sid_mods = array(); + + // If no rules in $rule_map, then nothing to do + if (empty($rule_map)) + return; + + // Attempt to open the 'enable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'enable_sid_file' \"{$suricatacfg['enable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + return; + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['enable_sid_file']}"); + + if (!empty($sid_mods)) + suricata_modify_sid_state($rule_map, $sid_mods, "enable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['enable_sid_file']}\".\n"), 3, $log_file); + } + + unset($sid_mods); +} + +function suricata_process_disablesid(&$rule_map, $suricatacfg, $log_results = FALSE, $log_file = NULL) { + + /**********************************************/ + /* This function loads and processes the file */ + /* specified by 'disable_sid_file' for the */ + /* interface. The file is assumed to be a */ + /* valid disablesid.conf file containing */ + /* instructions for disabling matching rule */ + /* SIDs. */ + /* */ + /* $rule_map ==> reference to array of */ + /* current rules */ + /* $suricatacfg ==> interface config params */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename */ + /* of log file to write to */ + /* */ + /* On Return ==> suitably modified */ + /* $rule_map array */ + /**********************************************/ + + $suricata_sidmods_dir = SURICATA_SID_MODS_PATH; + $suricatalogdir = SURICATALOGDIR; + $sid_mods = array(); + + // If no rules in $rule_map, then nothing to do + if (empty($rule_map)) + return; + + // Attempt to open the 'disable_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'disable_sid_file' \"{$suricatacfg['disable_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + return; + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['disable_sid_file']}"); + + if (!empty($sid_mods)) + suricata_modify_sid_state($rule_map, $sid_mods, "disable", $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['disable_sid_file']}\".\n"), 3, $log_file); + } + + unset($sid_mods); +} + +function suricata_process_modifysid(&$rule_map, $suricatacfg, $log_results = FALSE, $log_file = NULL) { + + /**********************************************/ + /* This function loads and processes the file */ + /* specified by 'modify_sid_file' for the */ + /* interface. The file is assumed to be a */ + /* valid modifysid.conf file containing */ + /* instructions for modifying matching rule */ + /* SIDs. */ + /* */ + /* $rule_map ==> reference to array of */ + /* current rules */ + /* $suricatacfg ==> interface config params */ + /* $log_results ==> [optional] 'yes' to log */ + /* results to $log_file */ + /* $log_file ==> full path and filename */ + /* of log file to write to */ + /* */ + /* On Return ==> suitably modified */ + /* $rule_map array */ + /**********************************************/ + + $suricata_sidmods_dir = SURICATA_SID_MODS_PATH; + $suricatalogdir = SURICATALOGDIR; + $sid_mods = array(); + + // If no rules in $rule_map, then nothing to do + if (empty($rule_map)) + return; + + // Attempt to open the 'modify_sid_file' for the interface + if (!file_exists("{$suricata_sidmods_dir}{$suricatacfg['modify_sid_file']}")) { + log_error(gettext("[Suricata] Error - unable to open 'modify_sid_file' \"{$suricatacfg['modify_sid_file']}\" specified for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + return; + } + else + $sid_mods = suricata_parse_sidconf_file("{$suricata_sidmods_dir}{$suricatacfg['modify_sid_file']}"); + + if (!empty($sid_mods)) + suricata_modify_sid_content($rule_map, $sid_mods, $log_results, $log_file); + elseif ($log_results == TRUE && !empty($log_file)) { + error_log(gettext("WARNING: no valid SID match tokens found in file \"{$suricatacfg['modify_sid_file']}\".\n"), 3, $log_file); + } + + unset($sid_mods); +} + +function suricata_auto_sid_mgmt(&$rule_map, $suricatacfg, $log_results = FALSE) { + + /**************************************************/ + /* This function modifies the rules in the */ + /* passed rule_map array based on values in the */ + /* files 'enable_sid_file', 'disable_sid_file' */ + /* and 'modify_sid_file' for the interface. */ + /* */ + /* If auto-mgmt of SIDs is enabled via the */ + /* settings on the UPDATE RULES tab, then the */ + /* rules are processed against these settings. */ + /* */ + /* $rule_map ==> array of current rules */ + /* $suricatacfg ==> interface config settings */ + /* $log_results ==> [optional] log results to */ + /* 'sid_changes.log' in the */ + /* interface directory in */ + /* /var/log/suricata when TRUE */ + /* */ + /* Returns ==> TRUE if rules were changed; */ + /* otherwise FALSE */ + /**************************************************/ + + global $config; + $result = FALSE; + + // Configure the interface's logging subdirectory if log results is enabled + if ($log_results == TRUE) + $log_file = SURICATALOGDIR . $suricatalogdir . "suricata_" . get_real_interface($suricatacfg['interface']) . "{$suricatacfg['uuid']}/sid_changes.log"; + else + $log_file = NULL; + + // Check if auto-mgmt of SIDs is enabled and files are specified + // for the interface. + if ($config['installedpackages']['suricata']['config'][0]['auto_manage_sids'] == 'on' && + (!empty($suricatacfg['disable_sid_file']) || !empty($suricatacfg['enable_sid_file']) || + !empty($suricatacfg['modify_sid_file']))) { + if ($log_results == TRUE) { + error_log(gettext("********************************************************\n"), 3, $log_file); + error_log(gettext("Starting auto SID management for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) ."\n"), 3, $log_file); + error_log(gettext("Start Time: " . date("Y-m-d H:i:s") . "\n"), 3, $log_file); + } + + switch ($suricatacfg['sid_state_order']) { + case "disable_enable": + if (!empty($suricatacfg['disable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing disable_sid file: {$suricatacfg['disable_sid_file']}\n"), 3, $log_file); + suricata_process_disablesid($rule_map, $suricatacfg, $log_results, $log_file); + } + if (!empty($suricatacfg['enable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing enable_sid file: {$suricatacfg['enable_sid_file']}\n"), 3, $log_file); + suricata_process_enablesid($rule_map, $suricatacfg, $log_results, $log_file); + } + if (!empty($suricatacfg['modify_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing modify_sid file: {$suricatacfg['modify_sid_file']}\n"), 3, $log_file); + suricata_process_modifysid($rule_map, $suricatacfg, $log_results, $log_file); + } + $result = TRUE; + break; + + case "enable_disable": + if (!empty($suricatacfg['enable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing enable_sid file: {$suricatacfg['enable_sid_file']}\n"), 3, $log_file); + suricata_process_enablesid($rule_map, $suricatacfg, $log_results, $log_file); + } + if (!empty($suricatacfg['disable_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing disable_sid file: {$suricatacfg['disable_sid_file']}\n"), 3, $log_file); + suricata_process_disablesid($rule_map, $suricatacfg, $log_results, $log_file); + } + if (!empty($suricatacfg['modify_sid_file'])) { + if ($log_results == TRUE) + error_log(gettext("Processing modify_sid file: {$suricatacfg['modify_sid_file']}\n"), 3, $log_file); + suricata_process_modifysid($rule_map, $suricatacfg, $log_results, $log_file); + } + $result = TRUE; + break; + + default: + log_error(gettext("[Suricata] Unrecognized 'sid_state_order' value. Skipping auto SID mgmt step for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']))); + if ($log_results == TRUE) { + error_log(gettext("ERROR: unrecognized 'sid_state_order' value. Skipping auto SID mgmt step for ") . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']). ".\n", 3, $log_file); + } + $result = FALSE; + } + + if ($log_results == TRUE) { + error_log(gettext("End Time: " . date("Y-m-d H:i:s") . "\n"), 3, $log_file); + error_log(gettext("********************************************************\n\n"), 3, $log_file); + } + } + return $result; +} + function suricata_load_sid_mods($sids) { /*****************************************/ @@ -1572,15 +2575,15 @@ function suricata_load_sid_mods($sids) { function suricata_modify_sids(&$rule_map, $suricatacfg) { - /*****************************************/ - /* This function modifies the rules in */ - /* the passed rules_map array based on */ - /* values in the enablesid/disablesid */ - /* configuration parameters. */ - /* */ - /* $rule_map = array of current rules */ - /* $suricatacfg = config settings */ - /*****************************************/ + /***********************************************/ + /* This function modifies the rules in the */ + /* passed rules_map array based on values in */ + /* the enablesid/disablesid configuration */ + /* parameters for the interface. */ + /* */ + /* $rule_map = array of current rules */ + /* $suricatacfg = interface config settings */ + /***********************************************/ if (!isset($suricatacfg['rule_sid_on']) && !isset($suricatacfg['rule_sid_off'])) @@ -1634,11 +2637,15 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { /* to be written. */ /***********************************************************/ - global $rebuild_rules; + global $config, $rebuild_rules; $suricatadir = SURICATADIR; $flowbit_rules_file = FLOWBITS_FILENAME; - $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME; + $suricata_enforcing_rules_file = SURICATA_ENFORCING_RULES_FILENAME; + $enabled_rules = array(); + $enabled_files = array(); + $all_rules = array(); + $cat_mods = array(); $no_rules_defined = true; // If there is no reason to rebuild the rules, exit to save time. @@ -1648,11 +2655,12 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { // Log a message for rules rebuild in progress log_error(gettext("[Suricata] Updating rules configuration for: " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . " ...")); + // Get any automatic rule category enable/disable modifications + // if auto-SID Mgmt is enabled and conf files exist for the interface. + $cat_mods = suricata_sid_mgmt_auto_categories($suricatacfg, TRUE); + // Only rebuild rules if some are selected or an IPS Policy is enabled - if (!empty($suricatacfg['rulesets']) || $suricatacfg['ips_policy_enable'] == 'on') { - $enabled_rules = array(); - $enabled_files = array(); - $all_rules = array(); + if (!empty($suricatacfg['rulesets']) || $suricatacfg['ips_policy_enable'] == 'on' || !empty($cat_mods)) { $no_rules_defined = false; // Load up all the rules into a Rules Map array. @@ -1660,12 +2668,37 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { // Create an array with the filenames of the enabled // rule category files if we have any. - if (!empty($suricatacfg['rulesets'])) { - foreach (explode("||", $suricatacfg['rulesets']) as $file){ - $category = basename($file, ".rules"); - if (!is_array($enabled_files[$category])) - $enabled_files[$category] = array(); - $enabled_files[$category] = $file; + if (!empty($suricatacfg['rulesets']) || !empty($cat_mods)) { + // First get all the user-enabled category files + if (!empty($suricatacfg['rulesets'])) { + foreach (explode("||", $suricatacfg['rulesets']) as $file){ + $category = basename($file, ".rules"); + if (!is_array($enabled_files[$category])) + $enabled_files[$category] = array(); + $enabled_files[$category] = $file; + } + } + + // Now adjust the list using any required changes as + // determined by auto-SID Mgmt policy files. + if (!empty($cat_mods)) { + foreach ($cat_mods as $k => $action) { + $key = basename($k, ".rules"); + switch ($action) { + case 'enabled': + if (!isset($enabled_files[$key])) + $enabled_files[$key] = $k; + break; + + case 'disabled': + if (isset($enabled_files[$key])) + unset($enabled_files[$key]); + break; + + default: + break; + } + } } /****************************************************/ @@ -1689,7 +2722,7 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { } // Release memory we no longer need. - unset($enabled_files, $rulem, $v); + unset($enabled_files, $cat_mods, $rulem, $v); } // Check if a pre-defined Snort VRT policy is selected. If so, @@ -1712,6 +2745,8 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { } // Process any enablesid or disablesid modifications for the selected rules. + // Do the auto-SID managment first, if enabled, then do any manual SID state changes. + suricata_auto_sid_mgmt($enabled_rules, $suricatacfg, TRUE); suricata_modify_sids($enabled_rules, $suricatacfg); // Write the enforcing rules file to the Suricata interface's "rules" directory. @@ -1730,7 +2765,45 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { } else // Just put an empty file to always have the file present suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); - } else { + unset($all_rules); + } + // If no rule categories were enabled, then use auto-SID management if enabled, since it may enable some rules + elseif ($config['installedpackages']['suricata']['config'][0]['auto_manage_sids'] == 'on' && + (!empty($suricatacfg['disable_sid_file']) || !empty($suricatacfg['enable_sid_file']) || + !empty($suricatacfg['modify_sid_file']))) { + + suricata_auto_sid_mgmt($enabled_rules, $suricatacfg, TRUE); + if (!empty($enabled_rules)) { + // Auto-SID management generated some rules, so use them + $no_rules_defined = false; + suricata_modify_sids($enabled_rules, $suricatacfg); + + // Write the enforcing rules file to the Suricata interface's "rules" directory. + suricata_write_enforcing_rules_file($enabled_rules, "{$suricatacfgdir}/rules/{$suricata_enforcing_rules_file}"); + + // If auto-flowbit resolution is enabled, generate the dependent flowbits rules file. + if ($suricatacfg['autoflowbitrules'] == 'on') { + log_error('[Suricata] Enabling any flowbit-required rules for: ' . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . '...'); + + // Load up all rules into a Rules Map array for flowbits assessment + $all_rules = suricata_load_rules_map("{$suricatadir}rules/"); + $fbits = suricata_resolve_flowbits($all_rules, $enabled_rules); + + // Check for and disable any flowbit-required rules the + // user has manually forced to a disabled state. + suricata_modify_sids($fbits, $suricatacfg); + suricata_write_flowbit_rules_file($fbits, "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + unset($all_rules, $fbits); + } else + // Just put an empty file to always have the file present + suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + } + else { + suricata_write_enforcing_rules_file(array(), "{$suricatacfgdir}/rules/{$suricata_enforcing_rules_file}"); + suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + } + } + else { suricata_write_enforcing_rules_file(array(), "{$suricatacfgdir}/rules/{$suricata_enforcing_rules_file}"); suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); } @@ -1748,7 +2821,7 @@ function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { // Build a new sid-msg.map file from the enabled // rules and copy it to the interface directory. - log_error(gettext("[Suricata] Building new sig-msg.map file for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . "...")); + log_error(gettext("[Suricata] Building new sid-msg.map file for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . "...")); suricata_build_sid_msg_map("{$suricatacfgdir}/rules/", "{$suricatacfgdir}/sid-msg.map"); } @@ -1767,7 +2840,7 @@ function suricata_write_enforcing_rules_file($rule_map, $rule_path) { /* rules file will be written. */ /************************************************/ - $rule_file = "/" . ENFORCING_RULES_FILENAME; + $rule_file = "/" . SURICATA_ENFORCING_RULES_FILENAME; // See if we were passed a directory or full // filename to write the rules to, and adjust @@ -1816,6 +2889,7 @@ function suricata_create_rc() { $suricatadir = SURICATADIR; $suricatalogdir = SURICATALOGDIR; + $suricatabindir = SURICATA_PBI_BINDIR; $rcdir = RCFILEPREFIX; // If no interfaces are configured for Suricata, exit @@ -1833,7 +2907,7 @@ function suricata_create_rc() { // the shell script. foreach ($suricataconf as $value) { // Skip disabled Suricata interfaces - if ($value['enable'] <> 'on') + if ($value['enable'] != 'on') continue; $suricata_uuid = $value['uuid']; $if_real = get_real_interface($value['interface']); @@ -1846,14 +2920,10 @@ function suricata_create_rc() { pid=`/bin/pgrep -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid` fi - if [ ! -z \$pid ]; then - /usr/bin/logger -p daemon.info -i -t SuricataStartup "Barnyard2 SOFT RESTART for {$value['descr']}({$suricata_uuid}_{$if_real})..." - /bin/pkill -HUP \$pid - else + if [ -z \$pid ]; then /usr/bin/logger -p daemon.info -i -t SuricataStartup "Barnyard2 START for {$value['descr']}({$suricata_uuid}_{$if_real})..." - /usr/local/bin/barnyard2 -r {$suricata_uuid} -f unified2.alert --pid-path {$g['varrun_path']} --nolock-pidfile -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/barnyard2.conf -d {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} -D -q + {$suricatabindir}/barnyard2 -r {$suricata_uuid} -f unified2.alert --pid-path {$g['varrun_path']} --nolock-pidfile -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/barnyard2.conf -d {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} -D -q > /dev/null 2>&1 fi - EOE; $stop_barnyard2 = <<<EOE @@ -1869,8 +2939,8 @@ EOE; break fi done - if [ -f /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then - /bin/rm /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid + if [ -f {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then + /bin/rm {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid fi else pid=`/bin/pgrep -fn "barnyard2 -r {$suricata_uuid} "` @@ -1886,7 +2956,6 @@ EOE; done fi fi - EOE; if ($value['barnyard_enable'] == 'on') $start_barnyard2 = $start_barnyard; @@ -1895,25 +2964,20 @@ EOE; $start_suricata_iface_start[] = <<<EOE -###### For Each Iface - # Start suricata and barnyard2 + ## Start suricata on {$value['descr']} ({$if_real}) ## if [ ! -f {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid ]; then pid=`/bin/pgrep -fn "suricata -i {$if_real} "` else pid=`/bin/pgrep -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid` fi - if [ ! -z \$pid ]; then - /usr/bin/logger -p daemon.info -i -t SuricataStartup "Suricata SOFT RESTART for {$value['descr']}({$suricata_uuid}_{$if_real})..." - /bin/pkill -USR2 \$pid - else + if [ -z \$pid ]; then /usr/bin/logger -p daemon.info -i -t SuricataStartup "Suricata START for {$value['descr']}({$suricata_uuid}_{$if_real})..." - /usr/local/bin/suricata -i {$if_real} -D -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/suricata.yaml --pidfile {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid + {$suricatabindir}suricata -i {$if_real} -D -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/suricata.yaml --pidfile {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid > /dev/null 2>&1 fi - sleep 2 + sleep 1 {$start_barnyard2} - EOE; $start_suricata_iface_stop[] = <<<EOE @@ -1930,8 +2994,8 @@ EOE; break fi done - if [ -f /var/run/suricata_{$if_real}{$suricata_uuid}.pid ]; then - /bin/rm /var/run/suricata_{$if_real}{$suricata_uuid}.pid + if [ -f {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid ]; then + /bin/rm {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid fi else pid=`/bin/pgrep -fn "suricata -i {$if_real} "` @@ -1949,9 +3013,8 @@ EOE; fi fi - sleep 2 + sleep 1 {$stop_barnyard2} - EOE; } @@ -1966,7 +3029,15 @@ EOE; ######## Start of main suricata.sh rc_start() { + + ### Lock out other start signals until we are done + /usr/bin/touch {$g['varrun_path']}/suricata_pkg_starting.lck {$rc_start} + + ### Remove the lock since we have started all interfaces + if [ -f {$g['varrun_path']}/suricata_pkg_starting.lck ]; then + /bin/rm {$g['varrun_path']}/suricata_pkg_starting.lck + fi } rc_stop() { @@ -1975,7 +3046,11 @@ rc_stop() { case $1 in start) - rc_start + if [ ! -f {$g['varrun_path']}/suricata_pkg_starting.lck ]; then + rc_start + else + /usr/bin/logger -p daemon.info -i -t SuricataStartup "Ignoring additional START command since Suricata is already starting..." + fi ;; stop) rc_stop @@ -1989,8 +3064,8 @@ esac EOD; // Write out the suricata.sh script file - @file_put_contents("{$rcdir}/suricata.sh", $suricata_sh_text); - @chmod("{$rcdir}/suricata.sh", 0755); + @file_put_contents("{$rcdir}suricata.sh", $suricata_sh_text); + @chmod("{$rcdir}suricata.sh", 0755); unset($suricata_sh_text); } @@ -2051,7 +3126,7 @@ function suricata_generate_barnyard2_conf($suricatacfg, $if_real) { $suricatabarnyardlog_output_plugins .= "# syslog_full: log to a syslog receiver\n"; $suricatabarnyardlog_output_plugins .= "output alert_syslog_full: sensor_name {$suricatabarnyardlog_hostname_info_chk}, "; if ($suricatacfg['barnyard_syslog_local'] == 'on') - $suricatabarnyardlog_output_plugins .= "local, log_facility LOG_AUTH, log_priority LOG_INFO\n\n"; + $suricatabarnyardlog_output_plugins .= "local, log_facility {$suricatacfg['barnyard_syslog_facility']}, log_priority {$suricatacfg['barnyard_syslog_priority']}\n\n"; else { $suricatabarnyardlog_output_plugins .= "server {$suricatacfg['barnyard_syslog_rhost']}, protocol {$suricatacfg['barnyard_syslog_proto']}, "; $suricatabarnyardlog_output_plugins .= "port {$suricatacfg['barnyard_syslog_dport']}, operation_mode {$suricatacfg['barnyard_syslog_opmode']}, "; @@ -2126,30 +3201,296 @@ function suricata_generate_yaml($suricatacfg) { $suricatadir = SURICATADIR; $suricatalogdir = SURICATALOGDIR; $flowbit_rules_file = FLOWBITS_FILENAME; - $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME; + $suricata_enforcing_rules_file = SURICATA_ENFORCING_RULES_FILENAME; $if_real = get_real_interface($suricatacfg['interface']); $suricata_uuid = $suricatacfg['uuid']; $suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}"; - conf_mount_rw(); - if (!is_array($config['installedpackages']['suricata']['rule'])) return; // Pull in the PHP code that generates the suricata.yaml file // variables that will be substitued further down below. - include("/usr/local/www/suricata/suricata_generate_yaml.php"); + include("/usr/local/pkg/suricata/suricata_generate_yaml.php"); // Pull in the boilerplate template for the suricata.yaml // configuration file. The contents of the template along - // with substituted variables is stored in $suricata_conf_text + // with substituted variables are stored in $suricata_conf_text // (which is defined in the included file). include("/usr/local/pkg/suricata/suricata_yaml_template.inc"); // Now write out the conf file using $suricata_conf_text contents @file_put_contents("{$suricatacfgdir}/suricata.yaml", $suricata_conf_text); unset($suricata_conf_text); +} + +/* Uses XMLRPC to synchronize the changes to a remote node */ +function suricata_sync_on_changes() { + global $config, $g; + + /* Do not attempt a package sync while booting up or installing package */ + if ($g['booting'] || $g['suricata_postinstall'] == TRUE) { + log_error("[suricata] No xmlrpc sync to CARP targets when booting up or during package reinstallation."); + return; + } + + if (is_array($config['installedpackages']['suricatasync']['config'])){ + $suricata_sync=$config['installedpackages']['suricatasync']['config'][0]; + $synconchanges = $suricata_sync['varsynconchanges']; + $synctimeout = $suricata_sync['varsynctimeout']; + $syncdownloadrules = $suricata_sync['vardownloadrules']; + switch ($synconchanges){ + case "manual": + if (is_array($suricata_sync[row])){ + $rs=$suricata_sync[row]; + } + else{ + log_error("[suricata] xmlrpc CARP sync is enabled but there are no hosts configured as replication targets."); + return; + } + break; + case "auto": + if (is_array($config['installedpackages']['carpsettings']) && is_array($config['installedpackages']['carpsettings']['config'])){ + $system_carp=$config['installedpackages']['carpsettings']['config'][0]; + $rs[0]['varsyncipaddress']=$system_carp['synchronizetoip']; + $rs[0]['varsyncusername']=$system_carp['username']; + $rs[0]['varsyncpassword']=$system_carp['password']; + $rs[0]['varsyncsuricatastart']="no"; + if ($system_carp['synchronizetoip'] ==""){ + log_error("[suricata] xmlrpc CARP sync is enabled but there are no system backup hosts configured as replication targets."); + return; + } + } + else{ + log_error("[suricata] xmlrpc CARP sync is enabled but there are no system backup hosts configured as replication targets."); + return; + } + break; + default: + return; + break; + } + if (is_array($rs)){ + log_error("[suricata] Suricata pkg xmlrpc CARP sync is starting."); + foreach($rs as $sh){ + if ($sh['varsyncsuricatastart']) + $syncstartsuricata = $sh['varsyncsuricatastart']; + else + $syncstartsuricata = "OFF"; + $sync_to_ip = $sh['varsyncipaddress']; + $port = $sh['varsyncport']; + $password = $sh['varsyncpassword']; + if($sh['varsyncusername']) + $username = $sh['varsyncusername']; + else + $username = 'admin'; + if($password && $sync_to_ip) + suricata_do_xmlrpc_sync($syncdownloadrules, $sync_to_ip, $port, $username, $password, $synctimeout, $syncstartsuricata); + } + log_error("[suricata] Suricata pkg xmlrpc CARP sync completed."); + } + } +} + +/* Do the actual XMLRPC sync */ +function suricata_do_xmlrpc_sync($syncdownloadrules, $sync_to_ip, $port, $username, $password, $synctimeout = 150, $syncstartsuricata) { + global $config, $g; + + /* Do not attempt a package sync while booting up or installing package */ + if ($g['booting'] || isset($g['suricata_postinstall'])) { + log_error("[suricata] No xmlrpc sync to CARP targets when booting up or during package reinstallation."); + return; + } + + if($username == "" || $password == "" || $sync_to_ip == "") { + log_error("[suricata] A required XMLRPC CARP sync parameter (user, host IP or password) is empty ... aborting pkg sync"); + return; + } + + /* Test key variables and set defaults if empty */ + if(!$synctimeout) + $synctimeout=150; + + $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; + $url = $synchronizetoip; + + /*************************************************/ + /* Send over any auto-SID management files */ + /*************************************************/ + $sid_files = glob(SURICATA_SID_MODS_PATH . '*'); + foreach ($sid_files as $file) { + $content = base64_encode(file_get_contents($file)); + $payload = "@file_put_contents('{$file}', base64_decode('{$content}'));"; + + /* assemble xmlrpc payload */ + $method = 'pfsense.exec_php'; + $params = array( XML_RPC_encode($password), XML_RPC_encode($payload) ); + + log_error("[suricata] Suricata XMLRPC CARP sync sending auto-SID conf files to {$url}:{$port}."); + $msg = new XML_RPC_Message($method, $params); + $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port); + $cli->setCredentials($username, $password); + $resp = $cli->send($msg, $synctimeout); + $error = ""; + if(!$resp) { + $error = "A communications error occurred while attempting Suricata XMLRPC CARP sync with {$url}:{$port}. Failed to transfer file: " . basename($file); + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } elseif($resp->faultCode()) { + $error = "An error code was received while attempting Suricata XMLRPC CARP sync with {$url}:{$port}. Failed to transfer file: " . basename($file) . " - Code " . $resp->faultCode() . ": " . $resp->faultString(); + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } + } + + if (!empty($sid_files) && $error == "") + log_error("[suricata] Suricata pkg XMLRPC CARP sync auto-SID conf files success with {$url}:{$port} (pfsense.exec_php)."); + + /**************************************************/ + /* Send over the <suricata> portion of config.xml */ + /* $xml will hold the section to sync. */ + /**************************************************/ + $xml = array(); + $xml['suricata'] = $config['installedpackages']['suricata']; + /* assemble xmlrpc payload */ + $params = array( + XML_RPC_encode($password), + XML_RPC_encode($xml) + ); + + log_error("[suricata] Beginning Suricata pkg configuration 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($username, $password); + + /* send our XMLRPC message and timeout after defined sync timeout value*/ + $resp = $cli->send($msg, $synctimeout); + if(!$resp) { + $error = "A communications error occurred while attempting Suricata XMLRPC CARP sync with {$url}:{$port}."; + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } elseif($resp->faultCode()) { + $error = "An error code was received while attempting Suricata XMLRPC CARP sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } else { + log_error("[suricata] Suricata pkg configuration XMLRPC CARP sync successfully completed with {$url}:{$port}."); + } + + $downloadrulescmd = ""; + if ($syncdownloadrules == "yes") { + $downloadrulescmd = "log_error(gettext(\"[suricata] XMLRPC pkg CARP sync: Update of downloaded rule sets requested...\"));\n"; + $downloadrulescmd .= "\tinclude_once(\"/usr/local/pkg/suricata/suricata_check_for_rule_updates.php\");\n"; + } + $suricatastart = ""; + if ($syncstartsuricata == "ON") { + $suricatastart = "log_error(gettext(\"[suricata] XMLRPC pkg CARP sync: Checking Suricata status...\"));\n"; + $suricatastart .= "\tif (!is_process_running(\"suricata\")) {\n"; + $suricatastart .= "\t\tlog_error(gettext(\"[suricata] XMLRPC pkg CARP sync: Suricata not running. Sending a start command...\"));\n"; + $suricatastart .= "\t\t\$sh_script = RCFILEPREFIX . \"suricata.sh\";\n"; + $suricatastart .= "\t\tmwexec_bg(\"{\$sh_script} start\");\n\t}\n"; + $suricatastart .= "\telse {\n\t\tlog_error(gettext(\"[suricata] XMLRPC pkg CARP sync: Suricata is running...\"));\n\t}\n"; + } + + /*************************************************/ + /* Build a series of commands as a PHP file for */ + /* the secondary host to execute to load the new */ + /* settings. */ + /*************************************************/ + $suricata_sync_cmd = <<<EOD + <?php + require_once("/usr/local/pkg/suricata/suricata.inc"); + require_once("service-utils.inc"); + global \$g, \$rebuild_rules, \$suricata_gui_include, \$pkg_interface; + \$orig_pkg_interface = \$pkg_interface; + \$g["suricata_postinstall"] = true; + \$g["suricata_sync_in_progress"] = true; + \$suricata_gui_include = false; + \$pkg_interface = "console"; + {$downloadrulescmd} + unset(\$g["suricata_postinstall"]); + log_error(gettext("[suricata] XMLRPC pkg CARP sync: Generating suricata.yaml file using Master Host settings...")); + \$rebuild_rules = true; + conf_mount_rw(); + sync_suricata_package_config(); conf_mount_ro(); + \$rebuild_rules = false; + {$suricatastart} + log_error(gettext("[suricata] XMLRPC pkg CARP sync process on this host is complete...")); + \$pkg_interface = \$orig_pkg_interface; + unset(\$g["suricata_sync_in_progress"]); + return true; + ?> + +EOD; + + /*************************************************/ + /* First, have target host write the commands */ + /* to a PHP file in the /tmp directory. */ + /*************************************************/ + $execcmd = "file_put_contents('/tmp/suricata_sync_cmds.php', '{$suricata_sync_cmd}');"; + + /* assemble xmlrpc payload */ + $method = 'pfsense.exec_php'; + $params = array( + XML_RPC_encode($password), + XML_RPC_encode($execcmd) + ); + + log_error("[suricata] Suricata XMLRPC CARP sync 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); + $resp = $cli->send($msg, $synctimeout); + if(!$resp) { + $error = "A communications error occurred while attempting Suricata XMLRPC CARP sync with {$url}:{$port} (pfsense.exec_php)."; + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } elseif($resp->faultCode()) { + $error = "An error code was received while attempting Suricata XMLRPC CARP sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } else { + log_error("[suricata] Suricata pkg XMLRPC CARP sync 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/suricata_sync_cmds.php' > /dev/null 2>&1 &\");"; + $params2 = array( + XML_RPC_encode($password), + XML_RPC_encode($execcmd) + ); + log_error("[suricata] Suricata XMLRPC CARP sync 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 Suricata XMLRPC CARP sync with {$url}:{$port} (pfsense.exec_php)."; + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } elseif($resp->faultCode()) { + $error = "An error code was received while attempting Suricata XMLRPC CARP sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString(); + log_error($error); + file_notice("sync_settings", $error, "Suricata Settings Sync", ""); + } else { + log_error("[suricata] Suricata pkg XMLRPC CARP sync reload configuration success with {$url}:{$port} (pfsense.exec_php)."); + } } ?> diff --git a/config/suricata/suricata.priv.inc b/config/suricata/suricata.priv.inc index 3bbee55a..84ede368 100644 --- a/config/suricata/suricata.priv.inc +++ b/config/suricata/suricata.priv.inc @@ -25,6 +25,7 @@ $priv_list['page-services-suricata']['match'][] = "suricata/suricata_select_alia $priv_list['page-services-suricata']['match'][] = "suricata/suricata_list_view.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_logs_browser.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_logs_mgmt.php*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_sid_mgmt.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_passlist.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_passlist_edit.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_post_install.php*"; @@ -35,10 +36,16 @@ $priv_list['page-services-suricata']['match'][] = "suricata/suricata_rules_flowb $priv_list['page-services-suricata']['match'][] = "suricata/suricata_rulesets.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_os_policy_engine.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_global.php*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_ip_list_mgmt.php*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_ip_reputation.php*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_iprep_list_browser.php*"; $priv_list['page-services-suricata']['match'][] = "pkg_edit.php?xml=suricata/suricata.xml*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_check_cron_misc.inc*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_yaml_template.inc*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata.inc*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_defs.inc*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_geoipupdate.php*"; +$priv_list['page-services-suricata']['match'][] = "suricata/suricata_etiqrisk_update.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_post_install.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_uninstall.php*"; $priv_list['page-services-suricata']['match'][] = "suricata/suricata_generate_yaml.php*"; diff --git a/config/suricata/suricata.xml b/config/suricata/suricata.xml index 1a64d619..c510d72b 100644 --- a/config/suricata/suricata.xml +++ b/config/suricata/suricata.xml @@ -9,49 +9,40 @@ /* suricata.xml part of the Suricata package for pfSense + Copyright (C) 2014 Bill meeks - Significant portions are based on original work done for the Snort - package for pfSense from the following contributors: - - Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. - Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. - Copyright (C) 2006 Scott Ullrich - Copyright (C) 2009 Robert Zelaya Sr. Developer - Copyright (C) 2012 Ermal Luci - All rights reserved. - - Adapted for Suricata by: - Copyright (C) 2014 Bill Meeks - 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. + 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. + */ +/* ========================================================================== */ ]]> </copyright> <description>Suricata IDS/IPS Package</description> <requirements>None</requirements> <name>suricata</name> - <version>1.4.6 pkg v1.0</version> + <version>2.0.4 pkg v2.1.3</version> <title>Services: Suricata IDS</title> <include_file>/usr/local/pkg/suricata/suricata.inc</include_file> <menu> @@ -77,18 +68,58 @@ <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_sync.xml</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> <item>https://packages.pfsense.org/packages/config/suricata/suricata_check_cron_misc.inc</item> <prefix>/usr/local/pkg/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_check_for_rule_updates.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> <item>https://packages.pfsense.org/packages/config/suricata/suricata_yaml_template.inc</item> <prefix>/usr/local/pkg/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> <item>https://packages.pfsense.org/packages/config/suricata/suricata_generate_yaml.php</item> - <prefix>/usr/local/www/suricata/</prefix> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_migrate_config.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_post_install.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_uninstall.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_defs.inc</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_geoipupdate.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_etiqrisk_update.php</item> + <prefix>/usr/local/pkg/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> @@ -122,11 +153,6 @@ <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_check_for_rule_updates.php</item> - <prefix>/usr/local/www/suricata/</prefix> - <chmod>0755</chmod> - </additional_files_needed> - <additional_files_needed> <item>https://packages.pfsense.org/packages/config/suricata/suricata_rules.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> @@ -182,6 +208,11 @@ <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_sid_mgmt.php</item> + <prefix>/usr/local/www/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> <item>https://packages.pfsense.org/packages/config/suricata/suricata_list_view.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> @@ -197,26 +228,46 @@ <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_uninstall.php</item> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_define_vars.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_define_vars.php</item> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_barnyard.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_barnyard.php</item> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_ip_list_mgmt.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_post_install.php</item> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_ip_reputation.php</item> <prefix>/usr/local/www/suricata/</prefix> <chmod>0755</chmod> </additional_files_needed> <additional_files_needed> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_iprep_list_browser.php</item> + <prefix>/usr/local/www/suricata/</prefix> + <chmod>0755</chmod> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/www/widgets/javascript/</prefix> + <chmod>0644</chmod> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_alerts.js</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/www/widgets/widgets/</prefix> + <chmod>0644</chmod> + <item>https://packages.pfsense.org/packages/config/suricata/suricata_alerts.widget.php</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/www/widgets/include/</prefix> + <chmod>0644</chmod> + <item>https://packages.pfsense.org/packages/config/suricata/widget-suricata.inc</item> + </additional_files_needed> + <additional_files_needed> <prefix>/usr/local/www/suricata/</prefix> <chmod>0644</chmod> <item>https://packages.pfsense.org/packages/config/suricata/suricata_blocked.php</item> @@ -237,19 +288,19 @@ <item>https://packages.pfsense.org/packages/config/suricata/suricata_select_alias.php</item> </additional_files_needed> <additional_files_needed> - <prefix>/usr/local/www/widgets/javascript/</prefix> + <prefix>/var/db/suricata/sidmods/</prefix> <chmod>0644</chmod> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_alerts.js</item> + <item>https://packages.pfsense.org/packages/config/suricata/disablesid-sample.conf</item> </additional_files_needed> <additional_files_needed> - <prefix>/usr/local/www/widgets/widgets/</prefix> + <prefix>/var/db/suricata/sidmods/</prefix> <chmod>0644</chmod> - <item>https://packages.pfsense.org/packages/config/suricata/suricata_alerts.widget.php</item> + <item>https://packages.pfsense.org/packages/config/suricata/enablesid-sample.conf</item> </additional_files_needed> <additional_files_needed> - <prefix>/usr/local/www/widgets/include/</prefix> + <prefix>/var/db/suricata/sidmods/</prefix> <chmod>0644</chmod> - <item>https://packages.pfsense.org/packages/config/suricata/widget-suricata.inc</item> + <item>https://packages.pfsense.org/packages/config/suricata/modifysid-sample.conf</item> </additional_files_needed> <!-- configpath gets expanded out automatically and config items will be stored in that location --> <configpath>['installedpackages']['suricata']</configpath> @@ -259,12 +310,12 @@ </fields> <custom_php_install_command> <![CDATA[ - include_once("/usr/local/www/suricata/suricata_post_install.php"); + include_once("/usr/local/pkg/suricata/suricata_post_install.php"); ]]> </custom_php_install_command> <custom_php_deinstall_command> <![CDATA[ - include_once("/usr/local/www/suricata/suricata_uninstall.php"); + include_once("/usr/local/pkg/suricata/suricata_uninstall.php"); ]]> </custom_php_deinstall_command> <custom_php_resync_config_command> diff --git a/config/suricata/suricata_alerts.js b/config/suricata/suricata_alerts.js index b6a5d3c3..e56b586d 100644 --- a/config/suricata/suricata_alerts.js +++ b/config/suricata/suricata_alerts.js @@ -18,7 +18,7 @@ function suricata_alerts_fetch_new_rules_callback(callback_data) { line += '<td class="listMRr ellipsis" nowrap><div style="display:inline;" title="'; line += row_split[2] + '">' + row_split[2] + '</div><br/><div style="display:inline;" title="'; line += row_split[3] + '">' + row_split[3] + '</div></td>'; - line += '<td class="listMRr">' + 'Pri: ' + row_split[4] + ' ' + row_split[5] + '</td>'; + line += '<td class="listMRr"><div style="display: fixed; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.2em; max-height: 2.4em; overflow: hidden; text-overflow: ellipsis;" title="' + row_split[4] + '">' + row_split[4] + '</div></td>'; new_data_to_add[new_data_to_add.length] = line; } suricata_alerts_update_div_rows(new_data_to_add); diff --git a/config/suricata/suricata_alerts.php b/config/suricata/suricata_alerts.php index 07e4eb1f..f151e173 100644 --- a/config/suricata/suricata_alerts.php +++ b/config/suricata/suricata_alerts.php @@ -11,6 +11,7 @@ * Copyright (C) 2006 Scott Ullrich * Copyright (C) 2009 Robert Zelaya Sr. Developer * Copyright (C) 2012 Ermal Luci + * Copyright (C) 2014 Jim Pingle jim@pingle.org * All rights reserved. * * Adapted for Suricata by: @@ -42,8 +43,10 @@ require_once("guiconfig.inc"); require_once("/usr/local/pkg/suricata/suricata.inc"); +global $g, $config; $supplist = array(); $suri_pf_table = SURICATA_PF_TABLE; +$filterlogentries = FALSE; function suricata_is_alert_globally_suppressed($list, $gid, $sid) { @@ -125,13 +128,40 @@ function suricata_add_supplist_entry($suppress) { /* and return true; otherwise return false. */ if ($found_list) { write_config(); + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); return true; } else return false; } +function suricata_escape_filter_regex($filtertext) { + /* If the caller (user) has not already put a backslash before a slash, to escape it in the regex, */ + /* then this will do it. Take out any "\/" already there, then turn all ordinary "/" into "\/". */ + return str_replace('/', '\/', str_replace('\/', '/', $filtertext)); +} + +function suricata_match_filter_field($flent, $fields) { + foreach ($fields as $key => $field) { + if ($field == null) + continue; + if ((strpos($field, '!') === 0)) { + $field = substr($field, 1); + $field_regex = suricata_escape_filter_regex($field); + if (@preg_match("/{$field_regex}/i", $flent[$key])) + return false; + } + else { + $field_regex = suricata_escape_filter_regex($field); + if (!@preg_match("/{$field_regex}/i", $flent[$key])) + return false; + } + } + return true; +} + if (isset($_POST['instance']) && is_numericint($_POST['instance'])) $instanceid = $_POST['instance']; // This is for the auto-refresh so we can stay on the same interface @@ -164,6 +194,50 @@ if (empty($pconfig['arefresh'])) $pconfig['arefresh'] = 'off'; $anentries = $pconfig['alertnumber']; +# --- AJAX REVERSE DNS RESOLVE Start --- +if (isset($_POST['resolve'])) { + $ip = strtolower($_POST['resolve']); + $res = (is_ipaddr($ip) ? gethostbyaddr($ip) : ''); + + if ($res && $res != $ip) + $response = array('resolve_ip' => $ip, 'resolve_text' => $res); + else + $response = array('resolve_ip' => $ip, 'resolve_text' => gettext("Cannot resolve")); + + echo json_encode(str_replace("\\","\\\\", $response)); // single escape chars can break JSON decode + exit; +} +# --- AJAX REVERSE DNS RESOLVE End --- + +if ($_POST['filterlogentries_submit']) { + // Set flag for filtering alert entries + $filterlogentries = TRUE; + + // -- IMPORTANT -- + // Note the order of these fields must match the order decoded from the alerts log + $filterfieldsarray = array(); + $filterfieldsarray['time'] = $_POST['filterlogentries_time'] ? $_POST['filterlogentries_time'] : null; + $filterfieldsarray['action'] = null; + $filterfieldsarray['gid'] = $_POST['filterlogentries_gid'] ? $_POST['filterlogentries_gid'] : null; + $filterfieldsarray['sid'] = $_POST['filterlogentries_sid'] ? $_POST['filterlogentries_sid'] : null; + $filterfieldsarray['rev'] = null; + $filterfieldsarray['msg'] = $_POST['filterlogentries_description'] ? $_POST['filterlogentries_description'] : null; + $filterfieldsarray['class'] = $_POST['filterlogentries_classification'] ? $_POST['filterlogentries_classification'] : null; + $filterfieldsarray['priority'] = $_POST['filterlogentries_priority'] ? $_POST['filterlogentries_priority'] : null; + $filterfieldsarray['proto'] = $_POST['filterlogentries_protocol'] ? $_POST['filterlogentries_protocol'] : null; + // Remove any zero-length spaces added to the IP address that could creep in from a copy-paste operation + $filterfieldsarray['src'] = $_POST['filterlogentries_sourceipaddress'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_sourceipaddress']) : null; + $filterfieldsarray['sport'] = $_POST['filterlogentries_sourceport'] ? $_POST['filterlogentries_sourceport'] : null; + // Remove any zero-length spaces added to the IP address that could creep in from a copy-paste operation + $filterfieldsarray['dst'] = $_POST['filterlogentries_destinationipaddress'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_destinationipaddress']) : null; + $filterfieldsarray['dport'] = $_POST['filterlogentries_destinationport'] ? $_POST['filterlogentries_destinationport'] : null; +} + +if ($_POST['filterlogentries_clear']) { + $filterfieldsarray = array(); + $filterlogentries = TRUE; +} + if ($_POST['save']) { if (!is_array($config['installedpackages']['suricata']['alertsblocks'])) $config['installedpackages']['suricata']['alertsblocks'] = array(); @@ -224,6 +298,9 @@ if (($_POST['addsuppress_srcip'] || $_POST['addsuppress_dstip'] || $_POST['addsu if (suricata_add_supplist_entry($suppress)) { suricata_reload_config($a_instance[$instanceid]); $savemsg = $success; + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); sleep(2); } else @@ -277,11 +354,16 @@ if ($_POST['togglesid'] && is_numeric($_POST['sidid']) && is_numeric($_POST['gen /* rules for this interface. */ /*************************************************/ $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_instance[$instanceid]); + conf_mount_ro(); $rebuild_rules = false; /* Signal Suricata to live-load the new rules */ suricata_reload_config($a_instance[$instanceid]); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); sleep(2); $savemsg = gettext("The state for rule {$gid}:{$sid} has been modified. Suricata is 'live-reloading' the new rules list. Please wait at least 15 secs for the process to complete before toggling additional rules."); @@ -299,11 +381,11 @@ if ($_POST['delete']) { } if ($_POST['download']) { - $save_date = exec('/bin/date "+%Y-%m-%d-%H-%M-%S"'); + $save_date = date("Y-m-d-H-i-s"); $file_name = "suricata_logs_{$save_date}_{$if_real}.tar.gz"; - exec("cd {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} && /usr/bin/tar -czf /tmp/{$file_name} *"); + exec("cd {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} && /usr/bin/tar -czf {$g['tmp_path']}/{$file_name} *"); - if (file_exists("/tmp/{$file_name}")) { + if (file_exists("{$g['tmp_path']}/{$file_name}")) { ob_start(); //important or other posts will fail if (isset($_SERVER['HTTPS'])) { header('Pragma: '); @@ -313,13 +395,13 @@ if ($_POST['download']) { header("Cache-Control: private, must-revalidate"); } header("Content-Type: application/octet-stream"); - header("Content-length: " . filesize("/tmp/{$file_name}")); + header("Content-length: " . filesize("{$g['tmp_path']}/{$file_name}")); header("Content-disposition: attachment; filename = {$file_name}"); ob_end_clean(); //important or other post will fail - readfile("/tmp/{$file_name}"); + readfile("{$g['tmp_path']}/{$file_name}"); // Clean up the temp file - @unlink("/tmp/{$file_name}"); + unlink_if_exists("{$g['tmp_path']}/{$file_name}"); } else $savemsg = gettext("An error occurred while creating archive"); @@ -334,7 +416,6 @@ include_once("head.inc"); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> -<script src="/javascript/filter_log.js" type="text/javascript"></script> <?php include_once("fbegin.inc"); @@ -359,24 +440,29 @@ if ($savemsg) { <input type="hidden" name="descr" id="descr" value=""/> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), true, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td></tr> <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="6"> + <tbody> <tr> <td colspan="2" class="listtopic"><?php echo gettext("Alert Log View Settings"); ?></td> </tr> @@ -410,16 +496,104 @@ if ($savemsg) { <td width="78%" class="vtable"> <input name="save" type="submit" class="formbtns" value=" Save " title="<?=gettext("Save auto-refresh and view settings");?>"/> <?php echo gettext('Refresh');?> <input name="arefresh" type="checkbox" value="on" - <?php if ($config['installedpackages']['snortglobal']['alertsblocks']['arefresh']=="on") echo "checked"; ?>/> + <?php if ($config['installedpackages']['suricata']['alertsblocks']['arefresh']=="on") echo "checked"; ?>/> <?php printf(gettext('%sDefault%s is %sON%s.'), '<strong>', '</strong>', '<strong>', '</strong>'); ?> <input name="alertnumber" type="text" class="formfld unknown" id="alertnumber" size="5" value="<?=htmlspecialchars($anentries);?>"/> <?php printf(gettext('Enter number of log entries to view. %sDefault%s is %s250%s.'), '<strong>', '</strong>', '<strong>', '</strong>'); ?> </td> </tr> <tr> + <td colspan="2" class="listtopic"><?php echo gettext("Alert Log View Filter"); ?></td> + </tr> + <tr id="filter_enable_row" style="display:<?php if (!$filterlogentries) {echo "table-row;";} else {echo "none;";} ?>"> + <td width="22%" class="vncell"><?php echo gettext('Alert Log Filter Options'); ?></td> + <td width="78%" class="vtable"> + <input name="show_filter" id="show_filter" type="button" class="formbtns" value="<?=gettext("Show Filter");?>" onclick="enable_showFilter();" /> + <?=gettext("Click to display advanced filtering options dialog");?> + </td> + </tr> + <tr id="filter_options_row" style="display:<?php if (!$filterlogentries) {echo "none;";} else {echo "table-row;";} ?>"> + <td colspan="2"> + <table width="100%" border="0" cellpadding="0" cellspacing="1" summary="action"> + <tr> + <td valign="top"> + <div align="center"><?=gettext("Date");?></div> + <div align="center"><input id="filterlogentries_time" name="filterlogentries_time" class="formfld search" type="text" size="10" value="<?= $filterfieldsarray['time'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Source IP Address");?></div> + <div align="center"><input id="filterlogentries_sourceipaddress" name="filterlogentries_sourceipaddress" class="formfld search" type="text" size="28" value="<?= $filterfieldsarray['src'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Source Port");?></div> + <div align="center"><input id="filterlogentries_sourceport" name="filterlogentries_sourceport" class="formfld search" type="text" size="5" value="<?= $filterfieldsarray['sport'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Description");?></div> + <div align="center"><input id="filterlogentries_description" name="filterlogentries_description" class="formfld search" type="text" size="28" value="<?= $filterfieldsarray['msg'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("GID");?></div> + <div align="center"><input id="filterlogentries_gid" name="filterlogentries_gid" class="formfld search" type="text" size="6" value="<?= $filterfieldsarray['gid'] ?>" /></div> + </td> + </tr> + <tr> + <td valign="top"> + <div align="center"><?=gettext("Priority");?></div> + <div align="center"><input id="filterlogentries_priority" name="filterlogentries_priority" class="formfld search" type="text" size="10" value="<?= $filterfieldsarray['priority'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Destination IP Address");?></div> + <div align="center"><input id="filterlogentries_destinationipaddress" name="filterlogentries_destinationipaddress" class="formfld search" type="text" size="28" value="<?= $filterfieldsarray['dst'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Destination Port");?></div> + <div align="center"><input id="filterlogentries_destinationport" name="filterlogentries_destinationport" class="formfld search" type="text" size="5" value="<?= $filterfieldsarray['dport'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("Classification");?></div> + <div align="center"><input id="filterlogentries_classification" name="filterlogentries_classification" class="formfld search" type="text" size="28" value="<?= $filterfieldsarray['class'] ?>" /></div> + </td> + <td valign="top"> + <div align="center"><?=gettext("SID");?></div> + <div align="center"><input id="filterlogentries_sid" name="filterlogentries_sid" class="formfld search" type="text" size="6" value="<?= $filterfieldsarray['sid'] ?>" /></div> + </td> + </tr> + <tr> + <td valign="top"> + <div align="center"><?=gettext("Protocol");?></div> + <div align="center"><input id="filterlogentries_protocol" name="filterlogentries_protocol" class="formfld search" type="text" size="10" value="<?= $filterfieldsarray['proto'] ?>" /></div> + </td> + <td valign="top"> + </td> + <td valign="top"> + </td> + <td colspan="2" style="vertical-align:bottom"> + <div align="right"><input id="filterlogentries_submit" name="filterlogentries_submit" type="submit" class="formbtns" value="<?=gettext("Filter");?>" title="<?=gettext("Apply filter"); ?>" /> + <input id="filterlogentries_clear" name="filterlogentries_clear" type="submit" class="formbtns" value="<?=gettext("Clear");?>" title="<?=gettext("Remove filter");?>" /> + <input id="filterlogentries_hide" name="filterlogentries_hide" type="button" class="formbtns" value="<?=gettext("Hide");?>" onclick="enable_hideFilter();" title="<?=gettext("Hide filter options");?>" /></div> + </td> + </tr> + <tr> + <td colspan="5" style="vertical-align:bottom"> + <?printf(gettext('Matches %1$s regular expression%2$s.'), '<a target="_blank" href="http://www.php.net/manual/en/book.pcre.php">', '</a>');?> + <?=gettext("Precede with exclamation (!) as first character to exclude match.");?> + </td> + </tr> + </table> + </td> + </tr> + <?php if ($filterlogentries && count($filterfieldsarray)) : ?> + <tr> + <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), $anentries); ?> + <?php echo gettext("(Most recent listed first) ** FILTERED VIEW ** clear filter to see all entries"); ?></td> + </tr> + <?php else: ?> + <tr> <td colspan="2" class="listtopic"><?php printf(gettext("Last %s Alert Entries"), $anentries); ?> <?php echo gettext("(Most recent entries are listed first)"); ?></td> </tr> + <?php endif; ?> <tr> <td width="100%" colspan="2"> <table id="myTable" style="table-layout: fixed;" width="100%" class="sortable" border="0" cellpadding="0" cellspacing="0"> @@ -436,7 +610,7 @@ if ($savemsg) { <col axis="string"> </colgroup> <thead> - <tr> + <tr class="sortableHeaderRowIdentifier"> <th class="listhdrr" axis="date"><?php echo gettext("Date"); ?></th> <th class="listhdrr" axis="number"><?php echo gettext("Pri"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Proto"); ?></th> @@ -445,7 +619,7 @@ if ($savemsg) { <th class="listhdrr" axis="string"><?php echo gettext("SPort"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Dst"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("DPort"); ?></th> - <th class="listhdrr" axis="number"><?php echo gettext("SID"); ?></th> + <th class="listhdrr" axis="number"><?php echo gettext("GID:SID"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Description"); ?></th> </tr> </thead> @@ -453,100 +627,180 @@ if ($savemsg) { <?php /* make sure alert file exists */ -if (file_exists("/var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.log")) { - exec("tail -{$anentries} -r /var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.log > /tmp/alerts_suricata{$suricata_uuid}"); - if (file_exists("/tmp/alerts_suricata{$suricata_uuid}")) { +if (file_exists("{$g['varlog_path']}/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.log")) { + exec("tail -{$anentries} -r {$g['varlog_path']}/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.log > {$g['tmp_path']}/alerts_suricata{$suricata_uuid}"); + if (file_exists("{$g['tmp_path']}/alerts_suricata{$suricata_uuid}")) { $tmpblocked = array_flip(suricata_get_blocked_ips()); $counter = 0; - /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ - /* File format timestamp,action,sig_generator,sig_id,sig_rev,msg,classification,priority,proto,src,srcport,dst,dstport */ - $fd = fopen("/tmp/alerts_suricata{$suricata_uuid}", "r"); - while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { - if(count($fields) < 13) - continue; + + /*************** FORMAT without CSV patch -- ALERT -- ***********************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] {proto} src:srcport -> dst:dstport */ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ + /****************************************************************************************************************************************/ + + /**************** FORMAT without CSV patch -- DECODER EVENT -- **************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] [**] [Raw pkt: ...] */ + /* 0 1 2 3 4 5 6 7 */ + /************** *************************************************************************************************************************/ + + $fd = fopen("{$g['tmp_path']}/alerts_suricata{$suricata_uuid}", "r"); + $buf = ""; + while (($buf = fgets($fd)) !== FALSE) { + $fields = array(); + $tmp = array(); + $decoder_event = FALSE; + + /**************************************************************/ + /* Parse alert log entry to find the parts we want to display */ + /**************************************************************/ + + // Field 0 is the event timestamp + $fields['time'] = substr($buf, 0, strpos($buf, ' ')); + + // Field 1 is currently not used, so set to NULL + $fields['action'] = null; + + // The regular expression match below returns an array as follows: + // [2] => GID, [3] => SID, [4] => REV, [5] => MSG, [6] => CLASSIFICATION, [7] = PRIORITY + preg_match('/\[\*{2}\]\s\[((\d+):(\d+):(\d+))\]\s(.*)\[\*{2}\]\s\[Classification:\s(.*)\]\s\[Priority:\s(\d+)\]\s/', $buf, $tmp); + $fields['gid'] = trim($tmp[2]); + $fields['sid'] = trim($tmp[3]); + $fields['rev'] = trim($tmp[4]); + $fields['msg'] = trim($tmp[5]); + $fields['class'] = trim($tmp[6]); + $fields['priority'] = trim($tmp[7]); + + // The regular expression match below looks for the PROTO, SRC and DST fields + // and returns an array as follows: + // [1] = PROTO, [2] => SRC:SPORT [3] => DST:DPORT + if (preg_match('/\{(.*)\}\s(.*)\s->\s(.*)/', $buf, $tmp)) { + // Get PROTO + $fields['proto'] = trim($tmp[1]); + + // Get SRC + $fields['src'] = trim(substr($tmp[2], 0, strrpos($tmp[2], ':'))); + if (is_ipaddrv6($fields['src'])) + $fields['src'] = inet_ntop(inet_pton($fields['src'])); + + // Get SPORT + $fields['sport'] = trim(substr($tmp[2], strrpos($tmp[2], ':') + 1)); + + // Get DST + $fields['dst'] = trim(substr($tmp[3], 0, strrpos($tmp[3], ':'))); + if (is_ipaddrv6($fields['dst'])) + $fields['dst'] = inet_ntop(inet_pton($fields['dst'])); + + // Get DPORT + $fields['dport'] = trim(substr($tmp[3], strrpos($tmp[3], ':') + 1)); + } + else { + // If no PROTO nor IP ADDR, then this is a DECODER EVENT + $decoder_event = TRUE; + $fields['proto'] = gettext("n/a"); + $fields['sport'] = gettext("n/a"); + $fields['dport'] = gettext("n/a"); + } // Create a DateTime object from the event timestamp that // we can use to easily manipulate output formats. - $event_tm = date_create_from_format("m/d/Y-H:i:s.u", $fields[0]); + $event_tm = date_create_from_format("m/d/Y-H:i:s.u", $fields['time']); // Check the 'CATEGORY' field for the text "(null)" and // substitute "Not Assigned". - if ($fields[6] == "(null)") - $fields[6] = "Not Assigned"; + if ($fields['class'] == "(null)") + $fields['class'] = gettext("Not Assigned"); + + $fields['time'] = date_format($event_tm, "m/d/Y") . " " . date_format($event_tm, "H:i:s"); + if ($filterlogentries && !suricata_match_filter_field($fields, $filterfieldsarray)) { + continue; + } /* Time */ $alert_time = date_format($event_tm, "H:i:s"); /* Date */ $alert_date = date_format($event_tm, "m/d/Y"); /* Description */ - $alert_descr = $fields[5]; - $alert_descr_url = urlencode($fields[5]); + $alert_descr = $fields['msg']; + $alert_descr_url = urlencode($fields['msg']); /* Priority */ - $alert_priority = $fields[7]; + $alert_priority = $fields['priority']; /* Protocol */ - $alert_proto = $fields[8]; + $alert_proto = $fields['proto']; + /* IP SRC */ - $alert_ip_src = $fields[9]; - /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ - $alert_ip_src = str_replace(":", ":​", $alert_ip_src); - /* Add Reverse DNS lookup icons */ - $alert_ip_src .= "<br/><a onclick=\"javascript:getURL('/diag_dns.php?host={$fields[9]}&dialog_output=true', outputrule);\">"; - $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_log_d.gif' width='11' height='11' border='0' "; - $alert_ip_src .= "title='" . gettext("Resolve host via reverse DNS lookup (quick pop-up)") . "' style=\"cursor: pointer;\"></a> "; - $alert_ip_src .= "<a href='/diag_dns.php?host={$fields[9]}&instance={$instanceid}'>"; - $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; - $alert_ip_src .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; - /* Add icons for auto-adding to Suppress List if appropriate */ - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && - !isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { - $alert_ip_src .= " <input type='image' name='addsuppress_srcip[]' onClick=\"encRuleSig('{$fields[2]}','{$fields[3]}','{$fields[9]}','{$alert_descr}');\" "; - $alert_ip_src .= "src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; - $alert_ip_src .= "title='" . gettext("Add this alert to the Suppress List and track by_src IP") . "'/>"; - } - elseif (isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { - $alert_ip_src .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; - $alert_ip_src .= "title='" . gettext("This alert track by_src IP is already in the Suppress List") . "'/>"; + if ($decoder_event == FALSE) { + $alert_ip_src = $fields['src']; + /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ + $alert_ip_src = str_replace(":", ":​", $alert_ip_src); + /* Add Reverse DNS lookup icon */ + $alert_ip_src .= "<br/><img onclick=\"javascript:resolve_with_ajax('{$fields['src']}');\" title=\""; + $alert_ip_src .= gettext("Resolve host via reverse DNS lookup") . "\" border=\"0\" src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" alt=\"Icon Reverse Resolve with DNS\" "; + $alert_ip_src .= " style=\"cursor: pointer;\"/>"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields['gid'], $fields['sid']) && + !isset($supplist[$fields['gid']][$fields['sid']]['by_src'][$fields['src']])) { + $alert_ip_src .= " <input type='image' name='addsuppress_srcip[]' onClick=\"encRuleSig('{$fields['gid']}','{$fields['sid']}','{$fields['src']}','{$alert_descr}');\" "; + $alert_ip_src .= "src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; + $alert_ip_src .= "title='" . gettext("Add this alert to the Suppress List and track by_src IP") . "'/>"; + } + elseif (isset($supplist[$fields['gid']][$fields['sid']]['by_src'][$fields['src']])) { + $alert_ip_src .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; + $alert_ip_src .= "title='" . gettext("This alert track by_src IP is already in the Suppress List") . "'/>"; + } + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields['src']])) { + $alert_ip_src .= " <input type='image' name='unblock[]' onClick=\"document.getElementById('ip').value='{$fields['src']}';\" "; + $alert_ip_src .= "title='" . gettext("Remove host from Blocked Table") . "' border='0' width='12' height='12' src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/>"; + } } - /* Add icon for auto-removing from Blocked Table if required */ - if (isset($tmpblocked[$fields[9]])) { - $alert_ip_src .= " <input type='image' name='unblock[]' onClick=\"document.getElementById('ip').value='{$fields[9]}';\" "; - $alert_ip_src .= "title='" . gettext("Remove host from Blocked Table") . "' border='0' width='12' height='12' src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/>"; + else { + if (preg_match('/\s\[Raw pkt:(.*)\]/', $buf, $tmp)) + $alert_ip_src = "<div title='[Raw pkt: {$tmp[1]}]'>" . gettext("Decoder Event") . "</div>"; + else + $alert_ip_src = gettext("Decoder Event"); } + /* IP SRC Port */ - $alert_src_p = $fields[10]; - /* IP Destination */ - $alert_ip_dst = $fields[11]; - /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ - $alert_ip_dst = str_replace(":", ":​", $alert_ip_dst); - /* Add Reverse DNS lookup icons */ - $alert_ip_dst .= "<br/><a onclick=\"javascript:getURL('/diag_dns.php?host={$fields[11]}&dialog_output=true', outputrule);\">"; - $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_log_d.gif' width='11' height='11' border='0' "; - $alert_ip_dst .= "title='" . gettext("Resolve host via reverse DNS lookup (quick pop-up)") . "' style=\"cursor: pointer;\"></a> "; - $alert_ip_dst .= "<a href='/diag_dns.php?host={$fields[11]}&instance={$instanceid}'>"; - $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; - $alert_ip_dst .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; - /* Add icons for auto-adding to Suppress List if appropriate */ - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && - !isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) { - $alert_ip_dst .= " <input type='image' name='addsuppress_dstip[]' onClick=\"encRuleSig('{$fields[2]}','{$fields[3]}','{$fields[11]}','{$alert_descr}');\" "; - $alert_ip_dst .= "src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; - $alert_ip_dst .= "title='" . gettext("Add this alert to the Suppress List and track by_dst IP") . "'/>"; - } - elseif (isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) { - $alert_ip_dst .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; - $alert_ip_dst .= "title='" . gettext("This alert track by_dst IP is already in the Suppress List") . "'/>"; + $alert_src_p = $fields['sport']; + + /* IP DST */ + if ($decoder_event == FALSE) { + $alert_ip_dst = $fields['dst']; + /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ + $alert_ip_dst = str_replace(":", ":​", $alert_ip_dst); + /* Add Reverse DNS lookup icons */ + $alert_ip_dst .= "<br/><img onclick=\"javascript:resolve_with_ajax('{$fields['dst']}');\" title=\""; + $alert_ip_dst .= gettext("Resolve host via reverse DNS lookup") . "\" border=\"0\" src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" alt=\"Icon Reverse Resolve with DNS\" "; + $alert_ip_dst .= " style=\"cursor: pointer;\"/>"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields['gid'], $fields['sid']) && + !isset($supplist[$fields['gid']][$fields['sid']]['by_dst'][$fields['dst']])) { + $alert_ip_dst .= " <input type='image' name='addsuppress_dstip[]' onClick=\"encRuleSig('{$fields['gid']}','{$fields['sid']}','{$fields['dst']}','{$alert_descr}');\" "; + $alert_ip_dst .= "src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; + $alert_ip_dst .= "title='" . gettext("Add this alert to the Suppress List and track by_dst IP") . "'/>"; + } + elseif (isset($supplist[$fields['gid']][$fields['sid']]['by_dst'][$fields['dst']])) { + $alert_ip_dst .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; + $alert_ip_dst .= "title='" . gettext("This alert track by_dst IP is already in the Suppress List") . "'/>"; + } + + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields['dst']])) { + $alert_ip_dst .= " <input type='image' name='unblock[]' onClick=\"document.getElementById('ip').value='{$fields['dst']}';\" "; + $alert_ip_dst .= "title='" . gettext("Remove host from Blocked Table") . "' border='0' width='12' height='12' src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/>"; + } } - /* Add icon for auto-removing from Blocked Table if required */ - if (isset($tmpblocked[$fields[11]])) { - $alert_ip_dst .= " <input type='image' name='unblock[]' onClick=\"document.getElementById('ip').value='{$fields[11]}';\" "; - $alert_ip_dst .= "title='" . gettext("Remove host from Blocked Table") . "' border='0' width='12' height='12' src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/>"; + else { + $alert_ip_dst = gettext("n/a"); } + /* IP DST Port */ - $alert_dst_p = $fields[12]; + $alert_dst_p = $fields['dport']; + /* SID */ - $alert_sid_str = "{$fields[2]}:{$fields[3]}"; - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3])) { - $sidsupplink = "<input type='image' name='addsuppress[]' onClick=\"encRuleSig('{$fields[2]}','{$fields[3]}','','{$alert_descr}');\" "; + $alert_sid_str = "{$fields['gid']}:{$fields['sid']}"; + if (!suricata_is_alert_globally_suppressed($supplist, $fields['gid'], $fields['sid'])) { + $sidsupplink = "<input type='image' name='addsuppress[]' onClick=\"encRuleSig('{$fields['gid']}','{$fields['sid']}','','{$alert_descr}');\" "; $sidsupplink .= "src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; $sidsupplink .= "title='" . gettext("Add this alert to the Suppress List") . "'/>"; } @@ -555,46 +809,47 @@ if (file_exists("/var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.lo $sidsupplink .= "title='" . gettext("This alert is already in the Suppress List") . "'/>"; } /* Add icon for toggling rule state */ - if (isset($disablesid[$fields[2]][$fields[3]])) { - $sid_dsbl_link = "<input type='image' name='togglesid[]' onClick=\"encRuleSig('{$fields[2]}','{$fields[3]}','','');\" "; + if (isset($disablesid[$fields['gid']][$fields['sid']])) { + $sid_dsbl_link = "<input type='image' name='togglesid[]' onClick=\"encRuleSig('{$fields['gid']}','{$fields['sid']}','','');\" "; $sid_dsbl_link .= "src='../themes/{$g['theme']}/images/icons/icon_reject.gif' width='11' height='11' border='0' "; $sid_dsbl_link .= "title='" . gettext("Rule is forced to a disabled state. Click to remove the force-disable action from this rule.") . "'/>"; } else { - $sid_dsbl_link = "<input type='image' name='togglesid[]' onClick=\"encRuleSig('{$fields[2]}','{$fields[3]}','','');\" "; + $sid_dsbl_link = "<input type='image' name='togglesid[]' onClick=\"encRuleSig('{$fields['gid']}','{$fields['sid']}','','');\" "; $sid_dsbl_link .= "src='../themes/{$g['theme']}/images/icons/icon_block.gif' width='11' height='11' border='0' "; $sid_dsbl_link .= "title='" . gettext("Force-disable this rule and remove it from current rules set.") . "'/>"; } /* DESCRIPTION */ - $alert_class = $fields[6]; + $alert_class = $fields['class']; echo "<tr> <td class='listr' align='center'>{$alert_date}<br/>{$alert_time}</td> <td class='listr' align='center'>{$alert_priority}</td> <td class='listr' align='center'>{$alert_proto}</td> <td class='listr' style=\"word-wrap:break-word;\">{$alert_class}</td> - <td class='listr' align='center' sorttable_customkey='{$fields[9]}'>{$alert_ip_src}</td> + <td class='listr' style=\"sorttable_customkey:{$fields['src']};\" sorttable_customkey=\"{$fields['src']}\" align='center'>{$alert_ip_src}</td> <td class='listr' align='center'>{$alert_src_p}</td> - <td class='listr' align='center' sorttable_customkey='{$fields[11]}'>{$alert_ip_dst}</td> + <td class='listr' align='center' style=\"sorttable_customkey:{$fields['dst']};\" sorttable_customkey=\"{$fields['dst']}\">{$alert_ip_dst}</td> <td class='listr' align='center'>{$alert_dst_p}</td> - <td class='listr' align='center' sorttable_customkey='{$fields[3]}'>{$alert_sid_str}<br/>{$sidsupplink} {$sid_dsbl_link}</td> + <td class='listr' align='center' style=\"sorttable_customkey:{$fields['sid']};\" sorttable_customkey=\"{$fields['sid']}\">{$alert_sid_str}<br/>{$sidsupplink} {$sid_dsbl_link}</td> <td class='listbg' style=\"word-wrap:break-word;\">{$alert_descr}</td> </tr>\n"; $counter++; } + unset($fields, $buf, $tmp); fclose($fd); - @unlink("/tmp/alerts_suricata{$suricata_uuid}"); + unlink_if_exists("{$g['tmp_path']}/alerts_suricata{$suricata_uuid}"); } } ?> </tbody> </table> </td> -</tr> +</tr></tbody> </table> </div> -</td></tr> +</td></tr></tbody> </table> </form> <?php @@ -615,6 +870,50 @@ function encRuleSig(rulegid,rulesid,srcip,ruledescr) { document.getElementById("ip").value = srcip; document.getElementById("descr").value = ruledescr; } + +function enable_showFilter() { + document.getElementById("filter_enable_row").style.display="none"; + document.getElementById("filter_options_row").style.display="table-row"; +} + +function enable_hideFilter() { + document.getElementById("filter_enable_row").style.display="table-row"; + document.getElementById("filter_options_row").style.display="none"; +} + +</script> + +<!-- The following AJAX code was borrowed from the diag_logs_filter.php --> +<!-- file in pfSense. See copyright info at top of this page. --> +<script type="text/javascript"> +//<![CDATA[ +function resolve_with_ajax(ip_to_resolve) { + var url = "/suricata/suricata_alerts.php"; + + jQuery.ajax( + url, + { + type: 'post', + dataType: 'json', + data: { + resolve: ip_to_resolve, + }, + complete: resolve_ip_callback + }); +} + +function resolve_ip_callback(transport) { + var response = jQuery.parseJSON(transport.responseText); + var msg = 'IP address "' + response.resolve_ip + '" resolves to\n'; + alert(msg + 'host "' + htmlspecialchars(response.resolve_text) + '"'); +} + +// From http://stackoverflow.com/questions/5499078/fastest-method-to-escape-html-tags-as-html-entities +function htmlspecialchars(str) { + return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); +} +//]]> </script> + </body> </html> diff --git a/config/suricata/suricata_alerts.widget.php b/config/suricata/suricata_alerts.widget.php index 21fad03d..81d17c2e 100644 --- a/config/suricata/suricata_alerts.widget.php +++ b/config/suricata/suricata_alerts.widget.php @@ -42,8 +42,8 @@ if (!is_array($config['installedpackages']['suricata']['rule'])) $a_instance = &$config['installedpackages']['suricata']['rule']; /* array sorting */ -function sksort(&$array, $subkey="id", $sort_ascending=false) { - /* an empty array causes sksort to fail - this test alleviates the error */ +function suricata_sksort(&$array, $subkey="id", $sort_ascending=false) { + /* an empty array causes suricata_sksort to fail - this test alleviates the error */ if(empty($array)) return false; if (count($array)){ @@ -81,7 +81,7 @@ if (isset($_GET['getNewAlerts'])) { $counter = 0; foreach ($suri_alerts as $a) { $response .= $a['instanceid'] . " " . $a['dateonly'] . "||" . $a['timeonly'] . "||" . $a['src'] . "||"; - $response .= $a['dst'] . "||" . $a['priority'] . "||" . $a['category'] . "\n"; + $response .= $a['dst'] . "||" . $a['msg'] . "\n"; $counter++; if($counter >= $suri_nentries) break; @@ -114,12 +114,62 @@ function suricata_widget_get_alerts() { exec("tail -{$suri_nentries} -r /var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.log > /tmp/surialerts_{$suricata_uuid}"); if (file_exists("/tmp/surialerts_{$suricata_uuid}")) { - /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ - /* File format: timestamp,action,sig_generator,sig_id,sig_rev,msg,classification,priority,proto,src,srcport,dst,dstport */ + /*************** FORMAT without CSV patch -- ALERT -- ***********************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] {proto} src:srcport -> dst:dstport */ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ + /****************************************************************************************************************************************/ + + /**************** FORMAT without CSV patch -- DECODER EVENT -- **************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] [**] [Raw pkt: ...] */ + /* 0 1 2 3 4 5 6 7 */ + /************** *************************************************************************************************************************/ + $fd = fopen("/tmp/surialerts_{$suricata_uuid}", "r"); - while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { - if(count($fields) < 13) - continue; + $buf = ""; + while (($buf = fgets($fd)) !== FALSE) { + $fields = array(); + $tmp = array(); + + // Parse alert log entry to find the parts we want to display + $fields[0] = substr($buf, 0, strpos($buf, ' ')); + + // The regular expression match below returns an array as follows: + // [2] => GID, [3] => SID, [4] => REV, [5] => MSG, [6] => CLASSIFICATION, [7] = PRIORITY + preg_match('/\[\*{2}\]\s\[((\d+):(\d+):(\d+))\]\s(.*)\[\*{2}\]\s\[Classification:\s(.*)\]\s\[Priority:\s(\d+)\]\s/', $buf, $tmp); + $fields['gid'] = trim($tmp[2]); + $fields['sid'] = trim($tmp[3]); + $fields['rev'] = trim($tmp[4]); + $fields['msg'] = trim($tmp[5]); + $fields['class'] = trim($tmp[6]); + $fields['priority'] = trim($tmp[7]); + + // The regular expression match below looks for the PROTO, SRC and DST fields + // and returns an array as follows: + // [1] = PROTO, [2] => SRC:SPORT [3] => DST:DPORT + if (preg_match('/\{(.*)\}\s(.*)\s->\s(.*)/', $buf, $tmp)) { + // Get SRC + $fields['src'] = trim(substr($tmp[2], 0, strrpos($tmp[2], ':'))); + if (is_ipaddrv6($fields['src'])) + $fields['src'] = inet_ntop(inet_pton($fields['src'])); + + // Get SPORT + $fields['sport'] = trim(substr($tmp[2], strrpos($tmp[2], ':') + 1)); + + // Get DST + $fields['dst'] = trim(substr($tmp[3], 0, strrpos($tmp[3], ':'))); + if (is_ipaddrv6($fields['dst'])) + $fields['dst'] = inet_ntop(inet_pton($fields['dst'])); + + // Get DPORT + $fields['dport'] = trim(substr($tmp[3], strrpos($tmp[3], ':') + 1)); + } + else { + // If no PROTO and IP ADDR, then this is a DECODER EVENT + $fields['src'] = gettext("Decoder Event"); + $fields['sport'] = ""; + $fields['dst'] = ""; + $fields['dport'] = ""; + } // Create a DateTime object from the event timestamp that // we can use to easily manipulate output formats. @@ -127,31 +177,30 @@ function suricata_widget_get_alerts() { // Check the 'CATEGORY' field for the text "(null)" and // substitute "No classtype defined". - if ($fields[6] == "(null)") - $fields[6] = "No classtype assigned"; + if ($fields['class'] == "(null)") + $fields['class'] = "No classtype assigned"; - $suricata_alerts[$counter]['instanceid'] = strtoupper($a_instance[$instanceid]['interface']); + $suricata_alerts[$counter]['instanceid'] = strtoupper(convert_friendly_interface_to_friendly_descr($a_instance[$instanceid]['interface'])); $suricata_alerts[$counter]['timestamp'] = strval(date_timestamp_get($event_tm)); $suricata_alerts[$counter]['timeonly'] = date_format($event_tm, "H:i:s"); $suricata_alerts[$counter]['dateonly'] = date_format($event_tm, "M d"); + $suricata_alerts[$counter]['msg'] = $fields['msg']; // Add square brackets around any IPv6 address - if (is_ipaddrv6($fields[9])) - $suricata_alerts[$counter]['src'] = "[" . $fields[9] . "]"; + if (is_ipaddrv6($fields['src'])) + $suricata_alerts[$counter]['src'] = "[" . $fields['src'] . "]"; else - $suricata_alerts[$counter]['src'] = $fields[9]; + $suricata_alerts[$counter]['src'] = $fields['src']; // Add the SRC PORT if not null - if (!empty($fields[10])) - $suricata_alerts[$counter]['src'] .= ":" . $fields[10]; + if (!empty($fields['sport']) || $fields['sport'] == '0') + $suricata_alerts[$counter]['src'] .= ":" . $fields['sport']; // Add square brackets around any IPv6 address - if (is_ipaddrv6($fields[11])) - $suricata_alerts[$counter]['dst'] = "[" . $fields[11] . "]"; + if (is_ipaddrv6($fields['dst'])) + $suricata_alerts[$counter]['dst'] = "[" . $fields['dst'] . "]"; else - $suricata_alerts[$counter]['dst'] = $fields[11]; - // Add the SRC PORT if not null - if (!empty($fields[12])) - $suricata_alerts[$counter]['dst'] .= ":" . $fields[12]; - $suricata_alerts[$counter]['priority'] = $fields[7]; - $suricata_alerts[$counter]['category'] = $fields[6]; + $suricata_alerts[$counter]['dst'] = $fields['dst']; + // Add the DST PORT if not null + if (!empty($fields['dport']) || $fields['dport'] == '0') + $suricata_alerts[$counter]['dst'] .= ":" . $fields['dport']; $counter++; }; fclose($fd); @@ -162,9 +211,9 @@ function suricata_widget_get_alerts() { // Sort the alerts array if (isset($config['syslog']['reverse'])) { - sksort($suricata_alerts, 'timestamp', false); + suricata_sksort($suricata_alerts, 'timestamp', false); } else { - sksort($suricata_alerts, 'timestamp', true); + suricata_sksort($suricata_alerts, 'timestamp', true); } return $suricata_alerts; @@ -192,7 +241,7 @@ function suricata_widget_get_alerts() { <tr> <th class="listhdrr"><?=gettext("IF/Date");?></th> <th class="listhdrr"><?=gettext("Src/Dst Address");?></th> - <th class="listhdrr"><?=gettext("Classification");?></th> + <th class="listhdrr"><?=gettext("Description");?></th> </tr> </thead> <tbody id="suricata-alert-entries"> @@ -205,7 +254,7 @@ function suricata_widget_get_alerts() { echo(" <tr class='" . $evenRowClass . "'> <td class='listMRr'>" . $alert['instanceid'] . " " . $alert['dateonly'] . "<br/>" . $alert['timeonly'] . "</td> <td class='listMRr ellipsis' nowrap><div style='display:inline;' title='" . $alert['src'] . "'>" . $alert['src'] . "</div><br/><div style='display:inline;' title='" . $alert['dst'] . "'>" . $alert['dst'] . "</div></td> - <td class='listMRr'>Pri: " . $alert['priority'] . " " . $alert['category'] . "</td></tr>"); + <td class='listMRr'><div style='display: fixed; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.2em; max-height: 2.4em; overflow: hidden; text-overflow: ellipsis;' title='{$alert['msg']}'>" . $alert['msg'] . "</div></td></tr>"); $counter++; if($counter >= $suri_nentries) break; diff --git a/config/suricata/suricata_app_parsers.php b/config/suricata/suricata_app_parsers.php index c28b99d1..cfa34a54 100644 --- a/config/suricata/suricata_app_parsers.php +++ b/config/suricata/suricata_app_parsers.php @@ -86,13 +86,14 @@ if (isset($id) && $a_nat[$id]) { if (empty($pconfig['libhtp_policy']['item'])) { $default = array( "name" => "default", "bind_to" => "all", "personality" => "IDS", "request-body-limit" => 4096, "response-body-limit" => 4096, - "double-decode-path" => "no", "double-decode-query" => "no" ); + "double-decode-path" => "no", "double-decode-query" => "no", + "uri-include-all" => "no" ); $pconfig['libhtp_policy']['item'] = array(); $pconfig['libhtp_policy']['item'][] = $default; if (!is_array($a_nat[$id]['libhtp_policy']['item'])) $a_nat[$id]['libhtp_policy']['item'] = array(); $a_nat[$id]['libhtp_policy']['item'][] = $default; - write_config(); + write_config("Suricata pkg: created a new default HTTP server configuration for " . convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface'])); $libhtp_engine_next_id++; } else @@ -121,6 +122,7 @@ elseif ($_POST['select_alias']) { $eng_resp_body_limit = $_POST['resp_body_limit']; $eng_enable_double_decode_path = $_POST['enable_double_decode_path']; $eng_enable_double_decode_query = $_POST['enable_double_decode_query']; + $eng_enable_uri_include_all = $_POST['enable_uri_include_all']; $mode = "add_edit_libhtp_policy"; } if ($_POST['save_libhtp_policy']) { @@ -161,6 +163,7 @@ if ($_POST['save_libhtp_policy']) { if ($_POST['enable_double_decode_path']) { $engine['double-decode-path'] = 'yes'; }else{ $engine['double-decode-path'] = 'no'; } if ($_POST['enable_double_decode_query']) { $engine['double-decode-query'] = 'yes'; }else{ $engine['double-decode-query'] = 'no'; } + if ($_POST['enable_uri_include_all']) { $engine['uri-include-all'] = 'yes'; }else{ $engine['uri-include-all'] = 'no'; } // Can only have one "all" Bind_To address if ($engine['bind_to'] == "all" && $engine['name'] <> "default") @@ -196,7 +199,7 @@ if ($_POST['save_libhtp_policy']) { } // Now write the new engine array to conf - write_config(); + write_config("Suricata pkg: saved updated HTTP server configuration for " . convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface'])); $pconfig['libhtp_policy']['item'] = $a_nat[$id]['libhtp_policy']['item']; } else { @@ -209,7 +212,7 @@ elseif ($_POST['add_libhtp_policy']) { $add_edit_libhtp_policy = true; $pengcfg = array( "name" => "engine_{$libhtp_engine_next_id}", "bind_to" => "", "personality" => "IDS", "request-body-limit" => "4096", "response-body-limit" => "4096", - "double-decode-path" => "no", "double-decode-query" => "no" ); + "double-decode-path" => "no", "double-decode-query" => "no", "uri-include-all" => "no" ); $eng_id = $libhtp_engine_next_id; } elseif ($_POST['edit_libhtp_policy']) { @@ -229,7 +232,7 @@ elseif ($_POST['del_libhtp_policy']) { } if (isset($id) && $a_nat[$id]) { $a_nat[$id] = $natent; - write_config(); + write_config("Suricata pkg: deleted a HTTP server configuration for " . convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface'])); } } elseif ($_POST['cancel_libhtp_policy']) { @@ -239,9 +242,24 @@ elseif ($_POST['ResetAll']) { /* Reset all the settings to defaults */ $pconfig['asn1_max_frames'] = "256"; + $pconfig['dns_global_memcap'] = "16777216"; + $pconfig['dns_state_memcap'] = "524288"; + $pconfig['dns_request_flood_limit'] = "500"; + $pconfig['http_parser_memcap'] = "67108864"; + $pconfig['dns_parser_udp'] = "yes"; + $pconfig['dns_parser_tcp'] = "yes"; + $pconfig['http_parser'] = "yes"; + $pconfig['tls_parser'] = "yes"; + $pconfig['smtp_parser'] = "yes"; + $pconfig['imap_parser'] = "detection-only"; + $pconfig['ssh_parser'] = "yes"; + $pconfig['ftp_parser'] = "yes"; + $pconfig['dcerpc_parser'] = "yes"; + $pconfig['smb_parser'] = "yes"; + $pconfig['msn_parser'] = "detection-only"; /* Log a message at the top of the page to inform the user */ - $savemsg = gettext("All flow and stream settings have been reset to their defaults."); + $savemsg = gettext("All flow and stream settings on this page have been reset to their defaults. Click APPLY if you wish to keep these new settings."); } elseif ($_POST['save_import_alias']) { // If saving out of "select alias" mode, @@ -257,6 +275,7 @@ elseif ($_POST['save_import_alias']) { $pengcfg['response-body-limit'] = $_POST['eng_resp_body_limit']; $pengcfg['double-decode-path'] = $_POST['eng_enable_double_decode_path']; $pengcfg['double-decode-query'] = $_POST['eng_enable_double_decode_query']; + $pengcfg['uri-include-all'] = $_POST['eng_enable_uri_include_all']; $add_edit_libhtp_policy = true; $mode = "add_edit_libhtp_policy"; @@ -277,12 +296,13 @@ elseif ($_POST['save_import_alias']) { $eng_resp_body_limit = $_POST['eng_resp_body_limit']; $eng_enable_double_decode_path = $_POST['eng_enable_double_decode_path']; $eng_enable_double_decode_query = $_POST['eng_enable_double_decode_query']; + $eng_enable_uri_include_all = $_POST['eng_enable_uri_include_all']; } } else { $engine = array( "name" => "", "bind_to" => "", "personality" => "IDS", "request-body-limit" => "4096", "response-body-limit" => "4096", - "double-decode-path" => "no", "double-decode-query" => "no" ); + "double-decode-path" => "no", "double-decode-query" => "no", "uri-include-all" => "no" ); // See if anything was checked to import if (is_array($_POST['aliastoimport']) && count($_POST['aliastoimport']) > 0) { @@ -322,7 +342,7 @@ elseif ($_POST['save_import_alias']) { } // Write the new engine array to config file - write_config(); + write_config("Suricata pkg: saved an updated HTTP server configuration for " . convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface'])); $importalias = false; } } @@ -344,10 +364,11 @@ elseif ($_POST['cancel_import_alias']) { $pengcfg['response-body-limit'] = $_POST['eng_resp_body_limit']; $pengcfg['double-decode-path'] = $_POST['eng_enable_double_decode_path']; $pengcfg['double-decode-query'] = $_POST['eng_enable_double_decode_query']; + $pengcfg['uri-include-all'] = $_POST['eng_enable_uri_include_all']; $add_edit_libhtp_policy = true; } } -elseif ($_POST['save']) { +elseif ($_POST['save'] || $_POST['apply']) { $natent = array(); $natent = $pconfig; @@ -355,9 +376,37 @@ elseif ($_POST['save']) { if (!is_numeric($_POST['asn1_max_frames'] ) || $_POST['asn1_max_frames'] < 1) $input_errors[] = gettext("The value for 'ASN1 Max Frames' must be all numbers and greater than 0."); + if (!is_numeric($_POST['dns_global_memcap'] ) || $_POST['dns_global_memcap'] < 1) + $input_errors[] = gettext("The value for 'DNS Global Memcap' must be all numbers and greater than 0."); + + if (!is_numeric($_POST['dns_state_memcap'] ) || $_POST['dns_state_memcap'] < 1) + $input_errors[] = gettext("The value for 'DNS Flow/State Memcap' must be all numbers and greater than 0."); + + if (!is_numeric($_POST['dns_request_flood_limit'] ) || $_POST['dns_request_flood_limit'] < 1) + $input_errors[] = gettext("The value for 'DNS Request Flood Limit' must be all numbers and greater than 0."); + + if (!is_numeric($_POST['http_parser_memcap'] ) || $_POST['http_parser_memcap'] < 1) + $input_errors[] = gettext("The value for 'HTTP Memcap' must be all numbers and greater than 0."); + /* if no errors write to conf */ if (!$input_errors) { if ($_POST['asn1_max_frames'] != "") { $natent['asn1_max_frames'] = $_POST['asn1_max_frames']; }else{ $natent['asn1_max_frames'] = "256"; } + if ($_POST['dns_global_memcap'] != ""){ $natent['dns_global_memcap'] = $_POST['dns_global_memcap']; }else{ $natent['dns_global_memcap'] = "16777216"; } + if ($_POST['dns_state_memcap'] != ""){ $natent['dns_state_memcap'] = $_POST['dns_state_memcap']; }else{ $natent['dns_state_memcap'] = "524288"; } + if ($_POST['dns_request_flood_limit'] != ""){ $natent['dns_request_flood_limit'] = $_POST['dns_request_flood_limit']; }else{ $natent['dns_request_flood_limit'] = "500"; } + if ($_POST['http_parser_memcap'] != ""){ $natent['http_parser_memcap'] = $_POST['http_parser_memcap']; }else{ $natent['http_parser_memcap'] = "67108864"; } + + $natent['dns_parser_udp'] = $_POST['dns_parser_udp']; + $natent['dns_parser_tcp'] = $_POST['dns_parser_tcp']; + $natent['http_parser'] = $_POST['http_parser']; + $natent['tls_parser'] = $_POST['tls_parser']; + $natent['smtp_parser'] = $_POST['smtp_parser']; + $natent['imap_parser'] = $_POST['imap_parser']; + $natent['ssh_parser'] = $_POST['ssh_parser']; + $natent['ftp_parser'] = $_POST['ftp_parser']; + $natent['dcerpc_parser'] = $_POST['dcerpc_parser']; + $natent['smb_parser'] = $_POST['smb_parser']; + $natent['msn_parser'] = $_POST['msn_parser']; /**************************************************/ /* If we have a valid rule ID, save configuration */ @@ -366,9 +415,14 @@ elseif ($_POST['save']) { /**************************************************/ if (isset($id) && $a_nat[$id]) { $a_nat[$id] = $natent; - write_config(); + write_config("Suricata pkg: saved updated app-layer parser configuration for " . convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface'])); $rebuild_rules = false; + conf_mount_rw(); suricata_generate_yaml($natent); + conf_mount_ro(); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); @@ -382,37 +436,46 @@ elseif ($_POST['save']) { } $if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']); -$pgtitle = gettext("Suricata: Interface {$if_friendly} - Layer 7 Application Parsers"); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Application Layer Parsers"); include_once("head.inc"); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); - /* Display error or save message */ + /* Display error message */ if ($input_errors) { print_input_errors($input_errors); } - if ($savemsg) { - print_info_box($savemsg); - } ?> <form action="suricata_app_parsers.php" method="post" name="iform" id="iform"> <input name="id" type="hidden" value="<?=$id;?>"/> <input type="hidden" name="eng_id" id="eng_id" value="<?=$eng_id;?>"/> + +<?php +if ($savemsg) { + /* Display save message */ + print_info_box($savemsg); +} +?> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td>'; @@ -425,6 +488,7 @@ include_once("head.inc"); $tab_array[] = array($menu_iface . gettext("App Parsers"), true, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> @@ -440,6 +504,7 @@ include_once("head.inc"); echo '<input type="hidden" name="eng_resp_body_limit" value="' . $eng_resp_body_limit . '"/>'; echo '<input type="hidden" name="eng_enable_double_decode_path" value="' . $eng_enable_double_decode_path . '"/>'; echo '<input type="hidden" name="eng_enable_double_decode_query" value="' . $eng_enable_double_decode_query . '"/>'; + echo '<input type="hidden" name="eng_enable_uri_include_all" value="' . $eng_enable_uri_include_all . '"/>'; } ?> @@ -449,6 +514,7 @@ include_once("head.inc"); <?php else: ?> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Abstract Syntax One Settings"); ?></td> @@ -465,11 +531,103 @@ include_once("head.inc"); gettext("H.323 (VoIP), and SNMP, use ASN.1 to describe the protocol data units (PDUs) they exchange."); ?> </td> </tr> + + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("DNS App-Layer Parser Settings"); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Global Memcap"); ?></td> + <td width="78%" class="vtable"> + <input name="dns_global_memcap" type="text" class="formfld unknown" id="dns_global_memcap" size="9" + value="<?=htmlspecialchars($pconfig['dns_global_memcap']);?>"> + <?php echo gettext("Sets the global memcap limit for the DNS parser. Default is ") . + "<strong>" . gettext("16777216") . "</strong>" . gettext(" bytes (16MB)."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Flow/State Memcap"); ?></td> + <td width="78%" class="vtable"> + <input name="dns_state_memcap" type="text" class="formfld unknown" id="dns_state_memcap" size="9" + value="<?=htmlspecialchars($pconfig['dns_state_memcap']);?>"> + <?php echo gettext("Sets per flow/state memcap limit for the DNS parser. Default is ") . + "<strong>" . gettext("524288") . "</strong>" . gettext(" bytes (512KB)."); ?> + </td> + </tr> <tr> - <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Host-Specific HTTP Server Settings"); ?></td> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Request Flood Limit"); ?></td> + <td width="78%" class="vtable"> + <input name="dns_request_flood_limit" type="text" class="formfld unknown" id="dns_request_flood_limit" size="9" + value="<?=htmlspecialchars($pconfig['dns_request_flood_limit']);?>"> + <?php echo gettext("How many unreplied DNS requests are considered a flood. Default is ") . + "<strong>" . gettext("500") . "</strong>" . gettext(" requests."); ?><br/> + <?php echo gettext("If this limit is reached, 'app-layer-event:dns.flooded' will match and alert. "); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("UDP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="dns_parser_udp" id="dns_parser_udp" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['dns_parser_udp']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for UDP. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("TCP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="dns_parser_tcp" id="dns_parser_tcp" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['dns_parser_tcp']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for TCP. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("HTTP App-Layer Parser Settings"); ?></td> </tr> <tr> - <td width="22%" valign="top" class="vncell"><?php echo gettext("Server Configuration"); ?></td> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Memcap"); ?></td> + <td width="78%" class="vtable"> + <input name="http_parser_memcap" type="text" class="formfld unknown" id="http_parser_memcap" size="9" + value="<?=htmlspecialchars($pconfig['http_parser_memcap']);?>"> + <?php echo gettext("Sets the memcap limit for the HTTP parser. Default is ") . + "<strong>" . gettext("67108864") . "</strong>" . gettext(" bytes (64MB)."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("HTTP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="http_parser" id="http_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['http_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for HTTP. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Server Configurations"); ?></td> <td width="78%" class="vtable"> <table width="95%" align="left" id="libhtpEnginesTable" style="table-layout: fixed;" border="0" cellspacing="0" cellpadding="0"> <colgroup> @@ -487,6 +645,7 @@ include_once("head.inc"); height="17" border="0" title="<?php echo gettext("Add a new server configuration");?>"></th> </tr> </thead> + <tbody> <?php foreach ($pconfig['libhtp_policy']['item'] as $f => $v): ?> <tr> <td class="listlr" align="left"><?=gettext($v['name']);?></td> @@ -505,19 +664,159 @@ include_once("head.inc"); </td> </tr> <?php endforeach; ?> + </tbody> </table> </td> </tr> <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Other App-Layer Parser Settings"); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("TLS Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="tls_parser" id="tls_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['tls_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for TLS. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("SMTP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="smtp_parser" id="smtp_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['smtp_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for SMTP. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("IMAP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="imap_parser" id="imap_parser" class="formselect"> + <?php + $opt = array( "detection-only", "yes", "no" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['imap_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for IMAP. Default is ") . "<strong>" . gettext("detection-only") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("SSH Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="ssh_parser" id="ssh_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['ssh_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for SSH. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("FTP Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="ftp_parser" id="ftp_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['ftp_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for FTP. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("DCERPC Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="dcerpc_parser" id="dcerpc_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['dcerpc_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for DCERPC. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("SMB Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="smb_parser" id="smb_parser" class="formselect"> + <?php + $opt = array( "yes", "no", "detection-only" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['smb_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for SMB. Default is ") . "<strong>" . gettext("yes") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("MSN Parser"); ?></td> + <td width="78%" class="vtable"> + <select name="msn_parser" id="msn_parser" class="formselect"> + <?php + $opt = array( "detection-only", "yes", "no" ); + foreach ($opt as $val) { + $selected = ""; + if ($val == $pconfig['msn_parser']) + $selected = " selected"; + echo "<option value='{$val}'{$selected}>" . $val . "</option>\n"; + } + ?></select> + <?php echo gettext("Choose the parser/detection setting for MSN. Default is ") . "<strong>" . gettext("detection-only") . "</strong>" . gettext("."); ?><br/> + <?php echo gettext("Selecting \"yes\" enables detection and parser, \"no\" disables both and \"detection-only\" disables parser."); ?> + </td> + </tr> + <tr> <td width="22%" valign="top"> </td> <td width="78%"> <input name="save" type="submit" class="formbtn" value="Save" title="<?php echo - gettext("Save flow and stream settings"); ?>"> + gettext("Save flow and stream settings"); ?>"/> <input name="ResetAll" type="submit" class="formbtn" value="Reset" title="<?php echo gettext("Reset all settings to defaults") . "\" onclick=\"return confirm('" . gettext("WARNING: This will reset ALL App Parsers settings to their defaults. Click OK to continue or CANCEL to quit.") . - "');\""; ?>></td> + "');\""; ?>/></td> </tr> <tr> <td width="22%" valign="top"> </td> @@ -525,12 +824,13 @@ include_once("head.inc"); <?php echo gettext("Please save your settings before you exit. Changes will rebuild the rules file. This "); ?> <?php echo gettext("may take several seconds. Suricata must also be restarted to activate any changes made on this screen."); ?></td> </tr> + </tbody> </table> <?php endif; ?> </div> -</td></tr></table> +</td></tr></tbody></table> </form> <?php include("fend.inc"); ?> </body> diff --git a/config/suricata/suricata_barnyard.php b/config/suricata/suricata_barnyard.php index d4afe4f4..2938136f 100644 --- a/config/suricata/suricata_barnyard.php +++ b/config/suricata/suricata_barnyard.php @@ -79,23 +79,50 @@ if (isset($id) && $a_nat[$id]) { if (empty($a_nat[$id]['barnyard_syslog_opmode'])) $pconfig['barnyard_syslog_opmode'] = "default"; if (empty($a_nat[$id]['barnyard_syslog_facility'])) - $pconfig['barnyard_syslog_facility'] = "LOG_USER"; + $pconfig['barnyard_syslog_facility'] = "LOG_LOCAL1"; if (empty($a_nat[$id]['barnyard_syslog_priority'])) $pconfig['barnyard_syslog_priority'] = "LOG_INFO"; if (empty($a_nat[$id]['barnyard_bro_ids_dport'])) $pconfig['barnyard_bro_ids_dport'] = "47760"; if (empty($a_nat[$id]['barnyard_sensor_id'])) $pconfig['barnyard_sensor_id'] = "0"; - if (empty($a_nat[$id]['barnyard_sensor_name'])) - $pconfig['barnyard_sensor_name'] = php_uname("n"); } if ($_POST['save']) { + + // If disabling Barnyard2 on the interface, stop any + // currently running instance, then save the disabled + // state and exit so as to preserve settings. + if ($_POST['barnyard_enable'] != 'on') { + $a_nat[$id]['barnyard_enable'] = 'off'; + write_config("Suricata pkg: modified Barnyard2 settings."); + suricata_barnyard_stop($a_nat[$id], get_real_interface($a_nat[$id]['interface'])); + + // No need to rebuild rules for Barnyard2 changes + $rebuild_rules = false; + conf_mount_rw(); + sync_suricata_package_config(); + conf_mount_ro(); + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_barnyard.php"); + exit; + } + // Check that at least one output plugin is enabled if ($_POST['barnyard_mysql_enable'] != 'on' && $_POST['barnyard_syslog_enable'] != 'on' && $_POST['barnyard_bro_ids_enable'] != 'on' && $_POST['barnyard_enable'] == "on") $input_errors[] = gettext("You must enable at least one output option when using Barnyard2."); + // Validate Sensor Name contains no spaces + if ($_POST['barnyard_enable'] == 'on') { + if (!empty($_POST['barnyard_sensor_name']) && strpos($_POST['barnyard_sensor_name'], " ") !== FALSE) + $input_errors[] = gettext("The value for 'Sensor Name' cannot contain spaces."); + } + // Validate Sensor ID is a valid integer if ($_POST['barnyard_enable'] == 'on') { if (!is_numericint($_POST['barnyard_sensor_id']) || $_POST['barnyard_sensor_id'] < 0) @@ -160,14 +187,16 @@ if ($_POST['save']) { if ($_POST['barnyard_syslog_priority']) $natent['barnyard_syslog_priority'] = $_POST['barnyard_syslog_priority']; else $natent['barnyard_syslog_priority'] = 'LOG_INFO'; if ($_POST['barnyard_bro_ids_rhost']) $natent['barnyard_bro_ids_rhost'] = $_POST['barnyard_bro_ids_rhost']; else unset($natent['barnyard_bro_ids_rhost']); if ($_POST['barnyard_bro_ids_dport']) $natent['barnyard_bro_ids_dport'] = $_POST['barnyard_bro_ids_dport']; else $natent['barnyard_bro_ids_dport'] = '47760'; - if ($_POST['barnconfigpassthru']) $natent['barnconfigpassthru'] = base64_encode($_POST['barnconfigpassthru']); else unset($natent['barnconfigpassthru']); + if ($_POST['barnconfigpassthru']) $natent['barnconfigpassthru'] = base64_encode(str_replace("\r\n", "\n", $_POST['barnconfigpassthru'])); else unset($natent['barnconfigpassthru']); $a_nat[$id] = $natent; - write_config(); + write_config("Suricata pkg: modified Barnyard2 settings."); // No need to rebuild rules for Barnyard2 changes $rebuild_rules = false; + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); // If disabling Barnyard2 on the interface, stop any // currently running instance. If an instance is @@ -215,18 +244,22 @@ include_once("head.inc"); <form action="suricata_barnyard.php" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td class="tabnavtbl">'; @@ -239,12 +272,14 @@ include_once("head.inc"); $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), true, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("General Barnyard2 " . "Settings"); ?></td> @@ -382,7 +417,7 @@ include_once("head.inc"); <input name="barnyard_syslog_local" type="checkbox" value="on" <?php if ($pconfig['barnyard_syslog_local'] == "on") echo "checked"; ?> onClick="toggle_local_syslog()"/> <?php echo gettext("Enable logging of alerts to the local system only"); ?><br/> - <?php echo gettext("This will send alert data to the local system only and overrides the host, port, protocol, facility and priority values below."); ?></td> + <?php echo gettext("This will send alert data to the local system only and overrides the host, port and protocol values below."); ?></td> </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Remote Host"); ?></td> @@ -416,8 +451,8 @@ include_once("head.inc"); <td width="78%" class="vtable"> <select name="barnyard_syslog_facility" id="barnyard_syslog_facility" class="formselect"> <?php - $log_facility = array( "LOG_AUTH", "LOG_AUTHPRIV", "LOG_DAEMON", "LOG_KERN", "LOG_SYSLOG", "LOG_USER", "LOG_LOCAL1", - "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7" ); + $log_facility = array( "LOG_AUTH", "LOG_AUTHPRIV", "LOG_DAEMON", "LOG_KERN", "LOG_SYSLOG", "LOG_USER", "LOG_LOCAL0", + "LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4", "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7" ); foreach ($log_facility as $facility) { $selected = ""; if ($facility == $pconfig['barnyard_syslog_facility']) @@ -425,7 +460,7 @@ include_once("head.inc"); echo "<option value='{$facility}'{$selected}>" . $facility . "</option>\n"; } ?></select> - <?php echo gettext("Select Syslog Facility to use for remote reporting. Default is ") . "<strong>" . gettext("LOG_USER") . "</strong>."; ?> + <?php echo gettext("Select Syslog Facility to use for remote reporting. Default is ") . "<strong>" . gettext("LOG_LOCAL1") . "</strong>."; ?> </td> </tr> <tr> @@ -433,7 +468,7 @@ include_once("head.inc"); <td width="78%" class="vtable"> <select name="barnyard_syslog_priority" id="barnyard_syslog_priority" class="formselect"> <?php - $log_priority = array( "LOG_EMERG", "LOG_ALERT", "LOG_CRIT", "LOG_ERR", "LOG_WARNING", "LOG_NOTICE", "LOG_INFO" ); + $log_priority = array( "LOG_EMERG", "LOG_CRIT", "LOG_ALERT", "LOG_ERR", "LOG_WARNING", "LOG_NOTICE", "LOG_INFO" ); foreach ($log_priority as $priority) { $selected = ""; if ($priority == $pconfig['barnyard_syslog_priority']) @@ -498,10 +533,12 @@ include_once("head.inc"); <br/> <?php echo gettext("Please save your settings before you click start."); ?> </td> </tr> + </tbody> </table> </div> </td> </tr> + </tbody> </table> </form> @@ -549,8 +586,6 @@ function toggle_local_syslog() { document.iform.barnyard_syslog_dport.disabled = endis; document.iform.barnyard_syslog_proto_udp.disabled = endis; document.iform.barnyard_syslog_proto_tcp.disabled = endis; - document.iform.barnyard_syslog_facility.disabled = endis; - document.iform.barnyard_syslog_priority.disabled = endis; } } @@ -598,11 +633,11 @@ function enable_change(enable_change) { document.iform.barnconfigpassthru.disabled = endis; } -enable_change(false); toggle_mySQL(); toggle_syslog(); toggle_local_syslog(); toggle_bro_ids(); +enable_change(false); </script> diff --git a/config/suricata/suricata_blocked.php b/config/suricata/suricata_blocked.php index 96171c1e..4f4bf095 100644 --- a/config/suricata/suricata_blocked.php +++ b/config/suricata/suricata_blocked.php @@ -10,6 +10,7 @@ * Copyright (C) 2006 Scott Ullrich * Copyright (C) 2009 Robert Zelaya Sr. Developer * Copyright (C) 2012 Ermal Luci + * Copyright (C) 2014 Jim Pingle jim@pingle.org * All rights reserved. * * Adapted for Suricata by: @@ -41,6 +42,8 @@ require_once("guiconfig.inc"); require_once("/usr/local/pkg/suricata/suricata.inc"); +global $g, $config; + $suricatalogdir = SURICATALOGDIR; $suri_pf_table = SURICATA_PF_TABLE; @@ -55,6 +58,21 @@ if (empty($pconfig['blertnumber'])) else $bnentries = $pconfig['blertnumber']; +# --- AJAX REVERSE DNS RESOLVE Start --- +if (isset($_POST['resolve'])) { + $ip = strtolower($_POST['resolve']); + $res = (is_ipaddr($ip) ? gethostbyaddr($ip) : ''); + + if ($res && $res != $ip) + $response = array('resolve_ip' => $ip, 'resolve_text' => $res); + else + $response = array('resolve_ip' => $ip, 'resolve_text' => gettext("Cannot resolve")); + + echo json_encode(str_replace("\\","\\\\", $response)); // single escape chars can break JSON decode + exit; +} +# --- AJAX REVERSE DNS RESOLVE End --- + if ($_POST['todelete']) { $ip = ""; if ($_POST['ip']) @@ -78,22 +96,22 @@ if ($_POST['download']) exec("/sbin/pfctl -t {$suri_pf_table} -T show", $blocked_ips_array_save); /* build the list */ if (is_array($blocked_ips_array_save) && count($blocked_ips_array_save) > 0) { - $save_date = exec('/bin/date "+%Y-%m-%d-%H-%M-%S"'); + $save_date = date("Y-m-d-H-i-s"); $file_name = "suricata_blocked_{$save_date}.tar.gz"; - exec('/bin/mkdir -p /tmp/suricata_blocked'); - file_put_contents("/tmp/suricata_blocked/suricata_block.pf", ""); + safe_mkdir("{$g['tmp_path']}/suricata_blocked"); + file_put_contents("{$g['tmp_path']}/suricata_blocked/suricata_block.pf", ""); foreach($blocked_ips_array_save as $counter => $fileline) { if (empty($fileline)) continue; $fileline = trim($fileline, " \n\t"); - file_put_contents("/tmp/suricata_blocked/suricata_block.pf", "{$fileline}\n", FILE_APPEND); + file_put_contents("{$g['tmp_path']}/suricata_blocked/suricata_block.pf", "{$fileline}\n", FILE_APPEND); } // Create a tar gzip archive of blocked host IP addresses - exec("/usr/bin/tar -czf /tmp/{$file_name} -C/tmp/suricata_blocked suricata_block.pf"); + exec("/usr/bin/tar -czf {$g['tmp_path']}/{$file_name} -C{$g['tmp_path']}/suricata_blocked suricata_block.pf"); // If we successfully created the archive, send it to the browser. - if(file_exists("/tmp/{$file_name}")) { + if(file_exists("{$g['tmp_path']}/{$file_name}")) { ob_start(); //important or other posts will fail if (isset($_SERVER['HTTPS'])) { header('Pragma: '); @@ -103,14 +121,14 @@ if ($_POST['download']) header("Cache-Control: private, must-revalidate"); } header("Content-Type: application/octet-stream"); - header("Content-length: " . filesize("/tmp/{$file_name}")); + header("Content-length: " . filesize("{$g['tmp_path']}/{$file_name}")); header("Content-disposition: attachment; filename = {$file_name}"); ob_end_clean(); //important or other post will fail - readfile("/tmp/{$file_name}"); + readfile("{$g['tmp_path']}/{$file_name}"); // Clean up the temp files and directory - @unlink("/tmp/{$file_name}"); - exec("/bin/rm -fr /tmp/suricata_blocked"); + unlink_if_exists("{$g['tmp_path']}/{$file_name}"); + rmdir_recursive("{$g['tmp_path']}/suricata_blocked"); } else $savemsg = gettext("An error occurred while creating archive"); } else @@ -138,8 +156,6 @@ include_once("head.inc"); ?> <body link="#000000" vlink="#000000" alink="#000000"> -<script src="/javascript/filter_log.js" type="text/javascript"></script> - <?php include_once("fbegin.inc"); @@ -161,19 +177,23 @@ if ($savemsg) { <input type="hidden" name="ip" id="ip" value=""/> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr> <td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), true, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), true, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> @@ -181,6 +201,7 @@ if ($savemsg) { <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" class="listtopic"><?php echo gettext("Blocked Hosts Log View Settings"); ?></td> </tr> @@ -190,7 +211,7 @@ if ($savemsg) { <input name="download" type="submit" class="formbtns" value="Download" title="<?=gettext("Download list of blocked hosts as a gzip archive");?>"/> <?php echo gettext("All blocked hosts will be saved."); ?> <input name="remove" type="submit" class="formbtns" value="Clear" title="<?=gettext("Remove blocks for all listed hosts");?>" - onClick="return confirm('<?=gettext("Are you sure you want to remove all blocked hosts? Click OK to continue or CANCLE to quit.");?>');"/> + onClick="return confirm('<?=gettext("Are you sure you want to remove all blocked hosts? Click OK to continue or CANCEL to quit.");?>');"/> <span class="red"><strong><?php echo gettext("Warning:"); ?></strong></span> <?php echo gettext("all hosts will be removed."); ?> </td> </tr> @@ -219,11 +240,11 @@ if ($savemsg) { <col width="10%" align="center"> </colgroup> <thead> - <tr> + <tr class="sortableHeaderRowIdentifier"> <th class="listhdrr" axis="number">#</th> <th class="listhdrr" axis="string"><?php echo gettext("IP"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Alert Description"); ?></th> - <th class="listhdrr"><?php echo gettext("Remove"); ?></th> + <th class="listhdrr sorttable_nosort"><?php echo gettext("Remove"); ?></th> </tr> </thead> <tbody> @@ -239,16 +260,67 @@ if ($savemsg) { foreach (glob("{$suricatalogdir}*/block.log*") as $alertfile) { $fd = fopen($alertfile, "r"); if ($fd) { - /* 0 1 2 3 4 5 6 7 8 9 10 */ - /* File format timestamp,action,sig_generator,sig_id,sig_rev,msg,classification,priority,proto,ip,port */ - while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { - if(count($fields) < 11) + + /*************** FORMAT for file -- BLOCK -- **************************************************************************/ + /* Line format: timestamp action [**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] {proto} ip:port */ + /* 0 1 2 3 4 5 6 7 8 9 10 */ + /**********************************************************************************************************************/ + + $buf = ""; + while (($buf = fgets($fd)) !== FALSE) { + $fields = array(); + $tmp = array(); + + /***************************************************************/ + /* Parse block log entry to find the parts we want to display. */ + /* We parse out all the fields even though we currently use */ + /* just a few of them. */ + /***************************************************************/ + + // Field 0 is the event timestamp + $fields['time'] = substr($buf, 0, strpos($buf, ' ')); + + // Field 1 is the action + if (strpos($buf, '[') !== FALSE && strpos($buf, ']') !== FALSE) + $fields['action'] = substr($buf, strpos($buf, '[') + 1, strpos($buf, ']') - strpos($buf, '[') - 1); + else + $fields['action'] = null; + + // The regular expression match below returns an array as follows: + // [2] => GID, [3] => SID, [4] => REV, [5] => MSG, [6] => CLASSIFICATION, [7] = PRIORITY + preg_match('/\[\*{2}\]\s\[((\d+):(\d+):(\d+))\]\s(.*)\[\*{2}\]\s\[Classification:\s(.*)\]\s\[Priority:\s(\d+)\]\s/', $buf, $tmp); + $fields['gid'] = trim($tmp[2]); + $fields['sid'] = trim($tmp[3]); + $fields['rev'] = trim($tmp[4]); + $fields['msg'] = trim($tmp[5]); + $fields['class'] = trim($tmp[6]); + $fields['priority'] = trim($tmp[7]); + + // The regular expression match below looks for the PROTO, IP and PORT fields + // and returns an array as follows: + // [1] = PROTO, [2] => IP:PORT + if (preg_match('/\{(.*)\}\s(.*)/', $buf, $tmp)) { + // Get PROTO + $fields['proto'] = trim($tmp[1]); + + // Get IP + $fields['ip'] = trim(substr($tmp[2], 0, strrpos($tmp[2], ':'))); + if (is_ipaddrv6($fields['ip'])) + $fields['ip'] = inet_ntop(inet_pton($fields['ip'])); + + // Get PORT + $fields['port'] = trim(substr($tmp[2], strrpos($tmp[2], ':') + 1)); + } + + // In the unlikely event we read an old log file and fail to parse + // out an IP address, just skip the record since we can't use it. + if (empty($fields['ip'])) continue; - $fields[9] = inet_pton($fields[9]); - if (isset($tmpblocked[$fields[9]])) { - if (!is_array($src_ip_list[$fields[9]])) - $src_ip_list[$fields[9]] = array(); - $src_ip_list[$fields[9]][$fields[5]] = "{$fields[5]} - " . substr($fields[0], 0, -7); + $fields['ip'] = inet_pton($fields['ip']); + if (isset($tmpblocked[$fields['ip']])) { + if (!is_array($src_ip_list[$fields['ip']])) + $src_ip_list[$fields['ip']] = array(); + $src_ip_list[$fields['ip']][$fields['msg']] = "{$fields['msg']} - " . substr($fields['time'], 0, -7); } } fclose($fd); @@ -274,18 +346,15 @@ if ($savemsg) { $tmp_ip = str_replace(":", ":​", $block_ip_str); /* Add reverse DNS lookup icons */ $rdns_link = ""; - $rdns_link .= "<a onclick=\"javascript:getURL('/diag_dns.php?host={$block_ip_str}&dialog_output=true', outputrule);\">"; - $rdns_link .= "<img src='../themes/{$g['theme']}/images/icons/icon_log_d.gif' width='11' height='11' border='0' "; - $rdns_link .= "title='" . gettext("Resolve host via reverse DNS lookup (quick pop-up)") . "' style=\"cursor: pointer;\"></a> "; - $rdns_link .= "<a href='/diag_dns.php?host={$block_ip_str}'>"; - $rdns_link .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; - $rdns_link .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; + $rdns_link .= "<img onclick=\"javascript:resolve_with_ajax('{$block_ip_str}');\" title=\""; + $rdns_link .= gettext("Resolve host via reverse DNS lookup") . "\" border=\"0\" src=\"/themes/{$g['theme']}/images/icons/icon_log.gif\" alt=\"Icon Reverse Resolve with DNS\" "; + $rdns_link.= " style=\"cursor: pointer;\"/>"; /* use one echo to do the magic*/ echo "<tr> <td align=\"center\" valign=\"middle\" class=\"listr\">{$counter}</td> <td align=\"center\" valign=\"middle\" class=\"listr\">{$tmp_ip}<br/>{$rdns_link}</td> <td valign=\"middle\" class=\"listr\">{$blocked_desc}</td> - <td align=\"center\" valign=\"middle\" class=\"listr\" sorttable_customkey=\"\"> + <td align=\"center\" valign=\"middle\" class=\"listr\"> <input type=\"image\" name=\"todelete[]\" onClick=\"document.getElementById('ip').value='{$block_ip_str}';\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\" title=\"" . gettext("Delete host from Blocked Table") . "\" border=\"0\" /></td> </tr>\n"; @@ -310,14 +379,49 @@ if ($savemsg) { ?> </td> </tr> + </tbody> </table> </div> </td> </tr> +</tbody> </table> </form> <?php include("fend.inc"); ?> + +<!-- The following AJAX code was borrowed from the diag_logs_filter.php --> +<!-- file in pfSense. See copyright info at top of this page. --> +<script type="text/javascript"> +//<![CDATA[ +function resolve_with_ajax(ip_to_resolve) { + var url = "/suricata/suricata_blocked.php"; + + jQuery.ajax( + url, + { + type: 'post', + dataType: 'json', + data: { + resolve: ip_to_resolve, + }, + complete: resolve_ip_callback + }); +} + +function resolve_ip_callback(transport) { + var response = jQuery.parseJSON(transport.responseText); + var msg = 'IP address "' + response.resolve_ip + '" resolves to\n'; + alert(msg + 'host "' + htmlspecialchars(response.resolve_text) + '"'); +} + +// From http://stackoverflow.com/questions/5499078/fastest-method-to-escape-html-tags-as-html-entities +function htmlspecialchars(str) { + return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); +} +//]]> +</script> + </body> </html> diff --git a/config/suricata/suricata_check_cron_misc.inc b/config/suricata/suricata_check_cron_misc.inc index f750c530..eb1ba2d0 100644 --- a/config/suricata/suricata_check_cron_misc.inc +++ b/config/suricata/suricata_check_cron_misc.inc @@ -66,13 +66,13 @@ function suricata_check_dir_size_limit($suricataloglimitsize) { conf_mount_rw(); // Truncate the Rules Update Log file if it exists - if (file_exists(RULES_UPD_LOGFILE)) { + if (file_exists(SURICATA_RULES_UPD_LOGFILE)) { log_error(gettext("[Suricata] Truncating the Rules Update Log file...")); - @file_put_contents(RULES_UPD_LOGFILE, ""); + @file_put_contents(SURICATA_RULES_UPD_LOGFILE, ""); } // Initialize an array of the log files we want to prune - $logs = array ( "alerts.log", "http.log", "files-json.log", "tls.log", "stats.log" ); + $logs = array ( "alerts.log", "block.log", "dns.log", "eve.json", "http.log", "files-json.log", "sid_changes.log", "stats.log", "tls.log" ); // Clean-up the logs for each configured Suricata instance foreach ($config['installedpackages']['suricata']['rule'] as $value) { @@ -93,6 +93,14 @@ function suricata_check_dir_size_limit($suricataloglimitsize) { } } + // Cleanup any rotated logs + log_error(gettext("[Suricata] Deleting any rotated log files for {$value['descr']} ({$if_real})...")); + unlink_if_exists("{$suricata_log_dir}/*.log.*"); + + // Cleanup any rotated pcap logs + log_error(gettext("[Suricata] Deleting any rotated pcap log files for {$value['descr']} ({$if_real})...")); + unlink_if_exists("{$suricata_log_dir}/log.pcap.*"); + // Check for any captured stored files and clean them up unlink_if_exists("{$suricata_log_dir}/files/*"); @@ -126,8 +134,10 @@ function suricata_check_rotate_log($log_file, $log_limit, $retention) { // Check the current log to see if it needs rotating. // If it does, rotate it and put the current time // on the end of the filename as UNIX timestamp. + if (!file_exists($log_file)) + return; if (($log_limit > 0) && (filesize($log_file) >= $log_limit)) { - $newfile = $log_file . "." . strval(time()); + $newfile = $log_file . "." . date('Y_md_Hi'); try { copy($log_file, $newfile); file_put_contents($log_file, ""); @@ -168,10 +178,18 @@ $logs = array (); // Build an arry of files to check and limits to check them against from our saved configuration $logs['alerts.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['alert_log_limit_size']; $logs['alerts.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['alert_log_retention']; +$logs['block.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['block_log_limit_size']; +$logs['block.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['block_log_retention']; +$logs['dns.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['dns_log_limit_size']; +$logs['dns.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['dns_log_retention']; +$logs['eve.json']['limit'] = $config['installedpackages']['suricata']['config'][0]['eve_log_limit_size']; +$logs['eve.json']['retention'] = $config['installedpackages']['suricata']['config'][0]['eve_log_retention']; $logs['files-json.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['files_json_log_limit_size']; $logs['files-json.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['files_json_log_retention']; $logs['http.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['http_log_limit_size']; $logs['http.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['http_log_retention']; +$logs['sid_changes.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['sid_changes_log_limit_size']; +$logs['sid_changes.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['sid_changes_log_retention']; $logs['stats.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['stats_log_limit_size']; $logs['stats.log']['retention'] = $config['installedpackages']['suricata']['config'][0]['stats_log_retention']; $logs['tls.log']['limit'] = $config['installedpackages']['suricata']['config'][0]['tls_log_limit_size']; @@ -190,24 +208,53 @@ if ($config['installedpackages']['suricata']['config'][0]['enable_log_mgmt'] == $config['installedpackages']['suricata']['config'][0]['u2_archive_log_retention'] > 0) { $now = time(); $files = glob("{$suricata_log_dir}/barnyard2/archive/unified2.alert.*"); + $prune_count = 0; foreach ($files as $f) { - if (($now - filemtime($f)) > ($config['installedpackages']['suricata']['config'][0]['u2_archive_log_retention'] * 3600)) + if (($now - filemtime($f)) > ($config['installedpackages']['suricata']['config'][0]['u2_archive_log_retention'] * 3600)) { + $prune_count++; unlink_if_exists($f); + } } + if ($prune_count > 0) + log_error(gettext("[Suricata] Barnyard2 archived logs cleanup job removed {$prune_count} file(s) from {$suricata_log_dir}/barnyard2/archive/...")); + unset($files); } - unset($files); // Prune aged-out File Store files if any exist if (is_dir("{$suricata_log_dir}/files") && $config['installedpackages']['suricata']['config'][0]['file_store_retention'] > 0) { $now = time(); $files = glob("{$suricata_log_dir}/files/file.*"); + $prune_count = 0; foreach ($files as $f) { - if (($now - filemtime($f)) > ($config['installedpackages']['suricata']['config'][0]['file_store_retention'] * 3600)) + if (($now - filemtime($f)) > ($config['installedpackages']['suricata']['config'][0]['file_store_retention'] * 3600)) { + $prune_count++; unlink_if_exists($f); + } + } + if ($prune_count > 0) + log_error(gettext("[Suricata] File Store cleanup job removed {$prune_count} file(s) from {$suricata_log_dir}/files/...")); + unset($files); + } + + // Prune any pcap log files over configured limit + $files = glob("{$suricata_log_dir}/log.pcap.*"); + if (count($files) > $value['max_pcap_log_files']) { + $over = count($files) - $value['max_pcap_log_files']; + $remove_files = array(); + while ($over > 0) { + $remove_files[] = array_shift($files); + $over--; + } + $prune_count = 0; + foreach ($remove_files as $f) { + $prune_count++; + unlink_if_exists($f); } + if ($prune_count > 0) + log_error(gettext("[Suricata] Packet Capture log cleanup job removed {$prune_count} file(s) from {$suricata_log_dir}/...")); + unset($files, $remove_files); } - unset($files); } } diff --git a/config/suricata/suricata_check_for_rule_updates.php b/config/suricata/suricata_check_for_rule_updates.php index bb29078f..0fa4fb2d 100644 --- a/config/suricata/suricata_check_for_rule_updates.php +++ b/config/suricata/suricata_check_for_rule_updates.php @@ -41,41 +41,13 @@ require_once("functions.inc"); require_once("service-utils.inc"); require_once("/usr/local/pkg/suricata/suricata.inc"); +require_once("/usr/local/pkg/suricata/suricata_defs.inc"); global $g, $pkg_interface, $suricata_gui_include, $rebuild_rules; -if (!defined("VRT_DNLD_URL")) - define("VRT_DNLD_URL", "https://www.snort.org/reg-rules/"); -if (!defined("ET_VERSION")) - define("ET_VERSION", "2.9.0"); -if (!defined("ET_BASE_DNLD_URL")) - define("ET_BASE_DNLD_URL", "http://rules.emergingthreats.net/"); -if (!defined("ETPRO_BASE_DNLD_URL")) - define("ETPRO_BASE_DNLD_URL", "https://rules.emergingthreatspro.com/"); -if (!defined("ET_DNLD_FILENAME")) - define("ET_DNLD_FILENAME", "emerging.rules.tar.gz"); -if (!defined("ETPRO_DNLD_FILENAME")) - define("ETPRO_DNLD_FILENAME", "etpro.rules.tar.gz"); -if (!defined("VRT_DNLD_FILENAME")) - define("VRT_DNLD_FILENAME", "snortrules-snapshot-edge.tar.gz"); -if (!defined("GPLV2_DNLD_FILENAME")) - define("GPLV2_DNLD_FILENAME", "community-rules.tar.gz"); -if (!defined("GPLV2_DNLD_URL")) - define("GPLV2_DNLD_URL", "https://s3.amazonaws.com/snort-org/www/rules/community/"); -if (!defined("RULES_UPD_LOGFILE")) - define("RULES_UPD_LOGFILE", SURICATALOGDIR . "/suricata_rules_update.log"); -if (!defined("VRT_FILE_PREFIX")) - define("VRT_FILE_PREFIX", "snort_"); -if (!defined("GPL_FILE_PREFIX")) - define("GPL_FILE_PREFIX", "GPLv2_"); -if (!defined("ET_OPEN_FILE_PREFIX")) - define("ET_OPEN_FILE_PREFIX", "emerging-"); -if (!defined("ET_PRO_FILE_PREFIX")) - define("ET_PRO_FILE_PREFIX", "etpro-"); - $suricatadir = SURICATADIR; $suricatalogdir = SURICATALOGDIR; -$suricata_rules_upd_log = RULES_UPD_LOGFILE; +$mounted_rw = FALSE; /* Save the state of $pkg_interface so we can restore it */ $pkg_interface_orig = $pkg_interface; @@ -86,6 +58,7 @@ else /* define checks */ $oinkid = $config['installedpackages']['suricata']['config'][0]['oinkcode']; +$snort_filename = $config['installedpackages']['suricata']['config'][0]['snort_rules_file']; $etproid = $config['installedpackages']['suricata']['config'][0]['etprocode']; $snortdownload = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'] == 'on' ? 'on' : 'off'; $etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules'] == 'on' ? 'on' : 'off'; @@ -94,10 +67,9 @@ $vrt_enabled = $config['installedpackages']['suricata']['config'][0]['enable_vrt $snortcommunityrules = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules'] == 'on' ? 'on' : 'off'; /* Working directory for downloaded rules tarballs */ -$tmpfname = "/tmp/suricata_rules_up"; +$tmpfname = "{$g['tmp_path']}/suricata_rules_up"; -/* Snort Edge VRT Rules filenames and URL */ -$snort_filename = VRT_DNLD_FILENAME; +/* Snort VRT Rules filenames and URL */ $snort_filename_md5 = "{$snort_filename}.md5"; $snort_rule_url = VRT_DNLD_URL; @@ -107,7 +79,10 @@ $snort_community_rules_filename_md5 = GPLV2_DNLD_FILENAME . ".md5"; $snort_community_rules_url = GPLV2_DNLD_URL; /* Mount the Suricata conf directories R/W so we can modify files there */ -conf_mount_rw(); +if (!is_subsystem_dirty('mount')) { + conf_mount_rw(); + $mounted_rw = TRUE; +} /* Set up Emerging Threats rules filenames and URL */ if ($etpro == "on") { @@ -117,7 +92,7 @@ if ($etpro == "on") { $emergingthreats_url .= "{$etproid}/suricata/"; $et_name = "Emerging Threats Pro"; $et_md5_remove = ET_DNLD_FILENAME . ".md5"; - @unlink("{$suricatadir}{$et_md5_remove}"); + unlink_if_exists("{$suricatadir}{$et_md5_remove}"); } else { $emergingthreats_filename = ET_DNLD_FILENAME; @@ -128,7 +103,7 @@ else { $emergingthreats_url .= "suricata/"; $et_name = "Emerging Threats Open"; $et_md5_remove = ETPRO_DNLD_FILENAME . ".md5"; - @unlink("{$suricatadir}{$et_md5_remove}"); + unlink_if_exists("{$suricatadir}{$et_md5_remove}"); } // Set a common flag for all Emerging Threats rules (open and pro). @@ -211,7 +186,9 @@ function suricata_download_file_url($url, $file_out) { curl_setopt($ch, CURLOPT_FILE, $fout); // NOTE: required to suppress errors from XMLRPC due to progress bar output - if ($g['suricata_sync_in_progress']) + // and to prevent useless spam from rules update cron job execution. This + // prevents progress bar output during package sync and rules update cron task. + if ($g['suricata_sync_in_progress'] || $pkg_interface == "console") curl_setopt($ch, CURLOPT_HEADER, false); else { curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header'); @@ -285,21 +262,21 @@ function suricata_check_rule_md5($file_url, $file_dst, $desc = "") { /* error occurred. */ /**********************************************************/ - global $pkg_interface, $suricata_rules_upd_log, $last_curl_error, $update_errors; + global $pkg_interface, $last_curl_error, $update_errors; $suricatadir = SURICATADIR; $filename_md5 = basename($file_dst); if ($pkg_interface <> "console") update_status(gettext("Downloading {$desc} md5 file...")); - error_log(gettext("\tDownloading {$desc} md5 file {$filename_md5}...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tDownloading {$desc} md5 file {$filename_md5}...\n"), 3, SURICATA_RULES_UPD_LOGFILE); $rc = suricata_download_file_url($file_url, $file_dst); // See if download from URL was successful if ($rc === true) { if ($pkg_interface <> "console") update_status(gettext("Done downloading {$filename_md5}.")); - error_log("\tChecking {$desc} md5 file...\n", 3, $suricata_rules_upd_log); + error_log("\tChecking {$desc} md5 file...\n", 3, SURICATA_RULES_UPD_LOGFILE); // check md5 hash in new file against current file to see if new download is posted if (file_exists("{$suricatadir}{$filename_md5}")) { @@ -309,7 +286,7 @@ function suricata_check_rule_md5($file_url, $file_dst, $desc = "") { if ($pkg_interface <> "console") update_status(gettext("{$desc} are up to date...")); log_error(gettext("[Suricata] {$desc} are up to date...")); - error_log(gettext("\t{$desc} are up to date.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} are up to date.\n"), 3, SURICATA_RULES_UPD_LOGFILE); return false; } else @@ -318,7 +295,7 @@ function suricata_check_rule_md5($file_url, $file_dst, $desc = "") { return true; } else { - error_log(gettext("\t{$desc} md5 download failed.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} md5 download failed.\n"), 3, SURICATA_RULES_UPD_LOGFILE); $suricata_err_msg = gettext("Server returned error code {$rc}."); if ($pkg_interface <> "console") { update_status(gettext("{$desc} md5 error ... Server returned error code {$rc} ...")); @@ -326,10 +303,10 @@ function suricata_check_rule_md5($file_url, $file_dst, $desc = "") { } log_error(gettext("[Suricata] {$desc} md5 download failed...")); log_error(gettext("[Suricata] Server returned error code {$rc}...")); - error_log(gettext("\t{$suricata_err_msg}\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$suricata_err_msg}\n"), 3, SURICATA_RULES_UPD_LOGFILE); if ($pkg_interface == "console") - error_log(gettext("\tServer error message was: {$last_curl_error}\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\t{$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tServer error message was: {$last_curl_error}\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\t{$desc} will not be updated.\n"), 3, SURICATA_RULES_UPD_LOGFILE); $update_errors = true; return false; } @@ -354,7 +331,7 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { /* FALSE if download was not successful. */ /**********************************************************/ - global $pkg_interface, $suricata_rules_upd_log, $last_curl_error, $update_errors; + global $pkg_interface, $last_curl_error, $update_errors; $suricatadir = SURICATADIR; $filename = basename($file_dst); @@ -362,8 +339,8 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { if ($pkg_interface <> "console") update_status(gettext("There is a new set of {$desc} posted. Downloading...")); log_error(gettext("[Suricata] There is a new set of {$desc} posted. Downloading {$filename}...")); - error_log(gettext("\tThere is a new set of {$desc} posted.\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\tDownloading file '{$filename}'...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tThere is a new set of {$desc} posted.\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\tDownloading file '{$filename}'...\n"), 3, SURICATA_RULES_UPD_LOGFILE); $rc = suricata_download_file_url($file_url, $file_dst); // See if the download from the URL was successful @@ -371,7 +348,7 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { if ($pkg_interface <> "console") update_status(gettext("Done downloading {$desc} file.")); log_error("[Suricata] {$desc} file update downloaded successfully"); - error_log(gettext("\tDone downloading rules file.\n"),3, $suricata_rules_upd_log); + error_log(gettext("\tDone downloading rules file.\n"),3, SURICATA_RULES_UPD_LOGFILE); // Test integrity of the rules file. Turn off update if file has wrong md5 hash if ($file_md5 != trim(md5_file($file_dst))){ @@ -380,10 +357,10 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { log_error(gettext("[Suricata] {$desc} file download failed. Bad MD5 checksum...")); log_error(gettext("[Suricata] Downloaded File MD5: " . md5_file($file_dst))); log_error(gettext("[Suricata] Expected File MD5: {$file_md5}")); - error_log(gettext("\t{$desc} file download failed. Bad MD5 checksum.\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\tDownloaded {$desc} file MD5: " . md5_file($file_dst) . "\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\tExpected {$desc} file MD5: {$file_md5}\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\t{$desc} file download failed. {$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} file download failed. Bad MD5 checksum.\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\tDownloaded {$desc} file MD5: " . md5_file($file_dst) . "\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\tExpected {$desc} file MD5: {$file_md5}\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\t{$desc} file download failed. {$desc} will not be updated.\n"), 3, SURICATA_RULES_UPD_LOGFILE); $update_errors = true; return false; } @@ -393,10 +370,10 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { if ($pkg_interface <> "console") update_output_window(gettext("{$desc} file download failed...")); log_error(gettext("[Suricata] {$desc} file download failed... server returned error '{$rc}'...")); - error_log(gettext("\t{$desc} file download failed. Server returned error {$rc}.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} file download failed. Server returned error {$rc}.\n"), 3, SURICATA_RULES_UPD_LOGFILE); if ($pkg_interface == "console") - error_log(gettext("\tThe error text was: {$last_curl_error}\n"), 3, $suricata_rules_upd_log); - error_log(gettext("\t{$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tThe error text was: {$last_curl_error}\n"), 3, SURICATA_RULES_UPD_LOGFILE); + error_log(gettext("\t{$desc} will not be updated.\n"), 3, SURICATA_RULES_UPD_LOGFILE); $update_errors = true; return false; } @@ -407,21 +384,21 @@ function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { /* remove old $tmpfname files if present */ if (is_dir("{$tmpfname}")) - exec("/bin/rm -r {$tmpfname}"); + rmdir_recursive("{$tmpfname}"); /* Make sure required suricatadirs exsist */ -exec("/bin/mkdir -p {$suricatadir}rules"); -exec("/bin/mkdir -p {$tmpfname}"); -exec("/bin/mkdir -p {$suricatalogdir}"); +safe_mkdir("{$suricatadir}rules"); +safe_mkdir("{$tmpfname}"); +safe_mkdir("{$suricatalogdir}"); /* See if we need to automatically clear the Update Log based on 1024K size limit */ -if (file_exists($suricata_rules_upd_log)) { - if (1048576 < filesize($suricata_rules_upd_log)) - exec("/bin/rm -r {$suricata_rules_upd_log}"); +if (file_exists(SURICATA_RULES_UPD_LOGFILE)) { + if (1048576 < filesize(SURICATA_RULES_UPD_LOGFILE)) + unlink_if_exists("{SURICATA_RULES_UPD_LOGFILE}"); } /* Log start time for this rules update */ -error_log(gettext("Starting rules update... Time: " . date("Y-m-d H:i:s") . "\n"), 3, $suricata_rules_upd_log); +error_log(gettext("Starting rules update... Time: " . date("Y-m-d H:i:s") . "\n"), 3, SURICATA_RULES_UPD_LOGFILE); $last_curl_error = ""; $update_errors = false; @@ -439,10 +416,15 @@ if ($emergingthreats == 'on') { /* Check for and download any new Snort VRT sigs */ if ($snortdownload == 'on') { - if (suricata_check_rule_md5("{$snort_rule_url}{$snort_filename_md5}/{$oinkid}/", "{$tmpfname}/{$snort_filename_md5}", "Snort VRT rules")) { + if (empty($snort_filename)) { + log_error(gettext("No snortrules-snapshot filename has been set on Snort pkg GLOBAL SETTINGS tab. Snort VRT rules cannot be updated.")); + error_log(gettext("\tWARNING-- No snortrules-snapshot filename set on GLOBAL SETTINGS tab. Snort VRT rules cannot be updated!\n"), 3, SURICATA_RULES_UPD_LOGFILE); + $snortdownload = 'off'; + } + elseif (suricata_check_rule_md5("{$snort_rule_url}{$snort_filename_md5}?oinkcode={$oinkid}", "{$tmpfname}/{$snort_filename_md5}", "Snort VRT rules")) { /* download snortrules file */ $file_md5 = trim(file_get_contents("{$tmpfname}/{$snort_filename_md5}")); - if (!suricata_fetch_new_rules("{$snort_rule_url}{$snort_filename}/{$oinkid}/", "{$tmpfname}/{$snort_filename}", $file_md5, "Snort VRT rules")) + if (!suricata_fetch_new_rules("{$snort_rule_url}{$snort_filename}?oinkcode={$oinkid}", "{$tmpfname}/{$snort_filename}", $file_md5, "Snort VRT rules")) $snortdownload = 'off'; } else @@ -451,7 +433,7 @@ if ($snortdownload == 'on') { /* Check for and download any new Snort GPLv2 Community Rules sigs */ if ($snortcommunityrules == 'on') { - if (suricata_check_rule_md5("{$snort_community_rules_url}{$snort_community_rules_filename_md5}", "{$tmpfname}/{$snort_community_rules_filename_md5}", "Snort GPLv2 Community Rules")) { + if (suricata_check_rule_md5("{$snort_community_rules_url}{$snort_community_rules_filename}/md5", "{$tmpfname}/{$snort_community_rules_filename_md5}", "Snort GPLv2 Community Rules")) { /* download Snort GPLv2 Community Rules file */ $file_md5 = trim(file_get_contents("{$tmpfname}/{$snort_community_rules_filename_md5}")); if (!suricata_fetch_new_rules("{$snort_community_rules_url}{$snort_community_rules_filename}", "{$tmpfname}/{$snort_community_rules_filename}", $file_md5, "Snort GPLv2 Community Rules")) @@ -469,7 +451,7 @@ if ($emergingthreats == 'on') { update_status(gettext("Extracting {$et_name} rules...")); update_output_window(gettext("Installing {$et_name} rules...")); } - error_log(gettext("\tExtracting and installing {$et_name} rules...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tExtracting and installing {$et_name} rules...\n"), 3, SURICATA_RULES_UPD_LOGFILE); exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$tmpfname}/emerging rules/"); /* Remove the old Emerging Threats rules files */ @@ -483,7 +465,7 @@ if ($emergingthreats == 'on') { // The code below renames ET files with a prefix, so we // skip renaming the Suricata default events rule files // that are also bundled in the ET rules. - $default_rules = array( "decoder-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules", "tls-events.rules" ); + $default_rules = array( "decoder-events.rules", "dns-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules", "tls-events.rules" ); $files = glob("{$tmpfname}/emerging/rules/*.rules"); // Determine the correct prefix to use based on which // Emerging Threats rules package is enabled. @@ -527,8 +509,8 @@ if ($emergingthreats == 'on') { update_status(gettext("Extraction of {$et_name} rules completed...")); update_output_window(gettext("Installation of {$et_name} rules completed...")); } - error_log(gettext("\tInstallation of {$et_name} rules completed.\n"), 3, $suricata_rules_upd_log); - exec("rm -r {$tmpfname}/emerging"); + error_log(gettext("\tInstallation of {$et_name} rules completed.\n"), 3, SURICATA_RULES_UPD_LOGFILE); + rmdir_recursive("{$tmpfname}/emerging"); } } @@ -543,7 +525,7 @@ if ($snortdownload == 'on') { update_status(gettext("Extracting Snort VRT rules...")); update_output_window(gettext("Installing Sourcefire VRT rules...")); } - error_log(gettext("\tExtracting and installing Snort VRT rules...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tExtracting and installing Snort VRT rules...\n"), 3, SURICATA_RULES_UPD_LOGFILE); /* extract snort.org rules and add prefix to all snort.org files */ safe_mkdir("{$tmpfname}/snortrules"); @@ -560,7 +542,7 @@ if ($snortdownload == 'on') { $newfile = basename($file); @copy($file, "{$suricatadir}rules/{$newfile}"); } - exec("rm -r {$tmpfname}/snortrules"); + rmdir_recursive("{$tmpfname}/snortrules"); /* extract base etc files */ if ($pkg_interface <> "console") { @@ -572,7 +554,7 @@ if ($snortdownload == 'on') { if (file_exists("{$tmpfname}/etc/{$file}")) @copy("{$tmpfname}/etc/{$file}", "{$tmpfname}/VRT_{$file}"); } - exec("rm -r {$tmpfname}/etc"); + rmdir_recursive("{$tmpfname}/etc"); if (file_exists("{$tmpfname}/{$snort_filename_md5}")) { if ($pkg_interface <> "console") update_status(gettext("Copying md5 signature to Suricata directory...")); @@ -582,7 +564,7 @@ if ($snortdownload == 'on') { update_status(gettext("Extraction of Snort VRT rules completed...")); update_output_window(gettext("Installation of Sourcefire VRT rules completed...")); } - error_log(gettext("\tInstallation of Snort VRT rules completed.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tInstallation of Snort VRT rules completed.\n"), 3, SURICATA_RULES_UPD_LOGFILE); } } @@ -594,7 +576,7 @@ if ($snortcommunityrules == 'on') { update_status(gettext("Extracting Snort GPLv2 Community Rules...")); update_output_window(gettext("Installing Snort GPLv2 Community Rules...")); } - error_log(gettext("\tExtracting and installing Snort GPLv2 Community Rules...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tExtracting and installing Snort GPLv2 Community Rules...\n"), 3, SURICATA_RULES_UPD_LOGFILE); exec("/usr/bin/tar xzf {$tmpfname}/{$snort_community_rules_filename} -C {$tmpfname}/community/"); $files = glob("{$tmpfname}/community/community-rules/*.rules"); @@ -617,8 +599,8 @@ if ($snortcommunityrules == 'on') { update_status(gettext("Extraction of Snort GPLv2 Community Rules completed...")); update_output_window(gettext("Installation of Snort GPLv2 Community Rules file completed...")); } - error_log(gettext("\tInstallation of Snort GPLv2 Community Rules completed.\n"), 3, $suricata_rules_upd_log); - exec("rm -r {$tmpfname}/community"); + error_log(gettext("\tInstallation of Snort GPLv2 Community Rules completed.\n"), 3, SURICATA_RULES_UPD_LOGFILE); + rmdir_recursive("{$tmpfname}/community"); } } @@ -640,7 +622,7 @@ if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules = if ($pkg_interface <> "console") update_status(gettext('Copying new config and map files...')); - error_log(gettext("\tCopying new config and map files...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tCopying new config and map files...\n"), 3, SURICATA_RULES_UPD_LOGFILE); /******************************************************************/ /* Build the classification.config and reference.config files */ @@ -669,10 +651,14 @@ if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules = /* Start the rules rebuild proccess for each configured interface */ if (is_array($config['installedpackages']['suricata']['rule']) && - !empty($config['installedpackages']['suricata']['rule'])) { + count($config['installedpackages']['suricata']['rule']) > 0) { - /* Set the flag to force rule rebuilds since we downloaded new rules */ - $rebuild_rules = true; + /* Set the flag to force rule rebuilds since we downloaded new rules, */ + /* except when in post-install mode. Post-install does its own rebuild. */ + if ($g['suricata_postinstall']) + $rebuild_rules = false; + else + $rebuild_rules = true; /* Create configuration for each active Suricata interface */ foreach ($config['installedpackages']['suricata']['rule'] as $value) { @@ -690,7 +676,7 @@ if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules = } suricata_apply_customizations($value, $if_real); $tmp = "\t" . $tmp . "\n"; - error_log($tmp, 3, $suricata_rules_upd_log); + error_log($tmp, 3, SURICATA_RULES_UPD_LOGFILE); } } else { @@ -698,44 +684,43 @@ if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules = update_output_window(gettext("Warning: No interfaces configured for Suricata were found...")); update_output_window(gettext("No interfaces currently have Suricata configured and enabled on them...")); } - error_log(gettext("\tWarning: No interfaces configured for Suricata were found...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tWarning: No interfaces configured for Suricata were found...\n"), 3, SURICATA_RULES_UPD_LOGFILE); } /* Clear the rebuild rules flag. */ $rebuild_rules = false; - /* Restart Suricata if already running and we are not rebooting to pick up the new rules. */ - if (is_process_running("suricata") && !$g['booting'] && - !empty($config['installedpackages']['suricata']['rule'])) { + /* Restart Suricata if already running and we are not in post-install, so as to pick up the new rules. */ + if (is_process_running("suricata") && !$g['suricata_postinstall'] && + count($config['installedpackages']['suricata']['rule']) > 0) { // See if "Live Reload" is configured and signal each Suricata instance // if enabled, else just do a hard restart of all the instances. if ($config['installedpackages']['suricata']['config'][0]['live_swap_updates'] == 'on') { if ($pkg_interface <> "console") { - update_status(gettext('Signalling Suricata to live-load the new set of rules...')); + update_status(gettext('Signaling Suricata to live-load the new set of rules...')); update_output_window(gettext("Please wait ... the process should complete in a few seconds...")); } log_error(gettext("[Suricata] Live-Reload of rules from auto-update is enabled...")); - error_log(gettext("\tLive-Reload of updated rules is enabled...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tLive-Reload of updated rules is enabled...\n"), 3, SURICATA_RULES_UPD_LOGFILE); foreach ($config['installedpackages']['suricata']['rule'] as $value) { - $if_real = get_real_interface($value['interface']); suricata_reload_config($value); - error_log(gettext("\tLive swap of updated rules requested for " . convert_friendly_interface_to_friendly_descr($value['interface']) . ".\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tLive swap of updated rules requested for " . convert_friendly_interface_to_friendly_descr($value['interface']) . ".\n"), 3, SURICATA_RULES_UPD_LOGFILE); } log_error(gettext("[Suricata] Live-Reload of updated rules completed...")); - error_log(gettext("\tLive-Reload of the updated rules is complete.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tLive-Reload of the updated rules is complete.\n"), 3, SURICATA_RULES_UPD_LOGFILE); } else { if ($pkg_interface <> "console") { update_status(gettext('Restarting Suricata to activate the new set of rules...')); update_output_window(gettext("Please wait ... restarting Suricata will take some time...")); } - error_log(gettext("\tRestarting Suricata to activate the new set of rules...\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tRestarting Suricata to activate the new set of rules...\n"), 3, SURICATA_RULES_UPD_LOGFILE); restart_service("suricata"); if ($pkg_interface <> "console") update_output_window(gettext("Suricata has restarted with your new set of rules...")); log_error(gettext("[Suricata] Suricata has restarted with your new set of rules...")); - error_log(gettext("\tSuricata has restarted with your new set of rules.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tSuricata has restarted with your new set of rules.\n"), 3, SURICATA_RULES_UPD_LOGFILE); } } else { @@ -750,7 +735,7 @@ if (is_dir("{$tmpfname}")) { update_status(gettext("Cleaning up after rules extraction...")); update_output_window(gettext("Removing {$tmpfname} directory...")); } - exec("/bin/rm -r {$tmpfname}"); + rmdir_recursive("{$tmpfname}"); } if ($pkg_interface <> "console") { @@ -758,8 +743,11 @@ if ($pkg_interface <> "console") { update_output_window(""); } log_error(gettext("[Suricata] The Rules update has finished.")); -error_log(gettext("The Rules update has finished. Time: " . date("Y-m-d H:i:s"). "\n\n"), 3, $suricata_rules_upd_log); -conf_mount_ro(); +error_log(gettext("The Rules update has finished. Time: " . date("Y-m-d H:i:s"). "\n\n"), 3, SURICATA_RULES_UPD_LOGFILE); + +/* Remount filesystem read-only if we changed it in this module */ +if ($mounted_rw == TRUE) + conf_mount_ro(); // Restore the state of $pkg_interface $pkg_interface = $pkg_interface_orig; @@ -770,6 +758,6 @@ if ($update_errors) else $config['installedpackages']['suricata']['config'][0]['last_rule_upd_status'] = gettext("success"); $config['installedpackages']['suricata']['config'][0]['last_rule_upd_time'] = time(); -write_config(); +write_config("Suricata pkg: updated status for updated rules package(s) check.", FALSE); ?> diff --git a/config/suricata/suricata_define_vars.php b/config/suricata/suricata_define_vars.php index d072ff42..b94292c3 100644 --- a/config/suricata/suricata_define_vars.php +++ b/config/suricata/suricata_define_vars.php @@ -64,7 +64,7 @@ $suricata_servers = array ( "dns_servers" => "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", "dnp3_server" => "\$HOME_NET", "dnp3_client" => "\$HOME_NET", "modbus_server" => "\$HOME_NET", "modbus_client" => "\$HOME_NET", - "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", + "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", "ftp_servers" => "\$HOME_NET", "ssh_servers" => "\$HOME_NET", "aim_servers" => "64.12.24.0/23,64.12.28.0/23,64.12.161.0/24,64.12.163.0/24,64.12.200.0/24,205.188.3.0/24,205.188.5.0/24,205.188.7.0/24,205.188.9.0/24,205.188.153.0/24,205.188.179.0/24,205.188.248.0/24" ); @@ -74,6 +74,7 @@ if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port']) else $ssh_port = "22"; $suricata_ports = array( + "ftp_ports" => "21", "http_ports" => "80", "oracle_ports" => "1521", "ssh_ports" => $ssh_port, @@ -127,11 +128,16 @@ if ($_POST) { /* Update the suricata.yaml file for this interface. */ $rebuild_rules = false; + conf_mount_rw(); suricata_generate_yaml($a_nat[$id]); + conf_mount_ro(); /* Soft-restart Suricaa to live-load new variables. */ suricata_reload_config($a_nat[$id]); + /* Sync to configured CARP slaves if any are enabled */ + suricata_sync_on_changes(); + /* after click go to this page */ header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); @@ -166,18 +172,22 @@ if ($savemsg) </script> <form action="suricata_define_vars.php" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td class="tabnavtbl">'; @@ -190,12 +200,14 @@ if ($savemsg) $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), true, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Define Servers (IP variables)"); ?></td> </tr> @@ -254,9 +266,10 @@ if ($savemsg) <input name="id" type="hidden" value="<?=$id;?>"> </td> </tr> + </tbody> </table> </div> -</td></tr> +</td></tr></tbody> </table> </form> <script type="text/javascript"> diff --git a/config/suricata/suricata_defs.inc b/config/suricata/suricata_defs.inc new file mode 100644 index 00000000..7758a9f0 --- /dev/null +++ b/config/suricata/suricata_defs.inc @@ -0,0 +1,117 @@ +<?php +/* + * suricata_defs.inc + * + * Significant portions of this code are based on original work done + * for the Snort package for pfSense from the following contributors: + * + * Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. + * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. + * Copyright (C) 2006 Scott Ullrich + * Copyright (C) 2009 Robert Zelaya Sr. Developer + * Copyright (C) 2012 Ermal Luci + * All rights reserved. + * + * Adapted for Suricata by: + * Copyright (C) 2014 Bill Meeks + * 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("pkg-utils.inc"); + +/*************************************************************************/ +/* This file contains definitions for various CONSTANTS used throughout */ +/* the Suricata package. It is included via a "require_once()" call in */ +/* the "suricata.inc" and "suricata_post_install.php" files. */ +/*************************************************************************/ + +global $g, $config; + +if (!is_array($config['installedpackages']['suricata'])) + $config['installedpackages']['suricata'] = array(); + +/* Get installed package version for display */ +$suricata_package_version = "Suricata {$config['installedpackages']['package'][get_pkg_id("suricata")]['version']}"; + +// Define the installed package version +if (!defined('SURICATA_PKG_VER')) + define('SURICATA_PKG_VER', $suricata_package_version); + +// Define the PBI base directory +if (!defined('SURICATA_PBI_BASEDIR')) + define('SURICATA_PBI_BASEDIR', '/usr/pbi/suricata-' . php_uname("m") . '/'); + +// Define the PBI binary wrapper directory +if (!defined('SURICATA_PBI_BINDIR')) + define('SURICATA_PBI_BINDIR', SURICATA_PBI_BASEDIR . 'bin/'); + +// Define the name of the pf table used for IP blocks +if (!defined('SURICATA_PF_TABLE')) + define('SURICATA_PF_TABLE', 'snort2c'); + +// Create some other useful defines +if (!defined('SURICATADIR')) + define('SURICATADIR', SURICATA_PBI_BASEDIR . 'etc/suricata/'); +if (!defined('SURICATALOGDIR')) + define('SURICATALOGDIR', "{$g['varlog_path']}/suricata/"); +if (!defined('SURICATA_RULES_UPD_LOGFILE')) + define('SURICATA_RULES_UPD_LOGFILE', SURICATALOGDIR . 'suricata_rules_update.log'); +if (!defined('SURICATA_SID_MODS_PATH')) + define('SURICATA_SID_MODS_PATH', "{$g['vardb_path']}/suricata/sidmods/"); +if (!defined('SURICATA_IPREP_PATH')) + define('SURICATA_IPREP_PATH', "{$g['vardb_path']}/suricata/iprep/"); + +// Rule set download URLs, filenames and prefixes +if (!defined("VRT_DNLD_URL")) + define("VRT_DNLD_URL", "https://www.snort.org/rules/"); +if (!defined("ET_VERSION")) + define("ET_VERSION", "2.9.0"); +if (!defined("ET_BASE_DNLD_URL")) + define("ET_BASE_DNLD_URL", "http://rules.emergingthreats.net/"); +if (!defined("ETPRO_BASE_DNLD_URL")) + define("ETPRO_BASE_DNLD_URL", "https://rules.emergingthreatspro.com/"); +if (!defined("ET_DNLD_FILENAME")) + define("ET_DNLD_FILENAME", "emerging.rules.tar.gz"); +if (!defined("ETPRO_DNLD_FILENAME")) + define("ETPRO_DNLD_FILENAME", "etpro.rules.tar.gz"); +if (!defined("ET_IQRISK_DNLD_URL")) + define("ET_IQRISK_DNLD_URL", "https://rules.emergingthreatspro.com/_xxx_/reputation/"); +if (!defined("GPLV2_DNLD_FILENAME")) + define("GPLV2_DNLD_FILENAME", "community-rules.tar.gz"); +if (!defined("GPLV2_DNLD_URL")) + define("GPLV2_DNLD_URL", "https://www.snort.org/downloads/community/"); +if (!defined("VRT_FILE_PREFIX")) + define("VRT_FILE_PREFIX", "snort_"); +if (!defined("GPL_FILE_PREFIX")) + define("GPL_FILE_PREFIX", "GPLv2_"); +if (!defined("ET_OPEN_FILE_PREFIX")) + define("ET_OPEN_FILE_PREFIX", "emerging-"); +if (!defined("ET_PRO_FILE_PREFIX")) + define("ET_PRO_FILE_PREFIX", "etpro-"); +if (!defined('SURICATA_ENFORCING_RULES_FILENAME')) + define('SURICATA_ENFORCING_RULES_FILENAME', 'suricata.rules'); +if (!defined('FLOWBITS_FILENAME')) + define('FLOWBITS_FILENAME', 'flowbit-required.rules'); + +?> diff --git a/config/suricata/suricata_download_rules.php b/config/suricata/suricata_download_rules.php index 2de286ba..f0fbffeb 100644 --- a/config/suricata/suricata_download_rules.php +++ b/config/suricata/suricata_download_rules.php @@ -101,7 +101,7 @@ include("head.inc"); <?php $suricata_gui_include = true; -include("/usr/local/www/suricata/suricata_check_for_rule_updates.php"); +include("/usr/local/pkg/suricata/suricata_check_for_rule_updates.php"); /* hide progress bar and lets end this party */ echo "\n<script type=\"text/javascript\">document.progressbar.style.visibility='hidden';\n</script>"; diff --git a/config/suricata/suricata_download_updates.php b/config/suricata/suricata_download_updates.php index b5377351..1abb32d6 100644 --- a/config/suricata/suricata_download_updates.php +++ b/config/suricata/suricata_download_updates.php @@ -44,12 +44,13 @@ require_once("/usr/local/pkg/suricata/suricata.inc"); /* Define some locally required variables from Suricata constants */ $suricatadir = SURICATADIR; -$suricata_rules_upd_log = RULES_UPD_LOGFILE; +$suricata_rules_upd_log = SURICATA_RULES_UPD_LOGFILE; $snortdownload = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules']; $emergingthreats = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules']; $etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']; $snortcommunityrules = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules']; +$snort_rules_file = $config['installedpackages']['suricata']['config'][0]['snort_rules_file']; /* Get last update information if available */ if (!empty($config['installedpackages']['suricata']['config'][0]['last_rule_upd_time'])) @@ -61,7 +62,6 @@ if (!empty($config['installedpackages']['suricata']['config'][0]['last_rule_upd_ else $last_rule_upd_status = gettext("Unknown"); -$snort_rules_file = VRT_DNLD_FILENAME; $snort_community_rules_filename = GPLV2_DNLD_FILENAME; if ($etpro == "on") { @@ -82,7 +82,7 @@ else { $snort_org_sig_chk_local = 'Not Enabled'; $snort_org_sig_date = 'Not Enabled'; } -if (file_exists("{$suricatadir}{$snort_rules_file}.md5")){ +if ($snortdownload == 'on' && file_exists("{$suricatadir}{$snort_rules_file}.md5")){ $snort_org_sig_chk_local = file_get_contents("{$suricatadir}{$snort_rules_file}.md5"); $snort_org_sig_date = date(DATE_RFC850, filemtime("{$suricatadir}{$snort_rules_file}.md5")); } @@ -95,7 +95,7 @@ else { $emergingt_net_sig_chk_local = 'Not Enabled'; $emergingt_net_sig_date = 'Not Enabled'; } -if (file_exists("{$suricatadir}{$emergingthreats_filename}.md5")) { +if (($etpro == "on" || $emergingthreats == "on") && file_exists("{$suricatadir}{$emergingthreats_filename}.md5")) { $emergingt_net_sig_chk_local = file_get_contents("{$suricatadir}{$emergingthreats_filename}.md5"); $emergingt_net_sig_date = date(DATE_RFC850, filemtime("{$suricatadir}{$emergingthreats_filename}.md5")); } @@ -108,7 +108,7 @@ else { $snort_community_sig_chk_local = 'Not Enabled'; $snort_community_sig_sig_date = 'Not Enabled'; } -if (file_exists("{$suricatadir}{$snort_community_rules_filename}.md5")) { +if ($snortcommunityrules == 'on' && file_exists("{$suricatadir}{$snort_community_rules_filename}.md5")) { $snort_community_sig_chk_local = file_get_contents("{$suricatadir}{$snort_community_rules_filename}.md5"); $snort_community_sig_sig_date = date(DATE_RFC850, filemtime("{$suricatadir}{$snort_community_rules_filename}.md5")); } @@ -116,10 +116,10 @@ if (file_exists("{$suricatadir}{$snort_community_rules_filename}.md5")) { /* Check for postback to see if we should clear the update log file. */ if ($_POST['clear']) { if (file_exists("{$suricata_rules_upd_log}")) - mwexec("/bin/rm -f {$suricata_rules_upd_log}"); + unlink_if_exists("{$suricata_rules_upd_log}"); } -if ($_POST['check']) { +if ($_POST['update']) { // Go see if new updates for rule sets are available header("Location: /suricata/suricata_download_rules.php"); exit; @@ -130,12 +130,9 @@ if ($_POST['force']) { conf_mount_rw(); // Remove the existing MD5 signature files to force a download - if (file_exists("{$suricatadir}{$emergingthreats_filename}.md5")) - @unlink("{$suricatadir}{$emergingthreats_filename}.md5"); - if (file_exists("{$suricatadir}{$snort_community_rules_filename}.md5")) - @unlink("{$suricatadir}{$snort_community_rules_filename}.md5"); - if (file_exists("{$suricatadir}{$snort_rules_file}.md5")) - @unlink("{$suricatadir}{$snort_rules_file}.md5"); + unlink_if_exists("{$suricatadir}{$emergingthreats_filename}.md5"); + unlink_if_exists("{$suricatadir}{$snort_community_rules_filename}.md5"); + unlink_if_exists("{$suricatadir}{$snort_rules_file}.md5"); // Revert file system to R/O. conf_mount_ro(); @@ -177,21 +174,25 @@ include_once("head.inc"); print_info_box($savemsg); } ?> -<form action="suricata_download_updates.php" method="post" name="iform" id="iform"> +<form action="suricata_download_updates.php" enctype="multipart/form-data" method="post" name="iform" id="iform"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), true, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), true, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td></tr> @@ -199,6 +200,7 @@ include_once("head.inc"); <td> <div id="mainarea"> <table id="maintable4" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> <tr> <td valign="top" class="listtopic" align="center"><?php echo gettext("INSTALLED RULE SET MD5 SIGNATURE");?></td> </tr> @@ -212,6 +214,7 @@ include_once("head.inc"); <th class="listhdrr"><?=gettext("MD5 Signature Date");?></th> </tr> </thead> + <tbody> <tr> <td align="center" class="vncell vexpl"><b><?=$et_name;?></b></td> <td align="center" class="vncell vexpl"><? echo trim($emergingt_net_sig_chk_local);?></td> @@ -227,6 +230,7 @@ include_once("head.inc"); <td align="center" class="vncell vexpl"><? echo trim($snort_community_sig_chk_local);?></td> <td align="center" class="vncell vexpl"><?php echo gettext($snort_community_sig_sig_date);?></td> </tr> + </tbody> </table><br/> </td> </tr> @@ -262,8 +266,8 @@ include_once("head.inc"); <br/></p> <?php else: ?> <br/> - <input type="submit" value="<?=gettext("Check");?>" name="check" id="check" class="formbtn" - title="<?php echo gettext("Check for new updates to enabled rule sets"); ?>"/> + <input type="submit" value="<?=gettext("Update");?>" name="update" id="update" class="formbtn" + title="<?php echo gettext("Check for and apply new update to enabled rule sets"); ?>"/> <input type="submit" value="<?=gettext("Force");?>" name="force" id="force" class="formbtn" title="<?=gettext("Force an update of all enabled rule sets");?>" onclick="return confirm('<?=gettext("This will zero-out the MD5 hashes to force a fresh download of all enabled rule sets. Click OK to continue or CANCEL to quit");?>');"/> @@ -271,7 +275,6 @@ include_once("head.inc"); <?php endif; ?> </td> </tr> - <tr> <td valign="top" class="listtopic" align="center"><?php echo gettext("MANAGE RULE SET LOG");?></td> </tr> @@ -318,10 +321,12 @@ include_once("head.inc"); gettext(" will go down from time to time. Please be patient."); ?></span><br/> </td> </tr> + </tbody> </table> </div> </td> </tr> +</tbody> </table> <!-- end of final table --> </form> diff --git a/config/suricata/suricata_etiqrisk_update.php b/config/suricata/suricata_etiqrisk_update.php new file mode 100644 index 00000000..70fbdb79 --- /dev/null +++ b/config/suricata/suricata_etiqrisk_update.php @@ -0,0 +1,216 @@ +<?php +/* + * suricata_etiqrisk_update.php + * + * Significant portions of this code are based on original work done + * for the Snort package for pfSense from the following contributors: + * + * Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. + * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. + * Copyright (C) 2006 Scott Ullrich + * Copyright (C) 2009 Robert Zelaya Sr. Developer + * Copyright (C) 2012 Ermal Luci + * All rights reserved. + * + * Adapted for Suricata by: + * Copyright (C) 2014 Bill Meeks + * 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("config.inc"); +require_once("functions.inc"); +require_once("/usr/local/pkg/suricata/suricata.inc"); +require("/usr/local/pkg/suricata/suricata_defs.inc"); + +/************************************************************************* + * Hack for backwards compatibility with older 2.1.x pfSense versions * + * that did not contain the new "download_file()" utility function * + * present in 2.2 and higher. * + *************************************************************************/ +if(!function_exists("download_file")) { + function download_file($url, $destination, $verify_ssl = false, $connect_timeout = 60, $timeout = 0) { + global $config, $g; + + $fp = fopen($destination, "wb"); + + if (!$fp) + return false; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version"))); + + if (!empty($config['system']['proxyurl'])) { + curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']); + if (!empty($config['system']['proxyport'])) + curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']); + if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) { + @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE); + curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}"); + } + } + + @curl_exec($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + fclose($fp); + curl_close($ch); + return ($http_code == 200) ? true : $http_code; + } +} + +function suricata_check_iprep_md5($filename) { + + /**********************************************************/ + /* This function attempts to download the MD5 hash for */ + /* the passed file and compare its contents to the */ + /* currently stored hash file to see if a new file has */ + /* been posted. */ + /* */ + /* On Entry: $filename = IPREP file to check ('md5sum' */ + /* is auto-appended to the supplied */ + /* filename.) */ + /* */ + /* Returns: TRUE if new rule file download required. */ + /* FALSE if rule download not required or an */ + /* error occurred. */ + /**********************************************************/ + + global $iqRisk_tmppath, $iprep_path; + $new_md5 = $old_md5 = ""; + $et_iqrisk_url = str_replace("_xxx_", $config['installedpackages']['suricata']['config'][0]['iqrisk_code'], ET_IQRISK_DNLD_URL); + + if (download_file("{$et_iqrisk_url}{$filename}.md5sum", "{$iqRisk_tmppath}{$filename}.md5") == true) { + if (file_exists("{$iqRisk_tmppath}{$filename}.md5")) + $new_md5 = trim(file_get_contents("{$iqRisk_tmppath}{$filename}.md5")); + if (file_exists("{$iprep_path}{$filename}.md5")) + $old_md5 = trim(file_get_contents("{$iprep_path}{$filename}.md5")); + if ($new_md5 != $old_md5) + return TRUE; + else + log_error(gettext("[Suricata] IPREP file '{$filename}' is up to date.")); + } + else + log_error(gettext("[Suricata] An error occurred downloading {$et_iqrisk_url}{$filename}.md5sum for IPREP. Update of {$filename} file will be skipped.")); + + return FALSE; +} + +/********************************************************************** + * Start of main code * + **********************************************************************/ +global $g, $config; +$iprep_path = SURICATA_IPREP_PATH; +$iqRisk_tmppath = "{$g['tmp_path']}/IQRisk/"; +$success = FALSE; + +if (!is_array($config['installedpackages']['suricata']['config'][0])) + $config['installedpackages']['suricata']['config'][0] = array(); + +// If auto-updates of ET IQRisk are disabled, then exit +if ($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] == "off") + return(0); +else + log_error(gettext("[Suricata] Updating the Emerging Threats IQRisk IP List...")); + +// Construct the download URL using the saved ET IQRisk Subscriber Code +if (!empty($config['installedpackages']['suricata']['config'][0]['iqrisk_code'])) { + $et_iqrisk_url = str_replace("_xxx_", $config['installedpackages']['suricata']['config'][0]['iqrisk_code'], ET_IQRISK_DNLD_URL); +} +else { + log_error(gettext("[Suricata] No IQRisk subscriber code found! Aborting scheduled update of Emerging Threats IQRisk IP List.")); + return(0); +} + +// Download the IP List files to a temporary location +safe_mkdir("$iqRisk_tmppath"); + +// Test the posted MD5 checksum file against our local copy +// to see if an update has been posted for 'categories.txt'. +if (suricata_check_iprep_md5("categories.txt")) { + log_error(gettext("[Suricata] An updated IPREP 'categories.txt' file is available...downloading new file.")); + if (download_file("{$et_iqrisk_url}categories.txt", "{$iqRisk_tmppath}categories.txt") != true) + log_error(gettext("[Suricata] An error occurred downloading the 'categories.txt' file for IQRisk.")); + else { + // If the files downloaded successfully, unpack them and store + // the list files in the SURICATA_IPREP_PATH directory. + if (file_exists("{$iqRisk_tmppath}categories.txt") && file_exists("{$iqRisk_tmppath}categories.txt.md5")) { + $new_md5 = trim(file_get_contents("{$iqRisk_tmppath}categories.txt.md5")); + if ($new_md5 == md5_file("{$iqRisk_tmppath}categories.txt")) { + @rename("{$iqRisk_tmppath}categories.txt", "{$iprep_path}categories.txt"); + @rename("{$iqRisk_tmppath}categories.txt.md5", "{$iprep_path}categories.txt.md5"); + $success = TRUE; + log_error(gettext("[Suricata] Successfully updated IPREP file 'categories.txt'.")); + } + else + log_error(gettext("[Suricata] MD5 integrity check of downloaded 'categories.txt' file failed! Skipping update of this IPREP file.")); + } + } +} + +// Test the posted MD5 checksum file against our local copy +// to see if an update has been posted for 'iprepdata.txt.gz'. +if (suricata_check_iprep_md5("iprepdata.txt.gz")) { + log_error(gettext("[Suricata] An updated IPREP 'iprepdata.txt' file is available...downloading new file.")); + if (download_file("{$et_iqrisk_url}iprepdata.txt.gz", "{$iqRisk_tmppath}iprepdata.txt.gz") != true) + log_error(gettext("[Suricata] An error occurred downloading the 'iprepdata.txt.gz' file for IQRisk.")); + else { + // If the files downloaded successfully, unpack them and store + // the list files in the SURICATA_IPREP_PATH directory. + if (file_exists("{$iqRisk_tmppath}iprepdata.txt.gz") && file_exists("{$iqRisk_tmppath}iprepdata.txt.gz.md5")) { + $new_md5 = trim(file_get_contents("{$iqRisk_tmppath}iprepdata.txt.gz.md5")); + if ($new_md5 == md5_file("{$iqRisk_tmppath}iprepdata.txt.gz")) { + mwexec("/usr/bin/gunzip -f {$iqRisk_tmppath}iprepdata.txt.gz"); + @rename("{$iqRisk_tmppath}iprepdata.txt", "{$iprep_path}iprepdata.txt"); + @rename("{$iqRisk_tmppath}iprepdata.txt.gz.md5", "{$iprep_path}iprepdata.txt.gz.md5"); + $success = TRUE; + log_error(gettext("[Suricata] Successfully updated IPREP file 'iprepdata.txt'.")); + } + else + log_error(gettext("[Suricata] MD5 integrity check of downloaded 'iprepdata.txt.gz' file failed! Skipping update of this IPREP file.")); + } + } +} + +// Cleanup the tmp directory path +rmdir_recursive("$iqRisk_tmppath"); + +log_error(gettext("[Suricata] Emerging Threats IQRisk IP List update finished.")); + +// If successful, signal any running Suricata process to live reload the rules and IP lists +if ($success == TRUE && is_process_running("suricata")) { + foreach ($config['installedpackages']['suricata']['rule'] as $value) { + if ($value['enable_iprep'] == "on") { + suricata_reload_config($value); + sleep(2); + } + } +} + +?> diff --git a/config/suricata/suricata_flow_stream.php b/config/suricata/suricata_flow_stream.php index ba594d55..9467ea7c 100644 --- a/config/suricata/suricata_flow_stream.php +++ b/config/suricata/suricata_flow_stream.php @@ -251,7 +251,6 @@ elseif ($_POST['ResetAll']) { $pconfig['flow_icmp_emerg_established_timeout'] = '100'; $pconfig['stream_memcap'] = '33554432'; - $pconfig['stream_max_sessions'] = '262144'; $pconfig['stream_prealloc_sessions'] = '32768'; $pconfig['reassembly_memcap'] = '67108864'; $pconfig['reassembly_depth'] = '1048576'; @@ -261,9 +260,9 @@ elseif ($_POST['ResetAll']) { $pconfig['enable_async_sessions'] = 'off'; /* Log a message at the top of the page to inform the user */ - $savemsg = gettext("All flow and stream settings have been reset to their defaults."); + $savemsg = gettext("All flow and stream settings have been reset to their defaults. Click APPLY to save the changes."); } -elseif ($_POST['save']) { +elseif ($_POST['save'] || $_POST['apply']) { $natent = array(); $natent = $pconfig; @@ -300,7 +299,6 @@ elseif ($_POST['save']) { if ($_POST['flow_icmp_emerg_established_timeout'] != "") { $natent['flow_icmp_emerg_established_timeout'] = $_POST['flow_icmp_emerg_established_timeout']; }else{ $natent['flow_icmp_emerg_established_timeout'] = "100"; } if ($_POST['stream_memcap'] != "") { $natent['stream_memcap'] = $_POST['stream_memcap']; }else{ $natent['stream_memcap'] = "33554432"; } - if ($_POST['stream_max_sessions'] != "") { $natent['stream_max_sessions'] = $_POST['stream_max_sessions']; }else{ $natent['stream_max_sessions'] = "262144"; } if ($_POST['stream_prealloc_sessions'] != "") { $natent['stream_prealloc_sessions'] = $_POST['stream_prealloc_sessions']; }else{ $natent['stream_prealloc_sessions'] = "32768"; } if ($_POST['enable_midstream_sessions'] == "on") { $natent['enable_midstream_sessions'] = 'on'; }else{ $natent['enable_midstream_sessions'] = 'off'; } if ($_POST['enable_async_sessions'] == "on") { $natent['enable_async_sessions'] = 'on'; }else{ $natent['enable_async_sessions'] = 'off'; } @@ -318,7 +316,12 @@ elseif ($_POST['save']) { $a_nat[$id] = $natent; write_config(); $rebuild_rules = false; + conf_mount_rw(); suricata_generate_yaml($natent); + conf_mount_ro(); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); @@ -431,32 +434,40 @@ include_once("head.inc"); <body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); - - /* Display error or save message */ - if ($input_errors) { - print_input_errors($input_errors); // TODO: add checks - } - if ($savemsg) { - print_info_box($savemsg); - } +/* Display error message */ +if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks +} ?> <form action="suricata_flow_stream.php" method="post" name="iform" id="iform"> <input type="hidden" name="eng_id" id="eng_id" value="<?=$eng_id;?>"/> <input type="hidden" name="id" id="id" value="<?=$id;?>"/> +<?php +if ($savemsg) { + /* Display save message */ + print_info_box($savemsg); +} +?> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td>'; @@ -469,6 +480,7 @@ include_once("head.inc"); $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> @@ -489,6 +501,7 @@ include_once("head.inc"); <?php else: ?> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Host-Specific Defrag and Stream Settings"); ?></td> </tr> @@ -511,6 +524,7 @@ include_once("head.inc"); height="17" border="0" title="<?php echo gettext("Add a new policy configuration");?>"/></th> </tr> </thead> + <tbody> <?php foreach ($pconfig['host_os_policy']['item'] as $f => $v): ?> <tr> <td class="listlr" align="left"><?=gettext($v['name']);?></td> @@ -529,6 +543,7 @@ include_once("head.inc"); </td> </tr> <?php endforeach; ?> + </tbody> </table> </td> </tr> @@ -633,6 +648,7 @@ include_once("head.inc"); <td width="22%" valign="top" class="vncell"><?php echo gettext("TCP Connections"); ?></td> <td width="78%" class="vtable"> <table width="100%" cellspacing="4" cellpadding="0" border="0"> + <tbody> <tr> <td class="vexpl"><input name="flow_tcp_new_timeout" type="text" class="formfld unknown" id="flow_tcp_new_timeout" size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_new_timeout']);?>"> @@ -669,6 +685,7 @@ include_once("head.inc"); <?php echo gettext("Emergency Closed TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("20") . "</strong>."; ?> </td> </tr> + </tbody> </table> </td> </tr> @@ -676,6 +693,7 @@ include_once("head.inc"); <td width="22%" valign="top" class="vncell"><?php echo gettext("UDP Connections"); ?></td> <td width="78%" class="vtable"> <table width="100%" cellspacing="4" cellpadding="0" border="0"> + <tbody> <tr> <td class="vexpl"><input name="flow_udp_new_timeout" type="text" class="formfld unknown" id="flow_udp_new_timeout" size="9" value="<?=htmlspecialchars($pconfig['flow_udp_new_timeout']);?>"> @@ -700,6 +718,7 @@ include_once("head.inc"); <?php echo gettext("Emergency Established UDP connection timeout in seconds. Default is ") . "<strong>" . gettext("100") . "</strong>."; ?> </td> </tr> + </tbody> </table> </td> </tr> @@ -707,6 +726,7 @@ include_once("head.inc"); <td width="22%" valign="top" class="vncell"><?php echo gettext("ICMP Connections"); ?></td> <td width="78%" class="vtable"> <table width="100%" cellspacing="4" cellpadding="0" border="0"> + <tbody> <tr> <td class="vexpl"><input name="flow_icmp_new_timeout" type="text" class="formfld unknown" id="flow_icmp_new_timeout" size="9" value="<?=htmlspecialchars($pconfig['flow_icmp_new_timeout']);?>"> @@ -731,6 +751,7 @@ include_once("head.inc"); <?php echo gettext("Emergency Established ICMP connection timeout in seconds. Default is ") . "<strong>" . gettext("100") . "</strong>."; ?> </td> </tr> + </tbody> </table> </td> </tr> @@ -748,16 +769,6 @@ include_once("head.inc"); </td> </tr> <tr> - <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Sessions"); ?></td> - <td width="78%" class="vtable"> - <input name="stream_max_sessions" type="text" class="formfld unknown" id="stream_max_sessions" size="9" - value="<?=htmlspecialchars($pconfig['stream_max_sessions']);?>"> - <?php echo gettext("Max concurrent stream engine sessions. Default is ") . - "<strong>" . gettext("262,144") . "</strong>" . gettext(" sessions."); ?><br/><br/> - <?php echo gettext("Sets the maximum number of concurrent sessions to be used by the stream engine."); ?> - </td> - </tr> - <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Preallocated Sessions"); ?></td> <td width="78%" class="vtable"> <input name="stream_prealloc_sessions" type="text" class="formfld unknown" id="stream_prealloc_sessions" size="9" @@ -835,12 +846,13 @@ include_once("head.inc"); <?php echo gettext("Please save your settings before you exit. Changes will rebuild the rules file. This "); ?> <?php echo gettext("may take several seconds. Suricata must also be restarted to activate any changes made on this screen."); ?></td> </tr> + </tbody> </table> <?php endif; ?> </div> -</td></tr></table> +</td></tr></tbody></table> </form> <?php include("fend.inc"); ?> </body> diff --git a/config/suricata/suricata_generate_yaml.php b/config/suricata/suricata_generate_yaml.php index bd3ce368..328702b9 100644 --- a/config/suricata/suricata_generate_yaml.php +++ b/config/suricata/suricata_generate_yaml.php @@ -53,13 +53,6 @@ foreach ($config_files as $file) { @copy("{$suricatadir}{$file}", "{$suricatacfgdir}/{$file}"); } -// Create required files if they don't exist -$suricata_files = array( "{$suricatacfgdir}/magic" ); -foreach ($suricata_files as $file) { - if (!file_exists($file)) - file_put_contents($file, "\n"); -} - // Read the configuration parameters for the passed interface // and construct appropriate string variables for use in the // suricata.yaml template include file. @@ -68,11 +61,17 @@ foreach ($suricata_files as $file) { $home_net_list = suricata_build_list($suricatacfg, $suricatacfg['homelistname']); $home_net = implode(",", $home_net_list); $home_net = trim($home_net); -$external_net = '!$HOME_NET'; +$external_net = ""; if (!empty($suricatacfg['externallistname']) && $suricatacfg['externallistname'] != 'default') { - $external_net_list = suricata_build_list($suricatacfg, $suricatacfg['externallistname']); + $external_net_list = suricata_build_list($suricatacfg, $suricatacfg['externallistname'], false, true); $external_net = implode(",", $external_net_list); - $external_net = trim($external_net); + $external_net = "[" . trim($external_net) . "]"; +} +else { + $external_net = "["; + foreach ($home_net_list as $ip) + $external_net .= "!{$ip},"; + $external_net = trim($external_net, ', ') . "]"; } // Set the PASS LIST and write its contents to disk @@ -85,7 +84,7 @@ $suricata_servers = array ( "dns_servers" => "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", "dnp3_server" => "\$HOME_NET", "dnp3_client" => "\$HOME_NET", "modbus_server" => "\$HOME_NET", "modbus_client" => "\$HOME_NET", - "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", + "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", "ftp_servers" => "\$HOME_NET", "ssh_servers" => "\$HOME_NET", "aim_servers" => "64.12.24.0/23,64.12.28.0/23,64.12.161.0/24,64.12.163.0/24,64.12.200.0/24,205.188.3.0/24,205.188.5.0/24,205.188.7.0/24,205.188.9.0/24,205.188.153.0/24,205.188.179.0/24,205.188.248.0/24" ); $addr_vars = ""; @@ -102,6 +101,7 @@ if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port']) else $ssh_port = "22"; $suricata_ports = array( + "ftp_ports" => "21", "http_ports" => "80", "oracle_ports" => "1521", "ssh_ports" => $ssh_port, @@ -158,6 +158,11 @@ if ($suricatacfg['delayed_detect'] == 'on') else $delayed_detect = "no"; +if ($suricatacfg['intf_promisc_mode'] == 'on') + $intf_promisc_mode = "yes"; +else + $intf_promisc_mode = "no"; + // Add interface-specific blocking settings if ($suricatacfg['blockoffenders'] == 'on') $suri_blockoffenders = "yes"; @@ -184,6 +189,26 @@ if ($suricatacfg['alertsystemlog'] == 'on') else $alert_syslog = "no"; +if (!empty($suricatacfg['alertsystemlog_facility'])) + $alert_syslog_facility = $suricatacfg['alertsystemlog_facility']; +else + $alert_syslog_facility = "local5"; + +if (!empty($suricatacfg['alertsystemlog_priority'])) + $alert_syslog_priority = $suricatacfg['alertsystemlog_priority']; +else + $alert_syslog_priority = "Info"; + +if ($suricatacfg['enable_dns_log'] == 'on') + $dns_log_enabled = "yes"; +else + $dns_log_enabled = "no"; + +if ($suricatacfg['append_dns_log'] == 'on') + $dns_log_append = "yes"; +else + $dns_log_append = "no"; + if ($suricatacfg['enable_stats_log'] == 'on') $stats_log_enabled = "yes"; else @@ -209,6 +234,11 @@ if ($suricatacfg['append_http_log'] == 'on') else $http_log_append = "no"; +if ($suricatacfg['http_log_extended'] == 'on') + $http_log_extended = "yes"; +else + $http_log_extended = "no"; + if ($suricatacfg['enable_tls_log'] == 'on') $tls_log_enabled = "yes"; else @@ -277,6 +307,66 @@ if (isset($suricatacfg['barnyard_sensor_id'])) else $unified2_sensor_id = "0"; +// EVE JSON log output settings +if ($suricatacfg['enable_eve_log'] == 'on') + $enable_eve_log = "yes"; +else + $enable_eve_log = "no"; + +if ($suricatacfg['eve_output_type'] == 'syslog') + $eve_output_type = "syslog"; +else + $eve_output_type = "file"; + +if (!empty($suricatacfg['eve_systemlog_facility'])) + $eve_systemlog_facility = $suricatacfg['eve_systemlog_facility']; +else + $eve_systemlog_facility = "local1"; + +if (!empty($suricatacfg['eve_systemlog_priority'])) + $eve_systemlog_priority = $suricatacfg['eve_systemlog_priority']; +else + $eve_systemlog_priority = "info"; + +// EVE log output included information +$eve_out_types = ""; +if ($suricatacfg['eve_log_alerts'] == 'on') + $eve_out_types .= "\n - alert"; + +if ($suricatacfg['eve_log_http'] == 'on') { + $eve_out_types .= "\n - http:"; + if ($suricatacfg['http_log_extended'] == 'on') + $eve_out_types .= "\n extended: yes"; + else + $eve_out_types .= "\n extended: no"; +} + +if ($suricatacfg['eve_log_dns'] == 'on') + $eve_out_types .= "\n - dns"; + +if ($suricatacfg['eve_log_tls'] == 'on') { + $eve_out_types .= "\n - tls:"; + if ($suricatacfg['tls_log_extended'] == 'on') + $eve_out_types .= "\n extended: yes"; + else + $eve_out_types .= "\n extended: no"; +} + +if ($suricatacfg['eve_log_files'] == 'on') { + $eve_out_types .= "\n - files:"; + if ($suricatacfg['enable_tracked_files_magic'] == 'on') + $eve_out_types .= "\n force-magic: yes"; + else + $eve_out_types .= "\n force-magic: no"; + if ($suricatacfg['enable_tracked_files_md5'] == 'on') + $eve_out_types .= "\n force-md5: yes"; + else + $eve_out_types .= "\n force-md5: no"; +} + +if ($suricatacfg['eve_log_ssh'] == 'on') + $eve_out_types .= "\n - ssh"; + // Add interface-specific IP defrag settings if (!empty($suricatacfg['frag_memcap'])) $frag_memcap = $suricatacfg['frag_memcap']; @@ -406,11 +496,6 @@ if (!empty($suricatacfg['stream_memcap'])) else $stream_memcap = "33554432"; -if (!empty($suricatacfg['stream_max_sessions'])) - $stream_max_sessions = $suricatacfg['stream_max_sessions']; -else - $stream_max_sessions = "262144"; - if (!empty($suricatacfg['stream_prealloc_sessions'])) $stream_prealloc_sessions = $suricatacfg['stream_prealloc_sessions']; else @@ -448,9 +533,10 @@ else // Add the OS-specific host policies if configured, otherwise // just set default to BSD for all networks. +$host_os_policy = ""; if (!is_array($suricatacfg['host_os_policy']['item'])) $suricatacfg['host_os_policy']['item'] = array(); -if (empty($suricatacfg['host_os_policy']['item'])) +if (count($suricatacfg['host_os_policy']['item']) < 1) $host_os_policy = "bsd: [0.0.0.0/0]"; else { foreach ($suricatacfg['host_os_policy']['item'] as $k => $v) { @@ -488,11 +574,13 @@ else { // Add the HTTP Server-specific policies if configured, otherwise // just set default to IDS for all networks. +$http_hosts_policy = ""; +$http_hosts_default_policy = ""; if (!is_array($suricatacfg['libhtp_policy']['item'])) $suricatacfg['libhtp_policy']['item'] = array(); -if (empty($suricatacfg['libhtp_policy']['item'])) { - $http_hosts_default_policy = "default-config:\n personality: IDS\n request-body-limit: 4096\n response-body-limit: 4096\n"; - $http_hosts_default_policy .= " double-decode-path: no\n double-decode-query: no\n"; +if (count($suricatacfg['libhtp_policy']['item']) < 1) { + $http_hosts_default_policy = " personality: IDS\n request-body-limit: 4096\n response-body-limit: 4096\n"; + $http_hosts_default_policy .= " double-decode-path: no\n double-decode-query: no\n uri-include-all: no\n"; } else { foreach ($suricatacfg['libhtp_policy']['item'] as $k => $v) { @@ -519,6 +607,7 @@ else { $engine .= " response-body-limit: {$v['response-body-limit']}\n"; $engine .= " double-decode-path: {$v['double-decode-path']}\n"; $engine .= " double-decode-query: {$v['double-decode-query']}\n"; + $engine .= " uri-include-all: {$v['uri-include-all']}\n"; $http_hosts_policy .= " {$engine}\n"; } else { @@ -531,6 +620,7 @@ else { $http_hosts_default_policy .= " response-body-limit: {$v['response-body-limit']}\n"; $http_hosts_default_policy .= " double-decode-path: {$v['double-decode-path']}\n"; $http_hosts_default_policy .= " double-decode-query: {$v['double-decode-query']}\n"; + $http_hosts_default_policy .= " uri-include-all: {$v['uri-include-all']}\n"; } } // Remove trailing newline @@ -544,13 +634,108 @@ if (!empty($suricatacfg['asn1_max_frames'])) else $asn1_max_frames = "256"; +// Configure App-Layer Parsers/Detection +if (!empty($suricatacfg['tls_parser'])) + $tls_parser = $suricatacfg['tls_parser']; +else + $tls_parser = "yes"; +if (!empty($suricatacfg['dcerpc_parser'])) + $dcerpc_parser = $suricatacfg['dcerpc_parser']; +else + $dcerpc_parser = "yes"; +if (!empty($suricatacfg['ftp_parser'])) + $ftp_parser = $suricatacfg['ftp_parser']; +else + $ftp_parser = "yes"; +if (!empty($suricatacfg['ssh_parser'])) + $ssh_parser = $suricatacfg['ssh_parser']; +else + $ssh_parser = "yes"; +if (!empty($suricatacfg['smtp_parser'])) + $smtp_parser = $suricatacfg['smtp_parser']; +else + $smtp_parser = "yes"; +if (!empty($suricatacfg['imap_parser'])) + $imap_parser = $suricatacfg['imap_parser']; +else + $imap_parser = "detection-only"; +if (!empty($suricatacfg['msn_parser'])) + $msn_parser = $suricatacfg['msn_parser']; +else + $msn_parser = "detection-only"; +if (!empty($suricatacfg['smb_parser'])) + $smb_parser = $suricatacfg['smb_parser']; +else + $smb_parser = "yes"; + +/* DNS Parser */ +if (!empty($suricatacfg['dns_parser_tcp'])) + $dns_parser_tcp = $suricatacfg['dns_parser_tcp']; +else + $dns_parser_tcp = "yes"; +if (!empty($suricatacfg['dns_parser_udp'])) + $dns_parser_udp = $suricatacfg['dns_parser_udp']; +else + $dns_parser_udp = "yes"; +if (!empty($suricatacfg['dns_global_memcap'])) + $dns_global_memcap = $suricatacfg['dns_global_memcap']; +else + $dns_global_memcap = "16777216"; +if (!empty($suricatacfg['dns_state_memcap'])) + $dns_state_memcap = $suricatacfg['dns_state_memcap']; +else + $dns_state_memcap = "524288"; +if (!empty($suricatacfg['dns_request_flood_limit'])) + $dns_request_flood_limit = $suricatacfg['dns_request_flood_limit']; +else + $dns_request_flood_limit = "500"; + +/* HTTP Parser */ +if (!empty($suricatacfg['http_parser'])) + $http_parser = $suricatacfg['http_parser']; +else + $http_parser = "yes"; +if (!empty($suricatacfg['http_parser_memcap'])) + $http_parser_memcap = $suricatacfg['http_parser_memcap']; +else + $http_parser_memcap = "67108864"; + +/* Configure the IP REP section */ +$iprep_path = rtrim(SURICATA_IPREP_PATH, '/'); +$iprep_config = "# IP Reputation\n"; +if ($suricatacfg['enable_iprep'] == "on") { + $iprep_config .= "default-reputation-path: {$iprep_path}\n"; + $iprep_config .= "reputation-categories-file: {$iprep_path}/{$suricatacfg['iprep_catlist']}\n"; + $iprep_config .= "reputation-files:"; + + if (!is_array($suricatacfg['iplist_files']['item'])) + $suricatacfg['iplist_files']['item'] = array(); + + foreach ($suricatacfg['iplist_files']['item'] as $f) + $iprep_config .= "\n - $f"; +} + +/* Configure Host Table settings */ +if (!empty($suricatacfg['host_memcap'])) + $host_memcap = $suricatacfg['host_memcap']; +else + $host_memcap = "16777216"; +if (!empty($suricatacfg['host_hash_size'])) + $host_hash_size = $suricatacfg['host_hash_size']; +else + $host_hash_size = "4096"; +if (!empty($suricatacfg['host_prealloc'])) + $host_prealloc = $suricatacfg['host_prealloc']; +else + $host_prealloc = "1000"; + // Create the rules files and save in the interface directory suricata_prepare_rule_files($suricatacfg, $suricatacfgdir); // Check and configure only non-empty rules files for the interface $rules_files = ""; -if (filesize("{$suricatacfgdir}/rules/".ENFORCING_RULES_FILENAME) > 0) - $rules_files .= ENFORCING_RULES_FILENAME; +if (filesize("{$suricatacfgdir}/rules/".SURICATA_ENFORCING_RULES_FILENAME) > 0) + $rules_files .= SURICATA_ENFORCING_RULES_FILENAME; if (filesize("{$suricatacfgdir}/rules/".FLOWBITS_FILENAME) > 0) $rules_files .= "\n - " . FLOWBITS_FILENAME; if (filesize("{$suricatacfgdir}/rules/custom.rules") > 0) @@ -563,4 +748,9 @@ if ($config['installedpackages']['suricata']['config'][0]['log_to_systemlog'] == else $suricata_use_syslog = "no"; +if (!empty($config['installedpackages']['suricata']['config'][0]['log_to_systemlog'])) + $suricata_use_syslog_facility = $config['installedpackages']['suricata']['config'][0]['log_to_systemlog']; +else + $suricata_use_syslog_facility = "local1"; + ?> diff --git a/config/suricata/suricata_geoipupdate.php b/config/suricata/suricata_geoipupdate.php new file mode 100644 index 00000000..46e1177e --- /dev/null +++ b/config/suricata/suricata_geoipupdate.php @@ -0,0 +1,137 @@ +<?php +/* + * suricata_geoipupdate.php + * + * Significant portions of this code are based on original work done + * for the Snort package for pfSense from the following contributors: + * + * Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. + * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. + * Copyright (C) 2006 Scott Ullrich + * Copyright (C) 2009 Robert Zelaya Sr. Developer + * Copyright (C) 2012 Ermal Luci + * All rights reserved. + * + * Adapted for Suricata by: + * Copyright (C) 2014 Bill Meeks + * 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. +*/ + +/* This product includes GeoLite data created by MaxMind, available from + * http://www.maxmind.com +*/ + +require_once("config.inc"); +require_once("functions.inc"); +require("/usr/local/pkg/suricata/suricata_defs.inc"); + +/************************************************************************* + * Hack for backwards compatibility with older 2.1.x pfSense versions * + * that did not contain the new "download_file()" utility function * + * present in 2.2 and higher. * + *************************************************************************/ +if(!function_exists("download_file")) { + function download_file($url, $destination, $verify_ssl = false, $connect_timeout = 60, $timeout = 0) { + global $config, $g; + + $fp = fopen($destination, "wb"); + + if (!$fp) + return false; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_HEADER, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version"))); + + if (!empty($config['system']['proxyurl'])) { + curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']); + if (!empty($config['system']['proxyport'])) + curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']); + if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) { + @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE); + curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}"); + } + } + + @curl_exec($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + fclose($fp); + curl_close($ch); + return ($http_code == 200) ? true : $http_code; + } +} + +/********************************************************************** + * Start of main code * + **********************************************************************/ +global $g, $config; +$suricata_geoip_dbdir = SURICATA_PBI_BASEDIR . 'share/GeoIP/'; +$geoip_tmppath = "{$g['tmp_path']}/geoipup/"; + +// If auto-updates of GeoIP are disabled, then exit +if ($config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] == "off") + exit(0); +else + log_error(gettext("[Suricata] Updating the GeoIP country database files...")); + + +// Download the free GeoIP Legacy country name databases for IPv4 and IPv6 +// to a temporary location. +safe_mkdir("$geoip_tmppath"); +if (download_file("http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz", "{$geoip_tmppath}GeoIP.dat.gz") != true) + log_error(gettext("[Suricata] An error occurred downloading the 'GeoIP.dat.gz' update file for GeoIP.")); +if (download_file("http://geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz", "{$geoip_tmppath}GeoIPv6.dat.gz") != true) + log_error(gettext("[Suricata] An error occurred downloading the 'GeoIPv6.dat.gz' update file for GeoIP.")); + +// Mount filesystem read-write since we need to write +// the extracted databases to PBI_BASE/share/GeoIP. +conf_mount_rw(); + +// If the files downloaded successfully, unpack them and store +// the DB files in the PBI_BASE/share/GeoIP directory. +if (file_exists("{$geoip_tmppath}GeoIP.dat.gz")) { + mwexec("/usr/bin/gunzip -f {$geoip_tmppath}GeoIP.dat.gz"); + @rename("{$geoip_tmppath}GeoIP.dat", "{$suricata_geoip_dbdir}GeoIP.dat"); +} + +if (file_exists("{$geoip_tmppath}GeoIPv6.dat.gz")) { + mwexec("/usr/bin/gunzip -f {$geoip_tmppath}GeoIPv6.dat.gz"); + @rename("{$geoip_tmppath}GeoIPv6.dat", "{$suricata_geoip_dbdir}GeoIPv6.dat"); +} + +// Finished with filesystem mods, so remount read-only +conf_mount_ro(); + +// Cleanup the tmp directory path +rmdir_recursive("$geoip_tmppath"); + +log_error(gettext("[Suricata] GeoIP database update finished.")); + +?> diff --git a/config/suricata/suricata_global.php b/config/suricata/suricata_global.php index 9c932222..eb657465 100644 --- a/config/suricata/suricata_global.php +++ b/config/suricata/suricata_global.php @@ -45,29 +45,46 @@ require_once("/usr/local/pkg/suricata/suricata.inc"); global $g; $suricatadir = SURICATADIR; +$pconfig = array(); -$pconfig['enable_vrt_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules']; -$pconfig['oinkcode'] = $config['installedpackages']['suricata']['config'][0]['oinkcode']; -$pconfig['etprocode'] = $config['installedpackages']['suricata']['config'][0]['etprocode']; -$pconfig['enable_etopen_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules']; -$pconfig['enable_etpro_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']; -$pconfig['rm_blocked'] = $config['installedpackages']['suricata']['config'][0]['rm_blocked']; -$pconfig['autoruleupdate'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdate']; -$pconfig['autoruleupdatetime'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime']; -$pconfig['live_swap_updates'] = $config['installedpackages']['suricata']['config'][0]['live_swap_updates']; -$pconfig['log_to_systemlog'] = $config['installedpackages']['suricata']['config'][0]['log_to_systemlog']; -$pconfig['forcekeepsettings'] = $config['installedpackages']['suricata']['config'][0]['forcekeepsettings']; -$pconfig['snortcommunityrules'] = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules']; +// If doing a postback, used typed values, else load from stored config +if (!empty($_POST)) { + $pconfig = $_POST; +} +else { + $pconfig['enable_vrt_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules']; + $pconfig['oinkcode'] = $config['installedpackages']['suricata']['config'][0]['oinkcode']; + $pconfig['etprocode'] = $config['installedpackages']['suricata']['config'][0]['etprocode']; + $pconfig['enable_etopen_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules']; + $pconfig['enable_etpro_rules'] = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']; + $pconfig['rm_blocked'] = $config['installedpackages']['suricata']['config'][0]['rm_blocked']; + $pconfig['autoruleupdate'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdate']; + $pconfig['autoruleupdatetime'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime']; + $pconfig['live_swap_updates'] = $config['installedpackages']['suricata']['config'][0]['live_swap_updates']; + $pconfig['log_to_systemlog'] = $config['installedpackages']['suricata']['config'][0]['log_to_systemlog']; + $pconfig['log_to_systemlog_facility'] = $config['installedpackages']['suricata']['config'][0]['log_to_systemlog_facility']; + $pconfig['forcekeepsettings'] = $config['installedpackages']['suricata']['config'][0]['forcekeepsettings']; + $pconfig['snortcommunityrules'] = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules']; + $pconfig['snort_rules_file'] = $config['installedpackages']['suricata']['config'][0]['snort_rules_file']; + $pconfig['autogeoipupdate'] = $config['installedpackages']['suricata']['config'][0]['autogeoipupdate']; +} +// Do input validation on parameters if (empty($pconfig['autoruleupdatetime'])) $pconfig['autoruleupdatetime'] = '00:30'; +if (empty($pconfig['log_to_systemlog_facility'])) + $pconfig['log_to_systemlog_facility'] = "local1"; + if ($_POST['autoruleupdatetime']) { if (!preg_match('/^([01]?[0-9]|2[0-3]):?([0-5][0-9])$/', $_POST['autoruleupdatetime'])) $input_errors[] = "Invalid Rule Update Start Time! Please supply a value in 24-hour format as 'HH:MM'."; } -if ($_POST['suricatadownload'] == "on" && empty($_POST['oinkcode'])) +if ($_POST['enable_vrt_rules'] == "on" && empty($_POST['snort_rules_file'])) + $input_errors[] = "You must supply a snort rules tarball filename in the box provided in order to enable Snort VRT rules!"; + +if ($_POST['enable_vrt_rules'] == "on" && empty($_POST['oinkcode'])) $input_errors[] = "You must supply an Oinkmaster code in the box provided in order to enable Snort VRT rules!"; if ($_POST['enable_etpro_rules'] == "on" && empty($_POST['etprocode'])) @@ -81,6 +98,7 @@ if (!$input_errors) { $config['installedpackages']['suricata']['config'][0]['snortcommunityrules'] = $_POST['snortcommunityrules'] ? 'on' : 'off'; $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules'] = $_POST['enable_etopen_rules'] ? 'on' : 'off'; $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules'] = $_POST['enable_etpro_rules'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] = $_POST['autogeoipupdate'] ? 'on' : 'off'; // If any rule sets are being turned off, then remove them // from the active rules section of each interface. Start @@ -117,28 +135,42 @@ if (!$input_errors) { } } + $config['installedpackages']['suricata']['config'][0]['snort_rules_file'] = $_POST['snort_rules_file']; $config['installedpackages']['suricata']['config'][0]['oinkcode'] = $_POST['oinkcode']; $config['installedpackages']['suricata']['config'][0]['etprocode'] = $_POST['etprocode']; $config['installedpackages']['suricata']['config'][0]['rm_blocked'] = $_POST['rm_blocked']; $config['installedpackages']['suricata']['config'][0]['autoruleupdate'] = $_POST['autoruleupdate']; /* Check and adjust format of Rule Update Starttime string to add colon and leading zero if necessary */ - $pos = strpos($_POST['autoruleupdatetime'], ":"); - if ($pos === false) { - $tmp = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); - $_POST['autoruleupdatetime'] = substr($tmp, 0, 2) . ":" . substr($tmp, -2); + if ($_POST['autoruleupdatetime']) { + $pos = strpos($_POST['autoruleupdatetime'], ":"); + if ($pos === false) { + $tmp = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); + $_POST['autoruleupdatetime'] = substr($tmp, 0, 2) . ":" . substr($tmp, -2); + } + $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'] = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); } - $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'] = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); $config['installedpackages']['suricata']['config'][0]['log_to_systemlog'] = $_POST['log_to_systemlog'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['config'][0]['log_to_systemlog_facility'] = $_POST['log_to_systemlog_facility']; $config['installedpackages']['suricata']['config'][0]['live_swap_updates'] = $_POST['live_swap_updates'] ? 'on' : 'off'; $config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] = $_POST['forcekeepsettings'] ? 'on' : 'off'; $retval = 0; + write_config("Suricata pkg: modified global settings."); + + /* Toggle cron task for GeoIP database updates if setting was changed */ + if ($config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] == 'on' && !suricata_cron_job_exists("/usr/local/pkg/suricata/suricata_geoipupdate.php")) { + include("/usr/local/pkg/suricata/suricata_geoipupdate.php"); + install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_geoipupdate.php", TRUE, 0, 0, 8, "*", "*", "root"); + } + elseif ($config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] == 'off' && suricata_cron_job_exists("/usr/local/pkg/suricata/suricata_geoipupdate.php")) + install_cron_job("/usr/local/pkg/suricata/suricata_geoipupdate.php", FALSE); + /* create passlist and homenet file, then sync files */ + conf_mount_rw(); sync_suricata_package_config(); - - write_config(); + conf_mount_ro(); /* forces page to reload new settings */ header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); @@ -161,9 +193,6 @@ include_once("head.inc"); <?php include_once("fbegin.inc"); -if($pfsense_stable == 'yes') - echo '<p class="pgtitle">' . $pgtitle . '</p>'; - /* Display Alert message, under form tag or no refresh */ if ($input_errors) print_input_errors($input_errors); @@ -172,25 +201,30 @@ if ($input_errors) <form action="suricata_global.php" method="post" enctype="multipart/form-data" name="iform" id="iform"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php - $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); - $tab_array[] = array(gettext("Global Settings"), true, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array = array(); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Global Settings"), true, "/suricata/suricata_global.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); - display_top_tabs($tab_array, true); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); + display_top_tabs($tab_array, true); ?> </td></tr> <tr> <td> <div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> +<tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Please Choose The Type Of Rules You Wish To Download");?></td> </tr> @@ -198,6 +232,7 @@ if ($input_errors) <td width="22%" valign="top" class="vncell"><?php echo gettext("Install ") . "<strong>" . gettext("Emerging Threats") . "</strong>" . gettext(" rules");?></td> <td width="78%" class="vtable"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td valign="top" width="8%"><input name="enable_etopen_rules" type="checkbox" value="on" onclick="enable_et_rules();" <?php if ($config['installedpackages']['suricata']['config'][0]['enable_etopen_rules']=="on") echo "checked"; ?>/></td> @@ -218,8 +253,10 @@ if ($input_errors) <td class="vexpl"><?php echo "<span class='red'><strong>" . gettext("Note:") . "</strong></span>" . " " . gettext("The ETPro rules contain all of the ETOpen rules, so the ETOpen rules are not required and are disabled when the ETPro rules are selected."); ?></td> </tr> + </tbody> </table> <table id="etpro_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td colspan="2"> </td> </tr> @@ -232,6 +269,7 @@ if ($input_errors) value="<?=htmlspecialchars($pconfig['etprocode']);?>"/><br/> <?php echo gettext("Obtain an ETPro subscription code and paste it here."); ?></td> </tr> + </tbody> </table> </td> </tr> @@ -239,36 +277,45 @@ if ($input_errors) <td width="22%" valign="top" class="vncell"><?php echo gettext("Install ") . "<strong>" . gettext("Snort VRT") . "</strong>" . gettext(" rules");?></td> <td width="78%" class="vtable"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td><input name="enable_vrt_rules" type="checkbox" id="enable_vrt_rules" value="on" onclick="enable_snort_vrt();" <?php if($pconfig['enable_vrt_rules']=='on') echo 'checked'; ?>/></td> <td><span class="vexpl"><?php echo gettext("Snort VRT free Registered User or paid Subscriber rules"); ?></span></td> <tr> <td> </td> - <td><a href="https://www.snort.org/signup" target="_blank"><?php echo gettext("Sign Up for a free Registered User Rule Account"); ?> </a><br/> - <a href="http://www.snort.org/vrt/buy-a-subscription" target="_blank"> + <td><a href="https://www.snort.org/users/sign_up" target="_blank"><?php echo gettext("Sign Up for a free Registered User Rule Account"); ?> </a><br/> + <a href="https://www.snort.org/products" target="_blank"> <?php echo gettext("Sign Up for paid Sourcefire VRT Certified Subscriber Rules"); ?></a></td> </tr> + </tbody> </table> <table id="snort_oink_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> - <td colspan="2"> </td> + <td colspan="2" valign="top"><b><span class="vexpl"><?php echo gettext("Snort VRT Configuration"); ?></span></b></td> </tr> <tr> - <td colspan="2" valign="top"><b><span class="vexpl"><?php echo gettext("Snort VRT Oinkmaster Configuration"); ?></span></b></td> + <td valign="top" align="right"><span class="vexpl"><strong><?php echo gettext("Rules Filename:"); ?></strong></span> </td> + <td><input name="snort_rules_file" type="text" class="formfld unknown" id="snort_rules_file" size="52" + value="<?=htmlspecialchars($pconfig['snort_rules_file']);?>"/><br/> + <?php echo gettext("Enter the rules tarball filename (filename only, do not include the URL.)"); ?> + <br/><span class="red"><strong><?php echo gettext("Example: ") . "</strong></span>" . gettext("snortrules-snapshot-2962.tar.gz");?><br/><br/></td> </tr> <tr> - <td valign="top"><span class="vexpl"><strong><?php echo gettext("Code:"); ?></strong></span></td> + <td valign="top" align="right"><span class="vexpl"><strong><?php echo gettext("Oinkmaster Code:"); ?></strong></span> </td> <td><input name="oinkcode" type="text" class="formfld unknown" id="oinkcode" size="52" value="<?=htmlspecialchars($pconfig['oinkcode']);?>"/><br/> <?php echo gettext("Obtain a snort.org Oinkmaster code and paste it here."); ?></td> </tr> + </tbody> </table> </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Install ") . "<strong>" . gettext("Snort Community") . "</strong>" . gettext(" rules");?></td> <td width="78%" class="vtable"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td valign="top" width="8%"><input name="snortcommunityrules" type="checkbox" value="on" <?php if ($config['installedpackages']['suricata']['config'][0]['snortcommunityrules']=="on") echo " checked";?>/></td> @@ -278,6 +325,7 @@ if ($input_errors) gettext("If you are a Snort VRT Paid Subscriber, the community ruleset is already built into your download of the ") . gettext("Snort VRT rules, and there is no benefit in adding this rule set.");?><br/></td> </tr> + </tbody> </table></td> </tr> <tr> @@ -315,6 +363,15 @@ if ($input_errors) "If issues are encountered with live load, uncheck this option to perform a hard restart of all Suricata instances following an update."); ?></td> </tr> <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("GeoIP DB Update"); ?></td> + <td width="78%" class="vtable"><input name="autogeoipupdate" id="autogeoipupdate" type="checkbox" value="yes" + <?php if ($config['installedpackages']['suricata']['config'][0]['autogeoipupdate']=="on") echo " checked"; ?>/> + <?php echo gettext("Enable downloading of free GeoIP Country Database updates. Default is ") . "<strong>" . gettext("Checked") . "</strong>"; ?><br/><br/> + <?php echo gettext("When enabled, Suricata will automatically download updates for the free legacy GeoIP country database on the 8th of each month at midnight.") . + "<br/><br/>" . gettext("If you have a subscription for more current GeoIP updates, uncheck this option and instead create your own process to place the required database files in " . + SURICATA_PBI_BASEDIR . "share/GeoIP/."); ?></td> +</tr> +<tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("General Settings"); ?></td> </tr> <tr> @@ -334,10 +391,29 @@ if ($input_errors) </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Log to System Log"); ?></td> - <td width="78%" class="vtable"><input name="log_to_systemlog" id="log_to_systemlog" type="checkbox" value="yes" + <td width="78%" class="vtable"><input name="log_to_systemlog" id="log_to_systemlog" type="checkbox" value="yes" onclick="toggle_log_to_systemlog();" <?php if ($config['installedpackages']['suricata']['config'][0]['log_to_systemlog']=="on") echo " checked"; ?>/> <?php echo gettext("Copy Suricata messages to the firewall system log."); ?></td> </tr> + <tbody id="log_to_systemlog_rows"> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Facility"); ?></td> + <td width="78%" class="vtable"> + <select name="log_to_systemlog_facility" id="log_to_systemlog_facility" class="formselect"> + <?php + $log_facility = array( "auth", "authpriv", "daemon", "kern", "security", "syslog", "user", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7" ); + foreach ($log_facility as $facility) { + $selected = ""; + if ($facility == $pconfig['log_to_systemlog_facility']) + $selected = " selected"; + echo "<option value='{$facility}'{$selected}>" . $facility . "</option>\n"; + } + ?></select> + <?php echo gettext("Select system log facility to use for reporting. Default is ") . "<strong>" . gettext("local1") . "</strong>."; ?> + </td> + </tr> + </tbody> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Keep Suricata Settings After Deinstall"); ?></td> <td width="78%" class="vtable"><input name="forcekeepsettings" id="forcekeepsettings" type="checkbox" value="yes" @@ -351,9 +427,10 @@ if ($input_errors) <td colspan="2" class="vexpl" align="center"><span class="red"><strong><?php echo gettext("Note:");?></strong> </span><?php echo gettext("Changing any settings on this page will affect all Suricata-configured interfaces.");?></td> </tr> +</tbody> </table> </div><br/> -</td></tr> +</td></tr></tbody> </table> </form> <?php include("fend.inc"); ?> @@ -396,11 +473,20 @@ function enable_change_rules_upd() { document.iform.autoruleupdatetime.disabled=""; } +function toggle_log_to_systemlog() { + var endis = !document.iform.log_to_systemlog.checked; + if (endis) + document.getElementById("log_to_systemlog_rows").style.display="none"; + else + document.getElementById("log_to_systemlog_rows").style.display=""; +} + // Initialize the form controls state based on saved settings enable_snort_vrt(); enable_et_rules(); enable_pro_rules(); enable_change_rules_upd(); +toggle_log_to_systemlog(); //--> </script> diff --git a/config/suricata/suricata_import_aliases.php b/config/suricata/suricata_import_aliases.php index ccaaf29d..e2fa4f40 100644 --- a/config/suricata/suricata_import_aliases.php +++ b/config/suricata/suricata_import_aliases.php @@ -79,8 +79,8 @@ <col width="35%" align="left" axis="string"> </colgroup> <thead> - <tr> - <th class="listhdrr"></th> + <tr class="sortableHeaderRowIdentifier"> + <th class="listhdrr sorttable_nosort"></th> <th class="listhdrr" axis="string"><?=gettext("Alias Name"); ?></th> <th class="listhdrr" axis="string"><?=gettext("Values"); ?></th> <th class="listhdrr" axis="string"><?=gettext("Description"); ?></th> diff --git a/config/suricata/suricata_interfaces.php b/config/suricata/suricata_interfaces.php index 26d57b71..e996a24f 100644 --- a/config/suricata/suricata_interfaces.php +++ b/config/suricata/suricata_interfaces.php @@ -57,6 +57,9 @@ if (!is_array($config['installedpackages']['suricata']['rule'])) $a_nat = &$config['installedpackages']['suricata']['rule']; $id_gen = count($config['installedpackages']['suricata']['rule']); +// Get list of configured firewall interfaces +$ifaces = get_configured_interface_list(); + if ($_POST['del_x']) { /* delete selected interfaces */ if (is_array($_POST['rule'])) { @@ -65,8 +68,8 @@ if ($_POST['del_x']) { $if_real = get_real_interface($a_nat[$rulei]['interface']); $suricata_uuid = $a_nat[$rulei]['uuid']; suricata_stop($a_nat[$rulei], $if_real); - exec("/bin/rm -r {$suricatalogdir}suricata_{$if_real}{$suricata_uuid}"); - exec("/bin/rm -r {$suricatadir}suricata_{$suricata_uuid}_{$if_real}"); + rmdir_recursive("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}"); + rmdir_recursive("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}"); unset($a_nat[$rulei]); } conf_mount_ro(); @@ -75,19 +78,12 @@ if ($_POST['del_x']) { if (empty($a_nat)) unset($a_nat); - write_config(); + write_config("Suricata pkg: deleted one or more Suricata interfaces."); sleep(2); - /* if there are no ifaces remaining do not create suricata.sh */ - if (!empty($config['installedpackages']['suricata']['rule'])) - suricata_create_rc(); - else { - conf_mount_rw(); - @unlink("{$rcdir}/suricata.sh"); - conf_mount_ro(); - } - + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); @@ -107,7 +103,9 @@ if ($_POST['bartoggle']) { if (!suricata_is_running($suricatacfg['uuid'], $if_real, 'barnyard2')) { log_error("Toggle (barnyard starting) for {$if_friendly}({$suricatacfg['descr']})..."); + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); suricata_barnyard_start($suricatacfg, $if_real); } else { log_error("Toggle (barnyard stopping) for {$if_friendly}({$suricatacfg['descr']})..."); @@ -132,7 +130,9 @@ if ($_POST['toggle']) { log_error("Toggle (suricata starting) for {$if_friendly}({$suricatacfg['descr']})..."); // set flag to rebuild interface rules before starting Snort $rebuild_rules = true; + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); $rebuild_rules = false; suricata_start($suricatacfg, $if_real); } @@ -166,19 +166,23 @@ include_once("head.inc"); ?> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr> <td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), true, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> @@ -187,7 +191,6 @@ include_once("head.inc"); <td> <div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> - <colgroup> <col width="3%" align="center"> <col width="12%"> @@ -207,12 +210,26 @@ include_once("head.inc"); <th class="listhdrr"><?php echo gettext("Block"); ?></th> <th class="listhdrr"><?php echo gettext("Barnyard2"); ?></th> <th class="listhdr"><?php echo gettext("Description"); ?></th> - <th class="list"><a href="suricata_interfaces_edit.php?id=<?php echo $id_gen;?>"> - <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" - width="17" height="17" border="0" title="<?php echo gettext('Add Suricata interface mapping');?>"></a> + <th class="list"> + <?php if ($id_gen < count($ifaces)): ?> + <a href="suricata_interfaces_edit.php?id=<?php echo $id_gen;?>"> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" + width="17" height="17" border="0" title="<?php echo gettext('Add Suricata interface mapping');?>"></a> + <?php else: ?> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus_d.gif" width="17" height="17" border="0" + title="<?php echo gettext('No available interfaces for a new Suricata mapping');?>"> + <?php endif; ?> + <?php if ($id_gen == 0): ?> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_x_d.gif" width="17" height="17" " border="0"> + <?php else: ?> + <input name="del" type="image" src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" + width="17" height="17" title="<?php echo gettext("Delete selected Suricata interface mapping(s)"); ?>" + onclick="return intf_del()"> + <?php endif; ?> </th> </tr> </thead> + <tbody> <?php $nnats = $i = 0; // Turn on buffering to speed up rendering @@ -342,7 +359,15 @@ include_once("head.inc"); <td valign="middle" class="list" nowrap> <a href="suricata_interfaces_edit.php?id=<?=$i;?>"> <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" - width="17" height="17" border="0" title="<?php echo gettext('Edit Suricata interface mapping'); ?>"></a> + width="17" height="17" border="0" title="<?php echo gettext('Edit this Suricata interface mapping'); ?>"></a> + <?php if ($id_gen < count($ifaces)): ?> + <a href="suricata_interfaces_edit.php?id=<?=$i;?>&action=dup"> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" + width="17" height="17" border="0" title="<?php echo gettext('Add new interface mapping based on this one'); ?>"></a> + <?php else: ?> + <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus_d.gif" width="17" height="17" border="0" + title="<?php echo gettext('No available interfaces for a new Suricata mapping');?>"> + <?php endif; ?> </td> </tr> <?php $i++; $nnats++; endforeach; ob_end_flush(); ?> @@ -354,8 +379,16 @@ include_once("head.inc"); <?php else: ?> <?php endif; ?> </td> - <td class="list" valign="middle" nowrap> - <?php if ($nnats == 0): ?> + <td class="list"> + <?php if ($id_gen < count($ifaces)): ?> + <a href="suricata_interfaces_edit.php?id=<?php echo $id_gen;?>"> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" + width="17" height="17" border="0" title="<?php echo gettext('Add Suricata interface mapping');?>"></a> + <?php else: ?> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus_d.gif" width="17" height="17" border="0" + title="<?php echo gettext('No available interfaces for a new Suricata mapping');?>"> + <?php endif; ?> + <?php if ($id_gen == 0): ?> <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_x_d.gif" width="17" height="17" " border="0"> <?php else: ?> <input name="del" type="image" src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" @@ -371,6 +404,7 @@ include_once("head.inc"); <td> </td> <td colspan="6"> <table class="tabcont" width="100%" border="0" cellpadding="1" cellspacing="0"> + <tbody> <tr> <td colspan="3" class="vexpl"><span class="red"><strong><?php echo gettext("Note:"); ?></strong></span> <br> <?php echo gettext("This is the ") . "<strong>" . gettext("Suricata Menu ") . @@ -423,14 +457,17 @@ include_once("head.inc"); delete an interface and settings. </td> </tr> + </tbody> </table> </td> <td> </td> </tr> + </tbody> </table> </div> </td> </tr> +</tbody> </table> </form> diff --git a/config/suricata/suricata_interfaces_edit.php b/config/suricata/suricata_interfaces_edit.php index 3b61755c..13526031 100644 --- a/config/suricata/suricata_interfaces_edit.php +++ b/config/suricata/suricata_interfaces_edit.php @@ -59,12 +59,21 @@ if (isset($_POST['id']) && is_numericint($_POST['id'])) elseif (isset($_GET['id']) && is_numericint($_GET['id'])); $id = htmlspecialchars($_GET['id'], ENT_QUOTES | ENT_HTML401); -if (is_null($id)) - $id = 0; +if (is_null($id)) { + header("Location: /suricata/suricata_interfaces.php"); + exit; +} + +if (isset($_POST['action'])) + $action = htmlspecialchars($_POST['action'], ENT_QUOTES | ENT_HTML401); +elseif (isset($_GET['action'])) + $action = htmlspecialchars($_GET['action'], ENT_QUOTES | ENT_HTML401); +else + $action = ""; $pconfig = array(); if (empty($suricataglob['rule'][$id]['uuid'])) { - /* Adding new interface, so flag rules to build. */ + /* Adding new interface, so generate a new UUID and flag rules to build. */ $pconfig['uuid'] = suricata_generate_id(); $rebuild_rules = true; } @@ -80,14 +89,15 @@ $interfaces = get_configured_interface_with_descr(); // See if interface is already configured, and use its values if (isset($id) && $a_rule[$id]) { + /* old options */ $pconfig = $a_rule[$id]; if (!empty($pconfig['configpassthru'])) $pconfig['configpassthru'] = base64_decode($pconfig['configpassthru']); if (empty($pconfig['uuid'])) $pconfig['uuid'] = $suricata_uuid; } +// Must be a new interface, so try to pick next available physical interface to use elseif (isset($id) && !isset($a_rule[$id])) { - // Must be a new interface, so try to pick next available physical interface to use $ifaces = get_configured_interface_list(); $ifrules = array(); foreach($a_rule as $r) @@ -123,55 +133,109 @@ if (empty($pconfig['enable_http_log'])) $pconfig['enable_http_log'] = "on"; if (empty($pconfig['append_http_log'])) $pconfig['append_http_log'] = "on"; -if (empty($pconfig['enable_tls_log'])) - $pconfig['enable_tls_log'] = "off"; +if (empty($pconfig['http_log_extended'])) + $pconfig['http_log_extended'] = "on"; if (empty($pconfig['tls_log_extended'])) $pconfig['tls_log_extended'] = "on"; -if (empty($pconfig['enable_stats_log'])) - $pconfig['enable_stats_log'] = "off"; if (empty($pconfig['stats_upd_interval'])) $pconfig['stats_upd_interval'] = "10"; -if (empty($pconfig['append_stats_log'])) - $pconfig['append_stats_log'] = "off"; +if (empty($pconfig['append_dns_log'])) + $pconfig['append_dns_log'] = "on"; if (empty($pconfig['append_json_file_log'])) $pconfig['append_json_file_log'] = "on"; -if (empty($pconfig['enable_pcap_log'])) - $pconfig['enable_pcap_log'] = "off"; if (empty($pconfig['max_pcap_log_size'])) $pconfig['max_pcap_log_size'] = "32"; if (empty($pconfig['max_pcap_log_files'])) $pconfig['max_pcap_log_files'] = "1000"; +if (empty($pconfig['alertsystemlog_facility'])) + $pconfig['alertsystemlog_facility'] = "local1"; +if (empty($pconfig['alertsystemlog_priority'])) + $pconfig['alertsystemlog_priority'] = "notice"; +if (empty($pconfig['eve_output_type'])) + $pconfig['eve_output_type'] = "file"; +if (empty($pconfig['eve_systemlog_facility'])) + $pconfig['eve_systemlog_facility'] = "local1"; +if (empty($pconfig['eve_systemlog_priority'])) + $pconfig['eve_systemlog_priority'] = "notice"; +if (empty($pconfig['eve_log_alerts'])) + $pconfig['eve_log_alerts'] = "on"; +if (empty($pconfig['eve_log_http'])) + $pconfig['eve_log_http'] = "on"; +if (empty($pconfig['eve_log_dns'])) + $pconfig['eve_log_dns'] = "on"; +if (empty($pconfig['eve_log_tls'])) + $pconfig['eve_log_tls'] = "on"; +if (empty($pconfig['eve_log_files'])) + $pconfig['eve_log_files'] = "on"; +if (empty($pconfig['eve_log_ssh'])) + $pconfig['eve_log_ssh'] = "on"; +if (empty($pconfig['intf_promisc_mode'])) + $pconfig['intf_promisc_mode'] = "on"; -if ($_POST["save"]) { - // If the interface is not enabled, stop any running Suricata - // instance on it, save the new state and exit. - if (!isset($_POST['enable'])) { - if (isset($id) && $a_rule[$id]) { - $a_rule[$id]['enable'] = 'off'; - $a_rule[$id]['interface'] = htmlspecialchars($_POST['interface']); - $a_rule[$id]['descr'] = htmlspecialchars($_POST['descr']); - suricata_stop($a_rule[$id], get_real_interface($a_rule[$id]['interface'])); - - // Save configuration changes - write_config(); - - // Update suricata.conf and suricata.sh files for this interface - sync_suricata_package_config(); - - header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); - header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); - header( 'Cache-Control: no-store, no-cache, must-revalidate' ); - header( 'Cache-Control: post-check=0, pre-check=0', false ); - header( 'Pragma: no-cache' ); - header("Location: /suricata/suricata_interfaces.php"); - exit; +// See if creating a new interface by duplicating an existing one +if (strcasecmp($action, 'dup') == 0) { + + // Try to pick the next available physical interface to use + $ifaces = get_configured_interface_list(); + $ifrules = array(); + foreach($a_rule as $r) + $ifrules[] = $r['interface']; + foreach ($ifaces as $i) { + if (!in_array($i, $ifrules)) { + $pconfig['interface'] = $i; + $pconfig['enable'] = 'on'; + $pconfig['descr'] = strtoupper($i); + $pconfig['inspect_recursion_limit'] = '3000'; + break; } } + if (count($ifrules) == count($ifaces)) { + $input_errors[] = gettext("No more available interfaces to configure for Suricata!"); + $interfaces = array(); + $pconfig = array(); + } - // Validate inputs + // Set Home Net, External Net, Suppress List and Pass List to defaults + unset($pconfig['suppresslistname']); + unset($pconfig['passlistname']); + unset($pconfig['homelistname']); + unset($pconfig['externallistname']); +} + +if ($_POST["save"] && !$input_errors) { if (!isset($_POST['interface'])) $input_errors[] = gettext("Choosing an Interface is mandatory!"); + /* See if assigned interface is already in use */ + if (isset($_POST['interface'])) { + foreach ($a_rule as $k => $v) { + if (($v['interface'] == $_POST['interface']) && ($id <> $k)) { + $input_errors[] = gettext("The '{$_POST['interface']}' interface is already assigned to another Suricata instance."); + break; + } + } + } + + // If Suricata is disabled on this interface, stop any running instance, + // save the change and exit. + if ($_POST['enable'] != 'on') { + $a_rule[$id]['enable'] = $_POST['enable'] ? 'on' : 'off'; + suricata_stop($a_rule[$id], get_real_interface($a_rule[$id]['interface'])); + write_config("Suricata pkg: disabled Suricata on " . convert_friendly_interface_to_friendly_descr($a_rule[$id]['interface'])); + $rebuild_rules = false; + conf_mount_rw(); + sync_suricata_package_config(); + conf_mount_ro(); + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_interfaces.php"); + exit; + } + + // Validate inputs if (isset($_POST['stats_upd_interval']) && !is_numericint($_POST['stats_upd_interval'])) $input_errors[] = gettext("The value for Stats Update Interval must contain only digits and evaluate to an integer."); @@ -187,16 +251,6 @@ if ($_POST["save"]) { if (!empty($_POST['inspect_recursion_limit']) && !is_numeric($_POST['inspect_recursion_limit'])) $input_errors[] = gettext("The value for Inspect Recursion Limit can either be blank or contain only digits evaluating to an integer greater than or equal to 0."); - /* See if assigned interface is already in use */ - if (isset($_POST['interface'])) { - foreach ($a_rule as $k => $v) { - if (($v['interface'] == $_POST['interface']) && ($id <> $k)) { - $input_errors[] = gettext("The '{$_POST['interface']}' interface is already assigned to another Suricata instance."); - break; - } - } - } - // if no errors write to suricata.yaml if (!$input_errors) { $natent = $a_rule[$id]; @@ -213,6 +267,7 @@ if ($_POST["save"]) { if ($_POST['enable_http_log'] == "on") { $natent['enable_http_log'] = 'on'; }else{ $natent['enable_http_log'] = 'off'; } if ($_POST['append_http_log'] == "on") { $natent['append_http_log'] = 'on'; }else{ $natent['append_http_log'] = 'off'; } if ($_POST['enable_tls_log'] == "on") { $natent['enable_tls_log'] = 'on'; }else{ $natent['enable_tls_log'] = 'off'; } + if ($_POST['http_log_extended'] == "on") { $natent['http_log_extended'] = 'on'; }else{ $natent['http_log_extended'] = 'off'; } if ($_POST['tls_log_extended'] == "on") { $natent['tls_log_extended'] = 'on'; }else{ $natent['tls_log_extended'] = 'off'; } if ($_POST['enable_pcap_log'] == "on") { $natent['enable_pcap_log'] = 'on'; }else{ $natent['enable_pcap_log'] = 'off'; } if ($_POST['enable_json_file_log'] == "on") { $natent['enable_json_file_log'] = 'on'; }else{ $natent['enable_json_file_log'] = 'off'; } @@ -220,6 +275,7 @@ if ($_POST["save"]) { if ($_POST['enable_tracked_files_magic'] == "on") { $natent['enable_tracked_files_magic'] = 'on'; }else{ $natent['enable_tracked_files_magic'] = 'off'; } if ($_POST['enable_tracked_files_md5'] == "on") { $natent['enable_tracked_files_md5'] = 'on'; }else{ $natent['enable_tracked_files_md5'] = 'off'; } if ($_POST['enable_file_store'] == "on") { $natent['enable_file_store'] = 'on'; }else{ $natent['enable_file_store'] = 'off'; } + if ($_POST['enable_eve_log'] == "on") { $natent['enable_eve_log'] = 'on'; }else{ $natent['enable_eve_log'] = 'off'; } if ($_POST['max_pending_packets']) $natent['max_pending_packets'] = $_POST['max_pending_packets']; else unset($natent['max_pending_packets']); if ($_POST['inspect_recursion_limit'] >= '0') $natent['inspect_recursion_limit'] = $_POST['inspect_recursion_limit']; else unset($natent['inspect_recursion_limit']); if ($_POST['detect_eng_profile']) $natent['detect_eng_profile'] = $_POST['detect_eng_profile']; else unset($natent['detect_eng_profile']); @@ -233,11 +289,26 @@ if ($_POST["save"]) { if ($_POST['externallistname']) $natent['externallistname'] = $_POST['externallistname']; else unset($natent['externallistname']); if ($_POST['suppresslistname']) $natent['suppresslistname'] = $_POST['suppresslistname']; else unset($natent['suppresslistname']); if ($_POST['alertsystemlog'] == "on") { $natent['alertsystemlog'] = 'on'; }else{ $natent['alertsystemlog'] = 'off'; } + if ($_POST['alertsystemlog_facility']) $natent['alertsystemlog_facility'] = $_POST['alertsystemlog_facility']; + if ($_POST['alertsystemlog_priority']) $natent['alertsystemlog_priority'] = $_POST['alertsystemlog_priority']; + if ($_POST['enable_dns_log'] == "on") { $natent['enable_dns_log'] = 'on'; }else{ $natent['enable_dns_log'] = 'off'; } + if ($_POST['append_dns_log'] == "on") { $natent['append_dns_log'] = 'on'; }else{ $natent['append_dns_log'] = 'off'; } + if ($_POST['enable_eve_log'] == "on") { $natent['enable_eve_log'] = 'on'; }else{ $natent['enable_eve_log'] = 'off'; } + if ($_POST['eve_output_type']) $natent['eve_output_type'] = $_POST['eve_output_type']; + if ($_POST['eve_systemlog_facility']) $natent['eve_systemlog_facility'] = $_POST['eve_systemlog_facility']; + if ($_POST['eve_systemlog_priority']) $natent['eve_systemlog_priority'] = $_POST['eve_systemlog_priority']; + if ($_POST['eve_log_alerts'] == "on") { $natent['eve_log_alerts'] = 'on'; }else{ $natent['eve_log_alerts'] = 'off'; } + if ($_POST['eve_log_http'] == "on") { $natent['eve_log_http'] = 'on'; }else{ $natent['eve_log_http'] = 'off'; } + if ($_POST['eve_log_dns'] == "on") { $natent['eve_log_dns'] = 'on'; }else{ $natent['eve_log_dns'] = 'off'; } + if ($_POST['eve_log_tls'] == "on") { $natent['eve_log_tls'] = 'on'; }else{ $natent['eve_log_tls'] = 'off'; } + if ($_POST['eve_log_files'] == "on") { $natent['eve_log_files'] = 'on'; }else{ $natent['eve_log_files'] = 'off'; } + if ($_POST['eve_log_ssh'] == "on") { $natent['eve_log_ssh'] = 'on'; }else{ $natent['eve_log_ssh'] = 'off'; } if ($_POST['delayed_detect'] == "on") { $natent['delayed_detect'] = 'on'; }else{ $natent['delayed_detect'] = 'off'; } - if ($_POST['configpassthru']) $natent['configpassthru'] = base64_encode($_POST['configpassthru']); else unset($natent['configpassthru']); + if ($_POST['intf_promisc_mode'] == "on") { $natent['intf_promisc_mode'] = 'on'; }else{ $natent['intf_promisc_mode'] = 'off'; } + if ($_POST['configpassthru']) $natent['configpassthru'] = base64_encode(str_replace("\r\n", "\n", $_POST['configpassthru'])); else unset($natent['configpassthru']); $if_real = get_real_interface($natent['interface']); - if (isset($id) && $a_rule[$id]) { + if (isset($id) && $a_rule[$id] && $action == '') { // See if moving an existing Suricata instance to another physical interface if ($natent['interface'] != $a_rule[$id]['interface']) { $oif_real = get_real_interface($a_rule[$id]['interface']); @@ -247,13 +318,24 @@ if ($_POST["save"]) { } else $suricata_start = false; - exec("mv -f {$suricatalogdir}suricata_{$oif_real}" . $a_rule[$id]['uuid'] . " {$suricatalogdir}suricata_{$if_real}" . $a_rule[$id]['uuid']); + @rename("{$suricatalogdir}suricata_{$oif_real}{$a_rule[$id]['uuid']}", "{$suricatalogdir}suricata_{$if_real}{$a_rule[$id]['uuid']}"); conf_mount_rw(); - exec("mv -f {$suricatadir}suricata_" . $a_rule[$id]['uuid'] . "_{$oif_real} {$suricatadir}suricata_" . $a_rule[$id]['uuid'] . "_{$if_real}"); + @rename("{$suricatadir}suricata_{$a_rule[$id]['uuid']}_{$oif_real}", "{$suricatadir}suricata_{$a_rule[$id]['uuid']}_{$if_real}"); conf_mount_ro(); } $a_rule[$id] = $natent; - } else { + } + elseif (strcasecmp($action, 'dup') == 0) { + // Duplicating an existing interface to a new interface, so set flag to build new rules + $rebuild_rules = true; + + // Duplicating an interface, so need to generate a new UUID for the cloned interface + $natent['uuid'] = suricata_generate_id(); + + // Add the new duplicated interface configuration to the [rule] array in config + $a_rule[] = $natent; + } + else { // Adding new interface, so set interface configuration parameter defaults $natent['ip_max_frags'] = "65535"; $natent['ip_frag_timeout'] = "60"; @@ -285,7 +367,6 @@ if ($_POST["save"]) { $natent['flow_icmp_emerg_established_timeout'] = '100'; $natent['stream_memcap'] = '33554432'; - $natent['stream_max_sessions'] = '262144'; $natent['stream_prealloc_sessions'] = '32768'; $natent['reassembly_memcap'] = '67108864'; $natent['reassembly_depth'] = '1048576'; @@ -294,8 +375,29 @@ if ($_POST["save"]) { $natent['enable_midstream_sessions'] = 'off'; $natent['enable_async_sessions'] = 'off'; $natent['delayed_detect'] = 'off'; + $natent['intf_promisc_mode'] = 'on'; $natent['asn1_max_frames'] = '256'; + $natent['dns_global_memcap'] = "16777216"; + $natent['dns_state_memcap'] = "524288"; + $natent['dns_request_flood_limit'] = "500"; + $natent['http_parser_memcap'] = "67108864"; + $natent['dns_parser_udp'] = "yes"; + $natent['dns_parser_tcp'] = "yes"; + $natent['http_parser'] = "yes"; + $natent['tls_parser'] = "yes"; + $natent['smtp_parser'] = "yes"; + $natent['imap_parser'] = "detection-only"; + $natent['ssh_parser'] = "yes"; + $natent['ftp_parser'] = "yes"; + $natent['dcerpc_parser'] = "yes"; + $natent['smb_parser'] = "yes"; + $natent['msn_parser'] = "detection-only"; + + $natent['enable_iprep'] = "off"; + $natent['host_memcap'] = "16777216"; + $natent['host_hash_size'] = "4096"; + $natent['host_prealloc'] = "1000"; $default = array( "name" => "default", "bind_to" => "all", "policy" => "bsd" ); if (!is_array($natent['host_os_policy']['item'])) @@ -304,13 +406,14 @@ if ($_POST["save"]) { $default = array( "name" => "default", "bind_to" => "all", "personality" => "IDS", "request-body-limit" => 4096, "response-body-limit" => 4096, - "double-decode-path" => "no", "double-decode-query" => "no" ); + "double-decode-path" => "no", "double-decode-query" => "no", + "uri-include-all" => "no" ); if (!is_array($natent['libhtp_policy']['item'])) $natent['libhtp_policy']['item'] = array(); $natent['libhtp_policy']['item'][] = $default; // Enable the basic default rules for the interface - $natent['rulesets'] = "decoder-events.rules||files.rules||http-events.rules||smtp-events.rules||stream-events.rules||tls-events.rules"; + $natent['rulesets'] = "decoder-events.rules||dns-events.rules||files.rules||http-events.rules||smtp-events.rules||stream-events.rules||tls-events.rules"; // Adding a new interface, so set flag to build new rules $rebuild_rules = true; @@ -324,10 +427,12 @@ if ($_POST["save"]) { suricata_stop($natent, $if_real); // Save configuration changes - write_config(); + write_config("Suricata pkg: modified interface configuration for " . convert_friendly_interface_to_friendly_descr($natent['interface'])); // Update suricata.conf and suricata.sh files for this interface + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); @@ -358,19 +463,26 @@ if ($savemsg) { ?> <form action="suricata_interfaces_edit.php<?php echo "?id=$id";?>" method="post" name="iform" id="iform"> +<input name="id" type="hidden" value="<?=$id;?>"/> +<input name="action" type="hidden" value="<?=$action;?>"/> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td class="tabnavtbl">'; @@ -383,11 +495,13 @@ if ($savemsg) { $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> <tr><td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" class="listtopic"><?php echo gettext("General Settings"); ?></td> </tr> @@ -423,9 +537,57 @@ if ($savemsg) { </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Send Alerts to System Log"); ?></td> - <td width="78%" class="vtable"><input name="alertsystemlog" type="checkbox" value="on" <?php if ($pconfig['alertsystemlog'] == "on") echo "checked"; ?>/> - <?php echo gettext("Suricata will send Alerts to the firewall's system log."); ?></td> + <td width="78%" class="vtable"><input name="alertsystemlog" type="checkbox" value="on" onclick="toggle_system_log();" <?php if ($pconfig['alertsystemlog'] == "on") echo "checked"; ?>/> + <?php echo gettext("Suricata will send Alerts from this interface to the firewall's system log."); ?></td> </tr> + <tbody id="alertsystemlog_rows"> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Facility"); ?></td> + <td width="78%" class="vtable"> + <select name="alertsystemlog_facility" id="alertsystemlog_facility" class="formselect"> + <?php + $log_facility = array( "auth", "authpriv", "daemon", "kern", "security", "syslog", "user", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7" ); + foreach ($log_facility as $facility) { + $selected = ""; + if ($facility == $pconfig['alertsystemlog_facility']) + $selected = " selected"; + echo "<option value='{$facility}'{$selected}>" . $facility . "</option>\n"; + } + ?></select> + <?php echo gettext("Select system log Facility to use for reporting. Default is ") . "<strong>" . gettext("local1") . "</strong>."; ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Priority"); ?></td> + <td width="78%" class="vtable"> + <select name="alertsystemlog_priority" id="alertsystemlog_priority" class="formselect"> + <?php + $log_priority = array( "emerg", "crit", "alert", "err", "warning", "notice", "info" ); + foreach ($log_priority as $priority) { + $selected = ""; + if ($priority == $pconfig['alertsystemlog_priority']) + $selected = " selected"; + echo "<option value='{$priority}'{$selected}>" . $priority . "</option>\n"; + } + ?></select> + <?php echo gettext("Select system log Priority (Level) to use for reporting. Default is ") . "<strong>" . gettext("notice") . "</strong>."; ?> + </td> + </tr> + </tbody> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable DNS Log"); ?></td> + <td width="78%" class="vtable"><input name="enable_dns_log" type="checkbox" value="on" <?php if ($pconfig['enable_dns_log'] == "on") echo "checked"; ?> + onClick="toggle_dns_log();" id="enable_dns_log"/> + <?php echo gettext("Suricata will log DNS requests and replies for the interface. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?> + </td> + </tr> + <tr id="dns_log_append_row"> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Append DNS Log"); ?></td> + <td width="78%" class="vtable"><input name="append_dns_log" type="checkbox" value="on" <?php if ($pconfig['append_dns_log'] == "on") echo "checked"; ?>/> + <?php echo gettext("Suricata will append-to instead of clearing DNS log file when restarting. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td> + </tr> + <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Stats Log"); ?></td> <td width="78%" class="vtable"><input name="enable_stats_log" type="checkbox" value="on" <?php if ($pconfig['enable_stats_log'] == "on") echo "checked"; ?> @@ -457,6 +619,11 @@ if ($savemsg) { <td width="78%" class="vtable"><input name="append_http_log" type="checkbox" value="on" <?php if ($pconfig['append_http_log'] == "on") echo "checked"; ?>/> <?php echo gettext("Suricata will append-to instead of clearing HTTP log file when restarting. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td> </tr> + <tr id="http_log_extended_row"> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Extended HTTP Info"); ?></td> + <td width="78%" class="vtable"><input name="http_log_extended" type="checkbox" value="on" <?php if ($pconfig['http_log_extended'] == "on") echo "checked"; ?>/> + <?php echo gettext("Suricata will log extended HTTP information. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td> + </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable TLS Log"); ?></td> <td width="78%" class="vtable"><input name="enable_tls_log" type="checkbox" value="on" <?php if ($pconfig['enable_tls_log'] == "on") echo "checked"; ?> @@ -524,6 +691,99 @@ if ($savemsg) { <?php echo gettext("Enter maximum number of packet log files to maintain. Default is ") . "<strong>" . gettext("1000") . "</strong>."; ?><br/><br/><?php echo gettext("When the number of packet log files reaches the set limit, the oldest file will be overwritten.") ?></td> </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("EVE JSON Log"); ?></td> + <td width="78%" class="vtable"><input name="enable_eve_log" id="enable_eve_log" type="checkbox" value="on" <?php if ($pconfig['enable_eve_log'] == "on") echo "checked"; ?> + onClick="toggle_eve_log()"/> + <?php echo gettext("Suricata will output selected info in JSON format to a single file or to syslog. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?> + <div id="file_eve_warning" style="display: none;"><br/><span class="red"><strong><?php echo gettext("Warning: ") . "</strong></span>" . + gettext("This can consume a significant amount of disk space when enabled!"); ?></div> + </td> + </tr> + <tbody id="eve_log_option_rows"> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("EVE Output Type"); ?></td> + <td width="78%" class="vtable"> + <select name="eve_output_type" class="formselect" id="eve_output_type" onChange="eveOutSelect();" > + <?php + foreach (array("file", "syslog") as $btype) { + if ($btype == $pconfig['eve_output_type']) + echo "<option value='{$btype}' selected>"; + else + echo "<option value='{$btype}'>"; + echo htmlspecialchars($btype) . '</option>'; + } + ?> + </select> + <?php echo gettext("Select EVE log output destination."); ?><br/> + <span class="red"><?php echo gettext("Hint:") . "</span> " . gettext("Choosing FILE is suggested, and it is the default value."); ?><br/> + </td> + </tr> + <tr id="eve_systemlog_facility_row"> + <td width="22%" valign="top" class="vncell"><?php echo gettext("EVE Syslog Facility"); ?></td> + <td width="78%" class="vtable"> + <select name="eve_systemlog_facility" id="eve_systemlog_facility" class="formselect"> + <?php + $log_facility = array( "auth", "authpriv", "daemon", "kern", "security", "syslog", "user", "local0", + "local1", "local2", "local3", "local4", "local5", "local6", "local7" ); + foreach ($log_facility as $facility) { + $selected = ""; + if ($facility == $pconfig['eve_systemlog_facility']) + $selected = " selected"; + echo "<option value='{$facility}'{$selected}>" . $facility . "</option>\n"; + } + ?></select> + <?php echo gettext("Select system log Facility to use for reporting by EVE. Default is ") . "<strong>" . gettext("local1") . "</strong>."; ?> + </td> + </tr> + <tr id="eve_systemlog_priority_row"> + <td width="22%" valign="top" class="vncell"><?php echo gettext("EVE Syslog Priority"); ?></td> + <td width="78%" class="vtable"> + <select name="eve_systemlog_priority" id="eve_systemlog_priority" class="formselect"> + <?php + $log_priority = array( "emerg", "crit", "alert", "err", "warning", "notice", "info" ); + foreach ($log_priority as $priority) { + $selected = ""; + if ($priority == $pconfig['eve_systemlog_priority']) + $selected = " selected"; + echo "<option value='{$priority}'{$selected}>" . $priority . "</option>\n"; + } + ?></select> + <?php echo gettext("Select system log Priority (Level) to use for reporting by EVE. Default is ") . "<strong>" . gettext("notice") . "</strong>."; ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("EVE Logged Info"); ?></td> + <td width="78%" class="vtable"><?php echo gettext("Choose the information to log via EVE JSON output. Default is ") . "<strong>" . gettext("All Checked") . "</strong>."; ?><br/> + <table width="100%" cellpadding="0" cellspacing="0" border="0"> + <tbody> + <tr> + <td class="vexpl"><input name="eve_log_alerts" id="eve_log_alerts" type="checkbox" value="on" + <?php if ($pconfig['eve_log_alerts'] == "on") echo "checked"; ?>/>Alerts + </td> + <td class="vexpl"><input name="eve_log_http" id="eve_log_http" type="checkbox" value="on" + <?php if ($pconfig['eve_log_http'] == "on") echo "checked"; ?>/>HTTP Traffic + </td> + <td class="vexpl"><input name="eve_log_dns" id="eve_log_dns" type="checkbox" value="on" + <?php if ($pconfig['eve_log_dns'] == "on") echo "checked"; ?>/>DNS Requests/Replies + </td> + </tr> + <tr> + <td class="vexpl"><input name="eve_log_tls" id="eve_log_tls" type="checkbox" value="on" onClick="toggle_eve_tls();" + <?php if ($pconfig['eve_log_tls'] == "on") echo "checked"; ?>/>TLS Handshakes + </td> + <td class="vexpl"><input name="eve_log_files" id="eve_log_files" type="checkbox" value="on" + <?php if ($pconfig['eve_log_files'] == "on") echo "checked"; ?>/>Tracked Files + </td> + <td class="vexpl"><input name="eve_log_ssh" id="eve_log_ssh" type="checkbox" value="on" + <?php if ($pconfig['eve_log_ssh'] == "on") echo "checked"; ?>/>SSH Handshakes + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> <tr> <td colspan="2" class="listtopic"><?php echo gettext("Alert Settings"); ?></td> </tr> @@ -556,7 +816,7 @@ if ($savemsg) { ?> </select> <?php echo gettext("Select which IP extracted from the packet you wish to block."); ?><br/> - <span class="red"><?php echo gettext("Hint:") . "</span> " . gettext("Choosing BOTH is suggested, and it is the default value."); ?></span><br/></td> + <span class="red"><?php echo gettext("Hint:") . "</span> " . gettext("Choosing BOTH is suggested, and it is the default value."); ?><br/> </td> </tr> <tr> @@ -595,8 +855,8 @@ if ($savemsg) { <td width="78%" class="vtable"> <select name="mpm_algo" class="formselect" id="mpm_algo"> <?php - $interfaces2 = array('ac' => 'AC', 'ac-gfbs' => 'AC-GFBS', 'ac-bs' => 'AC-BS', - 'b2g' => 'B2G', 'b3g' => 'B3G', 'wumanber' => 'WUMANBER'); + $interfaces2 = array('ac' => 'AC', 'ac-gfbs' => 'AC-GFBS', 'b2g' => 'B2G', + 'b2gc' => 'B2GC', 'b2gm' => 'B2GM', 'b3g' => 'B3G', 'wumanber' => 'WUMANBER'); foreach ($interfaces2 as $iface2 => $ifacename2): ?> <option value="<?=$iface2;?>" <?php if ($iface2 == $pconfig['mpm_algo']) echo "selected"; ?>> @@ -643,6 +903,14 @@ if ($savemsg) { "<strong>" . gettext("Not Checked") . "</strong>."; ?></td> </tr> <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Promiscuous Mode"); ?></td> + <td width="78%" class="vtable"> + <input name="intf_promisc_mode" id="intf_promisc_mode" type="checkbox" value="on" + <?php if ($pconfig['intf_promisc_mode'] == "on") echo " checked"; ?>/> + <?php echo gettext("Suricata will place the monitored interface in promiscuous mode when checked. Default is ") . + "<strong>" . gettext("Checked") . "</strong>."; ?></td> + </tr> + <tr> <td colspan="2" class="listtopic"><?php echo gettext("Networks " . "Suricata Should Inspect and Protect"); ?></td> </tr> <tr> @@ -651,9 +919,9 @@ if ($savemsg) { <select name="homelistname" class="formselect" id="homelistname"> <?php echo "<option value='default' >default</option>"; - /* find whitelist names and filter by type */ - if (is_array($suricataglob['whitelist']['item'])) { - foreach ($suricataglob['whitelist']['item'] as $value) { + /* find Pass List names and filter by type */ + if (is_array($suricataglob['passlist']['item'])) { + foreach ($suricataglob['passlist']['item'] as $value) { $ilistname = $value['name']; if ($ilistname == $pconfig['homelistname']) echo "<option value='$ilistname' selected>"; @@ -668,12 +936,13 @@ if ($savemsg) { onclick="viewList('<?=$id;?>','homelistname','homenet')" id="btnHomeNet" title="<?php echo gettext("Click to view currently selected Home Net contents"); ?>"/> <br/> - <span class="vexpl"><?php echo gettext("Choose the Home Net you want this interface to use."); ?></span> + <span class="vexpl"><?php echo gettext("Choose the Home Net you want this interface to use. Most users should choose 'default'."); ?></span> <br/><br/> <span class="red"><?php echo gettext("Note:"); ?></span> <?php echo gettext("Default Home " . "Net adds only local networks, WAN IPs, Gateways, VPNs and VIPs."); ?><br/> <span class="red"><?php echo gettext("Hint:"); ?></span> <?php echo gettext("Create an Alias to hold a list of " . - "friendly IPs that the firewall cannot see or to customize the default Home Net."); ?><br/> + "friendly IPs that the firewall cannot see or to customize the default Home Net. Assign the Alias to a Pass List, and " . + "then assign that Pass List to Home Net."); ?><br/> </td> </tr> <tr> @@ -682,9 +951,9 @@ if ($savemsg) { <select name="externallistname" class="formselect" id="externallistname"> <?php echo "<option value='default' >default</option>"; - /* find whitelist names and filter by type */ - if (is_array($suricataglob['whitelist']['item'])) { - foreach ($suricataglob['whitelist']['item'] as $value) { + /* find Pass List names and filter by type */ + if (is_array($suricataglob['passlist']['item'])) { + foreach ($suricataglob['passlist']['item'] as $value) { $ilistname = $value['name']; if ($ilistname == $pconfig['externallistname']) echo "<option value='$ilistname' selected>"; @@ -694,7 +963,11 @@ if ($savemsg) { } } ?> - </select> + </select> + <input type="button" class="formbtns" value="View List" + onclick="viewList('<?=$id;?>','externallistname','externalnet')" id="btnExternalNet" + title="<?php echo gettext("Click to view currently selected External Net contents"); ?>"/> + <br/> <?php echo gettext("Choose the External Net you want this interface " . "to use."); ?> <br/><br/> <span class="red"><?php echo gettext("Note:"); ?></span> <?php echo gettext("Default " . @@ -724,7 +997,7 @@ if ($savemsg) { <input type="button" class="formbtns" value="View List" onclick="viewList('<?=$id;?>','passlistname','passlist')" id="btnPasslist" title="<?php echo gettext("Click to view currently selected Pass List contents"); ?>"/> <br/> - <?php echo gettext("Choose the Pass List you want this interface to use."); ?> <br/><br/> + <?php echo gettext("Choose the Pass List you want this interface to use. Addresses in a Pass List are never blocked."); ?> <br/><br/> <span class="red"><?php echo gettext("Note:"); ?></span> <?php echo gettext("This option will only be used when block offenders is on."); ?><br/> <span class="red"><?php echo gettext("Hint:"); ?></span> <?php echo gettext("Default " . "Pass List adds local networks, WAN IPs, Gateways, VPNs and VIPs. Create an Alias to customize."); ?> @@ -773,7 +1046,6 @@ if ($savemsg) { <tr> <td colspan="2" align="center" valign="middle"><input name="save" type="submit" class="formbtn" value="Save" title="<?php echo gettext("Click to save settings and exit"); ?>"/> - <input name="id" type="hidden" value="<?=$id;?>"/> </td> </tr> <tr> @@ -781,14 +1053,32 @@ if ($savemsg) { gettext("Please save your settings before you attempt to start Suricata."); ?> </td> </tr> +</tbody> </table> </div> </td></tr> +</tbody> </table> </form> <script language="JavaScript"> +function toggle_system_log() { + var endis = !(document.iform.alertsystemlog.checked); + if (endis) + document.getElementById("alertsystemlog_rows").style.display="none"; + else + document.getElementById("alertsystemlog_rows").style.display=""; +} + +function toggle_dns_log() { + var endis = !(document.iform.enable_dns_log.checked); + if (endis) + document.getElementById("dns_log_append_row").style.display="none"; + else + document.getElementById("dns_log_append_row").style.display="table-row"; +} + function enable_blockoffenders() { var endis = !(document.iform.blockoffenders.checked); document.iform.blockoffenderskill.disabled=endis; @@ -813,18 +1103,27 @@ function toggle_stats_log() { function toggle_http_log() { var endis = !(document.iform.enable_http_log.checked); - if (endis) + if (endis) { document.getElementById("http_log_append_row").style.display="none"; - else + document.getElementById("http_log_extended_row").style.display="none"; + } + else { document.getElementById("http_log_append_row").style.display="table-row"; + document.getElementById("http_log_extended_row").style.display="table-row"; + } } function toggle_tls_log() { var endis = !(document.iform.enable_tls_log.checked); if (endis) document.getElementById("tls_log_extended_row").style.display="none"; - else + else { document.getElementById("tls_log_extended_row").style.display="table-row"; + if (document.iform.enable_eve_log.checked && document.iform.eve_log_tls.checked) { + alert('Only one TLS log instance permitted...removing TLS log from EVE JSON output in order to enable standalone TLS logging.'); + document.iform.eve_log_tls.checked = false; + } + } } function toggle_json_file_log() { @@ -865,6 +1164,25 @@ function toggle_pcap_log() { } } +function toggle_eve_log() { + var endis = !(document.iform.enable_eve_log.checked); + if (endis) { + document.getElementById("eve_log_option_rows").style.display = "none"; + } + else { + document.getElementById("eve_log_option_rows").style.display = ""; + if (document.iform.enable_tls_log.checked) + document.iform.eve_log_tls.checked = false; + } +} + +function toggle_eve_tls() { + if (document.iform.enable_tls_log.checked) { + alert('Only one TLS log instance permitted...removing standalone TLS output in order to add EVE JSON TLS output.'); + document.iform.enable_tls_log.checked = false; + } +} + function enable_change(enable_change) { endis = !(document.iform.enable.checked || enable_change); // make sure a default answer is called if this is invoked. @@ -874,6 +1192,7 @@ function enable_change(enable_change) { document.iform.append_stats_log.disabled = endis; document.iform.enable_http_log.disabled = endis; document.iform.append_http_log.disabled = endis; + document.iform.http_log_extended.disabled = endis; document.iform.enable_tls_log.disabled = endis; document.iform.tls_log_extended.disabled = endis; document.iform.enable_json_file_log.disabled = endis; @@ -884,6 +1203,14 @@ function enable_change(enable_change) { document.iform.enable_pcap_log.disabled = endis; document.iform.max_pcap_log_size.disabled = endis; document.iform.max_pcap_log_files.disabled = endis; + document.iform.eve_output_type.disabled = endis; + document.iform.enable_eve_log.disabled = endis; + document.iform.eve_log_alerts.disabled = endis; + document.iform.eve_log_http.disabled = endis; + document.iform.eve_log_dns.disabled = endis; + document.iform.eve_log_tls.disabled = endis; + document.iform.eve_log_files.disabled = endis; + document.iform.eve_log_ssh.disabled = endis; document.iform.max_pending_packets.disabled = endis; document.iform.detect_eng_profile.disabled = endis; document.iform.mpm_algo.disabled = endis; @@ -901,8 +1228,9 @@ function enable_change(enable_change) { document.iform.btnHomeNet.disabled=endis; document.iform.btnPasslist.disabled=endis; document.iform.btnSuppressList.disabled=endis; -} document.iform.delayed_detect.disabled=endis; - + document.iform.delayed_detect.disabled=endis; + document.iform.intf_promisc_mode.disabled=endis; +} function wopen(url, name, w, h) { // Fudge factors for window decoration space. @@ -923,6 +1251,18 @@ function getSelectedValue(elemID) { return ctrl.options[ctrl.selectedIndex].value; } +function eveOutSelect() { + var ctrl = document.getElementById("eve_output_type"); + if (ctrl.options[ctrl.selectedIndex].value == 'syslog') { + document.getElementById("eve_systemlog_facility_row").style.display = "table-row"; + document.getElementById("eve_systemlog_priority_row").style.display = "table-row"; + } + else { + document.getElementById("eve_systemlog_facility_row").style.display = "none"; + document.getElementById("eve_systemlog_priority_row").style.display = "none"; + } +} + function viewList(id, elemID, elemType) { if (typeof elemType == "undefined") { elemType = "passlist"; @@ -935,12 +1275,16 @@ function viewList(id, elemID, elemType) { enable_change(false); //enable_blockoffenders(); +toggle_system_log(); +toggle_dns_log(); toggle_stats_log(); toggle_http_log(); toggle_tls_log(); toggle_json_file_log(); toggle_file_store(); toggle_pcap_log(); +toggle_eve_log(); +eveOutSelect(); </script> <?php include("fend.inc"); ?> diff --git a/config/suricata/suricata_ip_list_mgmt.php b/config/suricata/suricata_ip_list_mgmt.php new file mode 100644 index 00000000..37decaad --- /dev/null +++ b/config/suricata/suricata_ip_list_mgmt.php @@ -0,0 +1,398 @@ +<?php +/* + * suricata_ip_list_mgmt.php + * + * Significant portions of this code are based on original work done + * for the Snort package for pfSense from the following contributors: + * + * Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. + * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. + * Copyright (C) 2006 Scott Ullrich + * Copyright (C) 2009 Robert Zelaya Sr. Developer + * Copyright (C) 2012 Ermal Luci + * All rights reserved. + * + * Adapted for Suricata by: + * Copyright (C) 2014 Bill Meeks + * 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("guiconfig.inc"); +require_once("/usr/local/pkg/suricata/suricata.inc"); + +global $config, $g; + +if (!is_array($config['installedpackages']['suricata']['rule'])) + $config['installedpackages']['suricata']['rule'] = array(); + +// Hard-code the path where IP Lists are stored +// and disregard any user-supplied path element. +$iprep_path = SURICATA_IPREP_PATH; + +// Set default to not show IP List editor controls +$iplist_edit_style = "display: none;"; + +function suricata_is_iplist_active($iplist) { + + /*************************************************** + * This function checks all configured Suricata * + * interfaces to see if the passed IP List is used * + * as a whitelist or blacklist by an interface. * + * * + * Returns: TRUE if IP List is in use * + * FALSE if IP List is not in use * + ***************************************************/ + + global $g, $config; + + if (!is_array($config['installedpackages']['suricata']['rule'])) + return FALSE; + + foreach ($config['installedpackages']['suricata']['rule'] as $rule) { + if (is_array($rule['iplist_files']['item'])) { + foreach ($rule['iplist_files']['item'] as $file) { + if ($file == $iplist) + return TRUE; + } + } + } + return FALSE; +} + +// If doing a postback, used typed values, else load from stored config +if (!empty($_POST)) { + $pconfig = $_POST; +} +else { + $pconfig['et_iqrisk_enable'] = $config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable']; + $pconfig['iqrisk_code'] = $config['installedpackages']['suricata']['config'][0]['iqrisk_code']; +} + +// Validate IQRisk settings if enabled and saving them +if ($_POST['save']) { + if ($pconfig['et_iqrisk_enable'] == 'on' && empty($pconfig['iqrisk_code'])) + $input_errors[] = gettext("You must provide a valid IQRisk subscription code when IQRisk downloads are enabled!"); + + if (!$input_errors) { + $config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] = $_POST['et_iqrisk_enable'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['config'][0]['iqrisk_code'] = $_POST['iqrisk_code']; + write_config("Suricata pkg: modified IP Lists settings."); + + /* Toggle cron task for ET IQRisk updates if setting was changed */ + if ($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] == 'on' && !suricata_cron_job_exists("/usr/local/pkg/suricata/suricata_etiqrisk_update.php")) { + install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_etiqrisk_update.php", TRUE, 0, "*/6", "*", "*", "*", "root"); + } + elseif ($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] == 'off' && suricata_cron_job_exists("/usr/local/pkg/suricata/suricata_etiqrisk_update.php")) + install_cron_job("/usr/local/pkg/suricata/suricata_etiqrisk_update.php", FALSE); + + /* Peform a manual ET IQRisk file check/download */ + if ($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] == 'on') + include("/usr/local/pkg/suricata/suricata_etiqrisk_update.php"); + } +} + +if (isset($_POST['upload'])) { + if ($_FILES["iprep_fileup"]["error"] == UPLOAD_ERR_OK) { + $tmp_name = $_FILES["iprep_fileup"]["tmp_name"]; + $name = $_FILES["iprep_fileup"]["name"]; + move_uploaded_file($tmp_name, "{$iprep_path}{$name}"); + } + else + $input_errors[] = gettext("Failed to upload file {$_FILES["iprep_fileup"]["name"]}"); +} + +if (isset($_POST['iplist_delete']) && isset($_POST['iplist_fname'])) { + if (!suricata_is_iplist_active($_POST['iplist_fname'])) + unlink_if_exists("{$iprep_path}{$_POST['iplist_fname']}"); + else + $input_errors[] = gettext("This IP List is currently assigned to an interface and cannot be deleted until it is removed from the configured interface."); +} + +if (isset($_POST['iplist_edit']) && isset($_POST['iplist_fname'])) { + $file = $iprep_path . basename($_POST['iplist_fname']); + $data = file_get_contents($file); + if ($data !== FALSE) { + $iplist_data = htmlspecialchars($data); + $iplist_edit_style = "display: table-row-group;"; + $iplist_name = basename($_POST['iplist_fname']); + unset($data); + } + else { + $input_errors[] = gettext("An error occurred reading the file."); + } +} + +if (isset($_POST['iplist_edit_save']) && isset($_POST['iplist_data'])) { + if (strlen(basename($_POST['iplist_name'])) > 0) { + $file = $iprep_path . basename($_POST['iplist_name']); + $data = str_replace("\r\n", "\n", $_POST['iplist_data']); + file_put_contents($file, $data); + unset($data); + } + else { + $input_errors[] = gettext("You must provide a valid filename for the IP List."); + $iplist_edit_style = "display: table-row-group;"; + } +} + +// Get all files in the IP Lists sub-directory as an array +// Leave this as the last thing before spewing the page HTML +// so we can pick up any changes made to files in code above. +$ipfiles = return_dir_as_array($iprep_path); + +$pgtitle = gettext("Suricata: IP Reputation Lists"); +include_once("head.inc"); + +?> + +<body link="#000000" vlink="#000000" alink="#000000"> + +<?php +include_once("fbegin.inc"); +if ($input_errors) { + print_input_errors($input_errors); +} + +if ($savemsg) + print_info_box($savemsg); +?> + +<form action="/suricata/suricata_ip_list_mgmt.php" enctype="multipart/form-data" method="post" name="iform" id="iform"> +<input type="hidden" name="MAX_FILE_SIZE" value="100000000" /> +<input type="hidden" name="iplist_fname" id="iplist_fname" value=""/> +<table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> +<tr><td> +<?php + $tab_array = array(); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); + $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), true, "/suricata/suricata_ip_list_mgmt.php"); + display_top_tabs($tab_array, true); +?> +</td> +</tr> +<tr> + <td> + <div id="mainarea"> + <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> + <?php if ($g['platform'] == "nanobsd") : ?> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("IP Reputation is not supported on NanoBSD installs"); ?></td> + </tr> + <?php else: ?> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("Emerging Threats IQRisk Settings"); ?></td> + </tr> + <tr> + <td width="22%" valign="top"><?php echo gettext("Enable"); ?></td> + <td width="78%"> + <input id="et_iqrisk_enable" name="et_iqrisk_enable" type="checkbox" value="on" <?php if ($pconfig['et_iqrisk_enable'] == "on") echo "checked"; ?> onclick="IQRisk_enablechange();"/> + <?php echo gettext("Checking this box enables auto-download of IQRisk List updates with a valid subscription code."); ?> + </td> + </tr> + <tr> + <td width="22%"></td> + <td width="78%"> + <table id="iqrisk_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> + <tr> + <td colspan="2" class="vexpl"><?=gettext("IQRisk IP lists will auto-update nightly at midnight. Visit ") . + "<a href='http://emergingthreats.net/products/iqrisk-rep-list/' target='_blank'>" . gettext("http://emergingthreats.net/products/iqrisk-rep-list/") . "</a>" . + gettext(" for more information or to purchase a subscription.");?><br/><br/></td> + </tr> + <tr> + <td colspan="2" valign="top"><b><span class="vexpl"><?php echo gettext("IQRisk Subscription Configuration"); ?></span></b></td> + </tr> + <tr> + <td valign="top"><span class="vexpl"><strong><?php echo gettext("Code:"); ?></strong></span></td> + <td><input name="iqrisk_code" type="text" class="formfld unknown" id="iqrisk_code" size="52" + value="<?=htmlspecialchars($pconfig['iqrisk_code']);?>"/><br/> + <?php echo gettext("Obtain an Emerging Threats IQRisk List subscription code and paste it here."); ?></td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td colspan="2" align="center"><input name="save" id="save" type="submit" class="formbtn" value="Save" title="<?=gettext("Save IQRisk settings");?>"/></td> + </tr> + <tr> + <td colspan="2" class="vtable"></td> + </tr> + <tr> + <td colspan="2" class="listtopic"><?=gettext("IP Reputation List Files Management");?> + </td> + </tr> + <tbody id="uploader" style="display: none;"> + <tr> + <td colspan="2" class="list"><br/><?php echo gettext("Click BROWSE to select a file to import, and then click UPLOAD. Click CLOSE to quit."); ?></td> + </tr> + <tr> + <td colspan="2" class="list"><input type="file" name="iprep_fileup" id="iprep_fileup" class="formfld file" size="50" /> + <input type="submit" name="upload" id="upload" value="<?=gettext("Upload");?>" + title="<?=gettext("Upload selected IP list to firewall");?>"/> <input type="button" + value="<?=gettext("Close");?>" onClick="document.getElementById('uploader').style.display='none';" /></td> + </tr> + </tbody> + <tr> + <td colspan="2"> + <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> + <colgroup> + <col style="width: 50%;"> + <col style="width: 25%;"> + <col style="width: 15%;"> + <col style="width: 10%;"> + </colgroup> + <thead> + <tr> + <th class="listhdrr"><?php echo gettext("IP List File Name"); ?></th> + <th class="listhdrr"><?php echo gettext("Last Modified Time"); ?></th> + <th class="listhdrr"><?php echo gettext("File Size"); ?></th> + <th class="list" align="left"><img style="cursor:pointer;" name="iplist_new" id="iplist_new" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" + height="17" border="0" title="<?php echo gettext('Create a new IP List');?>" + onClick="document.getElementById('iplist_data').value=''; document.getElementById('iplist_name').value=''; document.getElementById('iplist_editor').style.display='table-row-group'; document.getElementById('iplist_name').focus();" /> + <img style="cursor:pointer;" name="iplist_import" id="iplist_import" + onClick="document.getElementById('uploader').style.display='table-row-group';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_import_alias.gif" width="17" + height="17" border="0" title="<?php echo gettext('Import/Upload an IP List');?>"/></th> + </tr> + </thead> + <?php foreach ($ipfiles as $file): + if (substr(strrchr($file, "."), 1) == "md5") + continue; ?> + <tr> + <td class="listr"><?php echo gettext($file); ?></td> + <td class="listr"><?=date('M-d Y g:i a', filemtime("{$iprep_path}{$file}")); ?></td> + <td class="listr"><?=format_bytes(filesize("{$iprep_path}{$file}")); ?> </td> + <td class="list"><input type="image" name="iplist_edit[]" id="iplist_edit[]" + onClick="document.getElementById('iplist_fname').value='<?=$file;?>';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" + height="17" border="0" title="<?php echo gettext('Edit this IP List');?>"/> + <input type="image" name="iplist_delete[]" id="iplist_delete[]" + onClick="document.getElementById('iplist_fname').value='<?=$file;?>'; + return confirm('<?=gettext("Are you sure you want to permanently delete this IP List file? Click OK to continue or CANCEL to quit.");?>');" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" + height="17" border="0" title="<?php echo gettext('Delete this IP List');?>"/></td> + </tr> + <?php endforeach; ?> + <tbody id="iplist_editor" style="<?=$iplist_edit_style;?>"> + <tr> + <td colspan="4"> </td> + </tr> + <tr> + <td colspan="4"><strong><?=gettext("File Name: ");?></strong><input type="text" size="45" class="formfld file" id="iplist_name" name="iplist_name" value="<?=$iplist_name;?>" /> + <input type="submit" id="iplist_edit_save" name="iplist_edit_save" value="<?=gettext(" Save ");?>" title="<?=gettext("Save changes and close editor");?>" /> + <input type="button" id="cancel" name="cancel" value="<?=gettext("Cancel");?>" onClick="document.getElementById('iplist_editor').style.display='none';" + title="<?=gettext("Abandon changes and quit editor");?>" /></td> + </tr> + <tr> + <td colspan="4"> </td> + </tr> + <tr> + <td colspan="4"><textarea wrap="off" cols="80" rows="20" name="iplist_data" id="iplist_data" + style="width:95%; height:100%;"><?=$iplist_data;?></textarea> + </td> + </tr> + </tbody> + <tbody> + <tr> + <td colspan="3" class="vexpl"><br/><span class="red"><strong><?php echo gettext("Notes:"); ?></strong></span> + <br/><?php echo gettext("1. A Categories file is required and contains CSV fields for Category Number, Short Name " . + "and Description per line."); ?></td> + <td class="list"></td> + </tr> + <tr> + <td colspan="3" class="vexpl"><?php echo gettext("2. IP Lists are CSV format text files " . + "with an IP address, category code and reputation score per line."); ?></td> + <td class="list"></td> + </tr> + <tr> + <td colspan="3" class="vexpl"><?php echo gettext("3. IP Lists are stored as local files " . + "on the firewall and their contents are not saved as part of the firewall configuration file."); ?></td> + <td class="list"></td> + </tr> + <tr> + <td colspan="3" class="vexpl"><?php echo gettext("4. Visit ") . + "<a href='https://redmine.openinfosecfoundation.org/projects/suricata/wiki/IPReputationFormat' target='_blank'>" . + gettext("https://redmine.openinfosecfoundation.org/projects/suricata/wiki/IPReputationFormat") . "</a>" . + gettext(" for IP Reputation file formats."); ?><br/></td> + <td class="list"></td> + </tr> + <tr> + <td colspan="3" class="vexpl"><br/><strong><?php echo gettext("IP List Controls:"); ?></strong><br/><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the editor window to create a new IP List. You must provide a valid filename before saving.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_import_alias.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the file upload control for uploading a new IP List from your local machine.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the IP List in a text edit control for viewing or editing its contents.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" /> + <?=gettext("Deletes the IP List from the file system after confirmation.");?></td> + <td class="list"></td> + </tr> + </tbody> + </table> + </td> + </tr> + <?php endif; ?> + </tbody> + </table> + </div> + </td> +</tr> +</tbody> +</table> +</form> +<?php include("fend.inc"); ?> + +<script language="JavaScript"> +<!-- + +function IQRisk_enablechange() { + var endis = !(document.iform.et_iqrisk_enable.checked); + if (endis) + document.getElementById("iqrisk_code_tbl").style.display = "none"; + else + document.getElementById("iqrisk_code_tbl").style.display = "table"; +} + +// Initialize the form controls state based on saved settings +IQRisk_enablechange(); + +//--> +</script> +</body> +</html> diff --git a/config/suricata/suricata_ip_reputation.php b/config/suricata/suricata_ip_reputation.php new file mode 100644 index 00000000..4615923a --- /dev/null +++ b/config/suricata/suricata_ip_reputation.php @@ -0,0 +1,482 @@ +<?php +/* + * suricata_ip_reputation.php + * part of pfSense + * + * Copyright (C) 2014 Bill Meeks + * 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("guiconfig.inc"); +require_once("/usr/local/pkg/suricata/suricata.inc"); + +global $g, $rebuild_rules; + +if (isset($_POST['id']) && is_numericint($_POST['id'])) + $id = $_POST['id']; +elseif (isset($_GET['id']) && is_numericint($_GET['id'])) + $id = htmlspecialchars($_GET['id']); + +if (is_null($id)) { + header("Location: /suricata/suricata_interfaces.php"); + exit; +} + +if (!is_array($config['installedpackages']['suricata']['rule'])) { + $config['installedpackages']['suricata']['rule'] = array(); +} +if (!is_array($config['installedpackages']['suricata']['rule'][$id]['iplist_files']['item'])) { + $config['installedpackages']['suricata']['rule'][$id]['iplist_files']['item'] = array(); +} + +$a_nat = &$config['installedpackages']['suricata']['rule']; + +// If doing a postback, used typed values, else load from stored config +if (!empty($_POST)) { + $pconfig = $_POST; +} +else { + $pconfig = $a_nat[$id]; +} + +$iprep_path = SURICATA_IPREP_PATH; +$if_real = get_real_interface($a_nat[$id]['interface']); +$suricata_uuid = $config['installedpackages']['suricata']['rule'][$id]['uuid']; + +if ($_POST['mode'] == 'iprep_catlist_add' && isset($_POST['iplist'])) { + $pconfig = $_POST; + + // Test the supplied IP List file to see if it exists + if (file_exists($_POST['iplist'])) { + if (!$input_errors) { + $a_nat[$id]['iprep_catlist'] = basename($_POST['iplist']); + write_config("Suricata pkg: added new IP Rep Categories file for IP REPUTATION preprocessor."); + mark_subsystem_dirty('suricata_iprep'); + } + } + else + $input_errors[] = gettext("The file '{$_POST['iplist']}' could not be found."); + + $pconfig['iprep_catlist'] = $a_nat[$id]['iprep_catlist']; + $pconfig['iplist_files'] = $a_nat[$id]['iplist_files']; +} + +if ($_POST['mode'] == 'iplist_add' && isset($_POST['iplist'])) { + $pconfig = $_POST; + + // Test the supplied IP List file to see if it exists + if (file_exists($_POST['iplist'])) { + // See if the file is already assigned to the interface + foreach ($a_nat[$id]['iplist_files']['item'] as $f) { + if ($f == basename($_POST['iplist'])) { + $input_errors[] = gettext("The file {$f} is already assigned as a whitelist file."); + break; + } + } + if (!$input_errors) { + $a_nat[$id]['iplist_files']['item'][] = basename($_POST['iplist']); + write_config("Suricata pkg: added new whitelist file for IP REPUTATION preprocessor."); + mark_subsystem_dirty('suricata_iprep'); + } + } + else + $input_errors[] = gettext("The file '{$_POST['iplist']}' could not be found."); + + $pconfig['iprep_catlist'] = $a_nat[$id]['iprep_catlist']; + $pconfig['iplist_files'] = $a_nat[$id]['iplist_files']; +} + +if ($_POST['iprep_catlist_del']) { + $pconfig = $_POST; + unset($a_nat[$id]['iprep_catlist']); + write_config("Suricata pkg: deleted blacklist file for IP REPUTATION preprocessor."); + mark_subsystem_dirty('suricata_iprep'); + $pconfig['iprep_catlist'] = $a_nat[$id]['iprep_catlist']; + $pconfig['iplist_files'] = $a_nat[$id]['iplist_files']; +} + +if ($_POST['iplist_del'] && is_numericint($_POST['list_id'])) { + $pconfig = $_POST; + unset($a_nat[$id]['iplist_files']['item'][$_POST['list_id']]); + write_config("Suricata pkg: deleted whitelist file for IP REPUTATION preprocessor."); + mark_subsystem_dirty('suricata_iprep'); + $pconfig['iplist_files'] = $a_nat[$id]['iplist_files']; + $pconfig['iprep_catlist'] = $a_nat[$id]['iprep_catlist']; +} + +if ($_POST['save'] || $_POST['apply']) { + + $pconfig['iprep_catlist'] = $a_nat[$id]['iprep_catlist']; + $pconfig['iplist_files'] = $a_nat[$id]['iplist_files']; + + // Validate HOST TABLE values + if ($_POST['host_memcap'] < 1000000 || !is_numericint($_POST['host_memcap'])) + $input_errors[] = gettext("The value for 'Host Memcap' must be a numeric integer greater than 1MB (1,048,576!"); + if ($_POST['host_hash_size'] < 1024 || !is_numericint($_POST['host_hash_size'])) + $input_errors[] = gettext("The value for 'Host Hash Size' must be a numeric integer greater than 1024!"); + if ($_POST['host_prealloc'] < 10 || !is_numericint($_POST['host_prealloc'])) + $input_errors[] = gettext("The value for 'Host Preallocations' must be a numeric integer greater than 10!"); + + // Validate CATEGORIES FILE + if ($_POST['enable_iprep'] == 'on') { + if (empty($a_nat[$id]['iprep_catlist'])) + $input_errors[] = gettext("Assignment of a 'Categories File' is required when IP Reputation is enabled!"); + } + + // If no errors write to conf + if (!$input_errors) { + + $a_nat[$id]['enable_iprep'] = $_POST['enable_iprep'] ? 'on' : 'off'; + $a_nat[$id]['host_memcap'] = str_replace(",", "", $_POST['host_memcap']); + $a_nat[$id]['host_hash_size'] = str_replace(",", "", $_POST['host_hash_size']); + $a_nat[$id]['host_prealloc'] = str_replace(",", "", $_POST['host_prealloc']); + + write_config("Suricata pkg: modified IP REPUTATION preprocessor settings for {$a_nat[$id]['interface']}."); + + // Update the suricata conf file for this interface + $rebuild_rules = false; + conf_mount_rw(); + suricata_generate_yaml($a_nat[$id]); + conf_mount_ro(); + + // Soft-restart Suricata to live-load new variables + suricata_reload_config($a_nat[$id]); + + // We have saved changes and done a soft restart, so clear "dirty" flag + clear_subsystem_dirty('suricata_iprep'); + } +} + +$if_friendly = convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} IP Reputation Preprocessor"); +include_once("head.inc"); + +?> +<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> + +<?php +include("fbegin.inc"); +/* Display Alert message */ +if ($input_errors) + print_input_errors($input_errors); +if ($savemsg) + print_info_box($savemsg); +?> + +<form action="suricata_ip_reputation.php" method="post" name="iform" id="iform" > +<input name="id" type="hidden" value="<?=$id;?>" /> +<input type="hidden" id="mode" name="mode" value="" /> +<input name="iplist" id="iplist" type="hidden" value="" /> +<input name="list_id" id="list_id" type="hidden" value="" /> + +<?php if (is_subsystem_dirty('suricata_iprep') && !$input_errors): ?><p> +<?php print_info_box_np(gettext("A change has been made to IP List file assignments.") . "<br/>" . gettext("You must apply the change in order for it to take effect."));?> +<?php endif; ?> + +<table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> + <tr> + <td> + <?php + $tab_array = array(); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); + $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); + display_top_tabs($tab_array, true); + echo '</td></tr>'; + echo '<tr><td class="tabnavtbl">'; + $tab_array = array(); + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), true, "/suricata/suricata_ip_reputation.php?id={$id}"); + display_top_tabs($tab_array, true); + ?> + </td> + </tr> + <tr> + <td><div id="mainarea"> + <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> + <?php if ($g['platform'] == "nanobsd") : ?> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("IP Reputation is not supported on NanoBSD installs"); ?></td> + </tr> + <?php else: ?> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("IP Reputation Configuration"); ?></td> + </tr> + <tr> + <td width="22%" valign='top' class='vncell'><?php echo gettext("Enable"); ?> + </td> + <td width="78%" class="vtable"><input name="enable_iprep" type="checkbox" value="on" <?php if ($pconfig['enable_iprep'] == "on") echo "checked"; ?>/> + <?php echo gettext("Use IP Reputation Lists on this interface. Default is ") . "<strong>" . gettext("Not Checked.") . "</strong>"; ?> + </td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Host Memcap"); ?></td> + <td width="78%" class="vtable"><input name="host_memcap" type="text" + class="formfld unknown" id="host_memcap" size="8" value="<?=htmlspecialchars($pconfig['host_memcap']); ?>"/> + <?php echo gettext("Host table memory cap in bytes. Default is ") . "<strong>" . + gettext("16777216") . "</strong>" . gettext(" (16 MB). Min value is 1048576 (1 MB)."); ?><br/><br/><?php echo gettext("When using large IP Reputation Lists, this value may need to be increased " . + "to avoid exhausting Host Table memory.") ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Host Hash Size"); ?></td> + <td width="78%" class="vtable"><input name="host_hash_size" type="text" + class="formfld unknown" id="host_hash_size" size="8" value="<?=htmlspecialchars($pconfig['host_hash_size']); ?>"/> + <?php echo gettext("Host Hash Size in bytes. Default is ") . "<strong>" . + gettext("4096") . "</strong>" . gettext(". Min value is 1024."); ?><br/><br/><?php echo gettext("When using large IP Reputation Lists, this value may need to be increased."); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Host Preallocations"); ?></td> + <td width="78%" class="vtable"><input name="host_prealloc" type="text" + class="formfld unknown" id="host_prealloc" size="8" value="<?=htmlspecialchars($pconfig['host_prealloc']); ?>"/> + <?php echo gettext("Number of Host Table entries to preallocate. Default is ") . "<strong>" . + gettext("1000") . "</strong>" . gettext(". Min value is 10."); ?><br/><br/><?php echo gettext("Increasing this value may slightly improve performance when using large IP Reputation Lists."); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"> </td> + <td width="78%" class="vtable"> + <input name="save" type="submit" class="formbtn" value="Save" title="<?=gettext("Save IP Reputation configuration");?>" /> + <?=gettext("Click to save configuration settings and live-reload the running Suricata configuration.");?> + </td> + </tr> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Assign Categories File"); ?></td> + </tr> + <tr> + <td width="22%" valign='top' class='vncell'><?php echo gettext("Categories File"); ?> + </td> + <td width="78%" class="vtable"> + <!-- iprep_catlist_chooser --> + <div id="iprep_catlistChooser" name="iprep_catlistChooser" style="display:none; border:1px dashed gray; width:98%;"></div> + <table width="95%" border="0" cellpadding="2" cellspacing="0"> + <colgroup> + <col style="text-align:left;"> + <col style="width: 30%; text-align:left;"> + <col style="width: 17px;"> + </colgroup> + <thead> + <tr> + <th class="listhdrr"><?php echo gettext("Categories Filename"); ?></th> + <th class="listhdrr"><?php echo gettext("Modification Time"); ?></th> + <th class="list" align="left" valign="middle"><img style="cursor:pointer;" name="iprep_catlist_add" id="iprep_catlist_add" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" + height="17" border="0" title="<?php echo gettext('Assign a Categories file');?>"/></th> + </tr> + </thead> + <tbody> + <?php if (!empty($pconfig['iprep_catlist'])) : + $class = "listr"; + if (!file_exists("{$iprep_path}{$pconfig['iprep_catlist']}")) { + $filedate = gettext("Unknown -- file missing"); + $class .= " red"; + } + else + $filedate = date('M-d Y g:i a', filemtime("{$iprep_path}{$pconfig['iprep_catlist']}")); + ?> + <tr> + <td class="<?=$class;?>"><?=htmlspecialchars($pconfig['iprep_catlist']);?></td> + <td class="<?=$class;?>" align="center"><?=$filedate;?></td> + <td class="list"><input type="image" name="iprep_catlist_del[]" id="iprep_catlist_del[]" onClick="document.getElementById('list_id').value='0';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" + border="0" title="<?php echo gettext('Remove this Categories file');?>"/></td> + </tr> + <?php endif; ?> + <tr> + <td colspan="2" class="vexpl"><span class="red"><strong><?=gettext("Note: ");?></strong></span> + <?=gettext("change to Categories File assignment is immediately saved.");?></td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Assign IP Reputation Lists"); ?></td> + </tr> + <tr> + <td width="22%" valign='top' class='vncell'><?php echo gettext("IP Reputation Files"); ?> + </td> + <td width="78%" class="vtable"> + <table width="95%" border="0" cellpadding="2" cellspacing="0"> + <!-- iplist_chooser --> + <div id="iplistChooser" name="iplistChooser" style="display:none; border:1px dashed gray; width:98%;"></div> + <colgroup> + <col style="text-align:left;"> + <col style="width: 30%; text-align:left;"> + <col style="width: 17px;"> + </colgroup> + <thead> + <tr> + <th class="listhdrr"><?php echo gettext("IP Reputation List Filename"); ?></th> + <th class="listhdrr"><?php echo gettext("Modification Time"); ?></th> + <th class="list" align="left" valign="middle"><img style="cursor:pointer;" name="iplist_add" id="iplist_add" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" + border="0" title="<?php echo gettext('Assign a whitelist file');?>"/></th> + </tr> + </thead> + <tbody> + <?php foreach($pconfig['iplist_files']['item'] as $k => $f): + $class = "listr"; + if (!file_exists("{$iprep_path}{$f}")) { + $filedate = gettext("Unknown -- file missing"); + $class .= " red"; + } + else + $filedate = date('M-d Y g:i a', filemtime("{$iprep_path}{$f}")); + ?> + <tr> + <td class="<?=$class;?>"><?=htmlspecialchars($f);?></td> + <td class="<?=$class;?>" align="center"><?=$filedate;?></td> + <td class="list"><input type="image" name="iplist_del[]" id="iplist_del[]" onClick="document.getElementById('list_id').value='<?=$k;?>';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" + border="0" title="<?php echo gettext('Remove this whitelist file');?>"/></td> + </tr> + <?php endforeach; ?> + <tr> + <td colspan="2" class="vexpl"><span class="red"><strong><?=gettext("Note: ");?></strong></span> + <?=gettext("changes to IP Reputation List assignments are immediately saved.");?></td> + </tr> + </tbody> + </table> + </td> + </tr> + <?php endif; ?> + </tbody> + </table> + </div> + </td> + </tr> + </tbody> +</table> + +<?php if ($g['platform'] != "nanobsd") : ?> +<script type="text/javascript"> +Event.observe( + window, "load", + function() { + Event.observe( + "iprep_catlist_add", "click", + function() { + Effect.Appear("iprep_catlistChooser", { duration: 0.25 }); + iprep_catlistChoose(); + } + ); + + Event.observe( + "iplist_add", "click", + function() { + Effect.Appear("iplistChooser", { duration: 0.25 }); + iplistChoose(); + } + ); + } +); + +function iprep_catlistChoose() { + Effect.Appear("iprep_catlistChooser", { duration: 0.25 }); + if($("fbCurrentDir")) + $("fbCurrentDir").innerHTML = "Loading ..."; + + new Ajax.Request( + "/suricata/suricata_iprep_list_browser.php?container=iprep_catlistChooser&target=iplist&val=" + new Date().getTime(), + { method: "get", onComplete: iprep_catlistComplete } + ); +} + +function iplistChoose() { + Effect.Appear("iplistChooser", { duration: 0.25 }); + if($("fbCurrentDir")) + $("fbCurrentDir").innerHTML = "Loading ..."; + + new Ajax.Request( + "/suricata/suricata_iprep_list_browser.php?container=iplistChooser&target=iplist&val=" + new Date().getTime(), + { method: "get", onComplete: iplistComplete } + ); +} + +function iprep_catlistComplete(req) { + $("iprep_catlistChooser").innerHTML = req.responseText; + + var actions = { + fbClose: function() { $("iprep_catlistChooser").hide(); }, + fbFile: function() { $("iplist").value = this.id; + $("mode").value = 'iprep_catlist_add'; + document.getElementById('iform').submit(); + } + } + + for(var type in actions) { + var elem = $("iprep_catlistChooser"); + var list = elem.getElementsByClassName(type); + for (var i=0; i<list.length; i++) { + Event.observe(list[i], "click", actions[type]); + list[i].style.cursor = "pointer"; + } + } +} + +function iplistComplete(req) { + $("iplistChooser").innerHTML = req.responseText; + + var actions = { + fbClose: function() { $("iplistChooser").hide(); }, + fbFile: function() { $("iplist").value = this.id; + $("mode").value = 'iplist_add'; + document.getElementById('iform').submit(); + } + } + + for(var type in actions) { + var elem = $("iplistChooser"); + var list = elem.getElementsByClassName(type); + for (var i=0; i<list.length; i++) { + Event.observe(list[i], "click", actions[type]); + list[i].style.cursor = "pointer"; + } + } +} + +</script> +<?php endif; ?> + +</form> +<?php include("fend.inc"); ?> +</body> +</html> diff --git a/config/suricata/suricata_iprep_list_browser.php b/config/suricata/suricata_iprep_list_browser.php new file mode 100644 index 00000000..9dd65311 --- /dev/null +++ b/config/suricata/suricata_iprep_list_browser.php @@ -0,0 +1,99 @@ +<?php + +require_once("guiconfig.inc"); +require_once("/usr/local/pkg/suricata/suricata.inc"); + +// Fetch a list of files inside a given directory +function get_content($dir) { + $files = array(); + + clearstatcache(); + $fd = @opendir($dir); + while($entry = @readdir($fd)) { + if($entry == ".") continue; + if($entry == "..") continue; + + if(is_dir("{$dir}/{$entry}")) + continue; + else + array_push($files, $entry); + } + @closedir($fd); + natsort($files); + return $files; +} + +$path = SURICATA_IPREP_PATH; +$container = htmlspecialchars($_GET['container']); +$target = htmlspecialchars($_GET['target']); + +// ----- header ----- +?> +<table width="100%"> + <tr> + <td width="25px" align="left"> + <img src="/filebrowser/images/icon_home.gif" alt="Home" title="Home" /> + </td> + <td><b><?=$path;?></b></td> + <td class="fbClose" align="right"> + <img onClick="$('<?=$container;?>').hide();" border="0" src="/filebrowser/images/icon_cancel.gif" alt="Close" title="Close" /> + </td> + </tr> + <tr> + <td id="fbCurrentDir" colspan="3" class="vexpl" align="left"> + </td> + </tr> +<?php +$files = get_content($path); + +// ----- files ----- +foreach($files as $file): + $ext = strrchr($file, "."); + + if($ext == ".css" ) $type = "code"; + elseif($ext == ".html") $type = "code"; + elseif($ext == ".xml" ) $type = "code"; + elseif($ext == ".rrd" ) $type = "database"; + elseif($ext == ".gif" ) $type = "image"; + elseif($ext == ".jpg" ) $type = "image"; + elseif($ext == ".png" ) $type = "image"; + elseif($ext == ".js" ) $type = "js"; + elseif($ext == ".pdf" ) $type = "pdf"; + elseif($ext == ".inc" ) $type = "php"; + elseif($ext == ".php" ) $type = "php"; + elseif($ext == ".conf") $type = "system"; + elseif($ext == ".pid" ) $type = "system"; + elseif($ext == ".sh" ) $type = "system"; + elseif($ext == ".bz2" ) $type = "zip"; + elseif($ext == ".gz" ) $type = "zip"; + elseif($ext == ".tgz" ) $type = "zip"; + elseif($ext == ".zip" ) $type = "zip"; + else $type = "generic"; + + $fqpn = "{$path}/{$file}"; + + if(is_file($fqpn)) { + $fqpn = realpath($fqpn); + $size = sprintf("%.2f KiB", filesize($fqpn) / 1024); + } + else + $size = ""; +?> + <tr> + <td></td> + <td class="fbFile vexpl" id="<?=$fqpn;?>" align="left"> + <?php $filename = str_replace("//","/", "{$path}/{$file}"); ?> + <div onClick="$('<?=$target;?>').value='<?=$filename?>'; $('<?=$container;?>').hide();"> + <img src="/filebrowser/images/file_<?=$type;?>.gif" alt="" title=""> + <?=$file;?> + </div> + </td> + <td align="right" class="vexpl"> + <?=$size;?> + </td> + </tr> +<?php +endforeach; +?> +</table> + diff --git a/config/suricata/suricata_libhtp_policy_engine.php b/config/suricata/suricata_libhtp_policy_engine.php index 7e6ffd6d..248f4c74 100644 --- a/config/suricata/suricata_libhtp_policy_engine.php +++ b/config/suricata/suricata_libhtp_policy_engine.php @@ -60,12 +60,14 @@ resp_body_limit --> Response Body Limit size enable_double_decode_path --> double-decode path part of URI enable_double_decode_query --> double-decode query string part of URI + enable_uri_include_all --> inspect all of URI save_libhtp_policy --> Submit button for save operation and exit cancel_libhtp_policy --> Submit button to cancel operation and exit **************************************************************************************/ ?> <table class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="middle" class="listtopic"><?php echo gettext("Suricata Target-Based HTTP Server Policy Configuration"); ?></td> </tr> @@ -73,7 +75,7 @@ <td valign="top" class="vncell"><?php echo gettext("Engine Name"); ?></td> <td class="vtable"> <input name="policy_name" type="text" class="formfld unknown" id="policy_name" size="25" maxlength="25" - value="<?=htmlspecialchars($pengcfg['name']);?>"<?php if (htmlspecialchars($pengcfg['name']) == "default") echo "readonly";?>> + value="<?=htmlspecialchars($pengcfg['name']);?>"<?php if (htmlspecialchars($pengcfg['name']) == " default") echo " readonly";?>> <?php if (htmlspecialchars($pengcfg['name']) <> "default") echo gettext("Name or description for this engine. (Max 25 characters)"); else @@ -87,6 +89,7 @@ <td class="vtable"> <?php if ($pengcfg['name'] <> "default") : ?> <table width="95%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td class="vexpl"><input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32" value="<?=htmlspecialchars($pengcfg['bind_to']);?>" title="<?=trim(filter_expand_alias($pengcfg['bind_to']));?>" autocomplete="off"> @@ -97,6 +100,7 @@ <tr> <td class="vexpl" colspan="2"><?php echo gettext("This policy will apply for packets with destination addresses contained within this IP List.");?></td> </tr> + </tbody> </table> <br/><span class="red"><strong><?php echo gettext("Note: ") . "</strong></span>" . gettext("Supplied value must be a pre-configured Alias or the keyword 'all'.");?> <?php else : ?> @@ -112,7 +116,7 @@ <td width="78%" class="vtable"> <select name="personality" class="formselect" id="personality"> <?php - $profile = array( 'Apache', 'Apache_2_2', 'Generic', 'IDS', 'IIS_4_0', 'IIS_5_0', 'IIS_5_1', 'IIS_6_0', 'IIS_7_0', 'IIS_7_5', 'Minimal' ); + $profile = array( 'Apache_2', 'Generic', 'IDS', 'IIS_4_0', 'IIS_5_0', 'IIS_5_1', 'IIS_6_0', 'IIS_7_0', 'IIS_7_5', 'Minimal' ); foreach ($profile as $val): ?> <option value="<?=$val;?>" <?php if ($val == $pengcfg['personality']) echo "selected"; ?>> @@ -120,7 +124,7 @@ <?php endforeach; ?> </select> <?php echo gettext("Choose the web server personality appropriate for the protected hosts. The default is ") . "<strong>" . gettext("IDS") . "</strong>"; ?>.<br/><br/> - <?php echo gettext("Available web server personality targets are: Apache, Apache 2.2, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, IIS_7_0, IIS_7_5 and Minimal."); ?><br/> + <?php echo gettext("Available web server personality targets are: Apache 2, Generic, IDS (default), IIS_4_0, IIS_5_0, IIS_5_1, IIS_6_0, IIS_7_0, IIS_7_5 and Minimal."); ?><br/> </td> </tr> <tr> @@ -155,15 +159,22 @@ </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Double-Decode Path"); ?></td> - <td width="78%" class="vtable"><input name="enable_double_decode_path" type="checkbox" value="yes" <?php if ($pengcfg['double-decode-path'] == "yes") echo "checked"; ?>> + <td width="78%" class="vtable"><input name="enable_double_decode_path" type="checkbox" value="yes" <?php if ($pengcfg['double-decode-path'] == "yes") echo " checked"; ?>> <?php echo gettext("Suricata will double-decode path section of the URI. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td> </tr> <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Double-Decode Query"); ?></td> - <td width="78%" class="vtable"><input name="enable_double_decode_query" type="checkbox" value="yes" <?php if ($pengcfg['double-decode-query'] == "yes") echo "checked"; ?>> + <td width="78%" class="vtable"><input name="enable_double_decode_query" type="checkbox" value="yes" <?php if ($pengcfg['double-decode-query'] == "yes") echo " checked"; ?>> <?php echo gettext("Suricata will double-decode query string section of the URI. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td> </tr> <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("URI Include-All"); ?></td> + <td width="78%" class="vtable"><input name="enable_uri_include_all" type="checkbox" value="yes" <?php if ($pengcfg['uri-include-all'] == "yes") echo " checked"; ?>> + <?php echo gettext("Include all parts of the URI. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?><br/><br/> + <?php echo gettext("By default the 'scheme', username/password, hostname and port are excluded from inspection. Enabling this option " . + "adds all of them to the normalized uri. This was the default in Suricata versions prior to 2.0."); ?></td> + </tr> + <tr> <td width="22%" valign="bottom"> </td> <td width="78%" valign="bottom"> <input name="save_libhtp_policy" id="save_libhtp_policy" type="submit" class="formbtn" value=" Save " title="<?php echo @@ -172,6 +183,7 @@ <input name="cancel_libhtp_policy" id="cancel_libhtp_policy" type="submit" class="formbtn" value="Cancel" title="<?php echo gettext("Cancel changes and return to App Parsers tab"); ?>"></td> </tr> + </tbody> </table> <script type="text/javascript" src="/javascript/autosuggest.js"> diff --git a/config/suricata/suricata_list_view.php b/config/suricata/suricata_list_view.php index 722bf47a..ec335abd 100644 --- a/config/suricata/suricata_list_view.php +++ b/config/suricata/suricata_list_view.php @@ -42,7 +42,7 @@ $type = htmlspecialchars($_GET['type']); $title = "List"; if (isset($id) && isset($wlist)) { - $a_rule = $config['installedpackages']['suricataglobal']['rule'][$id]; + $a_rule = $config['installedpackages']['suricata']['rule'][$id]; if ($type == "homenet") { $list = suricata_build_list($a_rule, $wlist); $contents = implode("\n", $list); @@ -58,6 +58,20 @@ if (isset($id) && isset($wlist)) { $contents = str_replace("\r", "", base64_decode($list['suppresspassthru'])); $title = "Suppress List"; } + elseif ($type == "externalnet") { + if ($wlist == "default") { + $list = suricata_build_list($a_rule, $a_rule['homelistname']); + $contents = ""; + foreach ($list as $ip) + $contents .= "!{$ip}\n"; + $contents = trim($contents, "\n"); + } + else { + $list = suricata_build_list($a_rule, $wlist, false, true); + $contents = implode("\n", $list); + } + $title = "EXTERNAL_NET"; + } else $contents = gettext("\n\nERROR -- Requested List Type entity is not valid!"); } diff --git a/config/suricata/suricata_logs_browser.php b/config/suricata/suricata_logs_browser.php index 04edf373..320ba23f 100644 --- a/config/suricata/suricata_logs_browser.php +++ b/config/suricata/suricata_logs_browser.php @@ -55,21 +55,22 @@ $suricata_uuid = $a_instance[$instanceid]['uuid']; $if_real = get_real_interface($a_instance[$instanceid]['interface']); // Construct a pointer to the instance's logging subdirectory -$suricatalogdir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}"; +$suricatalogdir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}/"; -$logfile = $_POST['file']; +// Limit all file access to just the currently selected interface's logging subdirectory +$logfile = htmlspecialchars($suricatalogdir . basename($_POST['file'])); if ($_POST['action'] == 'load') { - if(!is_file($_POST['file'])) { + if(!is_file($logfile)) { echo "|3|" . gettext("Log file does not exist or that logging feature is not enabled") . ".|"; } else { - $data = file_get_contents($_POST['file']); + $data = file_get_contents($logfile); if($data === false) { echo "|1|" . gettext("Failed to read log file") . ".|"; } else { $data = base64_encode($data); - echo "|0|{$_POST['file']}|{$data}|"; + echo "|0|{$logfile}|{$data}|"; } } exit; @@ -84,7 +85,6 @@ include_once("head.inc"); <?php include_once("fbegin.inc"); -if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';} if ($input_errors) { print_input_errors($input_errors); } @@ -94,21 +94,21 @@ if ($input_errors) { <script type="text/javascript"> function loadFile() { jQuery("#fileStatus").html("<?=gettext("Loading file"); ?> ..."); - jQuery("#fileStatusBox").show(500); - jQuery("#filePathBox").show(500); + jQuery("#fileStatusBox").show(250); + jQuery("#filePathBox").show(250); jQuery("#fbTarget").html(""); jQuery.ajax( "<?=$_SERVER['SCRIPT_NAME'];?>", { type: 'POST', - data: "action=load&file=" + jQuery("#logFile").val(), + data: "instance=" + jQuery("#instance").val() + "&action=load&file=" + jQuery("#logFile").val(), complete: loadComplete } ); } function loadComplete(req) { - jQuery("#fileContent").show(1000); + jQuery("#fileContent").show(250); var values = req.responseText.split("|"); values.shift(); values.pop(); @@ -117,14 +117,17 @@ if ($input_errors) { var fileContent = Base64.decode(values.join("|")); jQuery("#fileStatus").html("<?=gettext("File successfully loaded"); ?>."); jQuery("#fbTarget").html(file); + jQuery("#fileRefreshBtn").show(); + jQuery("#fileContent").prop("disabled", false); jQuery("#fileContent").val(fileContent); } else { jQuery("#fileStatus").html(values[0]); jQuery("#fbTarget").html(""); + jQuery("#fileRefreshBtn").hide(); jQuery("#fileContent").val(""); + jQuery("#fileContent").prop("disabled", true); } - jQuery("#fileContent").show(1000); } </script> @@ -133,18 +136,22 @@ if ($input_errors) { <input type="hidden" id="instance" value="<?=$instanceid;?>"/> <?php if ($savemsg) print_info_box($savemsg); ?> <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$instanceid}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), true, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), true, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> @@ -152,6 +159,7 @@ if ($input_errors) { <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="6"> + <tbody> <tr> <td colspan="2" class="listtopic"><?php echo gettext("Logs Browser Selections"); ?></td> </tr> @@ -175,12 +183,12 @@ if ($input_errors) { <td width="78%" class="vtable"> <select name="logFile" id="logFile" class="formselect" onChange="loadFile();"> <?php - $logs = array( "alerts.log", "block.log", "files-json.log", "http.log", "stats.log", "suricata.log", "tls.log" ); + $logs = array( "alerts.log", "block.log", "dns.log", "eve.json", "files-json.log", "http.log", "sid_changes.log", "stats.log", "suricata.log", "tls.log" ); foreach ($logs as $log) { $selected = ""; if ($log == basename($logfile)) $selected = "selected"; - echo "<option value='{$suricatalogdir}/{$log}' {$selected}>" . $log . "</option>\n"; + echo "<option value='{$suricatalogdir}{$log}' {$selected}>" . $log . "</option>\n"; } ?> </select> <?php echo gettext('Choose which log you want to view.'); ?> @@ -191,38 +199,55 @@ if ($input_errors) { </tr> <tr> <td colspan="2"> - <div style="display:none; " id="fileStatusBox"> - <div class="list" style="padding-left:15px;"> - <strong id="fileStatus"></strong> - </div> - </div> - <div style="padding-left:15px; display:none;" id="filePathBox"> - <strong><?=gettext("Log File Path"); ?>:</strong> - <div class="list" style="display:inline;" id="fbTarget"></div> - </div> + <table width="100%"> + <tbody> + <tr> + <td width="75%"> + <div style="display:none; " id="fileStatusBox"> + <div class="list" style="padding-left:15px;"> + <strong id="fileStatus"></strong> + </div> + </div> + <div style="padding-left:15px; display:none;" id="filePathBox"> + <strong><?=gettext("Log File Path"); ?>:</strong> + <div class="list" style="display:inline;" id="fbTarget"></div> + </div> + </td> + <td align="right"> + <div style="padding-right:15px; display:none;" id="fileRefreshBtn"> + <input type="button" name="refresh" id="refresh" value="Refresh" class="formbtn" onclick="loadFile();" title="<?=gettext("Refresh current display");?>" /> + </div> + </td> + </tr> + </tbody> + </table> </td> </tr> <tr> <td colspan="2"> <table width="100%"> + <tbody> <tr> <td valign="top" class="label"> <div style="background:#eeeeee;" id="fileOutput"> - <textarea id="fileContent" name="fileContent" style="width:100%;" rows="30" wrap="off"></textarea> + <textarea id="fileContent" name="fileContent" style="width:100%;" rows="30" wrap="off" disabled></textarea> </div> </td> </tr> + </tbody> </table> </td> </tr> + </tbody> </table> </div> </td> </tr> + </tbody> </table> </form> -<?php if(empty($logfile)): ?> +<?php if(empty($_POST['file'])): ?> <script type="text/javascript"> document.getElementById("logFile").selectedIndex=-1; </script> diff --git a/config/suricata/suricata_logs_mgmt.php b/config/suricata/suricata_logs_mgmt.php index 16376c5b..aa353d6f 100644 --- a/config/suricata/suricata_logs_mgmt.php +++ b/config/suricata/suricata_logs_mgmt.php @@ -67,6 +67,12 @@ $pconfig['tls_log_retention'] = $config['installedpackages']['suricata']['config $pconfig['unified2_log_limit'] = $config['installedpackages']['suricata']['config'][0]['unified2_log_limit']; $pconfig['u2_archive_log_retention'] = $config['installedpackages']['suricata']['config'][0]['u2_archive_log_retention']; $pconfig['file_store_retention'] = $config['installedpackages']['suricata']['config'][0]['file_store_retention']; +$pconfig['dns_log_limit_size'] = $config['installedpackages']['suricata']['config'][0]['dns_log_limit_size']; +$pconfig['dns_log_retention'] = $config['installedpackages']['suricata']['config'][0]['dns_log_retention']; +$pconfig['eve_log_limit_size'] = $config['installedpackages']['suricata']['config'][0]['eve_log_limit_size']; +$pconfig['eve_log_retention'] = $config['installedpackages']['suricata']['config'][0]['eve_log_retention']; +$pconfig['sid_changes_log_limit_size'] = $config['installedpackages']['suricata']['config'][0]['sid_changes_log_limit_size']; +$pconfig['sid_changes_log_retention'] = $config['installedpackages']['suricata']['config'][0]['sid_changes_log_retention']; // Load up some arrays with selection values (we use these later). // The keys in the $retentions array are the retention period @@ -88,40 +94,99 @@ if (empty($pconfig['suricataloglimitsize'])) { } // Set default retention periods for rotated logs -if (empty($pconfig['alert_log_retention'])) +if (!isset($pconfig['alert_log_retention'])) $pconfig['alert_log_retention'] = "336"; -if (empty($pconfig['block_log_retention'])) +if (!isset($pconfig['block_log_retention'])) $pconfig['block_log_retention'] = "336"; -if (empty($pconfig['files_json_log_retention'])) +if (!isset($pconfig['files_json_log_retention'])) $pconfig['files_json_log_retention'] = "168"; -if (empty($pconfig['http_log_retention'])) +if (!isset($pconfig['http_log_retention'])) $pconfig['http_log_retention'] = "168"; -if (empty($pconfig['stats_log_retention'])) +if (!isset($pconfig['dns_log_retention'])) + $pconfig['dns_log_retention'] = "168"; +if (!isset($pconfig['stats_log_retention'])) $pconfig['stats_log_retention'] = "168"; -if (empty($pconfig['tls_log_retention'])) +if (!isset($pconfig['tls_log_retention'])) $pconfig['tls_log_retention'] = "336"; -if (empty($pconfig['u2_archive_log_retention'])) +if (!isset($pconfig['u2_archive_log_retention'])) $pconfig['u2_archive_log_retention'] = "168"; -if (empty($pconfig['file_store_retention'])) +if (!isset($pconfig['file_store_retention'])) $pconfig['file_store_retention'] = "168"; +if (!isset($pconfig['eve_log_retention'])) + $pconfig['eve_log_retention'] = "168"; +if (!isset($pconfig['sid_changes_log_retention'])) + $pconfig['sid_changes_log_retention'] = "336"; // Set default log file size limits -if (empty($pconfig['alert_log_limit_size'])) +if (!isset($pconfig['alert_log_limit_size'])) $pconfig['alert_log_limit_size'] = "500"; -if (empty($pconfig['block_log_limit_size'])) +if (!isset($pconfig['block_log_limit_size'])) $pconfig['block_log_limit_size'] = "500"; -if (empty($pconfig['files_json_log_limit_size'])) +if (!isset($pconfig['files_json_log_limit_size'])) $pconfig['files_json_log_limit_size'] = "1000"; -if (empty($pconfig['http_log_limit_size'])) +if (!isset($pconfig['http_log_limit_size'])) $pconfig['http_log_limit_size'] = "1000"; -if (empty($pconfig['stats_log_limit_size'])) +if (!isset($pconfig['dns_log_limit_size'])) + $pconfig['dns_log_limit_size'] = "750"; +if (!isset($pconfig['stats_log_limit_size'])) $pconfig['stats_log_limit_size'] = "500"; -if (empty($pconfig['tls_log_limit_size'])) +if (!isset($pconfig['tls_log_limit_size'])) $pconfig['tls_log_limit_size'] = "500"; -if (empty($pconfig['unified2_log_limit'])) +if (!isset($pconfig['unified2_log_limit'])) $pconfig['unified2_log_limit'] = "32"; +if (!isset($pconfig['eve_log_limit_size'])) + $pconfig['eve_log_limit_size'] = "5000"; +if (!isset($pconfig['sid_changes_log_limit_size'])) + $pconfig['sid_changes_log_limit_size'] = "250"; + +if ($_POST['ResetAll']) { + + // Reset all settings to their defaults + $pconfig['alert_log_retention'] = "336"; + $pconfig['block_log_retention'] = "336"; + $pconfig['files_json_log_retention'] = "168"; + $pconfig['http_log_retention'] = "168"; + $pconfig['dns_log_retention'] = "168"; + $pconfig['stats_log_retention'] = "168"; + $pconfig['tls_log_retention'] = "336"; + $pconfig['u2_archive_log_retention'] = "168"; + $pconfig['file_store_retention'] = "168"; + $pconfig['eve_log_retention'] = "168"; + $pconfig['sid_changes_log_retention'] = "336"; + + $pconfig['alert_log_limit_size'] = "500"; + $pconfig['block_log_limit_size'] = "500"; + $pconfig['files_json_log_limit_size'] = "1000"; + $pconfig['http_log_limit_size'] = "1000"; + $pconfig['dns_log_limit_size'] = "750"; + $pconfig['stats_log_limit_size'] = "500"; + $pconfig['tls_log_limit_size'] = "500"; + $pconfig['unified2_log_limit'] = "32"; + $pconfig['eve_log_limit_size'] = "5000"; + $pconfig['sid_changes_log_limit_size'] = "250"; + + /* Log a message at the top of the page to inform the user */ + $savemsg = gettext("All log management settings on this page have been reset to their defaults. Click APPLY if you wish to keep these new settings."); +} + +if ($_POST["save"] || $_POST['apply']) { + if ($_POST['enable_log_mgmt'] != 'on') { + $config['installedpackages']['suricata']['config'][0]['enable_log_mgmt'] = $_POST['enable_log_mgmt'] ? 'on' :'off'; + write_config("Suricata pkg: saved updated configuration for LOGS MGMT."); + conf_mount_rw(); + sync_suricata_package_config(); + conf_mount_ro(); + + /* forces page to reload new settings */ + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_logs_mgmt.php"); + exit; + } -if ($_POST["save"]) { if ($_POST['suricataloglimit'] == 'on') { if (!is_numericint($_POST['suricataloglimitsize']) || $_POST['suricataloglimitsize'] < 1) $input_errors[] = gettext("The 'Log Directory Size Limit' must be an integer value greater than zero."); @@ -151,9 +216,17 @@ if ($_POST["save"]) { $config['installedpackages']['suricata']['config'][0]['unified2_log_limit'] = $_POST['unified2_log_limit']; $config['installedpackages']['suricata']['config'][0]['u2_archive_log_retention'] = $_POST['u2_archive_log_retention']; $config['installedpackages']['suricata']['config'][0]['file_store_retention'] = $_POST['file_store_retention']; + $config['installedpackages']['suricata']['config'][0]['dns_log_limit_size'] = $_POST['dns_log_limit_size']; + $config['installedpackages']['suricata']['config'][0]['dns_log_retention'] = $_POST['dns_log_retention']; + $config['installedpackages']['suricata']['config'][0]['eve_log_limit_size'] = $_POST['eve_log_limit_size']; + $config['installedpackages']['suricata']['config'][0]['eve_log_retention'] = $_POST['eve_log_retention']; + $config['installedpackages']['suricata']['config'][0]['sid_changes_log_limit_size'] = $_POST['sid_changes_log_limit_size']; + $config['installedpackages']['suricata']['config'][0]['sid_changes_log_retention'] = $_POST['sid_changes_log_retention']; - write_config(); + write_config("Suricata pkg: saved updated configuration for LOGS MGMT."); + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); /* forces page to reload new settings */ header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); @@ -179,23 +252,33 @@ include_once("fbegin.inc"); /* Display Alert message, under form tag or no refresh */ if ($input_errors) print_input_errors($input_errors); - ?> <form action="suricata_logs_mgmt.php" method="post" enctype="multipart/form-data" name="iform" id="iform"> + +<?php +if ($savemsg) { + /* Display save message */ + print_info_box($savemsg); +} +?> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), true, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td></tr> @@ -267,7 +350,7 @@ if ($input_errors) <colgroup> <col style="width: 15%;"> <col style="width: 18%;"> - <col style="width: 20%;"> + <col style="width: 18%;"> <col> </colgroup> <thead> @@ -320,6 +403,46 @@ if ($input_errors) <td class="listbg"><?=gettext("Suricata blocked IPs and event details");?></td> </tr> <tr> + <td class="listbg">dns</td> + <td class="listr" align="center"><select name="dns_log_limit_size" class="formselect" id="dns_log_limit_size"> + <?php foreach ($log_sizes as $k => $l): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['dns_log_limit_size']) echo "selected"; ?>> + <?=htmlspecialchars($l);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listr" align="center"><select name="dns_log_retention" class="formselect" id="dns_log_retention"> + <?php foreach ($retentions as $k => $p): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['dns_log_retention']) echo "selected"; ?>> + <?=htmlspecialchars($p);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listbg"><?=gettext("DNS request/reply details");?></td> + </tr> + <tr> + <td class="listbg">eve-json</td> + <td class="listr" align="center"><select name="eve_log_limit_size" class="formselect" id="eve_log_limit_size"> + <?php foreach ($log_sizes as $k => $l): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['eve_log_limit_size']) echo "selected"; ?>> + <?=htmlspecialchars($l);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listr" align="center"><select name="eve_log_retention" class="formselect" id="eve_log_retention"> + <?php foreach ($retentions as $k => $p): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['eve_log_retention']) echo "selected"; ?>> + <?=htmlspecialchars($p);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listbg"><?=gettext("Eve-JSON (JavaScript Object Notation) data");?></td> + </tr> + <tr> <td class="listbg">files-json</td> <td class="listr" align="center"><select name="files_json_log_limit_size" class="formselect" id="files_json_log_limit_size"> <?php foreach ($log_sizes as $k => $l): ?> @@ -359,6 +482,28 @@ if ($input_errors) </td> <td class="listbg"><?=gettext("Captured HTTP events and session info");?></td> </tr> + + <tr> + <td class="listbg">sid_changes</td> + <td class="listr" align="center"><select name="sid_changes_log_limit_size" class="formselect" id="sid_changes_log_limit_size"> + <?php foreach ($log_sizes as $k => $l): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['sid_changes_log_limit_size']) echo "selected"; ?>> + <?=htmlspecialchars($l);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listr" align="center"><select name="sid_changes_log_retention" class="formselect" id="sid_changes_log_retention"> + <?php foreach ($retentions as $k => $p): ?> + <option value="<?=$k;?>" + <?php if ($k == $pconfig['sid_changes_log_retention']) echo "selected"; ?>> + <?=htmlspecialchars($p);?></option> + <?php endforeach; ?> + </select> + </td> + <td class="listbg"><?=gettext("Log of SID changes made by SID Mgmt conf files");?></td> + </tr> + <tr> <td class="listbg">stats</td> <td class="listr" align="center"><select name="stats_log_limit_size" class="formselect" id="stats_log_limit_size"> @@ -444,7 +589,11 @@ if ($input_errors) </tr> <tr> <td width="22%"></td> - <td width="78%" class="vexpl"><input name="save" type="submit" class="formbtn" value="Save"/><br/> + <td width="78%" class="vexpl"><input name="save" type="submit" class="formbtn" value="Save"/> + <input name="ResetAll" type="submit" class="formbtn" value="Reset" title="<?php echo + gettext("Reset all settings to defaults") . "\" onclick=\"return confirm('" . + gettext("WARNING: This will reset ALL Log Management settings to their defaults. Click OK to continue or CANCEL to quit.") . + "');\""; ?>/><br/> <br/><span class="red"><strong><?php echo gettext("Note:");?></strong> </span><?php echo gettext("Changing any settings on this page will affect all Suricata-configured interfaces.");?></td> </tr> @@ -472,6 +621,12 @@ function enable_change() { document.iform.unified2_log_limit.disabled = endis; document.iform.u2_archive_log_retention.disabled = endis; document.iform.file_store_retention.disabled = endis; + document.iform.dns_log_retention.disabled = endis; + document.iform.dns_log_limit_size.disabled = endis; + document.iform.eve_log_retention.disabled = endis; + document.iform.eve_log_limit_size.disabled = endis; + document.iform.sid_changes_log_retention.disabled = endis; + document.iform.sid_changes_log_limit_size.disabled = endis; } function enable_change_dirSize() { diff --git a/config/suricata/suricata_migrate_config.php b/config/suricata/suricata_migrate_config.php new file mode 100644 index 00000000..75e13315 --- /dev/null +++ b/config/suricata/suricata_migrate_config.php @@ -0,0 +1,387 @@ +<?php +/* + * suricata_migrate_config.php + * + * Copyright (C) 2014 Bill Meeks + * 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("config.inc"); +require_once("functions.inc"); + +/****************************************************************************/ +/* The code in this module is called once during the post-install process */ +/* via an "include" line. It is used to perform a one-time migration of */ +/* Suricata configuration parameters to any new format required by the */ +/* latest package version. */ +/****************************************************************************/ + +global $config; + +if (!is_array($config['installedpackages']['suricata'])) + $config['installedpackages']['suricata'] = array(); +if (!is_array($config['installedpackages']['suricata']['rule'])) + $config['installedpackages']['suricata']['rule'] = array(); + +// Just exit if this is a clean install with no saved settings +if (empty($config['installedpackages']['suricata']['rule'])) + return; + +$rule = &$config['installedpackages']['suricata']['rule']; + +/****************************************************************************/ +/* Loop through all the <rule> elements in the Suricata configuration and */ +/* migrate relevant parameters to the new format. */ +/****************************************************************************/ + +$updated_cfg = false; +log_error("[Suricata] Checking configuration settings version..."); + +// Check the configuration version to see if XMLRPC Sync should +// auto-disabled as part of the upgrade due to config format changes. +if ($config['installedpackages']['suricata']['config'][0]['suricata_config_ver'] < 2 && + ($config['installedpackages']['suricatasync']['config'][0]['varsynconchanges'] == 'auto' || + $config['installedpackages']['suricatasync']['config'][0]['varsynconchanges'] == 'manual')) { + $config['installedpackages']['suricatasync']['config'][0]['varsynconchanges'] = "disabled"; + log_error("[Suricata] Turning off Suricata Sync on this host due to configuration format changes in this update. Upgrade all Suricata Sync targets to this same Suricata package version before re-enabling Suricata Sync."); + $updated_cfg = true; +} + +/**********************************************************/ +/* Create new Auto SID Mgmt settings if not set */ +/**********************************************************/ +if (empty($config['installedpackages']['suricata']['config'][0]['auto_manage_sids'])) { + $config['installedpackages']['suricata']['config'][0]['auto_manage_sids'] = "off"; + $config['installedpackages']['suricata']['config'][0]['sid_changes_log_limit_size'] = "250"; + $config['installedpackages']['suricata']['config'][0]['sid_changes_log_retention'] = "336"; + $updated_cfg = true; +} + +/**********************************************************/ +/* Create new Auto GeoIP update setting if not set */ +/**********************************************************/ +if (empty($config['installedpackages']['suricata']['config'][0]['autogeoipupdate'])) { + $config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] = "on"; + $updated_cfg = true; +} + +/**********************************************************/ +/* Create new ET IQRisk IP Reputation setting if not set */ +/**********************************************************/ +if (empty($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'])) { + $config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] = "off"; + $updated_cfg = true; +} + +// Now process the interface-specific settings +foreach ($rule as &$r) { + + // Initialize arrays for supported preprocessors if necessary + if (!is_array($r['libhtp_policy']['item'])) + $r['libhtp_policy']['item'] = array(); + + $pconfig = array(); + $pconfig = $r; + + /***********************************************************/ + /* This setting is deprecated in Suricata 2.0 and higher, */ + /* so remove it from the configuration. */ + /***********************************************************/ + if (isset($pconfig['stream_max_sessions'])) { + unset($pconfig['stream_max_sessions']); + $updated_cfg = true; + } + + /***********************************************************/ + /* HTTP server personalities for "Apache" and "Apache_2_2" */ + /* are deprecated and replaced with "Apache_2" in Suricata */ + /* versions greater than 2.0. */ + /***********************************************************/ + $http_serv = &$pconfig['libhtp_policy']['item']; + foreach ($http_serv as &$policy) { + if ($policy['personality'] == "Apache" || $policy['personality'] == "Apache_2_2") { + $policy['personality'] = "Apache_2"; + $updated_cfg = true; + } + // Set new URI inspect option for Suricata 2.0 and higher + if (!isset($policy['uri-include-all'])) { + $policy['uri-include-all'] = "no"; + $updated_cfg = true; + } + } + + /***********************************************************/ + /* Add the new 'dns-events.rules' file to the rulesets. */ + /***********************************************************/ + if (strpos($pconfig['rulesets'], "dns-events.rules") === FALSE) { + $pconfig['rulesets'] = rtrim($pconfig['rulesets'], "||") . "||dns-events.rules"; + $updated_cfg = true; + } + + /***********************************************************/ + /* Add new interface promisc mode value and default 'on'. */ + /***********************************************************/ + if (empty($pconfig['intf_promisc_mode'])) { + $pconfig['intf_promisc_mode'] = "on"; + $updated_cfg = true; + } + + /***********************************************************/ + /* Add new HTTP Log Extended Info setting if not present */ + /***********************************************************/ + if (!isset($pconfig['http_log_extended'])) { + $pconfig['http_log_extended'] = "on"; + $updated_cfg = true; + } + + /***********************************************************/ + /* Add new EVE logging settings if not present */ + /***********************************************************/ + if (!isset($pconfig['eve_output_type'])) { + $pconfig['eve_output_type'] = "file"; + $updated_cfg = true; + } + if (empty($pconfig['eve_systemlog_facility'])) { + $pconfig['eve_systemlog_facility'] = "local1"; + $updated_cfg = true; + } + if (empty($pconfig['eve_systemlog_priority'])) { + $pconfig['eve_systemlog_priority'] = "info"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_alerts'])) { + $pconfig['eve_log_alerts'] = "on"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_http'])) { + $pconfig['eve_log_http'] = "on"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_dns'])) { + $pconfig['eve_log_dns'] = "on"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_tls'])) { + $pconfig['eve_log_tls'] = "on"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_files'])) { + $pconfig['eve_log_files'] = "on"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_ssh'])) { + $pconfig['eve_log_ssh'] = "on"; + $updated_cfg = true; + } + + /******************************************************************/ + /* Create default log size and retention limits if not set */ + /******************************************************************/ + if (!isset($pconfig['alert_log_retention']) && $pconfig['alert_log_retention'] != '0') { + $pconfig['alert_log_retention'] = "336"; + $updated_cfg = true; + } + if (!isset($pconfig['alert_log_limit_size']) && $pconfig['alert_log_limit_size'] != '0') { + $pconfig['alert_log_limit_size'] = "500"; + $updated_cfg = true; + } + + if (!isset($pconfig['block_log_retention']) && $pconfig['block_log_retention'] != '0') { + $pconfig['block_log_retention'] = "336"; + $updated_cfg = true; + } + if (!isset($pconfig['block_log_limit_size']) && $pconfig['block_log_limit_size'] != '0') { + $pconfig['block_log_limit_size'] = "500"; + $updated_cfg = true; + } + + if (!isset($pconfig['dns_log_retention']) && $pconfig['dns_log_retention'] != '0') { + $pconfig['dns_log_retention'] = "168"; + $updated_cfg = true; + } + if (!isset($pconfig['dns_log_limit_size']) && $pconfig['dns_log_limit_size'] != '0') { + $pconfig['dns_log_limit_size'] = "750"; + $updated_cfg = true; + } + + if (!isset($pconfig['eve_log_retention']) && $pconfig['eve_log_retention'] != '0') { + $pconfig['eve_log_retention'] = "168"; + $updated_cfg = true; + } + if (!isset($pconfig['eve_log_limit_size']) && $pconfig['eve_log_limit_size'] != '0') { + $pconfig['eve_log_limit_size'] = "5000"; + $updated_cfg = true; + } + + if (!isset($pconfig['files_json_log_retention']) && $pconfig['files_json_log_retention'] != '0') { + $pconfig['files_json_log_retention'] = "168"; + $updated_cfg = true; + } + if (!isset($pconfig['files_json_log_limit_size']) && $pconfig['files_json_log_limit_size'] != '0') { + $pconfig['files_json_log_limit_size'] = "1000"; + $updated_cfg = true; + } + + if (!isset($pconfig['http_log_retention']) && $pconfig['http_log_retention'] != '0') { + $pconfig['http_log_retention'] = "168"; + $updated_cfg = true; + } + if (!isset($pconfig['http_log_limit_size']) && $pconfig['http_log_limit_size'] != '0') { + $pconfig['http_log_limit_size'] = "1000"; + $updated_cfg = true; + } + + if (!isset($pconfig['stats_log_retention']) && $pconfig['stats_log_retention'] != '0') { + $pconfig['stats_log_retention'] = "168"; + $updated_cfg = true; + } + if (!isset($pconfig['stats_log_limit_size']) && $pconfig['stats_log_limit_size'] != '0') { + $pconfig['stats_log_limit_size'] = "500"; + $updated_cfg = true; + } + + if (!isset($pconfig['tls_log_retention']) && $pconfig['tls_log_retention'] != '0') { + $pconfig['tls_log_retention'] = "336"; + $updated_cfg = true; + } + if (!isset($pconfig['tls_log_limit_size']) && $pconfig['tls_log_limit_size'] != '0') { + $pconfig['tls_log_limit_size'] = "500"; + $updated_cfg = true; + } + + if (!isset($pconfig['file_store_retention']) && $pconfig['file_store_retention'] != '0') { + $pconfig['file_store_retention'] = "168"; + $updated_cfg = true; + } + + if (!isset($pconfig['u2_archive_log_retention']) && $pconfig['u2_archive_log_retention'] != '0') { + $pconfig['u2_archive_log_retention'] = "168"; + $updated_cfg = true; + } + + /************************************************************/ + /* Create new DNS App-Layer parser settings if not set */ + /************************************************************/ + if (empty($pconfig['dns_global_memcap'])) { + $pconfig['dns_global_memcap'] = "16777216"; + $updated_cfg = true; + } + if (empty($pconfig['dns_state_memcap'])) { + $pconfig['dns_state_memcap'] = "524288"; + $updated_cfg = true; + } + if (empty($pconfig['dns_request_flood_limit'])) { + $pconfig['dns_request_flood_limit'] = "500"; + $updated_cfg = true; + } + if (empty($pconfig['dns_parser_udp'])) { + $pconfig['dns_parser_udp'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['dns_parser_tcp'])) { + $pconfig['dns_parser_tcp'] = "yes"; + $updated_cfg = true; + } + + /***********************************************************/ + /* Create new HTTP App-Layer parser settings if not set */ + /***********************************************************/ + if (empty($pconfig['http_parser'])) { + $pconfig['http_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['http_parser_memcap'])) { + $pconfig['http_parser_memcap'] = "67108864"; + $updated_cfg = true; + } + + /**********************************************************/ + /* Create other App-Layer parser settings if not set */ + /**********************************************************/ + if (empty($pconfig['tls_parser'])) { + $pconfig['tls_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['smtp_parser'])) { + $pconfig['smtp_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['imap_parser'])) { + $pconfig['imap_parser'] = "detection-only"; + $updated_cfg = true; + } + if (empty($pconfig['ssh_parser'])) { + $pconfig['ssh_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['ftp_parser'])) { + $pconfig['ftp_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['dcerpc_parser'])) { + $pconfig['dcerpc_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['smb_parser'])) { + $pconfig['smb_parser'] = "yes"; + $updated_cfg = true; + } + if (empty($pconfig['msn_parser'])) { + $pconfig['msn_parser'] = "detection-only"; + $updated_cfg = true; + } + + /**********************************************************/ + /* Create interface IP Reputation settings if not set */ + /**********************************************************/ + if (empty($pconfig['enable_iprep'])) { + $pconfig['enable_iprep'] = "off"; + $updated_cfg = true; + } + if (empty($pconfig['host_memcap'])) { + $pconfig['host_memcap'] = "16777216"; + $updated_cfg = true; + } + if (empty($pconfig['host_hash_size'])) { + $pconfig['host_hash_size'] = "4096"; + $updated_cfg = true; + } + if (empty($pconfig['host_prealloc'])) { + $pconfig['host_prealloc'] = "1000"; + $updated_cfg = true; + } + + // Save the new configuration data into the $config array pointer + $r = $pconfig; +} +// Release reference to final array element +unset($r); + +// Write out the new configuration to disk if we changed anything +if ($updated_cfg) + log_error("[Suricata] Settings successfully migrated to new configuration format..."); +else + log_error("[Suricata] Configuration version is current..."); + +?> diff --git a/config/suricata/suricata_os_policy_engine.php b/config/suricata/suricata_os_policy_engine.php index 869d940c..9a881f3d 100644 --- a/config/suricata/suricata_os_policy_engine.php +++ b/config/suricata/suricata_os_policy_engine.php @@ -62,6 +62,7 @@ ?> <table class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" align="center" class="listtopic"><?php echo gettext("Suricata Target-Based Host OS Policy Engine Configuration"); ?></td> </tr> @@ -69,7 +70,7 @@ <td valign="top" class="vncell"><?php echo gettext("Policy Name"); ?></td> <td class="vtable"> <input name="policy_name" type="text" class="formfld unknown" id="policy_name" size="25" maxlength="25" - value="<?=htmlspecialchars($pengcfg['name']);?>"<?php if (htmlspecialchars($pengcfg['name']) == "default") echo "readonly";?>/> + value="<?=htmlspecialchars($pengcfg['name']);?>"<?php if (htmlspecialchars($pengcfg['name']) == " default") echo " readonly";?>/> <?php if (htmlspecialchars($pengcfg['name']) <> "default") echo gettext("Name or description for this engine. (Max 25 characters)"); else @@ -83,6 +84,7 @@ <td class="vtable"> <?php if ($pengcfg['name'] <> "default") : ?> <table width="95%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td class="vexpl"><input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32" value="<?=htmlspecialchars($pengcfg['bind_to']);?>" title="<?=trim(filter_expand_alias($pengcfg['bind_to']));?>" autocomplete="off"/> @@ -93,6 +95,7 @@ <tr> <td class="vexpl" colspan="2"><?php echo gettext("This policy will apply for packets with destination addresses contained within this IP List.");?></td> </tr> + </tbody> </table> <span class="red"><strong><?php echo gettext("Note: ") . "</strong></span>" . gettext("Supplied value must be a pre-configured Alias or the keyword 'all'.");?> @@ -129,6 +132,7 @@ <input name="cancel_os_policy" id="cancel_os_policy" type="submit" class="formbtn" value="Cancel" title="<?php echo gettext("Cancel changes and return to Flow/Stream tab"); ?>"></td> </tr> + </tbody> </table> <script type="text/javascript" src="/javascript/autosuggest.js"> </script> diff --git a/config/suricata/suricata_passlist.php b/config/suricata/suricata_passlist.php index fc7c60e2..af1c4ff5 100644 --- a/config/suricata/suricata_passlist.php +++ b/config/suricata/suricata_passlist.php @@ -87,7 +87,9 @@ if ($_POST['del'] && is_numericint($_POST['list_id'])) { if (!$input_errors) { unset($a_passlist[$_POST['list_id']]); write_config("Suricata pkg: deleted PASS LIST."); + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); header("Location: /suricata/suricata_passlist.php"); exit; } @@ -115,18 +117,22 @@ if ($savemsg) { <form action="/suricata/suricata_passlist.php" method="post"> <input type="hidden" name="list_id" id="list_id" value=""/> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), true, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> @@ -134,6 +140,7 @@ if ($savemsg) { <tr> <td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td width="25%" class="listhdrr">List Name</td> <td width="30%" class="listhdrr">Assigned Alias</td> @@ -142,19 +149,19 @@ if ($savemsg) { </tr> <?php foreach ($a_passlist as $i => $list): ?> <tr> - <td class="listlr" + <td class="listlr" ondblclick="document.location='suricata_passlist_edit.php?id=<?=$i;?>';"> <?=htmlspecialchars($list['name']);?></td> - <td class="listr" + <td class="listr" ondblclick="document.location='suricata_passlist_edit.php?id=<?=$i;?>';" title="<?=filter_expand_alias($list['address']);?>"> <?php echo gettext($list['address']);?></td> - <td class="listbg" + <td class="listbg" ondblclick="document.location='suricata_passlist_edit.php?id=<?=$i;?>';"> - <font color="#FFFFFF"> <?=htmlspecialchars($list['descr']);?> - </td> + <font color="#FFFFFF"><?=htmlspecialchars($list['descr']);?></font></td> <td valign="middle" nowrap class="list"> <table border="0" cellspacing="0" cellpadding="1"> + <tbody> <tr> <td valign="middle"><a href="suricata_passlist_edit.php?id=<?=$i;?>"> <img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0" title="<?php echo gettext("Edit pass list"); ?>"></a> @@ -163,6 +170,7 @@ if ($savemsg) { src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" title="<?php echo gettext("Delete pass list"); ?>"/> </td> </tr> + </tbody> </table> </td> </tr> @@ -171,6 +179,7 @@ if ($savemsg) { <td class="list" colspan="3"></td> <td class="list"> <table border="0" cellspacing="0" cellpadding="1"> + <tbody> <tr> <td valign="middle" width="17"> </td> <td valign="middle"><a href="suricata_passlist_edit.php?id=<?php echo $id_gen;?> "> @@ -178,27 +187,31 @@ if ($savemsg) { width="17" height="17" border="0" title="<?php echo gettext("add a new pass list"); ?>"/></a> </td> </tr> + </tbody> </table> </td> </tr> + </tbody> </table> </div> </td> </tr> + </tbody> </table> <br> -<table width="100%" border="0" cellpadding="1" - cellspacing="1"> +<table width="100%" border="0" cellpadding="1" cellspacing="1"> + <tbody> <tr> - <td width="100%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Notes:"); ?></strong></span> - <p><?php echo gettext("1. Here you can create Pass List files for your Suricata package rules. Hosts on a Pass List are never blocked by Suricata."); ?><br/> - <?php echo gettext("2. Add all the IP addresses or networks (in CIDR notation) you want to protect against Suricata block decisions."); ?><br/> - <?php echo gettext("3. The default Pass List includes the WAN IP and gateway, defined DNS servers, VPNs and locally-attached networks."); ?><br/> - <?php echo gettext("4. Be careful, it is very easy to get locked out of your system by altering the default settings."); ?></p></span></td> + <td width="100%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Notes:"); ?></strong></span> + <p><?php echo gettext("1. Here you can create Pass List files for your Suricata package rules. Hosts on a Pass List are never blocked by Suricata."); ?><br/> + <?php echo gettext("2. Add all the IP addresses or networks (in CIDR notation) you want to protect against Suricata block decisions."); ?><br/> + <?php echo gettext("3. The default Pass List includes the WAN IP and gateway, defined DNS servers, VPNs and locally-attached networks."); ?><br/> + <?php echo gettext("4. Be careful, it is very easy to get locked out of your system by altering the default settings."); ?></p></span></td> </tr> <tr> - <td width="100%"><span class="vexpl"><?php echo gettext("Remember you must restart Suricata on the interface for changes to take effect!"); ?></span></td> + <td width="100%"><span class="vexpl"><?php echo gettext("Remember you must restart Suricata on the interface for changes to take effect!"); ?></span></td> </tr> + </tbody> </table> </form> <?php include("fend.inc"); ?> diff --git a/config/suricata/suricata_passlist_edit.php b/config/suricata/suricata_passlist_edit.php index 35c7b66e..5bfeb8b9 100644 --- a/config/suricata/suricata_passlist_edit.php +++ b/config/suricata/suricata_passlist_edit.php @@ -63,15 +63,53 @@ if (is_null($id)) { exit; } +if (isset($id) && isset($a_passlist[$id])) { + /* Retrieve saved settings */ + $pconfig['name'] = $a_passlist[$id]['name']; + $pconfig['uuid'] = $a_passlist[$id]['uuid']; + $pconfig['address'] = $a_passlist[$id]['address']; + $pconfig['descr'] = html_entity_decode($a_passlist[$id]['descr']); + $pconfig['localnets'] = $a_passlist[$id]['localnets']; + $pconfig['wanips'] = $a_passlist[$id]['wanips']; + $pconfig['wangateips'] = $a_passlist[$id]['wangateips']; + $pconfig['wandnsips'] = $a_passlist[$id]['wandnsips']; + $pconfig['vips'] = $a_passlist[$id]['vips']; + $pconfig['vpnips'] = $a_passlist[$id]['vpnips']; +} + +// Check for returned "selected alias" if action is import +if ($_GET['act'] == "import") { + + // Retrieve previously typed values we passed to SELECT ALIAS page + $pconfig['name'] = htmlspecialchars($_GET['name']); + $pconfig['uuid'] = htmlspecialchars($_GET['uuid']); + $pconfig['address'] = htmlspecialchars($_GET['address']); + $pconfig['descr'] = htmlspecialchars($_GET['descr']); + $pconfig['localnets'] = htmlspecialchars($_GET['localnets'])? 'yes' : 'no'; + $pconfig['wanips'] = htmlspecialchars($_GET['wanips'])? 'yes' : 'no'; + $pconfig['wangateips'] = htmlspecialchars($_GET['wangateips'])? 'yes' : 'no'; + $pconfig['wandnsips'] = htmlspecialchars($_GET['wandnsips'])? 'yes' : 'no'; + $pconfig['vips'] = htmlspecialchars($_GET['vips'])? 'yes' : 'no'; + $pconfig['vpnips'] = htmlspecialchars($_GET['vpnips'])? 'yes' : 'no'; + + // Now retrieve the "selected alias" returned from SELECT ALIAS page + if ($_GET['varname'] == "address" && isset($_GET['varvalue'])) + $pconfig[$_GET['varname']] = htmlspecialchars($_GET['varvalue']); +} + /* If no entry for this passlist, then create a UUID and treat it like a new list */ -if (!isset($a_passlist[$id]['uuid'])) { +if (!isset($a_passlist[$id]['uuid']) && empty($pconfig['uuid'])) { $passlist_uuid = 0; while ($passlist_uuid > 65535 || $passlist_uuid == 0) { $passlist_uuid = mt_rand(1, 65535); $pconfig['uuid'] = $passlist_uuid; $pconfig['name'] = "passlist_{$passlist_uuid}"; } -} else +} +elseif (!empty($pconfig['uuid'])) { + $passlist_uuid = $pconfig['uuid']; +} +else $passlist_uuid = $a_passlist[$id]['uuid']; /* returns true if $name is a valid name for a pass list file name or ip */ @@ -85,28 +123,6 @@ function is_validpasslistname($name) { return false; } -if (isset($id) && $a_passlist[$id]) { - /* old settings */ - $pconfig = array(); - $pconfig['name'] = $a_passlist[$id]['name']; - $pconfig['uuid'] = $a_passlist[$id]['uuid']; - $pconfig['detail'] = $a_passlist[$id]['detail']; - $pconfig['address'] = $a_passlist[$id]['address']; - $pconfig['descr'] = html_entity_decode($a_passlist[$id]['descr']); - $pconfig['localnets'] = $a_passlist[$id]['localnets']; - $pconfig['wanips'] = $a_passlist[$id]['wanips']; - $pconfig['wangateips'] = $a_passlist[$id]['wangateips']; - $pconfig['wandnsips'] = $a_passlist[$id]['wandnsips']; - $pconfig['vips'] = $a_passlist[$id]['vips']; - $pconfig['vpnips'] = $a_passlist[$id]['vpnips']; -} - -// Check for returned "selected alias" if action is import -if ($_GET['act'] == "import") { - if ($_GET['varname'] == "address" && isset($_GET['varvalue'])) - $pconfig[$_GET['varname']] = htmlspecialchars($_GET['varvalue']); -} - if ($_POST['save']) { unset($input_errors); $pconfig = $_POST; @@ -114,7 +130,12 @@ if ($_POST['save']) { /* input validation */ $reqdfields = explode(" ", "name"); $reqdfieldsn = explode(",", "Name"); - do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); + + $pf_version=substr(trim(file_get_contents("/etc/version")),0,3); + if ($pf_version < 2.1) + $input_errors = eval('do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); return $input_errors;'); + else + do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); if(strtolower($_POST['name']) == "defaultpasslist") $input_errors[] = gettext("Pass List file names may not be named defaultpasslist."); @@ -123,11 +144,11 @@ if ($_POST['save']) { $input_errors[] = gettext("Pass List file name may only consist of the characters \"a-z, A-Z, 0-9 and _\". Note: No Spaces or dashes. Press Cancel to reset."); /* check for name conflicts */ - foreach ($a_passlist as $w_list) { - if (isset($id) && ($a_passlist[$id]) && ($a_passlist[$id] === $w_list)) + foreach ($a_passlist as $p_list) { + if (isset($id) && ($a_passlist[$id]) && ($a_passlist[$id] === $p_list)) continue; - if ($w_list['name'] == $_POST['name']) { + if ($p_list['name'] == $_POST['name']) { $input_errors[] = gettext("A Pass List file name with this name already exists."); break; } @@ -138,30 +159,32 @@ if ($_POST['save']) { $input_errors[] = gettext("A valid alias must be provided"); if (!$input_errors) { - $w_list = array(); + $p_list = array(); /* post user input */ - $w_list['name'] = $_POST['name']; - $w_list['uuid'] = $passlist_uuid; - $w_list['localnets'] = $_POST['localnets']? 'yes' : 'no'; - $w_list['wanips'] = $_POST['wanips']? 'yes' : 'no'; - $w_list['wangateips'] = $_POST['wangateips']? 'yes' : 'no'; - $w_list['wandnsips'] = $_POST['wandnsips']? 'yes' : 'no'; - $w_list['vips'] = $_POST['vips']? 'yes' : 'no'; - $w_list['vpnips'] = $_POST['vpnips']? 'yes' : 'no'; - - $w_list['address'] = $_POST['address']; - $w_list['descr'] = mb_convert_encoding($_POST['descr'],"HTML-ENTITIES","auto"); - $w_list['detail'] = $final_address_details; + $p_list['name'] = $_POST['name']; + $p_list['uuid'] = $passlist_uuid; + $p_list['localnets'] = $_POST['localnets']? 'yes' : 'no'; + $p_list['wanips'] = $_POST['wanips']? 'yes' : 'no'; + $p_list['wangateips'] = $_POST['wangateips']? 'yes' : 'no'; + $p_list['wandnsips'] = $_POST['wandnsips']? 'yes' : 'no'; + $p_list['vips'] = $_POST['vips']? 'yes' : 'no'; + $p_list['vpnips'] = $_POST['vpnips']? 'yes' : 'no'; + + $p_list['address'] = $_POST['address']; + $p_list['descr'] = mb_convert_encoding(str_replace("\r\n", "\n", $_POST['descr']),"HTML-ENTITIES","auto"); + $p_list['detail'] = $final_address_details; if (isset($id) && $a_passlist[$id]) - $a_passlist[$id] = $w_list; + $a_passlist[$id] = $p_list; else - $a_passlist[] = $w_list; + $a_passlist[] = $p_list; - write_config("Snort pkg: modified PASS LIST {$w_list['name']}."); + write_config("Suricata pkg: modified PASS LIST {$p_list['name']}."); /* create pass list and homenet file, then sync files */ + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); header("Location: /suricata/suricata_passlist.php"); exit; @@ -188,24 +211,29 @@ if ($savemsg) <form action="suricata_passlist_edit.php" method="post" name="iform" id="iform"> <input name="id" type="hidden" value="<?=$id;?>" /> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), true, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$instanceid}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> </tr> <tr><td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> <tr> <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Add the name and " . "description of the file."); ?></td> @@ -281,8 +309,8 @@ if ($savemsg) </td> <td width="78%" class="vtable"> <input autocomplete="off" name="address" type="text" class="formfldalias" id="address" size="30" value="<?=htmlspecialchars($pconfig['address']);?>" - title="<?=trim(filter_expand_alias($pconfig['address']));?>"/> - <input type="button" class="formbtns" value="Aliases" onclick="parent.location='suricata_select_alias.php?id=0&type=host|network&varname=address&act=import&multi_ip=yes&returl=<?=urlencode($_SERVER['PHP_SELF']);?>'" + title="<?=trim(filter_expand_alias($pconfig['address']));?>"/> + <input type="button" class="formbtns" value="Aliases" onclick="selectAlias();" title="<?php echo gettext("Select an existing IP alias");?>"/> </td> </tr> @@ -293,9 +321,10 @@ if ($savemsg) <input id="cancel" name="cancel" type="submit" class="formbtn" value="Cancel" /> </td> </tr> + </tbody> </table> </div> -</td></tr> +</td></tr></tbody> </table> </form> <script type="text/javascript"> @@ -321,6 +350,29 @@ function createAutoSuggest() { ?> } +function selectAlias() { + + var loc; + var fields = [ "name", "descr", "localnets", "wanips", "wangateips", "wandnsips", "vips", "vpnips", "address" ]; + + // Scrape current form field values and add to + // the select alias URL as a query string. + var loc = '/suricata/suricata_select_alias.php?id=<?=$id;?>&act=import&type=host|network'; + loc = loc + '&varname=address&multi_ip=yes'; + loc = loc + '&returl=<?=urlencode($_SERVER['PHP_SELF']);?>'; + loc = loc + '&uuid=<?=$passlist_uuid;?>'; + + // Iterate over just the specific form fields we want to pass to + // the select alias URL. + fields.forEach(function(entry) { + var tmp = $(entry).serialize(); + if (tmp.length > 0) + loc = loc + '&' + tmp; + }); + + window.parent.location = loc; +} + setTimeout("createAutoSuggest();", 500); </script> diff --git a/config/suricata/suricata_post_install.php b/config/suricata/suricata_post_install.php index c44b392f..070cf095 100644 --- a/config/suricata/suricata_post_install.php +++ b/config/suricata/suricata_post_install.php @@ -48,10 +48,36 @@ require_once("config.inc"); require_once("functions.inc"); require_once("/usr/local/pkg/suricata/suricata.inc"); +require("/usr/local/pkg/suricata/suricata_defs.inc"); global $config, $g, $rebuild_rules, $pkg_interface, $suricata_gui_include; +/**************************************** + * Define any new constants here that * + * may not be yet defined in the old * + * "suricata_defs.inc" include file * + * that might be cached and used by * + * the package manager installation * + * code. * + * * + * This is a hack to work around the * + * fact the old version of the inc file * + * is cached and used instead of the * + * updated version included with the * + * updated GUI package. * + ****************************************/ +if (!defined('SURICATA_PBI_BASEDIR')) + define('SURICATA_PBI_BASEDIR', '/usr/pbi/suricata-' . php_uname("m")); + +/**************************************** + * End of PHP caching workaround * + ****************************************/ + +// Initialize some common values from defined constants $suricatadir = SURICATADIR; +$suricatalogdir = SURICATALOGDIR; +$flowbit_rules_file = FLOWBITS_FILENAME; +$suricata_enforcing_rules_file = SURICATA_ENFORCING_RULES_FILENAME; $rcdir = RCFILEPREFIX; // Hard kill any running Suricata process that may have been started by any @@ -60,60 +86,131 @@ if(is_process_running("suricata")) { killbyname("suricata"); sleep(2); // Delete any leftover suricata PID files in /var/run - unlink_if_exists("/var/run/suricata_*.pid"); + unlink_if_exists("{$g['varrun_path']}/suricata_*.pid"); } // Hard kill any running Barnyard2 processes if(is_process_running("barnyard")) { killbyname("barnyard2"); sleep(2); // Delete any leftover barnyard2 PID files in /var/run - unlink_if_exists("/var/run/barnyard2_*.pid"); + unlink_if_exists("{$g['varrun_path']}/barnyard2_*.pid"); } // Set flag for post-install in progress $g['suricata_postinstall'] = true; +// Mount file system read/write so we can modify some files +conf_mount_rw(); + // Remove any previously installed script since we rebuild it -@unlink("{$rcdir}/suricata.sh"); +unlink_if_exists("{$rcdir}suricata.sh"); // Create the top-tier log directory safe_mkdir(SURICATALOGDIR); -// remake saved settings +// Create the IP Rep and SID Mods lists directory +safe_mkdir(SURICATA_SID_MODS_PATH); +safe_mkdir(SURICATA_IPREP_PATH); + +// Make sure config variable is an array +if (!is_array($config['installedpackages']['suricata']['config'][0])) + $config['installedpackages']['suricata']['config'][0] = array(); + +// Download the latest GeoIP DB updates and create cron task if the feature is not disabled +if ($config['installedpackages']['suricata']['config'][0]['autogeoipupdate'] != 'off') { + log_error(gettext("[Suricata] Installing free GeoIP country database files...")); + include("/usr/local/pkg/suricata/suricata_geoipupdate.php"); + install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_geoipupdate.php", TRUE, 0, 0, 8, "*", "*", "root"); +} + +// Download the latest ET IQRisk updates and create cron task if the feature is not disabled +if ($config['installedpackages']['suricata']['config'][0]['et_iqrisk_enable'] == 'on') { + log_error(gettext("[Suricata] Installing Emerging Threats IQRisk IP List...")); + include("/usr/local/pkg/suricata/suricata_etiqrisk_update.php"); + install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_etiqrisk_update.php", TRUE, 0, "*/6", "*", "*", "*", "root"); +} + +// remake saved settings if previously flagged if ($config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] == 'on') { log_error(gettext("[Suricata] Saved settings detected... rebuilding installation with saved settings...")); update_status(gettext("Saved settings detected...")); + + /****************************************************************/ + /* Do test and fix for duplicate UUIDs if this install was */ + /* impacted by the DUP (clone) bug that generated a duplicate */ + /* UUID for the cloned interface. Also fix any duplicate */ + /* entries in ['rulesets'] for "dns-events.rules". */ + /****************************************************************/ + if (count($config['installedpackages']['suricata']['rule']) > 0) { + $uuids = array(); + $suriconf = &$config['installedpackages']['suricata']['rule']; + foreach ($suriconf as &$suricatacfg) { + // Remove any duplicate ruleset names from earlier bug + $rulesets = explode("||", $suricatacfg['rulesets']); + $suricatacfg['rulesets'] = implode("||", array_keys(array_flip($rulesets))); + + // Now check for and fix a duplicate UUID + $if_real = get_real_interface($suricatacfg['interface']); + if (!isset($uuids[$suricatacfg['uuid']])) { + $uuids[$suricatacfg['uuid']] = $if_real; + continue; + } + else { + // Found a duplicate UUID, so generate a + // new one for the affected interface. + $old_uuid = $suricatacfg['uuid']; + $new_uuid = suricata_generate_id(); + if (file_exists("{$suricatalogdir}suricata_{$if_real}{$old_uuid}/")) + @rename("{$suricatalogdir}suricata_{$if_real}{$old_uuid}/", "{$suricatalogdir}suricata_{$if_real}{$new_uuid}/"); + $suricatacfg['uuid'] = $new_uuid; + $uuids[$new_uuid] = $if_real; + log_error(gettext("[Suricata] updated UUID for interface " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . " from {$old_uuid} to {$new_uuid}.")); + } + } + unset($uuids, $rulesets); + } + /****************************************************************/ + /* End of duplicate UUID and "dns-events.rules" bug fix. */ + /****************************************************************/ + + /* Do one-time settings migration for new version configuration */ + update_output_window(gettext("Please wait... migrating settings to new configuration...")); + include('/usr/local/pkg/suricata/suricata_migrate_config.php'); update_output_window(gettext("Please wait... rebuilding installation with saved settings...")); log_error(gettext("[Suricata] Downloading and updating configured rule types...")); update_output_window(gettext("Please wait... downloading and updating configured rule types...")); if ($pkg_interface <> "console") $suricata_gui_include = true; - include('/usr/local/www/suricata/suricata_check_for_rule_updates.php'); + include('/usr/local/pkg/suricata/suricata_check_for_rule_updates.php'); update_status(gettext("Generating suricata.yaml configuration file from saved settings...")); $rebuild_rules = true; + conf_mount_rw(); // Create the suricata.yaml files for each enabled interface $suriconf = $config['installedpackages']['suricata']['rule']; - foreach ($suriconf as $value) { - $if_real = get_real_interface($value['interface']); - - // ## BETA pkg bug fix-up -- be sure default rules enabled ## - $rules = explode("||", $value['rulesets']); - foreach (array( "decoder-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules", "tls-events.rules" ) as $r){ - if (!in_array($r, $rules)) - $rules[] = $r; - } - natcasesort($rules); - $value['rulesets'] = implode("||", $rules); - write_config(); - // ## end of BETA pkg bug fix-up ## + foreach ($suriconf as $suricatacfg) { + $if_real = get_real_interface($suricatacfg['interface']); + $suricata_uuid = $suricatacfg['uuid']; + $suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}"; + update_output_window(gettext("Generating configuration for " . convert_friendly_interface_to_friendly_descr($suricatacfg['interface']) . "...")); - // create a suricata.yaml file for interface - suricata_generate_yaml($value); + // Pull in the PHP code that generates the suricata.yaml file + // variables that will be substituted further down below. + include("/usr/local/pkg/suricata/suricata_generate_yaml.php"); + + // Pull in the boilerplate template for the suricata.yaml + // configuration file. The contents of the template along + // with substituted variables are stored in $suricata_conf_text + // (which is defined in the included file). + include("/usr/local/pkg/suricata/suricata_yaml_template.inc"); + + // Now write out the conf file using $suricata_conf_text contents + @file_put_contents("{$suricatacfgdir}/suricata.yaml", $suricata_conf_text); + unset($suricata_conf_text); // create barnyard2.conf file for interface - if ($value['barnyard_enable'] == 'on') - suricata_generate_barnyard2_conf($value, $if_real); + if ($suricatacfg['barnyard_enable'] == 'on') + suricata_generate_barnyard2_conf($suricatacfg, $if_real); } // create Suricata bootup file suricata.sh @@ -124,32 +221,45 @@ if ($config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] = suricata_rm_blocked_install_cron($config['installedpackages']['suricata']['config'][0]['rm_blocked'] != "never_b" ? true : false); suricata_rules_up_install_cron($config['installedpackages']['suricata']['config'][0]['autoruleupdate'] != "never_up" ? true : false); - // Add the recurring jobs created above to crontab - configure_cron(); - // Restore the Dashboard Widget if it was previously enabled and saved - if (!empty($config['installedpackages']['suricata']['config'][0]['dashboard_widget']) && !empty($config['widgets']['sequence'])) - $config['widgets']['sequence'] .= "," . $config['installedpackages']['suricata']['config'][0]['dashboard_widget']; - if (!empty($config['installedpackages']['suricata']['config'][0]['dashboard_widget_rows']) && !empty($config['widgets'])) - $config['widgets']['widget_suricata_display_lines'] = $config['installedpackages']['suricata']['config'][0]['dashboard_widget_rows']; + if (!empty($config['installedpackages']['suricata']['config'][0]['dashboard_widget']) && !empty($config['widgets']['sequence'])) { + if (strpos($config['widgets']['sequence'], "suricata_alerts-container") === FALSE) + $config['widgets']['sequence'] .= "," . $config['installedpackages']['suricata']['config'][0]['dashboard_widget']; + } + if (!empty($config['installedpackages']['suricata']['config'][0]['dashboard_widget_rows']) && !empty($config['widgets'])) { + if (empty($config['widgets']['widget_suricata_display_lines'])) + $config['widgets']['widget_suricata_display_lines'] = $config['installedpackages']['suricata']['config'][0]['dashboard_widget_rows']; + } $rebuild_rules = false; - update_output_window(gettext("Finished rebuilding Suricata configuration files...")); + if ($pkg_interface <> "console") + update_output_window(gettext("Finished rebuilding Suricata configuration files...")); log_error(gettext("[Suricata] Finished rebuilding installation from saved settings...")); // Only try to start Suricata if not in reboot if (!$g['booting']) { - update_status(gettext("Starting Suricata using rebuilt configuration...")); - update_output_window(gettext("Please wait... while Suricata is started...")); - log_error(gettext("[Suricata] Starting Suricata using rebuilt configuration...")); - start_service("suricata"); - update_output_window(gettext("Suricata has been started using the rebuilt configuration...")); + if ($pkg_interface <> "console") { + update_status(gettext("Starting Suricata using rebuilt configuration...")); + update_output_window(gettext("Please wait while Suricata is started...")); + mwexec("{$rcdir}suricata.sh start"); + update_output_window(gettext("Suricata has been started using the rebuilt configuration...")); + } + else + mwexec_bg("{$rcdir}suricata.sh start"); } } +// If this is first install and "forcekeepsettings" is empty, +// then default it to 'on'. +if (empty($config['installedpackages']['suricata']['config'][0]['forcekeepsettings'])) + $config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] = 'on'; + +// Finished with file system mods, so remount it read-only +conf_mount_ro(); + // Update Suricata package version in configuration -$config['installedpackages']['suricata']['config'][0]['suricata_config_ver'] = "v1.0.1"; -write_config(); +$config['installedpackages']['suricata']['config'][0]['suricata_config_ver'] = "2.1.2"; +write_config("Suricata pkg v2.1.2: post-install configuration saved."); // Done with post-install, so clear flag unset($g['suricata_postinstall']); diff --git a/config/suricata/suricata_rules.php b/config/suricata/suricata_rules.php index 82bb33eb..480bf3dc 100644 --- a/config/suricata/suricata_rules.php +++ b/config/suricata/suricata_rules.php @@ -41,7 +41,7 @@ require_once("guiconfig.inc"); require_once("/usr/local/pkg/suricata/suricata.inc"); -global $g, $rebuild_rules; +global $g, $config, $rebuild_rules; $suricatadir = SURICATADIR; $rules_map = array(); @@ -107,9 +107,27 @@ $emergingdownload = $config['installedpackages']['suricata']['config'][0]['enabl $etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']; $categories = explode("||", $pconfig['rulesets']); -// Add any previously saved rules files to the categories array -if (!empty($pconfig['rulesets'])) - $categories = explode("||", $pconfig['rulesets']); +// Get any automatic rule category enable/disable modifications +// if auto-SID Mgmt is enabled, and adjust the available rulesets +// in the CATEGORY drop-down box as necessary. +$cat_mods = suricata_sid_mgmt_auto_categories($a_rule[$id], FALSE); +foreach ($cat_mods as $k => $v) { + switch ($v) { + case 'disabled': + if (($key = array_search($k, $categories)) !== FALSE) + unset($categories[$key]); + break; + + case 'enabled': + if (!in_array($k, $categories)) + $categories[] = $k; + break; + + default: + break; + } +} + if ($_GET['openruleset']) $currentruleset = htmlspecialchars($_GET['openruleset'], ENT_QUOTES | ENT_HTML401); @@ -148,7 +166,10 @@ if ($currentruleset != 'custom.rules') { $rules_map = suricata_load_rules_map($rulefile); } -/* Load up our enablesid and disablesid arrays with enabled or disabled SIDs */ +/* Process the current category rules through any auto SID MGMT changes if enabled */ +suricata_auto_sid_mgmt($rules_map, $a_rule[$id], FALSE); + +/* Load up our enablesid and disablesid arrays with manually enabled or disabled SIDs */ $enablesid = suricata_load_sid_mods($a_rule[$id]['rule_sid_on']); $disablesid = suricata_load_sid_mods($a_rule[$id]['rule_sid_off']); @@ -159,12 +180,16 @@ if ($_POST['toggle'] && is_numeric($_POST['sid']) && is_numeric($_POST['gid']) & $sid = $_POST['sid']; // See if the target SID is in our list of modified SIDs, - // and toggle it back to default if present; otherwise, + // and toggle it opposite state if present; otherwise, // add it to the appropriate modified SID list. - if (isset($enablesid[$gid][$sid])) + if (isset($enablesid[$gid][$sid])) { unset($enablesid[$gid][$sid]); - elseif (isset($disablesid[$gid][$sid])) + $disablesid[$gid][$sid] = "disablesid"; + } + elseif (isset($disablesid[$gid][$sid])) { unset($disablesid[$gid][$sid]); + $enablesid[$gid][$sid] = "enablesid"; + } else { if ($rules_map[$gid][$sid]['disabled'] == 1) $enablesid[$gid][$sid] = "enablesid"; @@ -198,8 +223,12 @@ if ($_POST['toggle'] && is_numeric($_POST['sid']) && is_numeric($_POST['gid']) & unset($a_rule[$id]['rule_sid_off']); /* Update the config.xml file. */ - write_config(); + write_config("Suricata pkg: modified state for rule {$gid}:{$sid} on {$a_rule[$id]['interface']}."); + + // We changed a rule state, remind user to apply the changes + mark_subsystem_dirty('suricata_rules'); + // Set a scroll-to anchor location $anchor = "rule_{$gid}_{$sid}"; } elseif ($_POST['disable_all'] && !empty($rules_map)) { @@ -238,7 +267,10 @@ elseif ($_POST['disable_all'] && !empty($rules_map)) { else unset($a_rule[$id]['rule_sid_off']); - write_config(); + // We changed a rule state, remind user to apply the changes + mark_subsystem_dirty('suricata_rules'); + + write_config("Suricata pkg: disabled all rules in category {$currentruleset} for {$a_rule[$id]['interface']}."); } elseif ($_POST['enable_all'] && !empty($rules_map)) { @@ -275,7 +307,10 @@ elseif ($_POST['enable_all'] && !empty($rules_map)) { else unset($a_rule[$id]['rule_sid_off']); - write_config(); + // We changed a rule state, remind user to apply the changes + mark_subsystem_dirty('suricata_rules'); + + write_config("Suricata pkg: enable all rules in category {$currentruleset} for {$a_rule[$id]['interface']}."); } elseif ($_POST['resetcategory'] && !empty($rules_map)) { @@ -314,7 +349,10 @@ elseif ($_POST['resetcategory'] && !empty($rules_map)) { else unset($a_rule[$id]['rule_sid_off']); - write_config(); + // We changed a rule state, remind user to apply the changes + mark_subsystem_dirty('suricata_rules'); + + write_config("Suricata pkg: remove enablesid/disablesid changes for category {$currentruleset} on {$a_rule[$id]['interface']}."); } elseif ($_POST['resetall'] && !empty($rules_map)) { @@ -322,51 +360,73 @@ elseif ($_POST['resetall'] && !empty($rules_map)) { unset($a_rule[$id]['rule_sid_on']); unset($a_rule[$id]['rule_sid_off']); + // We changed a rule state, remind user to apply the changes + mark_subsystem_dirty('suricata_rules'); + /* Update the config.xml file. */ - write_config(); + write_config("Suricata pkg: remove all enablesid/disablesid changes for {$a_rule[$id]['interface']}."); } elseif ($_POST['clear']) { unset($a_rule[$id]['customrules']); - write_config(); + write_config("Suricata pkg: clear all custom rules for {$a_rule[$id]['interface']}."); $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_rule[$id]); + conf_mount_ro(); $rebuild_rules = false; $pconfig['customrules'] = ''; + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } elseif ($_POST['cancel']) { $pconfig['customrules'] = base64_decode($a_rule[$id]['customrules']); + clear_subsystem_dirty('suricata_rules'); } elseif ($_POST['save']) { $pconfig['customrules'] = $_POST['customrules']; if ($_POST['customrules']) - $a_rule[$id]['customrules'] = base64_encode($_POST['customrules']); + $a_rule[$id]['customrules'] = base64_encode(str_replace("\r\n", "\n", $_POST['customrules'])); else unset($a_rule[$id]['customrules']); - write_config(); + write_config("Suricata pkg: save modified custom rules for {$a_rule[$id]['interface']}."); $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_rule[$id]); + conf_mount_ro(); $rebuild_rules = false; /* Signal Suricata to "live reload" the rules */ suricata_reload_config($a_rule[$id]); + clear_subsystem_dirty('suricata_rules'); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } elseif ($_POST['apply']) { /* Save new configuration */ - write_config(); + write_config("Suricata pkg: new rules configuration for {$a_rule[$id]['interface']}."); /*************************************************/ /* Update the suricata.yaml file and rebuild the */ /* rules for this interface. */ /*************************************************/ $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_rule[$id]); + conf_mount_ro(); $rebuild_rules = false; /* Signal Suricata to "live reload" the rules */ suricata_reload_config($a_rule[$id]); + + // We have saved changes and done a soft restart, so clear "dirty" flag + clear_subsystem_dirty('suricata_rules'); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } -require_once("guiconfig.inc"); include_once("head.inc"); $if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']); @@ -392,19 +452,28 @@ if ($savemsg) { <input type='hidden' name='openruleset' id='openruleset' value='<?=$currentruleset;?>'/> <input type='hidden' name='sid' id='sid' value=''/> <input type='hidden' name='gid' id='gid' value=''/> + +<?php if (is_subsystem_dirty('suricata_rules')): ?><p> +<?php print_info_box_np(gettext("A change has been made to a rule state.") . "<br/>" . gettext("Click APPLY when finished to send the changes to the running configuration."));?> +<?php endif; ?> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td class="tabnavtbl">'; @@ -417,11 +486,13 @@ if ($savemsg) { $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> <tr><td><div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="4" cellspacing="0"> + <tbody> <tr> <td class="listtopic"><?php echo gettext("Available Rule Categories"); ?></td> </tr> @@ -430,7 +501,7 @@ if ($savemsg) { <select id="selectbox" name="selectbox" class="formselect" onChange="go();"> <option value='custom.rules'>custom.rules</option> <?php - $files = explode("||", $pconfig['rulesets']); + $files = $categories; if ($a_rule[$id]['ips_policy_enable'] == 'on') $files[] = "IPS Policy - " . ucfirst($a_rule[$id]['ips_policy']); if ($a_rule[$id]['autoflowbitrules'] == 'on') @@ -478,6 +549,7 @@ if ($savemsg) { <tr> <td class="vncell"> <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"> + <tbody> <tr> <td rowspan="5" width="48%" valign="middle"><input type="submit" name="apply" id="apply" value="<?php echo gettext("Apply"); ?>" class="formbtn" title="<?php echo gettext("Click to rebuild the rules with your changes"); ?>"/><br/><br/> @@ -534,6 +606,7 @@ if ($savemsg) { gettext("clicking here") . ".</a>";?></td> </tr> <?php endif;?> + </tbody> </table> </td> </tr> @@ -544,7 +617,7 @@ if ($savemsg) { <td> <table id="myTable" class="sortable" style="table-layout: fixed;" width="100%" border="0" cellpadding="0" cellspacing="0"> <colgroup> - <col width="14" align="left" valign="middle"> + <col width="16" align="center" valign="middle"> <col width="6%" align="center" axis="number"> <col width="9%" align="center" axis="number"> <col width="52" align="center" axis="string"> @@ -555,8 +628,8 @@ if ($savemsg) { <col axis="string"> </colgroup> <thead> - <tr> - <th class="list"> </th> + <tr class="sortableHeaderRowIdentifier"> + <th class="list sorttable_nosort"> </th> <th class="listhdrr"><?php echo gettext("GID"); ?></th> <th class="listhdrr"><?php echo gettext("SID"); ?></th> <th class="listhdrr"><?php echo gettext("Proto"); ?></th> @@ -570,18 +643,36 @@ if ($savemsg) { <tbody> <?php - $counter = $enable_cnt = $disable_cnt = 0; + $counter = $enable_cnt = $disable_cnt = $user_enable_cnt = $user_disable_cnt = $managed_count = 0; foreach ($rules_map as $k1 => $rulem) { foreach ($rulem as $k2 => $v) { $sid = suricata_get_sid($v['rule']); $gid = suricata_get_gid($v['rule']); - - if (isset($disablesid[$gid][$sid])) { + $ruleset = $currentruleset; + $style = ""; + + if ($v['managed'] == 1) { + if ($v['disabled'] == 1) { + $textss = "<span class=\"gray\">"; + $textse = "</span>"; + $style= "style=\"opacity: 0.4; filter: alpha(opacity=40);\""; + $title = gettext("Auto-disabled by settings on SID Mgmt tab"); + } + else { + $textss = $textse = ""; + $ruleset = "suricata.rules"; + $title = gettext("Auto-managed by settings on SID Mgmt tab"); + } + $iconb = "icon_advanced.gif"; + $managed_count++; + } + elseif (isset($disablesid[$gid][$sid])) { $textss = "<span class=\"gray\">"; $textse = "</span>"; $iconb = "icon_reject_d.gif"; $disable_cnt++; - $title = gettext("Disabled by user. Click to toggle to default state"); + $user_disable_cnt++; + $title = gettext("Disabled by user. Click to toggle to enabled state"); } elseif (($v['disabled'] == 1) && (!isset($enablesid[$gid][$sid]))) { $textss = "<span class=\"gray\">"; @@ -594,7 +685,8 @@ if ($savemsg) { $textss = $textse = ""; $iconb = "icon_reject.gif"; $enable_cnt++; - $title = gettext("Enabled by user. Click to toggle to default state"); + $user_enable_cnt++; + $title = gettext("Enabled by user. Click to toggle to disabled state"); } else { $textss = $textse = ""; @@ -623,36 +715,44 @@ if ($savemsg) { $message = suricata_get_msg($v['rule']); $sid_tooltip = gettext("View the raw text for this rule"); - echo "<tr><td class=\"listt\" align=\"left\" valign=\"middle\" sorttable_customkey=\"\">{$textss} - <a id=\"rule_{$gid}_{$sid}\" href='#'><input type=\"image\" onClick=\"document.getElementById('sid').value='{$sid}'; - document.getElementById('gid').value='{$gid}';\" - src=\"../themes/{$g['theme']}/images/icons/{$iconb}\" width=\"11\" height=\"11\" border=\"0\" - title='{$title}' name=\"toggle[]\"/></a>{$textse} - </td> - <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + echo "<tr><td class=\"listt\" style=\"align:center;\" valign=\"middle\">{$textss}"; + + if ($v['managed'] == 1) { + echo "<img {$style} src=\"../themes/{$g['theme']}/images/icons/{$iconb}\" width=\"11\" height=\"11\" border=\"0\" + title='{$title}'/>{$textse}"; + } + else { + echo "<a id=\"rule_{$gid}_{$sid}\" href='#'><input type=\"image\" onClick=\"document.getElementById('sid').value='{$sid}'; + document.getElementById('gid').value='{$gid}';\" + src=\"../themes/{$g['theme']}/images/icons/{$iconb}\" width=\"11\" height=\"11\" border=\"0\" + title='{$title}' name=\"toggle[]\"/></a>{$textse}"; + } + echo "</td> + + <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$textss}{$gid}{$textse} </td> - <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> <a href=\"javascript: void(0)\" - onclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\" + onclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\" title='{$sid_tooltip}'>{$textss}{$sid}{$textse}</a> </td> - <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr\" style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$textss}{$protocol}{$textse} </td> - <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$srcspan}{$source}</span> </td> - <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$srcprtspan}{$source_port}</span> </td> - <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$dstspan}{$destination}</span> </td> - <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listr ellipsis\" nowrap style=\"text-align:center;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$dstprtspan}{$destination_port}</span> </td> - <td class=\"listbg\" style=\"word-wrap:break-word; whitespace:pre-line;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> + <td class=\"listbg\" style=\"word-wrap:break-word; whitespace:pre-line;\" ondblclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$ruleset}&sid={$sid}&gid={$gid}','FileViewer',800,600);\"> {$textss}{$message}{$textse} </td> </tr>"; @@ -667,13 +767,17 @@ if ($savemsg) { <tr> <td> <table width="100%" border="0" cellspacing="0" cellpadding="1"> + <tbody> <tr> <td width="16"></td> <td class="vexpl" height="35" valign="top"> <strong><?php echo gettext("--- Category Rules Summary ---") . "</strong><br/>" . gettext("Total Rules: {$counter}") . " " . gettext("Enabled: {$enable_cnt}") . " " . - gettext("Disabled: {$disable_cnt}"); ?></td> + gettext("Disabled: {$disable_cnt}") . " " . + gettext("User Enabled: {$user_enable_cnt}") . " " . + gettext("User Disabled: {$user_disable_cnt}") . " " . + gettext("Auto-Managed: {$managed_count}"); ?></td> </tr> <tr> <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_block.gif" @@ -695,14 +799,29 @@ if ($savemsg) { width="11" height="11"></td> <td nowrap><?php echo gettext("Rule changed to Disabled by user"); ?></td> </tr> + <?php if (!empty($cat_mods)): ?> + <tr> + <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_advanced.gif" + width="11" height="11"></td> + <td nowrap><?php echo gettext("Rule auto-enabled by files configured on SID Mgmt tab"); ?></td> + </tr> + <tr> + <td width="16"><img style="opacity: 0.4; filter: alpha(opacity=40);" src="../themes/<?= $g['theme']; ?>/images/icons/icon_advanced.gif" + width="11" height="11"></td> + <td nowrap><?php echo gettext("Rule auto-disabled by files configured on SID Mgmt tab"); ?></td> + </tr> + <?php endif; ?> + </tbody> </table> </td> </tr> <?php endif;?> + </tbody> </table> </div> </td> </tr> + </tbody> </table> </form> <script language="javascript" type="text/javascript"> diff --git a/config/suricata/suricata_rules_edit.php b/config/suricata/suricata_rules_edit.php index 0a4bd62a..8329272f 100644 --- a/config/suricata/suricata_rules_edit.php +++ b/config/suricata/suricata_rules_edit.php @@ -73,6 +73,8 @@ $wrap_flag = "off"; // Correct displayed file title if necessary if ($file == "Auto-Flowbit Rules") $displayfile = FLOWBITS_FILENAME; +elseif ($file == "suricata.rules") + $displayfile = "Currently Active Rules"; else $displayfile = $file; @@ -102,6 +104,8 @@ elseif (isset($_GET['sid']) && is_numericint($_GET['sid']) && isset($_GET['gid'] // If flowbit rule, point to interface-specific file if ($file == "Auto-Flowbit Rules") $rules_map = suricata_load_rules_map("{$suricatacfgdir}rules/" . FLOWBITS_FILENAME); + elseif ($file == "suricata.rules") + $rules_map = suricata_load_rules_map("{$suricatacfgdir}rules/suricata.rules"); else $rules_map = suricata_load_rules_map("{$suricatadir}rules/{$file}"); $contents = $rules_map[$_GET['gid']][trim($_GET['sid'])]['rule']; diff --git a/config/suricata/suricata_rules_flowbits.php b/config/suricata/suricata_rules_flowbits.php index c5193a8b..1bb945d8 100644 --- a/config/suricata/suricata_rules_flowbits.php +++ b/config/suricata/suricata_rules_flowbits.php @@ -65,7 +65,7 @@ if (is_null($id)) { // Set who called us so we can return to the correct page with // the RETURN ('cancel') button. -if ($_POST['referrer']) +if (isset($_POST['referrer']) && strpos($_POST['referrer'], '://'.$_SERVER['SERVER_NAME'].'/') !== FALSE) $referrer = $_POST['referrer']; else $referrer = $_SERVER['HTTP_REFERER']; @@ -139,7 +139,9 @@ if ($_POST['addsuppress'] && is_numeric($_POST['sid']) && is_numeric($_POST['gid if ($found_list) { write_config(); $rebuild_rules = false; + conf_mount_rw(); sync_suricata_package_config(); + conf_mount_ro(); suricata_reload_config($a_nat[$id]); $savemsg = gettext("An entry to suppress the Alert for 'gen_id {$_POST['gid']}, sig_id {$_POST['sid']}' has been added to Suppress List '{$a_nat[$id]['suppresslistname']}'."); } @@ -159,7 +161,6 @@ include_once("head.inc"); ?> <body link="#0000CC" vlink="#0000CC" alink="#0000CC" > - <?php include("fbegin.inc"); if ($input_errors) print_input_errors($input_errors); @@ -227,7 +228,7 @@ if ($savemsg) <col axis="string"> </colgroup> <thead> - <tr> + <tr class="sortableHeaderRowIdentifier"> <th class="listhdrr" axis="number"><?php echo gettext("SID"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Proto"); ?></th> <th class="listhdrr" axis="string"><?php echo gettext("Source"); ?></th> @@ -274,7 +275,7 @@ if ($savemsg) // Use "echo" to write the table HTML row-by-row. echo "<tr>" . - "<td class=\"listr\" sorttable_customkey=\"{$sid}\">{$sid} {$supplink}</td>" . + "<td class=\"listr\" style=\"sorttable_customkey:{$sid};\" sorttable_customkey=\"{$sid}\">{$sid} {$supplink}</td>" . "<td class=\"listr\" style=\"text-align:center;\">{$protocol}</td>" . "<td class=\"listr ellipsis\" nowrap style=\"text-align:center;\"><span title=\"{$rule_content[2]}\">{$source}</span></td>" . "<td class=\"listr ellipsis\" nowrap style=\"text-align:center;\"><span title=\"{$rule_content[5]}\">{$destination}</span></td>" . diff --git a/config/suricata/suricata_rulesets.php b/config/suricata/suricata_rulesets.php index c939ef25..7f591b6c 100644 --- a/config/suricata/suricata_rulesets.php +++ b/config/suricata/suricata_rulesets.php @@ -47,7 +47,7 @@ $suricatadir = SURICATADIR; $flowbit_rules_file = FLOWBITS_FILENAME; // Array of default events rules for Suricata -$default_rules = array( "decoder-events.rules", "files.rules", "http-events.rules", +$default_rules = array( "decoder-events.rules", "dns-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules", "tls-events.rules" ); if (!is_array($config['installedpackages']['suricata']['rule'])) { @@ -63,15 +63,12 @@ if (is_null($id)) $id = 0; if (isset($id) && $a_nat[$id]) { - $pconfig['enable'] = $a_nat[$id]['enable']; - $pconfig['interface'] = $a_nat[$id]['interface']; - $pconfig['rulesets'] = $a_nat[$id]['rulesets']; - $pconfig['autoflowbitrules'] = $a_nat[$id]['autoflowbitrules']; + $pconfig['autoflowbits'] = $a_nat[$id]['autoflowbitrules']; $pconfig['ips_policy_enable'] = $a_nat[$id]['ips_policy_enable']; $pconfig['ips_policy'] = $a_nat[$id]['ips_policy']; } -$if_real = get_real_interface($pconfig['interface']); +$if_real = get_real_interface($a_nat[$id]['interface']); $suricata_uuid = $a_nat[$id]['uuid']; $snortdownload = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'] == 'on' ? 'on' : 'off'; $emergingdownload = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules'] == 'on' ? 'on' : 'off'; @@ -81,6 +78,8 @@ $snortcommunitydownload = $config['installedpackages']['suricata']['config'][0][ $no_emerging_files = false; $no_snort_files = false; +$enabled_rulesets_array = explode("||", $a_nat[$id]['rulesets']); + /* Test rule categories currently downloaded to $SURICATADIR/rules and set appropriate flags */ if ($emergingdownload == 'on') { $test = glob("{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "*.rules"); @@ -143,27 +142,33 @@ if ($_POST["save"]) { $a_nat[$id]['autoflowbitrules'] = 'on'; else { $a_nat[$id]['autoflowbitrules'] = 'off'; - if (file_exists("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}")) - @unlink("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}"); + unlink_if_exists("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}"); } - write_config(); + write_config("Suricata pkg: save enabled rule categories for {$a_nat[$id]['interface']}."); /*************************************************/ /* Update the suricata.yaml file and rebuild the */ /* rules for this interface. */ /*************************************************/ $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_nat[$id]); + conf_mount_ro(); $rebuild_rules = false; /* Signal Suricata to "live reload" the rules */ suricata_reload_config($a_nat[$id]); + + $pconfig = $_POST; + $enabled_rulesets_array = explode("||", $enabled_items); + if (suricata_is_running($suricata_uuid, $if_real)) + $savemsg = gettext("Suricata is 'live-loading' the new rule set on this interface."); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); } elseif ($_POST['unselectall']) { - // Remove all but the default events and files rules - $a_nat[$id]['rulesets'] = implode("||", $default_rules); - if ($_POST['ips_policy_enable'] == "on") { $a_nat[$id]['ips_policy_enable'] = 'on'; $a_nat[$id]['ips_policy'] = $_POST['ips_policy']; @@ -173,13 +178,21 @@ elseif ($_POST['unselectall']) { unset($a_nat[$id]['ips_policy']); } - write_config(); - sync_suricata_package_config(); + $pconfig['autoflowbits'] = $_POST['autoflowbits']; + $pconfig['ips_policy_enable'] = $_POST['ips_policy_enable']; + $pconfig['ips_policy'] = $_POST['ips_policy']; + + // Remove all but the default events and files rules + $enabled_rulesets_array = array(); + $enabled_rulesets_array = implode("||", $default_rules); + + $savemsg = gettext("All rule categories have been de-selected. "); + if ($_POST['ips_policy_enable'] == "on") + $savemsg .= gettext("Only the rules included in the selected IPS Policy will be used."); + else + $savemsg .= gettext("There currently are no inspection rules enabled for this Suricata instance!"); } elseif ($_POST['selectall']) { - // Start with the required default events and files rules - $rulesets = $default_rules; - if ($_POST['ips_policy_enable'] == "on") { $a_nat[$id]['ips_policy_enable'] = 'on'; $a_nat[$id]['ips_policy'] = $_POST['ips_policy']; @@ -189,39 +202,45 @@ elseif ($_POST['selectall']) { unset($a_nat[$id]['ips_policy']); } + $pconfig['autoflowbits'] = $_POST['autoflowbits']; + $pconfig['ips_policy_enable'] = $_POST['ips_policy_enable']; + $pconfig['ips_policy'] = $_POST['ips_policy']; + + // Start with the required default events and files rules + $enabled_rulesets_array = $default_rules; + if ($emergingdownload == 'on') { $files = glob("{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "*.rules"); foreach ($files as $file) - $rulesets[] = basename($file); + $enabled_rulesets_array[] = basename($file); } elseif ($etpro == 'on') { $files = glob("{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "*.rules"); foreach ($files as $file) - $rulesets[] = basename($file); + $enabled_rulesets_array[] = basename($file); } if ($snortcommunitydownload == 'on') { $files = glob("{$suricatadir}rules/" . GPL_FILE_PREFIX . "community.rules"); foreach ($files as $file) - $rulesets[] = basename($file); + $enabled_rulesets_array[] = basename($file); } /* Include the Snort VRT rules only if enabled and no IPS policy is set */ - if ($snortdownload == 'on' && $a_nat[$id]['ips_policy_enable'] == 'off') { + if ($snortdownload == 'on' && empty($_POST['ips_policy_enable'])) { $files = glob("{$suricatadir}rules/" . VRT_FILE_PREFIX . "*.rules"); foreach ($files as $file) - $rulesets[] = basename($file); + $enabled_rulesets_array[] = basename($file); } - - $a_nat[$id]['rulesets'] = implode("||", $rulesets); - - write_config(); - sync_suricata_package_config(); } +// Get any automatic rule category enable/disable modifications +// if auto-SID Mgmt is enabled. +$cat_mods = suricata_sid_mgmt_auto_categories($a_nat[$id], FALSE); + // See if we have any Auto-Flowbit rules and enable // the VIEW button if we do. -if ($a_nat[$id]['autoflowbitrules'] == 'on') { +if ($pconfig['autoflowbits'] == 'on') { if (file_exists("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}") && filesize("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}") > 0) { $btn_view_flowb_rules = " title=\"" . gettext("View flowbit-required rules") . "\""; @@ -232,9 +251,7 @@ if ($a_nat[$id]['autoflowbitrules'] == 'on') { else $btn_view_flowb_rules = " disabled"; -$enabled_rulesets_array = explode("||", $a_nat[$id]['rulesets']); - -$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']); +$if_friendly = convert_friendly_interface_to_friendly_descr($a_nat[$id]['interface']); $pgtitle = gettext("Suricata IDS: Interface {$if_friendly} - Categories"); include_once("head.inc"); ?> @@ -258,18 +275,22 @@ if ($savemsg) { <form action="suricata_rulesets.php" method="post" name="iform" id="iform"> <input type="hidden" name="id" id="id" value="<?=$id;?>" /> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), true, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php?instance={$id}"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); echo '</td></tr>'; echo '<tr><td class="tabnavtbl">'; @@ -282,6 +303,7 @@ if ($savemsg) { $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("IP Rep"), false, "/suricata/suricata_ip_reputation.php?id={$id}"); display_top_tabs($tab_array, true); ?> </td></tr> @@ -289,6 +311,7 @@ if ($savemsg) { <td> <div id="mainarea"> <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> <?php $isrulesfolderempty = glob("{$suricatadir}rules/*.rules"); $iscfgdirempty = array(); @@ -307,18 +330,19 @@ if ($savemsg) { <?php else: ?> <tr> <td> - <table width="100%" border="0" - cellpadding="0" cellspacing="0"> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> <tr> <td colspan="4" class="listtopic"><?php echo gettext("Automatic flowbit resolution"); ?><br/></td> </tr> <tr> - <td colspan="4" valign="center" class="listn"> + <td colspan="4" style="vertical-align: middle;" class="listn"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td width="15%" class="listn"><?php echo gettext("Resolve Flowbits"); ?></td> <td width="85%"><input name="autoflowbits" id="autoflowbitrules" type="checkbox" value="on" - <?php if ($a_nat[$id]['autoflowbitrules'] == "on" || empty($a_nat[$id]['autoflowbitrules'])) echo "checked"; ?>/> + <?php if ($pconfig['autoflowbits'] == "on" || empty($pconfig['autoflowbits'])) echo "checked"; ?>/> <span class="vexpl"><?php echo gettext("If checked, Suricata will auto-enable rules required for checked flowbits. "); echo gettext("The Default is "); ?><strong><?php echo gettext("Checked."); ?></strong></span></td> </tr> @@ -340,6 +364,7 @@ if ($savemsg) { <?php echo "<span class=\"red\"><strong>" . gettext("Note: ") . "</strong></span>" . gettext("Auto-enabled rules generating unwanted alerts should have their GID:SID added to the Suppression List for the interface."); ?> <br/></td> </tr> + </tbody> </table> </td> </tr> @@ -349,8 +374,9 @@ if ($savemsg) { <td colspan="4" class="listtopic"><?php echo gettext("Snort IPS Policy selection"); ?><br/></td> </tr> <tr> - <td colspan="4" valign="center" class="listn"> + <td colspan="4" style="vertical-align: middle;" class="listn"> <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> <tr> <td width="15%" class="listn"><?php echo gettext("Use IPS Policy"); ?></td> <td width="85%"><input name="ips_policy_enable" id="ips_policy_enable" type="checkbox" value="on" <?php if ($a_nat[$id]['ips_policy_enable'] == "on") echo "checked"; ?> @@ -365,7 +391,9 @@ if ($savemsg) { "although Emerging Threats categories may still be selected if enabled on the Global Settings tab. " . "These will be added to the pre-defined Snort IPS policy rules from the Snort VRT."); ?><br/></td> </tr> - <tr id="ips_row1"> + </tbody> + <tbody id="ips_controls"> + <tr> <td width="15%" class="listn"><?php echo gettext("IPS Policy Selection"); ?></td> <td width="85%"><select name="ips_policy" class="formselect" <?=$policy_select_disable?> > <option value="connectivity" <?php if ($pconfig['ips_policy'] == "connected") echo "selected"; ?>><?php echo gettext("Connectivity"); ?></option> @@ -374,7 +402,7 @@ if ($savemsg) { </select> <span class="vexpl"><?php echo gettext("Snort IPS policies are: Connectivity, Balanced or Security."); ?></span></td> </tr> - <tr id="ips_row2"> + <tr> <td width="15%"> </td> <td width="85%"> <?php echo gettext("Connectivity blocks most major threats with few or no false positives. " . @@ -383,6 +411,7 @@ if ($savemsg) { "Security is a stringent policy. It contains everything in the first two " . "plus policy-type rules such as Flash in an Excel file."); ?><br/></td> </tr> + </tbody> </table> </td> </tr> @@ -392,15 +421,27 @@ if ($savemsg) { </tr> <tr> <td colspan="4"> - <table width=90% align="center" border="0" cellpadding="2" cellspacing="0"> - <tr height="45px"> - <td valign="middle"><input value="Select All" class="formbtns" type="submit" name="selectall" id="selectall" title="<?php echo gettext("Add all to enforcing rules"); ?>"/></td> - <td valign="middle"><input value="Unselect All" class="formbtns" type="submit" name="unselectall" id="unselectall" title="<?php echo gettext("Remove all from enforcing rules"); ?>"/></td> - <td valign="middle"><input value=" Save " class="formbtns" type="submit" name="save" id="save" title="<?php echo gettext("Save changes to enforcing rules and rebuild"); ?>"/></td> - <td valign="middle"><span class="vexpl"><?php echo gettext("Click to save changes and auto-resolve flowbit rules (if option is selected above)"); ?></span></td> + <table width="95%" style="margin-left: auto; margin-right: auto;" border="0" cellpadding="2" cellspacing="0"> + <tbody> + <tr height="32px"> + <td style="vertical-align: middle;"><input value="Select All" class="formbtns" type="submit" name="selectall" id="selectall" title="<?php echo gettext("Add all to enforcing rules"); ?>"/></td> + <td style="vertical-align: middle;"><input value="Unselect All" class="formbtns" type="submit" name="unselectall" id="unselectall" title="<?php echo gettext("Remove all from enforcing rules"); ?>"/></td> + <td style="vertical-align: middle;"><input value=" Save " class="formbtns" type="submit" name="save" id="save" title="<?php echo gettext("Save changes to enforcing rules and rebuild"); ?>"/></td> + <td style="vertical-align: middle;"><span class="vexpl"><?php echo gettext("Click to save changes and auto-resolve flowbit rules (if option is selected above)"); ?></span></td> + </tr> + <?php if (!empty($cat_mods)): ?> + <tr height="20px"> + <td colspan="4" style="vertical-align: middle;"><img style="vertical-align: text-top;" src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" /> + <?=gettext("- Category is auto-enabled by SID Mgmt conf files");?> + <img style="opacity: 0.4; filter: alpha(opacity=40); vertical-align: text-top;" src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" /> + <?=gettext("- Category is auto-disabled by SID Mgmt conf files");?></td> </tr> + <?php endif; ?> + </tbody> </table> + </td> </tr> + <?php if ($no_community_files) $msg_community = "NOTE: Snort Community Rules have not been downloaded. Perform a Rules Update to enable them."; else @@ -412,15 +453,29 @@ if ($savemsg) { <td width="5%" class="listhdrr"><?php echo gettext("Enabled"); ?></td> <td colspan="5" class="listhdrr"><?php echo gettext('Ruleset: Snort GPLv2 Community Rules');?></td> </tr> - <?php if (in_array($community_rules_file, $enabled_rulesets_array)): ?> + <?php if (isset($cat_mods[$community_rules_file])): ?> + <?php if ($cat_mods[$community_rules_file] == 'enabled') : ?> + <tr> + <td width="5%" class="listr" style="text-align: center;"> + <img src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" title="<?=gettext("Auto-managed by settings on SID Mgmt tab");?>" /></td> + <td colspan="5" class="listr"><a href='suricata_rules.php?id=<?=$id;?>&openruleset=<?=$community_rules_file;?>'><?=gettext("{$msg_community}");?></a></td> + </tr> + <?php else: ?> + <tr> + <td width="5%" class="listr" style="text-align: center;"> + <img style="opacity: 0.4; filter: alpha(opacity=40);" src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" title="<?=gettext("Auto-managed by settings on SID Mgmt tab");?>" /></td> + <td colspan="5" class="listr"><?=gettext("{$msg_community}"); ?></td> + </tr> + <?php endif; ?> + <?php elseif (in_array($community_rules_file, $enabled_rulesets_array)): ?> <tr> - <td width="5" class="listr" align="center" valign="top"> + <td width="5%" class="listr" style="text-align: center;"> <input type="checkbox" name="toenable[]" value="<?=$community_rules_file;?>" checked="checked"/></td> <td colspan="5" class="listr"><a href='suricata_rules.php?id=<?=$id;?>&openruleset=<?=$community_rules_file;?>'><?php echo gettext("{$msg_community}"); ?></a></td> </tr> <?php else: ?> <tr> - <td width="5" class="listr" align="center" valign="top"> + <td width="5%" class="listr" style="text-align: center;"> <input type="checkbox" name="toenable[]" value="<?=$community_rules_file;?>" <?php if ($snortcommunitydownload == 'off') echo "disabled"; ?>/></td> <td colspan="5" class="listr"><?php echo gettext("{$msg_community}"); ?></td> </tr> @@ -438,19 +493,19 @@ if ($savemsg) { ?> <tr id="frheader"> <?php if ($emergingdownload == 'on' && !$no_emerging_files): ?> - <td width="5%" class="listhdrr" align="center"><?php echo gettext("Enabled"); ?></td> + <td width="5%" class="listhdrr" style="text-align: center;"><?php echo gettext("Enabled"); ?></td> <td width="45%" class="listhdrr"><?php echo gettext('Ruleset: ET Open Rules');?></td> <?php elseif ($etpro == 'on' && !$no_emerging_files): ?> - <td width="5%" class="listhdrr" align="center"><?php echo gettext("Enabled"); ?></td> + <td width="5%" class="listhdrr" style="text-align: center;"><?php echo gettext("Enabled"); ?></td> <td width="45%" class="listhdrr"><?php echo gettext('Ruleset: ET Pro Rules');?></td> <?php else: ?> - <td colspan="2" align="center" width="50%" class="listhdrr"><?php echo gettext("{$et_type} rules {$msg_emerging}"); ?></td> + <td colspan="2" style="text-align: center;" width="50%" class="listhdrr"><?php echo gettext("{$et_type} rules {$msg_emerging}"); ?></td> <?php endif; ?> <?php if ($snortdownload == 'on' && !$no_snort_files): ?> - <td width="5%" class="listhdrr" align="center"><?php echo gettext("Enabled"); ?></td> + <td width="5%" class="listhdrr" style="text-align: center;"><?php echo gettext("Enabled"); ?></td> <td width="45%" class="listhdrr"><?php echo gettext('Ruleset: Snort VRT Rules');?></td> <?php else: ?> - <td colspan="2" align="center" width="50%" class="listhdrr"><?php echo gettext("Snort VRT rules {$msg_snort}"); ?></td> + <td colspan="2" style="text-align: center;" width="50%" class="listhdrr"><?php echo gettext("Snort VRT rules {$msg_snort}"); ?></td> <?php endif; ?> </tr> <?php @@ -482,15 +537,28 @@ if ($savemsg) { echo "<tr>\n"; if (!empty($emergingrules[$j])) { $file = $emergingrules[$j]; - echo "<td width='5%' class='listr' align=\"center\" valign=\"top\">"; + echo "<td width='5%' class='listr' align=\"center\">"; if(is_array($enabled_rulesets_array)) { - if(in_array($file, $enabled_rulesets_array)) + if(in_array($file, $enabled_rulesets_array) && !isset($cat_mods[$file])) $CHECKED = " checked=\"checked\""; else $CHECKED = ""; } else $CHECKED = ""; - echo " \n<input type='checkbox' name='toenable[]' value='$file' {$CHECKED} />\n"; + if (isset($cat_mods[$file])) { + if (in_array($file, $enabled_rulesets_array)) + echo "<input type='hidden' name='toenable[]' value='{$file}' />\n"; + if ($cat_mods[$file] == 'enabled') { + $CHECKED = "enabled"; + echo " \n<img src=\"../themes/{$g['theme']}/images/icons/icon_advanced.gif\" width=\"11\" height=\"11\" border=\"0\" title=\"" . gettext("Auto-enabled by settings on SID Mgmt tab") . "\" />\n"; + } + else { + echo " \n<img style=\"opacity: 0.4; filter: alpha(opacity=40);\" src=\"../themes/{$g['theme']}/images/icons/icon_advanced.gif\" width=\"11\" height=\"11\" border=\"0\" title=\"" . gettext("Auto-disabled by settings on SID Mgmt tab") . "\" />\n"; + } + } + else { + echo " \n<input type='checkbox' name='toenable[]' value='{$file}' {$CHECKED} />\n"; + } echo "</td>\n"; echo "<td class='listr' width='45%' >\n"; if (empty($CHECKED)) @@ -503,17 +571,30 @@ if ($savemsg) { if (!empty($snortrules[$j])) { $file = $snortrules[$j]; - echo "<td class='listr' width='5%' align=\"center\" valign=\"top\">"; + echo "<td class='listr' width='5%' align=\"center\">"; if(is_array($enabled_rulesets_array)) { if (!empty($disable_vrt_rules)) $CHECKED = $disable_vrt_rules; - elseif(in_array($file, $enabled_rulesets_array)) + elseif(in_array($file, $enabled_rulesets_array) && !isset($cat_mods[$file])) $CHECKED = " checked=\"checked\""; else $CHECKED = ""; } else $CHECKED = ""; - echo " \n<input type='checkbox' name='toenable[]' value='{$file}' {$CHECKED} />\n"; + if (isset($cat_mods[$file])) { + if (in_array($file, $enabled_rulesets_array)) + echo "<input type='hidden' name='toenable[]' value='{$file}' />\n"; + if ($cat_mods[$file] == 'enabled') { + $CHECKED = "enabled"; + echo " \n<img src=\"../themes/{$g['theme']}/images/icons/icon_advanced.gif\" width=\"11\" height=\"11\" border=\"0\" title=\"" . gettext("Auto-enabled by settings on SID Mgmt tab") . "\" />\n"; + } + else { + echo " \n<img style=\"opacity: 0.4; filter: alpha(opacity=40);\" src=\"../themes/{$g['theme']}/images/icons/icon_advanced.gif\" width=\"11\" height=\"11\" border=\"0\" title=\"" . gettext("Auto-disabled by settings on SID Mgmt tab") . "\" />\n"; + } + } + else { + echo " \n<input type='checkbox' name='toenable[]' value='{$file}' {$CHECKED} />\n"; + } echo "</td>\n"; echo "<td class='listr' width='45%' >\n"; if (empty($CHECKED) || $CHECKED == "disabled") @@ -526,21 +607,30 @@ if ($savemsg) { echo "</tr>\n"; } ?> - </table> + </tbody> + </table> </td> </tr> -<tr> -<td colspan="4" class="vexpl"> <br/></td> -</tr> - <tr> - <td colspan="4" align="center" valign="middle"> - <input value="Save" type="submit" name="save" id="save" class="formbtn" title=" <?php echo gettext("Click to Save changes and rebuild rules"); ?>"/></td> - </tr> + <?php if (!empty($cat_mods)): ?> + <tr> + <td colspan="4" style="vertical-align: middle;"><br/> + <img style="vertical-align: text-top;" src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" /> + <?=gettext(" - Category auto-enabled by parameters in SID Mgmt conf files");?><br/> + <img style="opacity: 0.4; filter: alpha(opacity=40); vertical-align: text-top;" src="../themes/<?=$g['theme'];?>/images/icons/icon_advanced.gif" width="11" height="11" border="0" /> + <?=gettext(" - Category auto-disabled by parameters in SID Mgmt conf files");?><br/><br/></td> + </tr> + <?php endif; ?> + <tr height="32px"> + <td colspan="4" style="vertical-align: bottom; text-align: center;"> + <input value="Save" type="submit" name="save" id="save" class="formbtn" title=" <?php echo gettext("Click to Save changes and rebuild rules"); ?>"/></td> + </tr> <?php endif; ?> +</tbody> </table> </div> </td> </tr> +</tbody> </table> </form> <?php @@ -566,28 +656,29 @@ h += 96; function enable_change() { - var endis = !(document.iform.ips_policy_enable.checked); - document.iform.ips_policy.disabled=endis; - - if (endis) { - document.getElementById("ips_row1").style.display="none"; - document.getElementById("ips_row2").style.display="none"; - document.getElementById("ips_col1").className="vexpl"; - document.getElementById("ips_col2").className="vexpl"; - } - else { - document.getElementById("ips_row1").style.display="table-row"; - document.getElementById("ips_row2").style.display="table-row"; - document.getElementById("ips_col1").className="vncell"; - document.getElementById("ips_col2").className="vtable"; - } - for (var i = 0; i < document.iform.elements.length; i++) { - if (document.iform.elements[i].type == 'checkbox') { - var str = document.iform.elements[i].value; - if (str.substr(0,6) == "snort_") - document.iform.elements[i].disabled = !(endis); - } - } + + if (document.getElementById("ips_policy_enable")) { + var endis = !(document.iform.ips_policy_enable.checked); + document.iform.ips_policy.disabled=endis; + + if (endis) { + document.getElementById("ips_controls").style.display="none"; + document.getElementById("ips_col1").className=""; + document.getElementById("ips_col2").className=""; + } + else { + document.getElementById("ips_controls").style.display=""; + document.getElementById("ips_col1").className="vncell"; + document.getElementById("ips_col2").className="vtable"; + } + } + for (var i = 0; i < document.iform.elements.length; i++) { + if (document.iform.elements[i].type == 'checkbox') { + var str = document.iform.elements[i].value; + if (str.substr(0,6) == "snort_") + document.iform.elements[i].disabled = !(endis); + } + } } // Set initial state of dynamic HTML form controls diff --git a/config/suricata/suricata_select_alias.php b/config/suricata/suricata_select_alias.php index 527412d1..47bbec4a 100644 --- a/config/suricata/suricata_select_alias.php +++ b/config/suricata/suricata_select_alias.php @@ -47,29 +47,31 @@ else // Retrieve any passed QUERY STRING or POST variables if (isset($_POST['type'])) - $type = $_POST['type']; + $type = htmlspecialchars($_POST['type']); elseif (isset($_GET['type'])) $type = htmlspecialchars($_GET['type']); if (isset($_POST['varname'])) - $varname = $_POST['varname']; + $varname = htmlspecialchars($_POST['varname']); elseif (isset($_GET['varname'])) $varname = htmlspecialchars($_GET['varname']); if (isset($_POST['multi_ip'])) - $multi_ip = $_POST['multi_ip']; + $multi_ip = htmlspecialchars($_POST['multi_ip']); elseif (isset($_GET['multi_ip'])) $multi_ip = htmlspecialchars($_GET['multi_ip']); -if (isset($_POST['returl'])) +if (isset($_POST['returl']) && substr($_POST['returl'], 0, 1) == '/') $referrer = urldecode($_POST['returl']); -elseif (isset($_GET['returl'])) +elseif (isset($_GET['returl']) && substr($_GET['returl'], 0, 1) == '/') $referrer = urldecode($_GET['returl']); +else + $referrer = $_SERVER['HTTP_REFERER']; // Make sure we have a valid VARIABLE name // and ALIAS TYPE, or else bail out. if (is_null($type) || is_null($varname)) { - header("Location: http://{$referrer}?{$querystr}"); + header("Location: {$referrer}?{$querystr}"); exit; } @@ -132,8 +134,8 @@ include("head.inc"); <input type="hidden" name="varname" value="<?=$varname;?>"/> <input type="hidden" name="type" value="<?=$type;?>"/> <input type="hidden" name="multi_ip" value="<?=$multi_ip;?>"/> -<input type="hidden" name="returl" value="<?=$referrer;?>"/> -<input type="hidden" name="org_querystr" value="<?=$querystr;?>"/> +<input type="hidden" name="returl" value="<?=htmlspecialchars($referrer);?>"/> +<input type="hidden" name="org_querystr" value="<?=htmlspecialchars($querystr);?>"/> <?php if ($input_errors) print_input_errors($input_errors); ?> <div id="boxarea"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> @@ -151,8 +153,8 @@ include("head.inc"); <col width="35%" align="left" axis="string"> </colgroup> <thead> - <tr> - <th class="listhdrr"></th> + <tr class="sortableHeaderRowIdentifier"> + <th class="listhdrr sorttable_nosort"></th> <th class="listhdrr" axis="string"><?=gettext("Alias Name"); ?></th> <th class="listhdrr" axis="string"><?=gettext("Values"); ?></th> <th class="listhdrr" axis="string"><?=gettext("Description"); ?></th> diff --git a/config/suricata/suricata_sid_mgmt.php b/config/suricata/suricata_sid_mgmt.php new file mode 100644 index 00000000..c2d58af8 --- /dev/null +++ b/config/suricata/suricata_sid_mgmt.php @@ -0,0 +1,611 @@ +<?php +/* + * suricata_sid_mgmt.php + * + * Portions of this code are based on original work done for the + * Snort package for pfSense from the following contributors: + * + * Copyright (C) 2005 Bill Marquette <bill.marquette@gmail.com>. + * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>. + * Copyright (C) 2006 Scott Ullrich + * Copyright (C) 2009 Robert Zelaya Sr. Developer + * Copyright (C) 2012 Ermal Luci + * All rights reserved. + * + * Adapted for Suricata by: + * Copyright (C) 2014 Bill Meeks + * 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("guiconfig.inc"); +require_once("/usr/local/pkg/suricata/suricata.inc"); + +global $g, $config, $rebuild_rules; + +$suricatadir = SURICATADIR; +$pconfig = array(); + +// Grab saved settings from configuration +if (!is_array($config['installedpackages']['suricata']['rule'])) + $config['installedpackages']['suricata']['rule'] = array(); +$a_nat = &$config['installedpackages']['suricata']['rule']; + +$pconfig['auto_manage_sids'] = $config['installedpackages']['suricata']['config'][0]['auto_manage_sids']; + +// Hard-code the path where SID Mods Lists are stored +// and disregard any user-supplied path element. +$sidmods_path = SURICATA_SID_MODS_PATH; + +// Set default to not show SID modification lists editor controls +$sidmodlist_edit_style = "display: none;"; + +if (!empty($_POST)) + $pconfig = $_POST; + +function suricata_is_sidmodslist_active($sidlist) { + + /***************************************************** + * This function checks all the configured Suricata * + * interfaces to see if the passed SID Mods List is * + * used by an interface. * + * * + * Returns: TRUE if List is in use * + * FALSE if List is not in use * + *****************************************************/ + + global $g, $config; + + if (!is_array($config['installedpackages']['suricata']['rule'])) + return FALSE; + + foreach ($config['installedpackages']['suricata']['rule'] as $rule) { + if ($rule['enable_sid_file'] == $sidlist) { + return TRUE; + } + if ($rule['disable_sid_file'] == $sidlist) { + return TRUE; + } + if ($rule['modify_sid_file'] == $sidlist) { + return TRUE; + } + } + return FALSE; +} + +if (isset($_POST['upload'])) { + if ($_FILES["sidmods_fileup"]["error"] == UPLOAD_ERR_OK) { + $tmp_name = $_FILES["sidmods_fileup"]["tmp_name"]; + $name = basename($_FILES["sidmods_fileup"]["name"]); + move_uploaded_file($tmp_name, "{$sidmods_path}{$name}"); + } + else + $input_errors[] = gettext("Failed to upload file {$_FILES["sidmods_fileup"]["name"]}"); +} + +if (isset($_POST['sidlist_delete']) && isset($_POST['sidlist_fname'])) { + if (!suricata_is_sidmodslist_active(basename($_POST['sidlist_fname']))) + unlink_if_exists($sidmods_path . basename($_POST['sidlist_fname'])); + else + $input_errors[] = gettext("This SID Mods List is currently assigned to an interface and cannot be deleted."); +} + +if (isset($_POST['sidlist_edit']) && isset($_POST['sidlist_fname'])) { + $file = $sidmods_path . basename($_POST['sidlist_fname']); + $data = file_get_contents($file); + if ($data !== FALSE) { + $sidmodlist_data = htmlspecialchars($data); + $sidmodlist_edit_style = "display: table-row-group;"; + $sidmodlist_name = basename($_POST['sidlist_fname']); + unset($data); + } + else { + $input_errors[] = gettext("An error occurred reading the file."); + } +} + +if (isset($_POST['save']) && isset($_POST['sidlist_data'])) { + if (strlen(basename($_POST['sidlist_name'])) > 0) { + $file = $sidmods_path . basename($_POST['sidlist_name']); + $data = str_replace("\r\n", "\n", $_POST['sidlist_data']); + file_put_contents($file, $data); + unset($data); + } + else { + $input_errors[] = gettext("You must provide a valid filename for the SID Mods List."); + $sidmodlist_edit_style = "display: table-row-group;"; + } +} + +if (isset($_POST['save_auto_sid_conf'])) { + $config['installedpackages']['suricata']['config'][0]['auto_manage_sids'] = $pconfig['auto_manage_sids'] ? "on" : "off"; + + // Grab the SID Mods config for the interfaces from the form's controls array + foreach ($_POST['sid_state_order'] as $k => $v) { + $a_nat[$k]['sid_state_order'] = $v; + } + foreach ($_POST['enable_sid_file'] as $k => $v) { + if ($v == "None") { + unset($a_nat[$k]['enable_sid_file']); + continue; + } + $a_nat[$k]['enable_sid_file'] = $v; + } + foreach ($_POST['disable_sid_file'] as $k => $v) { + if ($v == "None") { + unset($a_nat[$k]['disable_sid_file']); + continue; + } + $a_nat[$k]['disable_sid_file'] = $v; + } + foreach ($_POST['modify_sid_file'] as $k => $v) { + if ($v == "None") { + unset($a_nat[$k]['modify_sid_file']); + continue; + } + $a_nat[$k]['modify_sid_file'] = $v; + } + + // Write the new configuration + write_config("Suricata pkg: updated automatic SID management settings."); + + $intf_msg = ""; + + // If any interfaces were marked for restart, then do it + if (is_array($_POST['torestart'])) { + foreach ($_POST['torestart'] as $k) { + // Update the suricata.yaml file and + // rebuild rules for this interface. + $rebuild_rules = true; + conf_mount_rw(); + suricata_generate_yaml($a_nat[$k]); + conf_mount_ro(); + $rebuild_rules = false; + + // Signal Suricata to "live reload" the rules + suricata_reload_config($a_nat[$k]); + + $intf_msg .= convert_friendly_interface_to_friendly_descr($a_nat[$k]['interface']) . ", "; + } + $savemsg = gettext("Changes were applied to these interfaces: " . trim($intf_msg, ' ,') . " and Suricata signaled to live-load the new rules."); + + // Sync to configured CARP slaves if any are enabled + suricata_sync_on_changes(); + } +} + +if (isset($_POST['sidlist_dnload']) && isset($_POST['sidlist_fname'])) { + $file = $sidmods_path . basename($_POST['sidlist_fname']); + if (file_exists($file)) { + ob_start(); //important or other posts will fail + if (isset($_SERVER['HTTPS'])) { + header('Pragma: '); + header('Cache-Control: '); + } else { + header("Pragma: private"); + header("Cache-Control: private, must-revalidate"); + } + header("Content-Type: application/octet-stream"); + header("Content-length: " . filesize($file)); + header("Content-disposition: attachment; filename = " . basename($file)); + ob_end_clean(); //important or other post will fail + readfile($file); + } + else + $savemsg = gettext("Unable to locate the file specified!"); +} + +if (isset($_POST['sidlist_dnload_all_x'])) { + $save_date = date("Y-m-d-H-i-s"); + $file_name = "suricata_sid_conf_files_{$save_date}.tar.gz"; + exec("cd {$sidmods_path} && /usr/bin/tar -czf /tmp/{$file_name} *"); + + if (file_exists("/tmp/{$file_name}")) { + ob_start(); //important or other posts will fail + if (isset($_SERVER['HTTPS'])) { + header('Pragma: '); + header('Cache-Control: '); + } else { + header("Pragma: private"); + header("Cache-Control: private, must-revalidate"); + } + header("Content-Type: application/octet-stream"); + header("Content-length: " . filesize("/tmp/{$file_name}")); + header("Content-disposition: attachment; filename = {$file_name}"); + ob_end_clean(); //important or other post will fail + readfile("/tmp/{$file_name}"); + + // Clean up the temp file + unlink_if_exists("/tmp/{$file_name}"); + } + else + $savemsg = gettext("An error occurred while creating the gzip archive!"); +} + +// Get all files in the SID Mods Lists sub-directory as an array +// Leave this as the last thing before spewing the page HTML +// so we can pick up any changes made to files in code above. +$sidmodfiles = return_dir_as_array($sidmods_path); +$sidmodselections = array_merge(Array( "None" ), $sidmodfiles); + +$pgtitle = gettext("Suricata: SID Management"); +include_once("head.inc"); + +?> + +<body link="#000000" vlink="#000000" alink="#000000"> + +<?php +include_once("fbegin.inc"); + +/* Display Alert message, under form tag or no refresh */ +if ($input_errors) + print_input_errors($input_errors); +?> + +<form action="suricata_sid_mgmt.php" method="post" enctype="multipart/form-data" name="iform" id="iform"> +<input type="hidden" name="MAX_FILE_SIZE" value="100000000" /> +<input type="hidden" name="sidlist_fname" id="sidlist_fname" value=""/> + +<?php +if ($savemsg) { + /* Display save message */ + print_info_box($savemsg); +} +?> + +<table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tbody> + <tr><td> + <?php + $tab_array = array(); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); + $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), true, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); + display_top_tabs($tab_array, true); + ?> + </td></tr> + <tr><td> + <div id="mainarea"> + <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0"> + <tbody> + <?php if ($g['platform'] == "nanobsd") : ?> + <tr> + <td colspan="2" class="listtopic"><?php echo gettext("SID auto-management is not supported on NanoBSD installs"); ?></td> + </tr> + <?php else: ?> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("General Settings"); ?></td> + </tr> + <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Automatic SID State Management"); ?></td> + <td width="78%" class="vtable"><input type="checkbox" id="auto_manage_sids" name="auto_manage_sids" value="on" + <?php if ($pconfig['auto_manage_sids'] == 'on') echo " checked"; ?> onclick="enable_sid_conf();" /> <?=gettext("Enable automatic management of rule state ") . + gettext("and content using configuration files. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>";?>.<br/><br/> + <?=gettext("Suricata will automatically enable/disable/modify text rules upon each update using criteria specified in configuration files. ") . + gettext("The supported configuration file format is the same as that used in the PulledPork and Oinkmaster enablesid.conf, disablesid.conf and ") . + gettext("modifysid.conf files. You can either upload existing files or create your own."); ?> + </td> + </tr> + </tbody> + <tbody id="sid_conf_rows"> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("SID Management Configuration Files"); ?></td> + </tr> + <tr> + <td colspan="2" class="vtable" align="center" > + <table width="100%" border="0" cellpadding="4" cellspacing="0"> + <tbody id="uploader" style="display: none;"> + <tr> + <td class="list"><br/><?php echo gettext("Click BROWSE to select a file to import, and then click UPLOAD. Click CLOSE to quit."); ?></td> + </tr> + <tr> + <td class="list"><input type="file" name="sidmods_fileup" id="sidmods_fileup" class="formfld file" size="50" /> + <input type="submit" name="upload" id="upload" value="<?=gettext("Upload");?>" + title="<?=gettext("Upload selected SID mods list to firewall");?>"/> <input type="button" + value="<?=gettext("Close");?>" onClick="document.getElementById('uploader').style.display='none';" /><br/></td> + <td class="list"></td> + </tr> + </tbody> + <tbody> + <tr> + <td> + <table id="maintable" width="100%" border="0" cellpadding="4" cellspacing="0"> + <colgroup> + <col style="width: 45%;"> + <col style="width: 25%;"> + <col style="width: 15%;"> + <col style="width: 15%;"> + </colgroup> + <thead> + <tr> + <th class="listhdrr"><?php echo gettext("SID Mods List File Name"); ?></th> + <th class="listhdrr"><?php echo gettext("Last Modified Time"); ?></th> + <th class="listhdrr"><?php echo gettext("File Size"); ?></th> + <th class="list" align="left"><img style="cursor:pointer;" name="sidlist_new" id="sidlist_new" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" + height="17" border="0" title="<?php echo gettext('Create a new SID Mods List');?>" + onClick="document.getElementById('sidlist_data').value=''; document.getElementById('sidlist_name').value=''; document.getElementById('sidlist_editor').style.display='table-row-group'; document.getElementById('sidlist_name').focus();" /> + <img style="cursor:pointer;" name="sidlist_import" id="sidlist_import" + onClick="document.getElementById('uploader').style.display='table-row-group';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_import_alias.gif" width="17" + height="17" border="0" title="<?php echo gettext('Import/Upload a SID Mods List');?>"/> + <input type="image" name="sidlist_dnload_all" id="sidlist_dnload_all" + src="../tree/page-file_play.gif" width="16" height="16" border="0" + title="<?php echo gettext('Download all SID Mods List files in a single gzip archive');?>"/> + </th> + </tr> + </thead> + <tbody> + <?php foreach ($sidmodfiles as $file): ?> + <tr> + <td class="listr"><?php echo gettext($file); ?></td> + <td class="listr"><?=date('M-d Y g:i a', filemtime("{$sidmods_path}{$file}")); ?></td> + <td class="listr"><?=format_bytes(filesize("{$sidmods_path}{$file}")); ?> </td> + <td class="list"><input type="image" name="sidlist_edit[]" id="sidlist_edit[]" + onClick="document.getElementById('sidlist_fname').value='<?=$file;?>';" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" + height="17" border="0" title="<?php echo gettext('Edit this SID Mods List');?>"/> + <input type="image" name="sidlist_delete[]" id="sidlist_delete[]" + onClick="document.getElementById('sidlist_fname').value='<?=$file;?>'; + return confirm('<?=gettext("Are you sure you want to permanently delete this file? Click OK to continue or CANCEL to quit.");?>');" + src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" + height="17" border="0" title="<?php echo gettext('Delete this SID Mods List');?>"/> + <input type="image" name="sidlist_dnload[]" id="sidlist_dnload[]" + onClick="document.getElementById('sidlist_fname').value='<?=$file;?>';" + src="../tree/page-file_play.gif" width="16" height="16" border="0" + title="<?php echo gettext('Download this SID Mods List file');?>"/> + </td> + </tr> + <?php endforeach; ?> + </tbody> + <tbody id="sidlist_editor" style="<?=$sidmodlist_edit_style;?>"> + <tr> + <td colspan="4"> </td> + </tr> + <tr> + <td colspan="4"><strong><?=gettext("File Name: ");?></strong><input type="text" size="45" class="formfld file" id="sidlist_name" name="sidlist_name" value="<?=$sidmodlist_name;?>" /> + <input type="submit" id="save" name="save" value="<?=gettext(" Save ");?>" title="<?=gettext("Save changes and close editor");?>" /> + <input type="button" id="cancel" name="cancel" value="<?=gettext("Cancel");?>" onClick="document.getElementById('sidlist_editor').style.display='none';" + title="<?=gettext("Abandon changes and quit editor");?>" /></td> + </tr> + <tr> + <td colspan="4"> </td> + </tr> + <tr> + <td colspan="4"><textarea wrap="off" cols="80" rows="20" name="sidlist_data" id="sidlist_data" + style="width:95%; height:100%;"><?=$sidmodlist_data;?></textarea> + </td> + </tr> + </tbody> + <tbody> + <tr> + <td colspan="3" class="vexpl"><br/><span class="red"><strong><?php echo gettext("Note:"); ?></strong></span> + <br/><?php echo gettext("SID Mods Lists are stored as local files on the firewall and their contents are " . + "not saved as part of the firewall configuration file."); ?></td> + <td class="list"></td> + </tr> + <tr> + <td colspan="3" class="vexpl"><br/><strong><?php echo gettext("File List Controls:"); ?></strong><br/><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the editor window to create a new SID Mods List. You must provide a valid filename before saving.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_import_alias.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the file upload control for uploading a new SID Mods List from your local machine.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" width="17" height="17" border="0" /> + <?=gettext("Opens the SID Mods List in a text edit control for viewing or editing its contents.");?><br/> + <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" /> + <?=gettext("Deletes the SID Mods List from the file system after confirmation.");?><br/> + <img src="../tree/page-file_play.gif" width="16" height="16" border="0" /> + <?=gettext("Downloads the SID Mods List file to your local machine.");?><br/> + </td> + <td class="list"></td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Interface SID Management File Assignments"); ?></td> + </tr> + <tr> + <td colspan="2" class="vtable" align="center" > + <table width="100%" border="0" cellpadding="2" cellspacing="0"> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <colgroup> + <col width="4%" align="center"> + <col width="20" align="center"> + <col width="16%" align="center"> + <col width="20%" align="center"> + <col width="20%" align="center"> + <col width="20%" align="center"> + </colgroup> + <thead> + <tr> + <th class="listhdrr"><?=gettext("Rebuild"); ?></th> + <th class="listhdrr"><?=gettext("Interface"); ?></th> + <th class="listhdrr"><?=gettext("SID State Order"); ?></th> + <th class="listhdrr"><?=gettext("Enable SID File"); ?></th> + <th class="listhdrr"><?=gettext("Disable SID File"); ?></th> + <th class="listhdrr"><?=gettext("Modify SID File"); ?></th> + </tr> + </thead> + <tbody> + <?php foreach ($a_nat as $k => $natent): ?> + <tr> + <td class="listr" align="center"> + <input type="checkbox" name="torestart[]" id="torestart[]" value="<?=$k;?>" title="<?=gettext("Apply new configuration and rebuild rules for this interface when saving");?>" /> + </td> + <td class="listbg"><?=convert_friendly_interface_to_friendly_descr($natent['interface']); ?></td> + <td class="listr" align="center"> + <select name="sid_state_order[<?=$k?>]" class="formselect" id="sid_state_order[<?=$k?>]"> + <?php + foreach (array("disable_enable" => "Disable, Enable", "enable_disable" => "Enable, Disable") as $key => $order) { + if ($key == $natent['sid_state_order']) + echo "<option value='{$key}' selected>"; + else + echo "<option value='{$key}'>"; + echo htmlspecialchars($order) . '</option>'; + } + ?> + </select> + </td> + <td class="listr" align="center"> + <select name="enable_sid_file[<?=$k?>]" class="formselect" id="enable_sid_file[<?=$k?>]"> + <?php + foreach ($sidmodselections as $choice) { + if ($choice == $natent['enable_sid_file']) + echo "<option value='{$choice}' selected>"; + else + echo "<option value='{$choice}'>"; + echo htmlspecialchars(gettext($choice)) . '</option>'; + } + ?> + </select> + </td> + <td class="listr" align="center"> + <select name="disable_sid_file[<?=$k?>]" class="formselect" id="disable_sid_file[<?=$k?>]"> + <?php + foreach ($sidmodselections as $choice) { + if ($choice == $natent['disable_sid_file']) + echo "<option value='{$choice}' selected>"; + else + echo "<option value='{$choice}'>"; + echo htmlspecialchars(gettext($choice)) . '</option>'; + } + ?> + </select> + </td> + <td class="listr" align="center"> + <select name="modify_sid_file[<?=$k?>]" class="formselect" id="modify_sid_file[<?=$k?>]"> + <?php + foreach ($sidmodselections as $choice) { + if ($choice == $natent['modify_sid_file']) + echo "<option value='{$choice}' selected>"; + else + echo "<option value='{$choice}'>"; + echo htmlspecialchars(gettext($choice)) . '</option>'; + } + ?> + </select> + </td> + </tr> + <?php endforeach; ?> + </tbody> + </table> + </td> + </tr> + <tr> + <td class="vexpl"> + </td> + </tr> + <tr> + <td> + <table width="100%" cellpadding="2" cellspacing="2" border="0"> + <tbody> + <tr> + <td colspan="2" class="vexpl" style="text-align: bottom;"><strong><span class="red"><?=gettext("Notes:");?></span></strong></td> + </tr> + <tr> + <td class="vexpl" style="vertical-align: top;"><?=gettext("1.");?></td> + <td class="vexpl"><?=gettext("Check the box beside an interface to immediately apply new auto-SID management ") . + gettext("changes and signal Suricata to live-load the new rules for the interface when clicking SAVE; ") . + gettext("otherwise only the new file assignments will be saved.");?> + </td> + </tr> + <tr> + <td class="vexpl" style="vertical-align: top;"><?=gettext("2.");?></td> + <td class="vexpl"><?=gettext("SID State Order controls the order in which enable and disable state modifications are performed. ") . + gettext("An example would be to disable an entire category and later enable only a rule or two from it. In this case you would ") . + gettext("choose 'disable,enable' for the State Order. Note that the last action performed takes priority.");?> + </td> + </tr> + <tr> + <td class="vexpl" style="vertical-align: top;"><?=gettext("3.");?></td> + <td class="vexpl"><?=gettext("The Enable SID File, Disable SID File and Modify SID File controls specify which rule modification ") . + gettext("files are run automatically for the interface. Setting a file control to 'None' disables that modification. ") . + gettext("Setting all file controls for an interface to 'None' disables automatic SID state management for the interface.");?> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + <tbody> + <tr> + <td colspan="2" class="vexpl" align="center"><input type="submit" id="save_auto_sid_conf" name="save_auto_sid_conf" class="formbtn" value="<?=gettext("Save");?>" title="<?=gettext("Save SID Management configuration");?>" /> + <?=gettext("Remember to save changes before exiting this page"); ?> + </td> + </tr> + <?php endif; ?> + </tbody> + </table> + </div> + </td></tr> + </tbody> +</table> +</form> + + +<?php include("fend.inc"); ?> + +<?php if ($g['platform'] != "nanobsd") : ?> +<script type="text/javascript"> + +function enable_sid_conf() { + var endis = !document.iform.auto_manage_sids.checked; + if (endis) { + document.getElementById("sid_conf_rows").style.display = "none"; + } + else { + document.getElementById("sid_conf_rows").style.display = ""; + } +} + +enable_sid_conf(); + +</script> +<?php endif; ?> + +</body> +</html> diff --git a/config/suricata/suricata_suppress.php b/config/suricata/suricata_suppress.php index 4f2e8d0d..8fcb3dd5 100644 --- a/config/suricata/suricata_suppress.php +++ b/config/suricata/suricata_suppress.php @@ -94,15 +94,18 @@ function suricata_find_suppresslist_interface($supplist) { return false; } -if ($_GET['act'] == "del") { - if ($a_suppress[$_GET['id']]) { +if ($_POST['del'] && is_numericint($_POST['list_id'])) { + if ($a_suppress[$_POST['list_id']]) { // make sure list is not being referenced by any Suricata-configured interface - if (suricata_suppresslist_used($a_suppress[$_GET['id']]['name'])) { + if (suricata_suppresslist_used($a_suppress[$_POST['list_id']]['name'])) { $input_errors[] = gettext("ERROR -- Suppress List is currently assigned to an interface and cannot be removed!"); } else { - unset($a_suppress[$_GET['id']]); - write_config(); + unset($a_suppress[$_POST['list_id']]); + write_config("Suricata pkg: deleted SUPPRESS LIST."); + conf_mount_rw(); + sync_suricata_package_config(); + conf_mount_ro(); header("Location: /suricata/suricata_suppress.php"); exit; } @@ -126,19 +129,24 @@ if ($input_errors) { ?> <form action="/suricata/suricata_suppress.php" method="post"><?php if ($savemsg) print_info_box($savemsg); ?> +<input type="hidden" name="list_id" id="list_id" value=""/> <table width="100%" border="0" cellpadding="0" cellspacing="0"> +<tbody> <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), true, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td> @@ -172,6 +180,7 @@ if ($input_errors) { </td> <td height="20px" valign="middle" nowrap class="list"> <table border="0" cellspacing="0" cellpadding="1"> + <tbody> <tr> <td valign="middle"><a href="suricata_suppress_edit.php?id=<?=$i;?>"><img @@ -185,13 +194,12 @@ if ($input_errors) { width="17" height="17" border="0" title="<?php echo gettext("Goto first instance associated with this Suppress List");?>"/></a> </td> <?php else : ?> - <td><a href="/suricata/suricata_suppress.php?act=del&id=<?=$i;?>" - onclick="return confirm('<?php echo gettext("Do you really want to delete this Suppress List?"); ?>')"><img - src="/themes/<?=$g['theme'];?>/images/icons/icon_x.gif" - width="17" height="17" border="0" title="<?php echo gettext("delete Suppress List"); ?>"></a></td> + <td><input type="image" name="del[]" onclick="document.getElementById('list_id').value='<?=$i;?>';return confirm('<?=gettext("Do you really want to delete this Suppress List?");?>');" + src="/themes/<?=$g['theme'];?>/images/icons/icon_x.gif" width="17" height="17" border="0" title="<?=gettext("delete Suppress List");?>"/></td> <td> </td> <?php endif; ?> </tr> + </tbody> </table> </td> </tr> @@ -200,6 +208,7 @@ if ($input_errors) { <td class="list" colspan="2"></td> <td class="list"> <table border="0" cellspacing="0" cellpadding="1"> + <tbody> <tr> <td valign="middle" width="17"> </td> <td valign="middle"><a @@ -207,6 +216,7 @@ if ($input_errors) { src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" title="<?php echo gettext("add a new list"); ?>"></a></td> </tr> + </tbody> </table> </td> </tr> @@ -224,6 +234,7 @@ if ($input_errors) { gettext("You must first unassign the Suppress List on the Interface Edit tab."); ?> </p></span></td> </tr> +</tbody> </table> </form> <?php include("fend.inc"); ?> diff --git a/config/suricata/suricata_suppress_edit.php b/config/suricata/suricata_suppress_edit.php index a46e9e99..8814d3db 100644 --- a/config/suricata/suricata_suppress_edit.php +++ b/config/suricata/suricata_suppress_edit.php @@ -88,7 +88,12 @@ if ($_POST['save']) { $reqdfields = explode(" ", "name"); $reqdfieldsn = array("Name"); - do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); + + $pf_version=substr(trim(file_get_contents("/etc/version")),0,3); + if ($pf_version < 2.1) + $input_errors = eval('do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors); return $input_errors;'); + else + do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); if(strtolower($_POST['name']) == "defaultwhitelist") $input_errors[] = "Whitelist file names may not be named defaultwhitelist."; @@ -152,15 +157,18 @@ if ($savemsg) <tr><td> <?php $tab_array = array(); - $tab_array[] = array(gettext("Suricata Interfaces"), false, "/suricata/suricata_interfaces.php"); + $tab_array[] = array(gettext("Interfaces"), false, "/suricata/suricata_interfaces.php"); $tab_array[] = array(gettext("Global Settings"), false, "/suricata/suricata_global.php"); - $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php"); + $tab_array[] = array(gettext("Updates"), false, "/suricata/suricata_download_updates.php"); $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php"); - $tab_array[] = array(gettext("Blocked"), false, "/suricata/suricata_blocked.php"); + $tab_array[] = array(gettext("Blocks"), false, "/suricata/suricata_blocked.php"); $tab_array[] = array(gettext("Pass Lists"), false, "/suricata/suricata_passlist.php"); $tab_array[] = array(gettext("Suppress"), true, "/suricata/suricata_suppress.php"); - $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php"); + $tab_array[] = array(gettext("Logs View"), false, "/suricata/suricata_logs_browser.php"); $tab_array[] = array(gettext("Logs Mgmt"), false, "/suricata/suricata_logs_mgmt.php"); + $tab_array[] = array(gettext("SID Mgmt"), false, "/suricata/suricata_sid_mgmt.php"); + $tab_array[] = array(gettext("Sync"), false, "/pkg_edit.php?xml=suricata/suricata_sync.xml"); + $tab_array[] = array(gettext("IP Lists"), false, "/suricata/suricata_ip_list_mgmt.php"); display_top_tabs($tab_array, true); ?> </td></tr> diff --git a/config/suricata/suricata_sync.xml b/config/suricata/suricata_sync.xml new file mode 100644 index 00000000..28083d8d --- /dev/null +++ b/config/suricata/suricata_sync.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE packagegui SYSTEM "./schema/packages.dtd"> +<?xml-stylesheet type="text/xsl" href="./xsl/package.xsl"?> +<packagegui> + <copyright> +<![CDATA[ +/* $Id$ */ +/* ========================================================================== */ +/* +based on snortsync.xml developed as part +of pfSense (http://www.pfSense.com) +Copyright (C) 2013 Marcello Coutinho +based on pfblocker_sync.xml +All rights reserved. + +modified for use with Suricata package +Copyright (C) 2014 Bill Meeks +All rights reserved. + +Based on m0n0wall (http://m0n0.ch/wall) +Copyright (C) 2003-2006 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. +*/ +/* ========================================================================== */ +]]></copyright> + <description><![CDATA[Describe your package here]]></description> + <requirements>Describe your package requirements here</requirements> + <faq>Currently there are no FAQ items provided.</faq> + <name>suricatasync</name> + <version>1.0</version> + <title>Suricata: XMLRPC Sync</title> + <include_file>/usr/local/pkg/suricata/suricata.inc</include_file> + <tabs> + <tab> + <text>Interfaces</text> + <url>/suricata/suricata_interfaces.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Global Settings</text> + <url>/suricata/suricata_global.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Updates</text> + <url>/suricata/suricata_download_updates.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Alerts</text> + <url>/suricata/suricata_alerts.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Blocks</text> + <url>/suricata/suricata_blocked.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Pass Lists</text> + <url>/suricata/suricata_passlist.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Suppress</text> + <url>/suricata/suricata_suppress.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Logs View</text> + <url>/suricata/suricata_logs_browser.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Logs Mgmt</text> + <url>/suricata/suricata_logs_mgmt.php</url> + <no_drop_down/> + </tab> + <tab> + <text>SID Mgmt</text> + <url>/suricata/suricata_sid_mgmt.php</url> + <no_drop_down/> + </tab> + <tab> + <text>Sync</text> + <url>/pkg_edit.php?xml=suricata/suricata_sync.xml</url> + <no_drop_down/> + <active/> + </tab> + <tab> + <text>IP Lists</text> + <url>/suricata/suricata_ip_list_mgmt.php</url> + <no_drop_down/> + </tab> + </tabs> + <fields> + <field> + <name>Suricata Package XMLRPC Sync Settings</name> + <type>listtopic</type> + </field> + <field> + <fielddescr>Enable Sync</fielddescr> + <fieldname>varsynconchanges</fieldname> + <description><![CDATA[All changes will be synced with apply config to the IPs listed below if this option is checked.<br/><br/> + <b>Important:</b> While using "Sync to hosts defined below", only sync from host A to B, A to C but <b>do not</B> enable XMLRPC sync <b>to</b> A. This will result in a loop!]]></description> + <type>select</type> + <required/> + <default_value>disabled</default_value> + <options> + <option><name>Sync to configured system backup server</name><value>auto</value></option> + <option><name>Sync to host(s) defined below</name><value>manual</value></option> + <option><name>Do not sync this package configuration</name><value>disabled</value></option> + </options> + </field> + <field> + <fielddescr>XMLRPC Timeout</fielddescr> + <fieldname>varsynctimeout</fieldname> + <description><![CDATA[Timeout in seconds for the XMLRPC timeout. Default: 150]]></description> + <type>input</type> + <default_value>150</default_value> + <size>5</size> + </field> + + <field> + <fielddescr>Refresh Rule Sets</fielddescr> + <fieldname>vardownloadrules</fieldname> + <description><![CDATA[Ask target hosts to refresh rule sets files on each sync operation.<br/><br/> + During each Suricata package sync operation, ask the target remote host to check for + a new set of posted rule sets files and refresh the local copies if necessary. The default is + to refresh the files if newer versions have been posted.<br/><br/> + <b>Note: </b>The sync process will wait for the rules download and rebuild to finish on the target remote host before returning.]]></description> + <type>select</type> + <default_value>yes</default_value> + <options> + <option><name>Signal target host to refresh rules files</name><value>yes</value></option> + <option><name>Do NOT ask target host to refresh rules files</name><value>no</value></option> + </options> + </field> + + <field> + <fielddescr>Replication Targets</fielddescr> + <fieldname>none</fieldname> + <type>rowhelper</type> + <rowhelper> + <rowhelperfield> + <fielddescr>Enable</fielddescr> + <fieldname>varsyncdestinenable</fieldname> + <description><![CDATA[Enable this host as a replication target]]></description> + <type>checkbox</type> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Protocol</fielddescr> + <fieldname>varsyncprotocol</fieldname> + <description><![CDATA[Choose the protocol of the destination host. Probably <b>http</b> or <b>https</b>]]></description> + <type>select</type> + <default_value>HTTP</default_value> + <options> + <option><name>HTTP</name><value>http</value></option> + <option><name>HTTPS</name><value>https</value></option> + </options> + </rowhelperfield> + <rowhelperfield> + <fielddescr>IP-Address</fielddescr> + <fieldname>varsyncipaddress</fieldname> + <description><![CDATA[IP Address of the destination host.]]></description> + <type>input</type> + <size>15</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Port</fielddescr> + <fieldname>varsyncport</fieldname> + <description><![CDATA[Choose the sync port of the destination host.]]></description> + <type>input</type> + <size>3</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Admin Password</fielddescr> + <fieldname>varsyncpassword</fieldname> + <description><![CDATA[Password of the user "admin" on the destination host.]]></description> + <type>password</type> + <size>20</size> + </rowhelperfield> + <rowhelperfield> + <fielddescr>Start Suricata</fielddescr> + <fieldname>varsyncsuricatastart</fieldname> + <description><![CDATA[Start Suricata on target host if not already running.]]></description> + <type>checkbox</type> + <value>ON</value> + </rowhelperfield> + </rowhelper> + </field> + </fields> + <custom_delete_php_command> + </custom_delete_php_command> + <custom_php_resync_config_command> + write_config("Suricata pkg: updating CARP sync info.");suricata_sync_on_changes(); + </custom_php_resync_config_command> +</packagegui> diff --git a/config/suricata/suricata_uninstall.php b/config/suricata/suricata_uninstall.php index 2317578e..c8048a1c 100644 --- a/config/suricata/suricata_uninstall.php +++ b/config/suricata/suricata_uninstall.php @@ -44,9 +44,12 @@ global $config, $g; $suricatadir = SURICATADIR; $suricatalogdir = SURICATALOGDIR; +$sidmodspath = SURICATA_SID_MODS_PATH; +$iprep_path = SURICATA_IPREP_PATH; $rcdir = RCFILEPREFIX; -$suricata_rules_upd_log = RULES_UPD_LOGFILE; +$suricata_rules_upd_log = SURICATA_RULES_UPD_LOGFILE; $suri_pf_table = SURICATA_PF_TABLE; +$mounted_rw = FALSE; log_error(gettext("[Suricata] Suricata package uninstall in progress...")); @@ -58,7 +61,7 @@ killbyname("suricata"); sleep(1); // Delete any leftover suricata PID files in /var/run -array_map('@unlink', glob("/var/run/suricata_*.pid")); +unlink_if_exists("{$g['varrun_path']}/suricata_*.pid"); /* Make sure all active Barnyard2 processes are terminated */ /* Log a message only if a running process is detected */ @@ -68,26 +71,35 @@ killbyname("barnyard2"); sleep(1); // Delete any leftover barnyard2 PID files in /var/run -array_map('@unlink', glob("/var/run/barnyard2_*.pid")); - -/* Remove the suricata user and group */ -mwexec('/usr/sbin/pw userdel suricata; /usr/sbin/pw groupdel suricata', true); +unlink_if_exists("{$g['varrun_path']}/barnyard2_*.pid"); /* Remove the Suricata cron jobs. */ -install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/www/suricata/suricata_check_for_rule_updates.php", false); -install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_check_cron_misc.inc", false); -install_cron_job("pfctl -t {$suri_pf_table} -T expire" , false); +install_cron_job("suricata_check_for_rule_updates.php", false); +install_cron_job("suricata_check_cron_misc.inc", false); +install_cron_job("{$suri_pf_table}" , false); +install_cron_job("suricata_geoipupdate.php" , false); +install_cron_job("suricata_etiqrisk_update.php", false); /* See if we are to keep Suricata log files on uninstall */ if ($config['installedpackages']['suricata']['config'][0]['clearlogs'] == 'on') { log_error(gettext("[Suricata] Clearing all Suricata-related log files...")); - @unlink("{$suricata_rules_upd_log}"); - mwexec("/bin/rm -rf {$suricatalogdir}"); + unlink_if_exists("{$suricata_rules_upd_log}"); + rmdir_recursive("{$suricatalogdir}"); +} + +/**************************************************/ +/* If not already, set Suricata conf partition to */ +/* read-write so we can make changes there */ +/**************************************************/ +if (!is_subsystem_dirty('mount')) { + conf_mount_rw(); + $mounted_rw = TRUE; } /* Remove the Suricata GUI app directories */ -mwexec("/bin/rm -rf /usr/local/pkg/suricata"); -mwexec("/bin/rm -rf /usr/local/www/suricata"); +rmdir_recursive("/usr/local/pkg/suricata"); +rmdir_recursive("/usr/local/www/suricata"); +rmdir_recursive("/usr/local/etc/suricata"); /* Remove our associated Dashboard widget config and files. */ /* If "save settings" is enabled, then save old widget */ @@ -108,19 +120,26 @@ if (!empty($widgets)) { } } $config['widgets']['sequence'] = implode(",", $widgetlist); - write_config(); } -@unlink("/usr/local/www/widgets/include/widget-suricata.inc"); -@unlink("/usr/local/www/widgets/widgets/suricata_alerts.widget.php"); -@unlink("/usr/local/www/widgets/javascript/suricata_alerts.js"); +unlink_if_exists("/usr/local/www/widgets/include/widget-suricata.inc"); +unlink_if_exists("/usr/local/www/widgets/widgets/suricata_alerts.widget.php"); +unlink_if_exists("/usr/local/www/widgets/javascript/suricata_alerts.js"); + +/*******************************************************/ +/* We're finished with conf partition mods, return to */ +/* read-only if we changed it */ +/*******************************************************/ +if ($mounted_rw == TRUE) + conf_mount_ro(); /* Keep this as a last step */ if ($config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] != 'on') { log_error(gettext("Not saving settings... all Suricata configuration info and logs deleted...")); unset($config['installedpackages']['suricata']); unset($config['installedpackages']['suricatasync']); - @unlink("{$suricata_rules_upd_log}"); - mwexec("/bin/rm -rf {$suricatalogdir}"); + unlink_if_exists("{$suricata_rules_upd_log}"); + rmdir_recursive("{$suricatalogdir}"); + rmdir_recursive("{$g['vardb_path']}/suricata"); log_error(gettext("[Suricata] The package has been removed from this system...")); } diff --git a/config/suricata/suricata_yaml_template.inc b/config/suricata/suricata_yaml_template.inc index c20ca8db..a8b06ebe 100644 --- a/config/suricata/suricata_yaml_template.inc +++ b/config/suricata/suricata_yaml_template.inc @@ -15,6 +15,10 @@ max-pending-packets: {$max_pend_pkts} # Runmode the engine should use. runmode: autofp +# If set to auto, the variable is internally switched to 'router' in IPS +# mode and 'sniffer-only' in IDS mode. +host-mode: auto + # Specifies the kind of flow load balancer used by the flow pinned autofp mode. autofp-scheduler: active-packets @@ -29,7 +33,7 @@ default-log-dir: {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} # Configure the type of alert (and other) logging. outputs: - # alert_pf blocking plugin + # alert-pf blocking plugin - alert-pf: enabled: {$suri_blockoffenders} kill-state: {$suri_killstates} @@ -55,9 +59,7 @@ outputs: enabled: {$http_log_enabled} filename: http.log append: {$http_log_append} - #extended: yes # enable this for extended logging information - #custom: yes # enabled the custom logging format (defined by customformat) - #customformat: "%{%D-%H:%M:%S}t.%z %{X-Forwarded-For}i %H %m %h %u %s %B %a:%p -> %A:%P" + extended: {$http_log_extended} filetype: regular - pcap-log: @@ -82,8 +84,8 @@ outputs: - syslog: enabled: {$alert_syslog} identity: suricata - facility: auth - level: Info + facility: {$alert_syslog_facility} + level: {$alert_syslog_priority} - drop: enabled: no @@ -94,8 +96,8 @@ outputs: - file-store: enabled: {$file_store_enabled} log-dir: files - force-magic: no - force-md5: no + force-magic: {$json_log_magic} + force-md5: {$json_log_md5} waldo: file.waldo - file-log: @@ -106,6 +108,21 @@ outputs: force-magic: {$json_log_magic} force-md5: {$json_log_md5} + - dns-log: + enabled: {$dns_log_enabled} + filename: dns.log + append: {$dns_log_append} + filetype: regular + + - eve-log: + enabled: {$enable_eve_log} + type: {$eve_output_type} + filename: eve.json + identity: "suricata" + facility: {$eve_systemlog_facility} + level: {$eve_systemlog_priority} + types: {$eve_out_types} + # Magic file. The extension .mgc is added to the value here. magic-file: /usr/share/misc/magic @@ -208,9 +225,9 @@ reassembly: # Host table is used by tagging and per host thresholding subsystems. host: - hash-size: 4096 - prealloc: 1000 - memcap: 16777216 + hash-size: {$host_hash_size} + prealloc: {$host_prealloc} + memcap: {$host_memcap} # Host specific policies for defragmentation and TCP stream reassembly. host-os-policy: @@ -233,12 +250,13 @@ logging: filename: {$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/suricata.log - syslog: enabled: {$suricata_use_syslog} - facility: auth + facility: {$suricata_use_syslog_facility} format: "[%i] <%d> -- " pcap: - interface: {$if_real} checksum-checks: auto + promisc: {$intf_promisc_mode} # For FreeBSD ipfw(8) divert(4) support. # ipfw add 100 divert 8000 ip from any to any @@ -268,18 +286,14 @@ vars: port-groups: {$port_vars} -# Set the order of alerts bassed on actions +# Set the order of alerts based on actions action-order: - pass - drop - reject - alert -# IP Reputation -#reputation-categories-file: {$suricatacfgdir}/iprep/categories.txt -#default-reputation-path: {$suricatacfgdir}/iprep -#reputation-files: -# - reputation.list +{$iprep_config} # Limit for the maximum number of asn1 frames to decode (default 256) asn1-max-frames: {$asn1_max_frames} @@ -293,6 +307,47 @@ pcre: match-limit: 3500 match-limit-recursion: 1500 +# Holds details on the app-layer. The protocols section details each protocol. +app-layer: + protocols: + tls: + enabled: {$tls_parser} + detection-ports: + dp: 443 + #no-reassemble: yes + dcerpc: + enabled: {$dcerpc_parser} + ftp: + enabled: {$ftp_parser} + ssh: + enabled: {$ssh_parser} + smtp: + enabled: {$smtp_parser} + imap: + enabled: {$imap_parser} + msn: + enabled: {$msn_parser} + smb: + enabled: {$smb_parser} + detection-ports: + dp: 139 + dns: + global-memcap: {$dns_global_memcap} + state-memcap: {$dns_state_memcap} + request-flood: {$dns_request_flood_limit} + + tcp: + enabled: {$dns_parser_tcp} + detection-ports: + dp: 53 + udp: + enabled: {$dns_parser_udp} + detection-ports: + dp: 53 + http: + enabled: {$http_parser} + memcap: {$http_parser_memcap} + ########################################################################### # Configure libhtp. libhtp: |