aboutsummaryrefslogtreecommitdiffstats
path: root/config/suricata
diff options
context:
space:
mode:
Diffstat (limited to 'config/suricata')
-rw-r--r--config/suricata/suricata.inc2014
-rw-r--r--config/suricata/suricata.priv.inc45
-rw-r--r--config/suricata/suricata.xml236
-rw-r--r--config/suricata/suricata_alerts.php578
-rw-r--r--config/suricata/suricata_app_parsers.php303
-rw-r--r--config/suricata/suricata_barnyard.php503
-rw-r--r--config/suricata/suricata_check_cron_misc.inc109
-rw-r--r--config/suricata/suricata_check_for_rule_updates.php683
-rw-r--r--config/suricata/suricata_define_vars.php268
-rw-r--r--config/suricata/suricata_download_rules.php97
-rw-r--r--config/suricata/suricata_download_updates.php220
-rw-r--r--config/suricata/suricata_flow_stream.php644
-rw-r--r--config/suricata/suricata_generate_yaml.php515
-rw-r--r--config/suricata/suricata_global.php456
-rw-r--r--config/suricata/suricata_import_aliases.php272
-rw-r--r--config/suricata/suricata_interfaces.php474
-rw-r--r--config/suricata/suricata_interfaces_edit.php911
-rw-r--r--config/suricata/suricata_libhtp_policy_engine.php314
-rw-r--r--config/suricata/suricata_list_view.php100
-rw-r--r--config/suricata/suricata_logs_browser.php217
-rw-r--r--config/suricata/suricata_os_policy_engine.php261
-rw-r--r--config/suricata/suricata_post_install.php132
-rw-r--r--config/suricata/suricata_rules.php790
-rw-r--r--config/suricata/suricata_rules_edit.php154
-rw-r--r--config/suricata/suricata_rules_flowbits.php306
-rw-r--r--config/suricata/suricata_rulesets.php596
-rw-r--r--config/suricata/suricata_select_alias.php226
-rw-r--r--config/suricata/suricata_suppress.php172
-rw-r--r--config/suricata/suricata_suppress_edit.php213
-rw-r--r--config/suricata/suricata_uninstall.php90
-rw-r--r--config/suricata/suricata_yaml_template.inc302
31 files changed, 12201 insertions, 0 deletions
diff --git a/config/suricata/suricata.inc b/config/suricata/suricata.inc
new file mode 100644
index 00000000..b87e2f6a
--- /dev/null
+++ b/config/suricata/suricata.inc
@@ -0,0 +1,2014 @@
+<?php
+/*
+ suricata.inc
+
+ 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("pfsense-utils.inc");
+require_once("config.inc");
+require_once("functions.inc");
+require_once("services.inc");
+require_once("service-utils.inc");
+require_once("pkg-utils.inc");
+require_once("filter.inc");
+
+global $g, $config;
+
+if (!is_array($config['installedpackages']['suricata']))
+ $config['installedpackages']['suricata'] = array();
+
+// 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-');
+
+function suricata_generate_id() {
+ global $config;
+
+ $suricatacfg = $config['installedpackages']['suricata']['rule'];
+ while (true) {
+ $suricata_uuid = mt_rand(1, 65535);
+ foreach ($suricatacfg as $value) {
+ if ($value['uuid'] == $suricata_uuid)
+ continue 2;
+ }
+ break;
+ }
+
+ return $suricata_uuid;
+}
+
+function suricata_is_running($suricata_uuid, $if_real, $type = 'suricata') {
+ global $config, $g;
+
+ if (isvalidpid("{$g['varrun_path']}/{$type}_{$if_real}{$suricata_uuid}.pid"))
+ return 'yes';
+ else
+ return 'no';
+}
+
+function suricata_barnyard_stop($suricatacfg, $if_real) {
+ global $config, $g;
+
+ $suricata_uuid = $suricatacfg['uuid'];
+ if (isvalidpid("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid")) {
+ log_error("[Suricata] Barnyard2 STOP for {$suricatacfg['descr']}({$if_real})...");
+ killbypid("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid");
+ }
+}
+
+function suricata_stop($suricatacfg, $if_real) {
+ global $config, $g;
+
+ $suricata_uuid = $suricatacfg['uuid'];
+ if (isvalidpid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid")) {
+ log_error("[Suricata] Suricata STOP for {$suricatacfg['descr']}({$if_real})...");
+ killbypid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid");
+ sleep(2);
+
+ // For some reason Suricata seems to need a double TERM signal to actually shutdown
+ if (isvalidpid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid"))
+ killbypid("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid");
+ }
+ // Stop Barnyard2 on the interface if running
+ suricata_barnyard_stop($suricatacfg, $if_real);
+}
+
+function suricata_barnyard_start($suricatacfg, $if_real) {
+ global $config, $g;
+
+ $suricata_uuid = $suricatacfg['uuid'];
+ $suricatadir = SURICATADIR . "suricata_{$suricata_uuid}_{$if_real}";
+ $suricatalogdir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}";
+
+ if ($suricatacfg['barnyard_enable'] == 'on') {
+ log_error("[Suricata] Barnyard2 START for {$suricatacfg['descr']}({$if_real})...");
+ exec("/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");
+ }
+}
+
+function suricata_start($suricatacfg, $if_real) {
+ global $config, $g;
+
+ $suricatadir = SURICATADIR;
+ $suricata_uuid = $suricatacfg['uuid'];
+
+ if ($suricatacfg['enable'] == 'on') {
+ log_error("[Suricata] Suricata START for {$suricatacfg['descr']}({$if_real})...");
+ exec("/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");
+ }
+ else
+ return;
+
+ // Start Barnyard2 if enabled on the interface
+ suricata_barnyard_start($suricatacfg, $if_real);
+}
+
+function suricata_reload_config($suricatacfg, $signal="USR2") {
+
+ /**************************************************************/
+ /* This function sends the passed SIGNAL to the Suricata */
+ /* instance on the passed interface to cause Suricata to */
+ /* reload and parse the running configuration without */
+ /* impacting packet processing. It also executes the reload */
+ /* as a background process and returns control immediately */
+ /* to the caller. */
+ /* */
+ /* $signal = USR2 (default) parses and reloads config. */
+ /**************************************************************/
+ global $config, $g;
+
+ $suricatadir = SURICATADIR;
+ $suricata_uuid = $suricatacfg['uuid'];
+ $if_real = suricata_get_real_interface($suricatacfg['interface']);
+
+ /******************************************************/
+ /* Only send the SIGUSR2 if Suricata is running and */
+ /* we can find a valid PID for the process. */
+ /******************************************************/
+ 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);
+// exec("/bin/pkill -{$signal} -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid 2>&1 &");
+ }
+}
+
+function suricata_barnyard_reload_config($suricatacfg, $signal="HUP") {
+
+ /**************************************************************/
+ /* This function sends the passed SIGNAL to the Barnyard2 */
+ /* instance on the passed interface to cause Barnyard to */
+ /* reload and parse the running configuration without */
+ /* impacting packet processing. It also executes the reload */
+ /* as a background process and returns control immediately */
+ /* to the caller. */
+ /* */
+ /* $signal = HUP (default) parses and reloads config. */
+ /**************************************************************/
+ global $config, $g;
+
+ $suricatadir = SURICATADIR;
+ $suricata_uuid = $suricatacfg['uuid'];
+ $if_real = suricata_get_real_interface($suricatacfg['interface']);
+
+ /******************************************************/
+ /* Only send the SIGHUP if Barnyard2 is running and */
+ /* we can find a valid PID for the process. */
+ /******************************************************/
+ 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);
+// exec("/bin/pkill -{$signal} -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid 2>&1 &");
+ }
+}
+
+function suricata_get_friendly_interface($interface) {
+
+ // Pass this directly to the system for now.
+ // Later, this wrapper will be removed and all
+ // the Suricata code changed to use the system call.
+ return convert_friendly_interface_to_friendly_descr($interface);
+}
+
+function suricata_get_real_interface($interface) {
+
+ // Pass this directly to the system for now.
+ // Later, this wrapper will be removed and all
+ // the Suricata code changed to use the system call.
+ return get_real_interface($interface);
+}
+
+function suricata_get_blocked_ips() {
+
+ // This is a placeholder function for later use.
+ // Blocking is not currently enabled in Suricata.
+ return array();
+}
+
+/* func builds custom white lists */
+function suricata_find_list($find_name, $type = 'whitelist') {
+ global $config;
+
+ $suricataglob = $config['installedpackages']['suricata'];
+ if (!is_array($suricataglob[$type]))
+ return "";
+ if (!is_array($suricataglob[$type]['item']))
+ return "";
+
+ foreach ($suricataglob[$type]['item'] as $value) {
+ if ($value['name'] == $find_name)
+ return $value;
+ }
+
+ return array();
+}
+
+function suricata_build_list($suricatacfg, $listname = "", $whitelist = false) {
+
+ /***********************************************************/
+ /* The default is to build a HOME_NET variable unless */
+ /* '$whitelist' is set to 'true' when calling. */
+ /***********************************************************/
+
+ global $config, $g, $aliastable, $filterdns;
+ $home_net = array();
+
+ if ($listname == 'default' || empty($listname)) {
+ $localnet = 'yes'; $wanip = 'yes'; $wangw = 'yes'; $wandns = 'yes'; $vips = 'yes'; $vpns = 'yes';
+ } else {
+ $list = suricata_find_list($listname);
+ if (empty($list))
+ return $list;
+ $localnet = $list['localnets'];
+ $wanip = $list['wanips'];
+ $wangw = $list['wangateips'];
+ $wandns = $list['wandnsips'];
+ $vips = $list['vips'];
+ $vpns = $list['vpnips'];
+ if (!empty($list['address']) && is_alias($list['address']))
+ $home_net = explode(" ", trim(filter_expand_alias($list['address'])));
+ }
+
+ // Always add loopback to HOME_NET and whitelist (ftphelper)
+ if (!in_array("127.0.0.1", $home_net))
+ $home_net[] = "127.0.0.1";
+
+ /********************************************************************/
+ /* Always put the interface running Suricata in HOME_NET and */
+ /* whitelist unless it's the WAN. WAN options are handled further */
+ /* down. If the user specifically chose not to include LOCAL_NETS */
+ /* in the WHITELIST, then do not include the Suricata interface */
+ /* subnet in the WHITELIST. 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 ($suricatacfg['interface'] <> "wan") {
+ $sn = get_interface_subnet($suricatacfg['interface']);
+ $ip = gen_subnet($suricataip, $sn) . "/{$sn}";
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+ }
+ else {
+ if (is_ipaddr($suricataip)) {
+ if (!in_array($suricataip, $home_net))
+ $home_net[] = $suricataip;
+ }
+ }
+
+ $suricataip = get_interface_ipv6($suricatacfg['interface']);
+ if (!$whitelist || $localnet == 'yes' || empty($localnet)) {
+ if (is_ipaddrv6($suricataip)) {
+ if ($suricatacfg['interface'] <> "wan") {
+ $sn = get_interface_subnetv6($suricatacfg['interface']);
+ $ip = gen_subnetv6($suricataip, $sn). "/{$sn}";
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+ }
+ else {
+ if (is_ipaddrv6($suricataip)) {
+ if (!in_array($suricataip, $home_net))
+ $home_net[] = $suricataip;
+ }
+ }
+
+ if (!$whitelist || $localnet == 'yes' || empty($localnet)) {
+ /*************************************************************************/
+ /* Iterate through the interface list and write out whitelist items and */
+ /* also compile a HOME_NET list of all the local interfaces for suricata. */
+ /* Skip the WAN interface as we do not typically want that whole subnet */
+ /* whitelisted (just the i/f IP itself which was handled earlier). */
+ /*************************************************************************/
+ $int_array = get_configured_interface_list();
+ foreach ($int_array as $int) {
+ if ($int == "wan")
+ continue;
+ $subnet = get_interface_ip($int);
+ if (is_ipaddr($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);
+ if (is_ipaddrv6($subnet)) {
+ $sn = get_interface_subnetv6($int);
+ $ip = gen_subnetv6($subnet, $sn). "/{$sn}";
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+ }
+
+ if ($wanip == 'yes') {
+ $ip = get_interface_ip("wan");
+ if (is_ipaddr($ip)) {
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ $ip = get_interface_ipv6("wan");
+ if (is_ipaddrv6($ip)) {
+ if (!in_array($ip, $home_net))
+ $home_net[] = $ip;
+ }
+ }
+
+ 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;
+
+ // 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;
+ $gw = get_interface_gateway_v6($suricatacfg['interface']);
+ if (is_ipaddrv6($gw) && !in_array($gw, $home_net))
+ $home_net[] = $gw;
+ }
+
+ if ($wandns == 'yes') {
+ // Add DNS server for WAN interface to whitelist
+ $dns_servers = get_dns_servers();
+ foreach ($dns_servers as $dns) {
+ if ($dns && !in_array($dns, $home_net))
+ $home_net[] = $dns;
+ }
+ }
+
+ if($vips == 'yes') {
+ // iterate all vips and add to whitelist
+ if (is_array($config['virtualip']) && is_array($config['virtualip']['vip'])) {
+ foreach($config['virtualip']['vip'] as $vip) {
+ if ($vip['subnet'] && $vip['mode'] != 'proxyarp') {
+ if (!in_array("{$vip['subnet']}/{$vip['subnet_bits']}", $home_net))
+ $home_net[] = "{$vip['subnet']}/{$vip['subnet_bits']}";
+ }
+ }
+ }
+ }
+
+ // grab a list of vpns and whitelist if user desires
+ if ($vpns == 'yes') {
+ $vpns_list = filter_get_vpns_list();
+ if (!empty($vpns_list)) {
+ // Convert the returned space-delimited string to an array
+ // and then add each VPN address to our HOME_NET array.
+ $vpns = explode(" ", $vpns_list);
+ foreach ($vpns as $vpn)
+ $home_net[] = trim($vpn);
+ unset($vpns, $vpns_list);
+ }
+ }
+
+ $valresult = array();
+ foreach ($home_net as $vald) {
+ if (empty($vald))
+ continue;
+ $vald = trim($vald);
+ if (empty($valresult[$vald]))
+ $valresult[$vald] = $vald;
+ }
+
+ // Release memory no longer required
+ unset($home_net);
+
+ // Sort the list and return it
+ natsort($valresult);
+ return $valresult;
+}
+
+function suricata_rules_up_install_cron($should_install) {
+ global $config, $g;
+
+ $command = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/www/suricata/suricata_check_for_rule_updates.php";
+
+ // Get auto-rule update parameter from configuration
+ $suricata_rules_up_info_ck = $config['installedpackages']['suricata']['config'][0]['autoruleupdate'];
+
+ // See if a customized start time has been set for rule file updates
+ if (!empty($config['installedpackages']['suricata']['config'][0]['autoruleupdatetime']))
+ $suricata_rules_upd_time = $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'];
+ else
+ $suricata_rules_upd_time = "00:03";
+
+ if ($suricata_rules_up_info_ck == "6h_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $hour = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_hr = strval($hour);
+ for ($i=0; $i<3; $i++) {
+ $hour += 6;
+ if ($hour > 24)
+ $hour -= 24;
+ $suricata_rules_up_hr .= "," . strval($hour);
+ }
+ $suricata_rules_up_mday = "*";
+ $suricata_rules_up_month = "*";
+ $suricata_rules_up_wday = "*";
+ }
+ if ($suricata_rules_up_info_ck == "12h_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $hour = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_hr = strval($hour) . ",";
+ $hour += 12;
+ if ($hour > 24)
+ $hour -= 24;
+ $suricata_rules_up_hr .= strval($hour);
+ $suricata_rules_up_mday = "*";
+ $suricata_rules_up_month = "*";
+ $suricata_rules_up_wday = "*";
+ }
+ if ($suricata_rules_up_info_ck == "1d_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_mday = "*/1";
+ $suricata_rules_up_month = "*";
+ $suricata_rules_up_wday = "*";
+ }
+ if ($suricata_rules_up_info_ck == "4d_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_mday = "*/4";
+ $suricata_rules_up_month = "*";
+ $suricata_rules_up_wday = "*";
+ }
+ if ($suricata_rules_up_info_ck == "7d_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_mday = "*/7";
+ $suricata_rules_up_month = "*";
+ $suricata_rules_up_wday = "*";
+ }
+ if ($suricata_rules_up_info_ck == "28d_up") {
+ $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2));
+ $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2));
+ $suricata_rules_up_mday = "*/28";
+ $suricata_rules_up_month = "*";
+ $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");
+}
+
+function suricata_loglimit_install_cron($should_install) {
+
+ install_cron_job("/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_check_cron_misc.inc", $should_install, "*/5");
+}
+
+function sync_suricata_package_config() {
+ global $config, $g;
+
+ $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();
+ return;
+ }
+
+ $suricataconf = $config['installedpackages']['suricata']['rule'];
+ foreach ($suricataconf as $value) {
+ $if_real = suricata_get_real_interface($value['interface']);
+
+ // 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);
+ }
+
+ // 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($suricataglob['suricataloglimit'] == 'on' ? true : false);
+ // setup the suricata rules update job if enabled
+ suricata_rules_up_install_cron($suricataglob['autoruleupdate'] != "never_up" ? 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();
+}
+
+function suricata_load_suppress_sigs($suricatacfg, $track_by=false) {
+
+ global $config;
+
+ /**********************************************************/
+ /* This function loads the GEN_ID and SIG_ID for all the */
+ /* suppressed alert entries from the Suppression List of */
+ /* the passed Suricata interface. The results are */
+ /* returned in an array with GEN_ID and SIG_ID as the */
+ /* primary keys. Any "track by_src" or "track by_dst" */
+ /* entries in the Suppression List are tacked on as */
+ /* additional keys in the array along with the IP address */
+ /* in either IPv4 or IPv6 format when $track_by is passed */
+ /* as true. */
+ /* */
+ /* Sample returned array: */
+ /* $suppress[1][2069] = "suppress" */
+ /* $suppress[1][2070]['by_src']['10.1.1.5'] = "suppress" */
+ /* $suppress[1][2070]['by_dst']['10.1.1.6'] = "suppress" */
+ /* */
+ /**********************************************************/
+
+ $suppress = array();
+
+ if (!is_array($config['installedpackages']['suricata']))
+ return;
+ if (!is_array($config['installedpackages']['suricata']['suppress']))
+ return;
+ if (!is_array($config['installedpackages']['suricata']['suppress']['item']))
+ return;
+ $a_suppress = $config['installedpackages']['suricata']['suppress']['item'];
+
+ foreach ($a_suppress as $a_id => $alist) {
+ if ($alist['name'] == $suricatacfg['suppresslistname']) {
+ if (!empty($alist['suppresspassthru'])) {
+ $tmplist = str_replace("\r", "", base64_decode($alist['suppresspassthru']));
+ $tmp = explode("\n", $tmplist);
+ foreach ($tmp as $line) {
+ // Skip any blank lines
+ if (trim($line, " \n") == "")
+ continue;
+ // Skip any comment lines
+ if (preg_match('/^\s*#/', $line))
+ continue;
+ /* See if entry suppresses GID:SID for all hosts */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+)\s*$/i', $line, $matches)) {
+ $genid = $matches[1];
+ $sigid = $matches[2];
+ if (!empty($genid) && !empty($sigid)) {
+ if (!is_array($suppress[$genid]))
+ $suppress[$genid] = array();
+ if (!is_array($suppress[$genid][$sigid]))
+ $suppress[$genid][$sigid] = array();
+ $suppress[$genid][$sigid] = "suppress";
+ }
+ }
+
+ /* Get "track by IP" entries if requested */
+ if ($track_by) {
+ /* See if entry suppresses only by SRC or DST IPv4 address */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s*$/i', $line, $matches)) {
+ $genid = $matches[1];
+ $sigid = $matches[2];
+ $whichip = trim($matches[3]);
+ $ip = $matches[4];
+ if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) {
+ if (!is_array($suppress[$genid]))
+ $suppress[$genid] = array();
+ if (!is_array($suppress[$genid][$sigid]))
+ $suppress[$genid][$sigid] = array();
+ if (!is_array($suppress[$genid][$sigid][$whichip]))
+ $suppress[$genid][$sigid][$whichip] = array();
+ if (!is_array($suppress[$genid][$sigid][$whichip][$ip]))
+ $suppress[$genid][$sigid][$whichip][$ip] = array();
+ $suppress[$genid][$sigid][$whichip][$ip] = "suppress";
+ }
+ }
+ /* See if entry suppresses only by SRC or DST IPv6 address */
+ if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*([0-9a-f\.:]+)\s*$/i', $line, $matches)) {
+ $genid = $matches[1];
+ $sigid = $matches[2];
+ $whichip = trim($matches[3]);
+ $ip = trim($matches[4]);
+ if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) {
+ if (!is_array($suppress[$genid]))
+ $suppress[$genid] = array();
+ if (!is_array($suppress[$genid][$sigid]))
+ $suppress[$genid][$sigid] = array();
+ if (!is_array($suppress[$genid][$sigid][$whichip]))
+ $suppress[$genid][$sigid][$whichip] = array();
+ if (!is_array($suppress[$genid][$sigid][$whichip][$ip]))
+ $suppress[$genid][$sigid][$whichip][$ip] = array();
+ $suppress[$genid][$sigid][$whichip][$ip] = "suppress";
+ }
+ }
+ }
+ }
+ unset($tmp);
+ }
+ break;
+ }
+ }
+ unset($alist);
+ return $suppress;
+}
+
+function suricata_post_delete_logs($suricata_uuid = 0) {
+
+ /***********************************************/
+ /* This function cleans up related log files */
+ /* for the passed instance. These include */
+ /* Barnyard2 unified2 logs and pcap logs. */
+ /***********************************************/
+
+ global $config, $g;
+
+ // do nothing if no Suricata interfaces active
+ if (!is_array($config['installedpackages']['suricata']['rule']))
+ return;
+
+ foreach ($config['installedpackages']['suricata']['rule'] as $value) {
+ if ($value['uuid'] != $suricata_uuid)
+ continue;
+ $if_real = suricata_get_real_interface($value['interface']);
+ $suricata_log_dir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}";
+
+ if ($if_real != '') {
+ /* Clean-up Barnyard2 files if any exist */
+ $filelist = glob("{$suricata_log_dir}/unified2.alert.*");
+ // Keep most recent file
+ unset($filelist[count($filelist) - 1]);
+ foreach ($filelist as $file)
+ @unlink($file);
+
+ /* Clean-up Barnyard2 archived files if any exist */
+ $filelist = glob("{$suricata_log_dir}/barnyard2/archive/unified2.alert.*");
+ foreach ($filelist as $file)
+ @unlink($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);
+ unset($filelist);
+ }
+ }
+}
+
+/* This returns size of passed directory or file in 1024-byte blocks */
+function suricata_Getdirsize($node) {
+ if(!is_readable($node))
+ return false;
+
+ $blah = exec( "/usr/bin/du -kdc $node" );
+ return substr( $blah, 0, strpos($blah, 9) );
+}
+
+function suricata_build_sid_msg_map($rules_path, $sid_file) {
+
+ /*************************************************************/
+ /* This function reads all the rules file in the passed */
+ /* $rules_path variable and produces a properly formatted */
+ /* sid-msg.map file for use by Suricata and/or barnyard2. */
+ /*************************************************************/
+
+ $sidMap = array();
+ $rule_files = array();
+
+ // First check if we were passed a directory, a single file
+ // or an array of filenames to read. Set our $rule_files
+ // variable accordingly. If we can't figure it out, return
+ // and don't write a sid_msg_map file.
+ if (is_string($rules_path)) {
+ if (is_dir($rules_path))
+ $rule_files = glob($rules_path . "*.rules");
+ elseif (is_file($rules_path))
+ $rule_files = (array)$rules_path;
+ }
+ elseif (is_array($rules_path))
+ $rule_files = $rules_path;
+ else
+ return;
+
+ // Read the rule files into an array, then iterate the list
+ foreach ($rule_files as $file) {
+
+ // Don't process files with "deleted" in the filename
+ if (stristr($file, "deleted"))
+ continue;
+
+ // Read the file into an array, skipping missing files.
+ if (!file_exists($file))
+ continue;
+
+ $rules_array = file($file, FILE_SKIP_EMPTY_LINES);
+ $record = "";
+ $b_Multiline = false;
+
+ // Read and process each line from the rules in the current file
+ foreach ($rules_array as $rule) {
+
+ // Skip any non-rule lines unless we're in multiline mode.
+ if (!preg_match('/^\s*#*\s*(alert|drop|pass)/i', $rule) && !$b_Multiline)
+ continue;
+
+ // Test for a multi-line rule, and reassemble the
+ // pieces back into a single line.
+ if (preg_match('/\\\\s*[\n]$/m', $rule)) {
+ $rule = substr($rule, 0, strrpos($rule, '\\'));
+ $record .= $rule;
+ $b_Multiline = true;
+ continue;
+ }
+ // If the last segment of a multiline rule, then
+ // append it onto the previous parts to form a
+ // single-line rule for further processing below.
+ elseif (!preg_match('/\\\\s*[\n]$/m', $rule) && $b_Multiline) {
+ $record .= $rule;
+ $rule = $record;
+ }
+ $b_Multiline = false;
+ $record = "";
+
+ // Parse the rule to find sid and any references.
+ $sid = '';
+ $msg = '';
+ $matches = '';
+ $sidEntry = '';
+ if (preg_match('/\bmsg\s*:\s*"(.+?)"\s*;/i', $rule, $matches))
+ $msg = trim($matches[1]);
+ if (preg_match('/\bsid\s*:\s*(\d+)\s*;/i', $rule, $matches))
+ $sid = trim($matches[1]);
+ if (!empty($sid) && !empty($msg)) {
+ $sidEntry = $sid . ' || ' . $msg;
+ preg_match_all('/\breference\s*:\s*([^\;]+)/i', $rule, $matches);
+ foreach ($matches[1] as $ref)
+ $sidEntry .= " || " . trim($ref);
+ $sidEntry .= "\n";
+ if (!is_array($sidMap[$sid]))
+ $sidMap[$sid] = array();
+ $sidMap[$sid] = $sidEntry;
+ }
+ }
+ }
+ // Sort the generated sid-msg map by sid
+ ksort($sidMap);
+
+ // Now print the result to the supplied file
+ @file_put_contents($sid_file, array_values($sidMap));
+}
+
+function suricata_merge_reference_configs($cfg_in, $cfg_out) {
+
+ /***********************************************************/
+ /* This function takes a list of "reference.config" files */
+ /* in the $cfg_in array and merges them into a single */
+ /* file specified by $cfg_out. The merging is done so */
+ /* no duplication of lines occurs in the output file. */
+ /***********************************************************/
+
+ $outMap = array();
+ foreach ($cfg_in as $file) {
+ if (!file_exists($file))
+ continue;
+ $in = file($file, FILE_SKIP_EMPTY_LINES);
+ foreach ($in as $line) {
+ /* Skip comment lines */
+ if (preg_match('/^\s*#/', $line))
+ continue;
+ if (preg_match('/(\:)\s*(\w+)\s*(.*)/', $line, $matches)) {
+ if (!empty($matches[2]) && !empty($matches[3])) {
+ $matches[2] = trim($matches[2]);
+ if (!array_key_exists($matches[2], $outMap)) {
+ if (!is_array($outMap[$matches[2]]))
+ $outMap[$matches[2]] = array();
+ $outMap[$matches[2]] = trim($matches[3]);
+ }
+ }
+ }
+ }
+ }
+ // Sort the new reference map.
+ uksort($outMap,'strnatcasecmp');
+
+ // Do NOT write an empty references.config file, just
+ // exit instead.
+ if (empty($outMap))
+ return false;
+
+ // Format and write it to the supplied output file.
+ $format = "config reference: %-12s %s\n";
+ foreach ($outMap as $key=>$value)
+ $outMap[$key] = sprintf($format, $key, $value);
+ @file_put_contents($cfg_out, array_values($outMap));
+ return true;
+}
+
+function suricata_merge_classification_configs($cfg_in, $cfg_out) {
+
+ /************************************************************/
+ /* This function takes a list of "classification.config" */
+ /* files in the $cfg_in array and merges them into a */
+ /* single file specified by $cfg_out. The merging is done */
+ /* so no duplication of lines occurs in the output file. */
+ /************************************************************/
+
+ $outMap = array();
+ foreach ($cfg_in as $file) {
+ if (!file_exists($file))
+ continue;
+ $in = file($file, FILE_SKIP_EMPTY_LINES);
+ foreach ($in as $line) {
+ if (preg_match('/(.*:)(\s*.*),(.*),(.*)/', $line, $matches)) {
+ /* Skip comment lines */
+ if (preg_match('/^\s*#/', $line))
+ continue;
+ if (!empty($matches[2]) && !empty($matches[3]) && !empty($matches[4])) {
+ $matches[2] = trim($matches[2]);
+ if (!array_key_exists($matches[2], $outMap)) {
+ if (!is_array($outMap[$matches[2]]))
+ $outMap[$matches[2]] = array();
+ $outMap[$matches[2]] = trim($matches[3]) . "," . trim($matches[4]);
+ }
+ }
+ }
+ }
+ }
+ // Sort the new classification map.
+ uksort($outMap,'strnatcasecmp');
+
+ // Do NOT write an empty classification.config file, just
+ // exit instead.
+ if (empty($outMap))
+ return false;
+
+ // Format and write it to the supplied output file.
+ $format = "config classification: %s,%s\n";
+ foreach ($outMap as $key=>$value)
+ $outMap[$key] = sprintf($format, $key, $value);
+ @file_put_contents($cfg_out, array_values($outMap));
+ return true;
+}
+
+function suricata_load_rules_map($rules_path) {
+
+ /***************************************************************/
+ /* This function loads and returns an array with all the rules */
+ /* found in the *.rules files in the passed rules path. */
+ /* */
+ /* $rules_path can be: */
+ /* a directory (assumed to contain *.rules files) */
+ /* a filename (identifying a specific *.rules file) */
+ /* an array of filenames (identifying *.rules files) */
+ /***************************************************************/
+
+ $map_ref = array();
+ $rule_files = array();
+
+ 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']
+ *
+ * where:
+ * gid = Generator ID from rule, or 1 if general text
+ * rule
+ * sid = Signature ID from rule
+ * rule = Complete rule text
+ * category = File name of file containing the rule
+ * action = alert, drop, reject or pass
+ * disabled = 1 if rule is disabled (commented out), 0 if
+ * rule is enabled
+ * 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
+ // variable accordingly. If we can't figure it out, return
+ // an empty rules map array.
+ if (is_string($rules_path)) {
+ if (is_dir($rules_path))
+ $rule_files = glob($rules_path . "*.rules");
+ elseif (is_file($rules_path))
+ $rule_files = (array)$rules_path;
+ }
+ elseif (is_array($rules_path))
+ $rule_files = $rules_path;
+ else
+ return $map_ref;
+
+ // Read the rule files into an array, then iterate the list
+ // to process the rules from the files one-by-one.
+ foreach ($rule_files as $file) {
+
+ // Don't process files with "deleted" in the filename.
+ if (stristr($file, "deleted"))
+ continue;
+
+ // Read the file contents into an array, skipping
+ // missing files.
+ if (!file_exists($file))
+ continue;
+
+ $rules_array = file($file, FILE_SKIP_EMPTY_LINES);
+ $record = "";
+ $b_Multiline = false;
+
+ // Read and process each line from the rules in the
+ // current file into an array.
+ foreach ($rules_array as $rule) {
+
+ // Skip any lines that may be just spaces.
+ if (trim($rule, " \n") == "")
+ continue;
+
+ // Skip any non-rule lines unless we're in
+ // multiline mode.
+ if (!preg_match('/^\s*#*\s*(alert|drop|pass|reject)/i', $rule) && !$b_Multiline)
+ continue;
+
+ // Test for a multi-line rule; loop and reassemble
+ // the pieces back into a single line.
+ if (preg_match('/\\\\s*[\n]$/m', $rule)) {
+ $rule = substr($rule, 0, strrpos($rule, '\\'));
+ $record .= $rule;
+ $b_Multiline = true;
+ continue;
+ }
+ // If the last segment of a multiline rule, then
+ // append it onto the previous parts to form a
+ // single-line rule for further processing below.
+ elseif (!preg_match('/\\\\s*[\n]$/m', $rule) && $b_Multiline) {
+ $record .= $rule;
+ $rule = $record;
+ }
+
+ // We have an actual single-line rule, or else a
+ // re-assembled multiline rule that is now a
+ // single-line rule, so store it in our rules map.
+
+ // Get and test the SID. If we don't find one,
+ // ignore and skip this rule as it is invalid.
+ $sid = suricata_get_sid($rule);
+ if (empty($sid)) {
+ $b_Multiline = false;
+ $record = "";
+ continue;
+ }
+
+ $gid = suricata_get_gid($rule);
+ if (!is_array($map_ref[$gid]))
+ $map_ref[$gid] = array();
+ if (!is_array($map_ref[$gid][$sid]))
+ $map_ref[$gid][$sid] = array();
+ $map_ref[$gid][$sid]['rule'] = $rule;
+ $map_ref[$gid][$sid]['category'] = basename($file, ".rules");
+
+ // Grab the rule action
+ $matches = array();
+ if (preg_match('/^\s*#*\s*(alert|drop|pass|reject)/i', $rule, $matches))
+ $map_ref[$gid][$sid]['action'] = $matches[1];
+ else
+ $map_ref[$gid][$sid]['action'] = "";
+
+ // Determine if default state is "disabled"
+ if (preg_match('/^\s*\#+/', $rule))
+ $map_ref[$gid][$sid]['disabled'] = 1;
+ else
+ $map_ref[$gid][$sid]['disabled'] = 0;
+
+ // Grab any associated flowbits from the rule.
+ $map_ref[$gid][$sid]['flowbits'] = suricata_get_flowbits($rule);
+
+ // Reset our local flag and record variables
+ // for the next rule in the set.
+ $b_Multiline = false;
+ $record = "";
+ }
+
+ // Zero out our processing array and get the next file.
+ unset($rules_array);
+ }
+ return $map_ref;
+}
+
+function suricata_get_gid($rule) {
+
+ /****************************************************************/
+ /* If a gid is defined, then return it, else default to "1" for */
+ /* general text rules match. */
+ /****************************************************************/
+
+ if (preg_match('/\bgid\s*:\s*(\d+)\s*;/i', $rule, $matches))
+ return trim($matches[1]);
+ else
+ return "1";
+}
+
+function suricata_get_sid($rule) {
+
+ /***************************************************************/
+ /* If a sid is defined, then return it, else default to an */
+ /* empty value. */
+ /***************************************************************/
+
+ if (preg_match('/\bsid\s*:\s*(\d+)\s*;/i', $rule, $matches))
+ return trim($matches[1]);
+ else
+ return "";
+}
+
+function suricata_get_msg($rule) {
+
+ /**************************************************************/
+ /* Return the MSG section of the passed rule as a string. */
+ /**************************************************************/
+
+ $msg = "";
+ if (preg_match('/\bmsg\s*:\s*"(.+?)"\s*;/i', $rule, $matches))
+ $msg = trim($matches[1]);
+ return $msg;
+}
+
+function suricata_get_flowbits($rule) {
+
+ /*************************************************************/
+ /* This will pull out "flowbits:" options from the rule text */
+ /* and return them in an array (minus the "flowbits:" part). */
+ /*************************************************************/
+
+ $flowbits = array();
+
+ // Grab any "flowbits:set, setx, unset, isset or toggle" options first.
+ // Examine flowbits targets for logical operators to capture all targets.
+ if (preg_match_all('/flowbits\b\s*:\s*(set|setx|unset|toggle|isset|isnotset)\s*,([^;]+)/i', $rule, $matches)) {
+ $i = -1;
+ while (++$i < count($matches[1])) {
+ $action = trim($matches[1][$i]);
+ $target = preg_split('/[&|]/', $matches[2][$i]);
+ foreach ($target as $t)
+ $flowbits[] = "{$action}," . trim($t);
+ }
+ }
+
+ // Include the "flowbits:noalert or reset" options, if present.
+ if (preg_match_all('/flowbits\b\s*:\s*(noalert|reset)\b/i', $rule, $matches)) {
+ $i = -1;
+ while (++$i < count($matches[1])) {
+ $flowbits[] = trim($matches[1][$i]);
+ }
+ }
+
+ return $flowbits;
+}
+
+function suricata_get_checked_flowbits($rules_map) {
+
+ /*************************************************************/
+ /* This function checks all the currently enabled rules to */
+ /* find any checked flowbits, and returns the checked */
+ /* flowbit names in an array. */
+ /*************************************************************/
+
+ $checked_flowbits = array();
+ foreach ($rules_map as $rulem) {
+ if (!is_array($rulem))
+ continue;
+ foreach ($rulem as $rulem2) {
+ if (!is_array($rulem2))
+ continue;
+ if ($rulem2['disabled'] == 1)
+ continue;
+ if (empty($rulem2['flowbits']))
+ continue;
+ if (!is_array($rulem2['flowbits']))
+ continue;
+ foreach ($rulem2['flowbits'] as $flowbit) {
+ if (empty($flowbit))
+ continue;
+ // If no comma in flowbits option, then skip it.
+ $pos = strpos($flowbit, ",");
+ if ($pos === false)
+ continue;
+ $action = substr(strtolower($flowbit), 0, $pos);
+ if ($action == "isset" || $action == "isnotset") {
+ $target = preg_split('/[&|]/', substr($flowbit, $pos + 1));
+ foreach ($target as $t)
+ if (!empty($t) && !isset($checked_flowbits[$t])) {
+ if (!is_array($checked_flowbits[$t]))
+ $checked_flowbits[$t] = array();
+ $checked_flowbits[$t] = $action;
+ }
+ }
+ }
+ }
+ }
+ unset($rulem, $rulem2);
+ return $checked_flowbits;
+}
+
+function suricata_get_set_flowbits($rules_map) {
+
+ /*********************************************************/
+ /* This function checks all the currently enabled rules */
+ /* to find any set flowbits, and returns the flowbit */
+ /* names in an array. */
+ /*********************************************************/
+
+ $set_flowbits = array();
+ foreach ($rules_map as $rulem) {
+ if (!is_array($rulem))
+ continue;
+ foreach ($rulem as $rulem2) {
+ if ($rulem2['disabled'] == 1)
+ continue;
+ if (empty($rulem2['flowbits']))
+ continue;
+ if (!is_array($rulem2['flowbits']))
+ continue;
+ foreach ($rulem2['flowbits'] as $flowbit) {
+ if (empty($flowbit))
+ continue;
+ /* If no comma in flowbits option, then skip it. */
+ $pos = strpos($flowbit, ",");
+ if ($pos === false)
+ continue;
+ $action = substr(strtolower($flowbit), 0, $pos);
+ if ($action == "set" || $action == "toggle" || $action == "setx") {
+ $target = preg_split('/[&|]/', substr($flowbit, $pos + 1));
+ foreach ($target as $t)
+ if (!empty($t) && !isset($set_flowbits[$t])) {
+ if (!is_array($set_flowbits[$t]))
+ $set_flowbits[$t] = array();
+ $set_flowbits[$t] = $action;
+ }
+ }
+ }
+ }
+ }
+ unset($rulem, $rulem2);
+ return $set_flowbits;
+}
+
+function suricata_find_flowbit_required_rules($rules, $unchecked_flowbits) {
+
+ /********************************************************/
+ /* This function finds all rules that must be enabled */
+ /* in order to satisfy the "checked flowbits" used by */
+ /* the currently enabled rules. It returns the list */
+ /* of required rules in an array. */
+ /********************************************************/
+
+ $required_flowbits_rules = array();
+ foreach ($rules as $k1 => $rule) {
+ if (!is_array($rule))
+ continue;
+ foreach ($rule as $k2 => $rule2) {
+ if (empty($rule2['flowbits']))
+ continue;
+ if (!is_array($rule2['flowbits']))
+ continue;
+ foreach ($rule2['flowbits'] as $flowbit) {
+ if (empty($flowbit))
+ continue;
+ $action = substr($flowbit, 0, strpos($flowbit, ","));
+ if (!strcasecmp(substr($action, 0, 3), "set")) {
+ $tmp = substr($flowbit, strpos($flowbit, ",") +1 );
+ if (!empty($tmp) && isset($unchecked_flowbits[$tmp])) {
+ if (!is_array($required_flowbits_rules[$k1]))
+ $required_flowbits_rules[$k1] = array();
+ if (!is_array($required_flowbits_rules[$k1][$k2]))
+ $required_flowbits_rules[$k1][$k2] = array();
+ $required_flowbits_rules[$k1][$k2]['category'] = $rule2['category'];
+ if ($rule2['disabled'] == 0)
+ // If not disabled, just return the rule text "as is"
+ $required_flowbits_rules[$k1][$k2]['rule'] = ltrim($rule2['rule']);
+ else {
+ // If rule is disabled, remove leading '#' to enable it
+ $required_flowbits_rules[$k1][$k2]['rule'] = ltrim(substr($rule2['rule'], strpos($rule2['rule'], "#") + 1));
+ $required_flowbits_rules[$k1][$k2]['disabled'] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ unset($rule, $rule2);
+
+ return $required_flowbits_rules;
+}
+
+function suricata_resolve_flowbits($rules, $active_rules) {
+
+ /******************************************************/
+ /* This function auto-resolves flowbit requirements */
+ /* by finding all checked flowbits in the currently */
+ /* enabled rules, and then making sure all the "set" */
+ /* flowbit rules for those "checked" flowbits are */
+ /* enabled. For any that are not enabled, they are */
+ /* copied to an array, enabled, and returned. */
+ /* */
+ /* $active_rules --> Rules Map array containing */
+ /* the current rules for the */
+ /* interface to resolve flowbit */
+ /* dependencies for. */
+ /* */
+ /* $rules --> Rules Map array containing */
+ /* all the available rules. */
+ /******************************************************/
+
+ $suricatadir = SURICATADIR;
+
+ // Check $rules array to be sure it is filled.
+ if (empty($rules)) {
+ log_error(gettext("[Suricata] WARNING: Flowbit resolution not done - no rules in {$suricatadir}rules/ ..."));
+ return array();
+ }
+
+ // First, find all the "checked" and "set" flowbits.
+ $checked_flowbits = suricata_get_checked_flowbits($active_rules);
+ $set_flowbits = suricata_get_set_flowbits($active_rules);
+
+ // Next find any "checked" flowbits without matching
+ // "set" flowbit rules in the enabled rule set.
+ $delta_flowbits = array_diff_key($checked_flowbits, $set_flowbits);
+
+ // Cleanup and release the memory we no longer need.
+ unset($checked_flowbits);
+ unset($set_flowbits);
+
+ // Now find all the needed "set flowbit" rules from
+ // the master list of all rules.
+ $required_rules = suricata_find_flowbit_required_rules($rules, $delta_flowbits);
+
+ // Cleanup and release memory we no longer need.
+ unset($delta_flowbits);
+
+ return $required_rules;
+}
+
+function suricata_write_flowbit_rules_file($flowbit_rules, $rule_file) {
+
+ /************************************************/
+ /* This function takes an array of rules in the */
+ /* rules_map format and writes them to the file */
+ /* given. */
+ /* */
+ /* $flowbit_rules --> array of flowbit-required */
+ /* rules. */
+ /* */
+ /* $rule_file --> filename to write the */
+ /* flowbit-required rules */
+ /* to. */
+ /************************************************/
+
+ $flowbit_rules_file = FLOWBITS_FILENAME;
+
+ // See if we were passed a directory or full
+ // filename to write the rules to, and adjust
+ // the destination argument accordingly.
+ if (is_dir($rule_file))
+ $rule_file = rtrim($rule_file, '/')."/{$flowbit_rules_file}";
+
+ if (empty($flowbit_rules)) {
+ @file_put_contents($rule_file, "");
+ return;
+ }
+
+ $fp = fopen($rule_file, "w");
+ if ($fp) {
+ @fwrite($fp, "# These rules set flowbits checked by your other enabled rules. If the\n");
+ @fwrite($fp, "# dependent flowbits are not set, then some of your chosen rules may\n");
+ @fwrite($fp, "# not fire. Enabling all rules that set these dependent flowbits ensures\n");
+ @fwrite($fp, "# your chosen rules fire as intended.\n#\n");
+ @fwrite($fp, "# If you wish to prevent alerts from any of these rules, add the GID:SID\n");
+ @fwrite($fp, "# of the rule to the Suppression List for the interface.\n");
+ foreach ($flowbit_rules as $k1 => $rule) {
+ foreach ($rule as $k2 => $rule2) {
+ @fwrite($fp, "\n# Category: {$rule2['category']}");
+ @fwrite($fp, " GID:{$k1} SID:{$k2}\n");
+ @fwrite($fp, $rule2['rule']);
+ }
+ }
+ fclose($fp);
+ }
+}
+
+function suricata_load_vrt_policy($policy, $all_rules=null) {
+
+ /************************************************/
+ /* This function returns an array of all rules */
+ /* marked with the passed in $policy metadata. */
+ /* */
+ /* $policy --> desired VRT security policy */
+ /* 1. connectivity */
+ /* 2. balanced */
+ /* 3. security */
+ /* */
+ /* $all_rules --> optional Rules Map array of */
+ /* rules to scan for policy. */
+ /* If not provided, then an */
+ /* array will be created. */
+ /************************************************/
+
+ $suricatadir = SURICATADIR;
+ $vrt_policy_rules = array();
+
+ // Load a map of all the VRT rules if we were
+ // not passed a pre-loaded one to use.
+ if (is_null($all_rules)) {
+ /* Since only Snort VRT rules have IPS Policy metadata, */
+ /* limit our search to just those files. */
+ $suricata_file_pattern = VRT_FILE_PREFIX . "*.rules";
+ $suricata_vrt_files = glob("{$suricatadir}rules/{$suricata_file_pattern}");
+ $all_rules = suricata_load_rules_map($suricata_vrt_files);
+ }
+
+ // Now walk the rules list and find all those that are
+ // defined as active for the chosen security policy.
+ foreach ($all_rules as $k1 => $arulem) {
+ foreach ($arulem as $k2 => $arulem2) {
+ if (strripos($arulem2['rule'], "policy {$policy}-ips") !== false) {
+ if (!preg_match('/flowbits\s*:\s*noalert/i', $arulem2['rule'])) {
+ if (!is_array($vrt_policy_rules[$k1]))
+ $vrt_policy_rules[$k1] = array();
+ if (!is_array($vrt_policy_rules[$k1][$k2]))
+ $vrt_policy_rules[$k1][$k2] = array();
+ $vrt_policy_rules[$k1][$k2] = $arulem2;
+
+ // Enable the policy rule if disabled
+ if ($arulem2['disabled'] == 1) {
+ $vrt_policy_rules[$k1][$k2]['rule'] = ltrim(substr($arulem2['rule'], strpos($arulem2['rule'], "#") + 1));
+ $vrt_policy_rules[$k1][$k2]['disabled'] = 0;
+ }
+ }
+ }
+ }
+ }
+
+ // Release memory we no longer need.
+ unset($arulem, $arulem2);
+
+ // Return all the rules that match the policy.
+ return $vrt_policy_rules;
+}
+
+function suricata_load_sid_mods($sids) {
+
+ /*****************************************/
+ /* This function parses the string of */
+ /* SID values in $sids and returns an */
+ /* array with the SID as the key and */
+ /* value. The SID values in $sids are */
+ /* assumed to be delimited by "||". */
+ /* */
+ /* $sids ==> string of SID values from */
+ /* saved config file. */
+ /* */
+ /* Returns ==> a multidimensional array */
+ /* with GID and SID as the */
+ /* keys ($result[GID][SID]) */
+ /*****************************************/
+
+ $result = array();
+ if (empty($sids))
+ return $result;
+ $tmp = explode("||", $sids);
+ foreach ($tmp as $v) {
+ if (preg_match('/(\d+)\s*:\s*(\d+)/', $v, $match)) {
+ if (!is_array($result[$match[1]]))
+ $result[$match[1]] = array();
+ $result[$match[1]][$match[2]] = "{$match[1]}:{$match[2]}";
+ }
+ }
+ unset($tmp);
+
+ return $result;
+}
+
+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 */
+ /*****************************************/
+
+ if (!isset($suricatacfg['rule_sid_on']) &&
+ !isset($suricatacfg['rule_sid_off']))
+ return;
+
+ // Load up our enablesid and disablesid
+ // arrays with lists of modified SIDs.
+ $enablesid = suricata_load_sid_mods($suricatacfg['rule_sid_on'], "enablesid");
+ $disablesid = suricata_load_sid_mods($suricatacfg['rule_sid_off'], "disablesid");
+
+ /* Turn on any rules that need to be */
+ /* forced "on" with enablesid mods. */
+ if (!empty($enablesid)) {
+ foreach ($rule_map as $k1 => $rulem) {
+ foreach ($rulem as $k2 => $v) {
+ if (isset($enablesid[$k1][$k2]) && $v['disabled'] == 1) {
+ $rule_map[$k1][$k2]['rule'] = ltrim($v['rule'], " \t#");
+ $rule_map[$k1][$k2]['disabled'] = 0;
+ }
+ }
+ }
+ }
+
+ /* Turn off any rules that need to be */
+ /* forced "off" with disablesid mods. */
+ if (!empty($disablesid)) {
+ foreach ($rule_map as $k1 => $rulem) {
+ foreach ($rulem as $k2 => $v) {
+ if (isset($disablesid[$k1][$k2]) && $v['disabled'] == 0) {
+ $rule_map[$k1][$k2]['rule'] = "# " . $v['rule'];
+ $rule_map[$k1][$k2]['disabled'] = 1;
+ }
+ }
+ }
+ }
+ unset($enablesid, $disablesid);
+}
+
+function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) {
+
+ /***********************************************************/
+ /* This function builds a new set of enforcing rules for */
+ /* Suricata and writes them to disk. */
+ /* */
+ /* $suricatacfg --> pointer to applicable section of */
+ /* config.xml containing settings for */
+ /* the interface. */
+ /* */
+ /* $suricatacfgdir --> pointer to physical directory on */
+ /* disk where Suricata configuration is */
+ /* to be written. */
+ /***********************************************************/
+
+ global $rebuild_rules;
+
+ $suricatadir = SURICATADIR;
+ $flowbit_rules_file = FLOWBITS_FILENAME;
+ $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME;
+ $no_rules_defined = true;
+
+ // If there is no reason to rebuild the rules, exit to save time.
+ if (!$rebuild_rules)
+ return;
+
+ // Log a message for rules rebuild in progress
+ log_error(gettext("[Suricata] Updating rules configuration for: " . suricata_get_friendly_interface($suricatacfg['interface']) . " ..."));
+
+ // 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();
+ $no_rules_defined = false;
+
+ // Load up all the rules into a Rules Map array.
+ $all_rules = suricata_load_rules_map("{$suricatadir}rules/");
+
+ // 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;
+ }
+
+ /****************************************************/
+ /* Walk the ALL_RULES map array and copy the rules */
+ /* matching our selected file categories to the */
+ /* ENABLED_RULES map array. */
+ /****************************************************/
+ foreach ($all_rules as $k1 => $rulem) {
+ foreach ($rulem as $k2 => $v) {
+ if (isset($enabled_files[$v['category']])) {
+ if (!is_array($enabled_rules[$k1]))
+ $enabled_rules[$k1] = array();
+ if (!is_array($enabled_rules[$k1][$k2]))
+ $enabled_rules[$k1][$k2] = array();
+ $enabled_rules[$k1][$k2]['rule'] = $v['rule'];
+ $enabled_rules[$k1][$k2]['category'] = $v['category'];
+ $enabled_rules[$k1][$k2]['disabled'] = $v['disabled'];
+ $enabled_rules[$k1][$k2]['flowbits'] = $v['flowbits'];
+ }
+ }
+ }
+
+ // Release memory we no longer need.
+ unset($enabled_files, $rulem, $v);
+ }
+
+ // Check if a pre-defined Snort VRT policy is selected. If so,
+ // add all the VRT policy rules to our enforcing rule set.
+ if (!empty($suricatacfg['ips_policy'])) {
+ $policy_rules = suricata_load_vrt_policy($suricatacfg['ips_policy'], $all_rules);
+ foreach ($policy_rules as $k1 => $policy) {
+ foreach ($policy as $k2 => $p) {
+ if (!is_array($enabled_rules[$k1]))
+ $enabled_rules[$k1] = array();
+ if (!is_array($enabled_rules[$k1][$k2]))
+ $enabled_rules[$k1][$k2] = array();
+ $enabled_rules[$k1][$k2]['rule'] = $p['rule'];
+ $enabled_rules[$k1][$k2]['category'] = $p['category'];
+ $enabled_rules[$k1][$k2]['disabled'] = $p['disabled'];
+ $enabled_rules[$k1][$k2]['flowbits'] = $p['flowbits'];
+ }
+ }
+ unset($policy_rules, $policy, $p);
+ }
+
+ // Process any enablesid or disablesid modifications for the selected rules.
+ 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: ' . suricata_get_friendly_interface($suricatacfg['interface']) . '...');
+ $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($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}");
+ }
+
+ if (!empty($suricatacfg['customrules'])) {
+ @file_put_contents("{$suricatacfgdir}/rules/custom.rules", base64_decode($suricatacfg['customrules']));
+ $no_rules_defined = false;
+ }
+ else
+ @file_put_contents("{$suricatacfgdir}/rules/custom.rules", "");
+
+ // Log a warning if the interface has no rules defined or enabled
+ if ($no_rules_defined)
+ log_error(gettext("[Suricata] Warning - no text rules selected for: " . suricata_get_friendly_interface($suricatacfg['interface']) . " ..."));
+
+ // 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 " . suricata_get_friendly_interface($suricatacfg['interface']) . "..."));
+ suricata_build_sid_msg_map("{$suricatacfgdir}/rules/", "{$suricatacfgdir}/sid-msg.map");
+}
+
+
+function suricata_write_enforcing_rules_file($rule_map, $rule_path) {
+
+ /************************************************/
+ /* This function takes a rules map array of */
+ /* the rules chosen for the active rule set */
+ /* and writes them out to the passed path. */
+ /* */
+ /* $rule_map --> Rules Map array of rules to */
+ /* write to disk. */
+ /* */
+ /* $rule_path --> filename or directory where */
+ /* rules file will be written. */
+ /************************************************/
+
+ $rule_file = "/" . ENFORCING_RULES_FILENAME;
+
+ // See if we were passed a directory or full
+ // filename to write the rules to, and adjust
+ // the destination argument accordingly.
+ if (is_dir($rule_path))
+ $rule_file = rtrim($rule_path, '/').$rule_file;
+ else
+ $rule_file = $rule_path;
+
+ // If the $rule_map array is empty, then exit.
+ if (empty($rule_map)) {
+ file_put_contents($rule_file, "");
+ return;
+ }
+
+ $fp = fopen($rule_file, "w");
+ if ($fp) {
+ @fwrite($fp, "# These rules are your current set of enforced rules for the protected\n");
+ @fwrite($fp, "# interface. This list was compiled from the categories selected on the\n");
+ @fwrite($fp, "# CATEGORIES tab of the Suricata configuration for the interface and/or any\n");
+ @fwrite($fp, "# chosen Snort VRT pre-defined IPS Policy.\n#\n");
+ @fwrite($fp, "# Any enablesid or disablesid customizations you made have been applied\n");
+ @fwrite($fp, "# to the rules in this file.\n\n");
+ foreach ($rule_map as $rulem) {
+ foreach ($rulem as $rulem2) {
+ /* No reason to write disabled rules to enforcing file, so skip them. */
+ if ($rulem2['disabled'] == 1)
+ continue;
+ @fwrite($fp, $rulem2['rule']);
+ }
+ }
+ fclose($fp);
+ }
+}
+
+function suricata_create_rc() {
+
+ /************************************************************/
+ /* This function builds the /usr/local/etc/rc.d/suricata.sh */
+ /* shell script for starting and stopping Suricata. The */
+ /* script is rebuilt on each package sync operation and */
+ /* after any changes to suricata.conf saved in the GUI. */
+ /************************************************************/
+
+ global $config, $g;
+
+ $suricatadir = SURICATADIR;
+ $suricatalogdir = SURICATALOGDIR;
+ $rcdir = RCFILEPREFIX;
+
+ // If no interfaces are configured for Suricata, exit
+ if (!is_array($config['installedpackages']['suricata']['rule']))
+ return;
+ $suricataconf = $config['installedpackages']['suricata']['rule'];
+ if (empty($suricataconf))
+ return;
+
+ // At least one interface is configured, so OK
+ $start_suricata_iface_start = array();
+ $start_suricata_iface_stop = array();
+
+ // Loop thru each configured interface and build
+ // the shell script.
+ foreach ($suricataconf as $value) {
+ $suricata_uuid = $value['uuid'];
+ $if_real = suricata_get_real_interface($value['interface']);
+
+ $start_barnyard = <<<EOE
+
+ if [ ! -f {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then
+ pid=`/bin/pgrep -f "barnyard2 -r {$suricata_uuid} "`
+ else
+ 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 STOP for {$value['descr']}({$suricata_uuid}_{$if_real})..."
+ /bin/pkill -TERM \$pid
+ time=0 timeout=30
+ while /bin/kill -TERM \$pid 2>/dev/null; do
+ sleep 1
+ time=\$((time+1))
+ if [ \$time -gt \$timeout ]; then
+ break
+ fi
+ done
+ if [ -f /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then
+ /bin/rm /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid
+ fi
+ fi
+ /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
+
+EOE;
+ $stop_barnyard2 = <<<EOE
+
+ if [ -f {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then
+ /usr/bin/logger -p daemon.info -i -t SuricataStartup "Barnyard2 STOP for {$value['descr']}({$suricata_uuid}_{$if_real})..."
+ pid=`/bin/pgrep -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid`
+ /bin/pkill -TERM -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid
+ time=0 timeout=30
+ while /bin/kill -TERM \$pid 2>/dev/null; do
+ sleep 1
+ time=\$((time+1))
+ if [ \$time -gt \$timeout ]; then
+ break
+ fi
+ done
+ if [ -f /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then
+ /bin/rm /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid
+ fi
+ else
+ pid=`/bin/pgrep -f "barnyard2 -r {$suricata_uuid} "`
+ if [ ! -z \$pid ]; then
+ /bin/pkill -TERM -f "barnyard2 -r {$suricata_uuid} "
+ time=0 timeout=30
+ while /bin/kill -TERM \$pid 2>/dev/null; do
+ sleep 1
+ time=\$((time+1))
+ if [ \$time -gt \$timeout ]; then
+ break
+ fi
+ done
+ fi
+ fi
+
+EOE;
+ if ($value['barnyard_enable'] == 'on')
+ $start_barnyard2 = $start_barnyard;
+ else
+ $start_barnyard2 = $stop_barnyard2;
+
+ $start_suricata_iface_start[] = <<<EOE
+
+###### For Each Iface
+ # Start suricata and barnyard2
+ if [ ! -f {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid ]; then
+ pid=`/bin/pgrep -f "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
+ /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
+ fi
+
+ sleep 2
+ {$start_barnyard2}
+
+EOE;
+
+ $start_suricata_iface_stop[] = <<<EOE
+
+ if [ -f {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid ]; then
+ pid=`/bin/pgrep -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid`
+ /usr/bin/logger -p daemon.info -i -t SuricataStartup "Suricata STOP for {$value['descr']}({$suricata_uuid}_{$if_real})..."
+ /bin/pkill -TERM -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid
+ time=0 timeout=30
+ while /bin/kill -TERM \$pid 2>/dev/null; do
+ sleep 1
+ time=\$((time+1))
+ if [ \$time -gt \$timeout ]; then
+ break
+ fi
+ done
+ if [ -f /var/run/suricata_{$if_real}{$suricata_uuid}.pid ]; then
+ /bin/rm /var/run/suricata_{$if_real}{$suricata_uuid}.pid
+ fi
+ else
+ pid=`/bin/pgrep -f "suricata -i {$if_real} "`
+ if [ ! -z \$pid ]; then
+ /usr/bin/logger -p daemon.info -i -t SuricataStartup "Suricata STOP for {$value['descr']}({$suricata_uuid}_{$if_real})..."
+ /bin/pkill -TERM -f "suricata -i {$if_real} "
+ time=0 timeout=30
+ while /bin/kill -TERM \$pid 2>/dev/null; do
+ sleep 1
+ time=\$((time+1))
+ if [ \$time -gt \$timeout ]; then
+ break
+ fi
+ done
+ fi
+ fi
+
+ sleep 2
+ {$stop_barnyard2}
+
+EOE;
+ }
+
+ $rc_start = implode("\n", $start_suricata_iface_start);
+ $rc_stop = implode("\n", $start_suricata_iface_stop);
+
+ $suricata_sh_text = <<<EOD
+#!/bin/sh
+########
+# This file was automatically generated
+# by the pfSense service handler.
+######## Start of main suricata.sh
+
+rc_start() {
+ {$rc_start}
+}
+
+rc_stop() {
+ {$rc_stop}
+}
+
+case $1 in
+ start)
+ rc_start
+ ;;
+ stop)
+ rc_stop
+ ;;
+ restart)
+ rc_stop
+ rc_start
+ ;;
+esac
+
+EOD;
+
+ // Write out the suricata.sh script file
+ @file_put_contents("{$rcdir}/suricata.sh", $suricata_sh_text);
+ @chmod("{$rcdir}/suricata.sh", 0755);
+ unset($suricata_sh_text);
+}
+
+function suricata_generate_barnyard2_conf($suricatacfg, $if_real) {
+ global $config, $g;
+
+ $suricata_uuid = $suricatacfg['uuid'];
+ $suricatadir = SURICATADIR . "suricata_{$suricata_uuid}_{$if_real}";
+ $suricatalogdir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}";
+
+ // Create required directories for barnyard2 if missing
+ if (!is_dir("{$suricatalogdir}/barnyard2"))
+ safe_mkdir("{$suricatalogdir}/barnyard2");
+ if (!is_dir("{$suricatalogdir}/barnyard2/archive"))
+ safe_mkdir("{$suricatalogdir}/barnyard2/archive");
+
+ // Create the barnyard2 waldo file if missing
+ if (!file_exists("{$suricatalogdir}/barnyard2/{$suricata_uuid}_{$if_real}.waldo")) {
+ @touch("{$suricatalogdir}/barnyard2/{$suricata_uuid}_{$if_real}.waldo");
+ mwexec("/bin/chmod 770 {$suricatalogdir}/barnyard2/{$suricata_uuid}_{$if_real}.waldo", true);
+ }
+
+ // If there is no gen-msg.map file present, create an
+ // empty one so Barnyard2 will at least start.
+ if (!file_exists("{$suricatadir}/gen-msg.map"))
+ @file_put_contents("{$suricatadir}/gen-msg.map", "");
+
+ if (!empty($suricatacfg['barnyard_sensor_name']))
+ $suricatabarnyardlog_hostname_info_chk = $suricatacfg['barnyard_sensor_name'];
+ else
+ $suricatabarnyardlog_hostname_info_chk = php_uname("n");
+
+ // Set general config parameters
+ $gen_configs = "config quiet\nconfig daemon\nconfig decode_data_link\nconfig alert_with_interface_name\nconfig event_cache_size: 4096";
+ if ($suricatacfg['barnyard_show_year'] == 'on')
+ $gen_configs .= "\nconfig show_year";
+ if ($suricatacfg['barnyard_obfuscate_ip'] == 'on')
+ $gen_configs .= "\nconfig obfuscate";
+ if ($suricatacfg['barnyard_dump_payload'] == 'on')
+ $gen_configs .= "\nconfig dump_payload";
+ if ($suricatacfg['barnyard_archive_enable'] == 'on')
+ $gen_configs .= "\nconfig archivedir: {$suricatalogdir}/barnyard2/archive";
+
+ // Set output plugins
+ $suricatabarnyardlog_output_plugins = "";
+ if ($suricatacfg['barnyard_mysql_enable'] == 'on') {
+ $by2_dbpwd = base64_decode($suricatacfg['barnyard_dbpwd']);
+ $suricatabarnyardlog_output_plugins .= "# database: log to a MySQL DB\noutput database: alert, mysql, ";
+ $suricatabarnyardlog_output_plugins .= "user={$suricatacfg['barnyard_dbuser']} password={$by2_dbpwd} ";
+ $suricatabarnyardlog_output_plugins .= "dbname={$suricatacfg['barnyard_dbname']} host={$suricatacfg['barnyard_dbhost']}\n\n";
+ }
+ if ($suricatacfg['barnyard_syslog_enable'] == 'on') {
+ $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";
+ 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']}, ";
+ $suricatabarnyardlog_output_plugins .= "log_facility {$suricatacfg['barnyard_syslog_facility']}, log_priority {$suricatacfg['barnyard_syslog_priority']}\n";
+ }
+ }
+
+ // Trim leading and trailing newlines and spaces
+ $suricatabarnyardlog_output_plugins = rtrim($suricatabarnyardlog_output_plugins, "\n");
+
+ // User pass-through arguments
+ $suricatabarnyardlog_config_pass_thru = str_replace("\r", "", base64_decode($suricatacfg['barnconfigpassthru']));
+
+ // Create the conf file as a text string
+ $barnyard2_conf_text = <<<EOD
+
+# barnyard2.conf
+# barnyard2 can be found at http://www.securixlive.com/barnyard2/index.php
+#
+
+## General Barnyard2 settings ##
+{$gen_configs}
+config reference_file: {$suricatadir}/reference.config
+config classification_file: {$suricatadir}/classification.config
+config sid_file: {$suricatadir}/sid-msg.map
+config gen_file: {$suricatadir}/gen-msg.map
+config hostname: {$suricatabarnyardlog_hostname_info_chk}
+config interface: {$if_real}
+config waldo_file: {$suricatalogdir}/barnyard2/{$suricata_uuid}_{$if_real}.waldo
+config logdir: {$suricatalogdir}
+
+## START user pass through ##
+{$suricatabarnyardlog_config_pass_thru}
+## END user pass through ##
+
+## Setup input plugins ##
+input unified2
+
+## Setup output plugins ##
+{$suricatabarnyardlog_output_plugins}
+
+EOD;
+
+ /* Write out barnyard2_conf text string to disk */
+ @file_put_contents("{$suricatadir}/barnyard2.conf", $barnyard2_conf_text);
+ unset($barnyard2_conf_text);
+}
+
+function suricata_generate_yaml($suricatacfg) {
+
+ /************************************************************/
+ /* This function generates the suricata.yaml configuration */
+ /* file for Suricata on the passed interface instance. The */
+ /* code uses two included files: one that contains most of */
+ /* the PHP code, and another that provides the template for */
+ /* generating the configuration file. Using two include */
+ /* files works around the "require_once()" caching issues */
+ /* that can prevent new changes in this code from being */
+ /* available during package installs on pfSense. */
+ /* */
+ /* On Entry: suricatacfg --> Suricata instance info in */
+ /* the config.xml master config */
+ /* file. */
+ /************************************************************/
+
+ global $config, $g;
+
+ $suricatadir = SURICATADIR;
+ $suricatalogdir = SURICATALOGDIR;
+ $flowbit_rules_file = FLOWBITS_FILENAME;
+ $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME;
+ $if_real = suricata_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");
+
+ // 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
+ // (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);
+ conf_mount_ro();
+}
+
+?>
diff --git a/config/suricata/suricata.priv.inc b/config/suricata/suricata.priv.inc
new file mode 100644
index 00000000..7f5f1825
--- /dev/null
+++ b/config/suricata/suricata.priv.inc
@@ -0,0 +1,45 @@
+<?php
+
+global $priv_list;
+
+$priv_list['page-services-suricata'] = array();
+$priv_list['page-services-suricata']['name'] = "WebCfg - Services: suricata package.";
+$priv_list['page-services-suricata']['descr'] = "Allow access to suricata package gui";
+$priv_list['page-services-suricata']['match'] = array();
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_alerts.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_barnyard.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_blocked.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_check_for_rule_updates.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_define_vars.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_download_rules.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_download_updates.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_app_parsers.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_libhtp_policy_engine.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_import_aliases.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_interfaces.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_interfaces_edit.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_interfaces_global.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_suppress.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_suppress_edit.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_interfaces_whitelist.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_interfaces_whitelist_edit.php*";
+$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_post_install.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_flow_stream.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_rules.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_rules_edit.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_rules_flowbits.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_rulesets.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_select_alias.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'][] = "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_post_install.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_uninstall.php*";
+$priv_list['page-services-suricata']['match'][] = "suricata/suricata_generate_yaml.php*";
+
+?> \ No newline at end of file
diff --git a/config/suricata/suricata.xml b/config/suricata/suricata.xml
new file mode 100644
index 00000000..4760149d
--- /dev/null
+++ b/config/suricata/suricata.xml
@@ -0,0 +1,236 @@
+<?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$ */
+/* ========================================================================== */
+/*
+ suricata.xml
+ part of the Suricata package for 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.
+ */
+/* ========================================================================== */
+ ]]>
+ </copyright>
+ <description>Suricata IDS/IPS Package</description>
+ <requirements>None</requirements>
+ <name>suricata</name>
+ <version>1.4.6 pkg v0.1-BETA</version>
+ <title>Services: Suricata IDS</title>
+ <include_file>/usr/local/pkg/suricata/suricata.inc</include_file>
+ <menu>
+ <name>Suricata</name>
+ <tooltiptext>Configure Suricata settings</tooltiptext>
+ <section>Services</section>
+ <url>/suricata/suricata_interfaces.php</url>
+ </menu>
+ <service>
+ <name>suricata</name>
+ <rcfile>suricata.sh</rcfile>
+ <executable>suricata</executable>
+ <description>Suricata IDS/IPS Daemon</description>
+ </service>
+ <additional_files_needed>
+ <prefix>/etc/inc/priv/</prefix>
+ <chmod>077</chmod>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata.priv.inc</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata.inc</item>
+ <prefix>/usr/local/pkg/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/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>http://www.pfsense.com/packages/config/suricata/suricata_yaml_template.inc</item>
+ <prefix>/usr/local/pkg/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_generate_yaml.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_download_updates.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_global.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_alerts.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_interfaces.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_interfaces_edit.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_download_rules.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/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>http://www.pfsense.com/packages/config/suricata/suricata_rules.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_rulesets.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_rules_flowbits.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_rules_edit.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_flow_stream.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_os_policy_engine.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_import_aliases.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_select_alias.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_suppress.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_suppress_edit.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_logs_browser.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_list_view.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_app_parsers.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_libhtp_policy_engine.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_uninstall.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_define_vars.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_barnyard.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_post_install.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/suricata/suricata_uninstall.php</item>
+ <prefix>/usr/local/www/suricata/</prefix>
+ <chmod>0755</chmod>
+ </additional_files_needed>
+ <!-- configpath gets expanded out automatically and config items will be stored in that location -->
+ <configpath>['installedpackages']['suricata']</configpath>
+ <tabs>
+ </tabs>
+ <fields>
+ </fields>
+ <custom_php_install_command>
+ <![CDATA[
+ include_once("/usr/local/www/suricata/suricata_post_install.php");
+ ]]>
+ </custom_php_install_command>
+ <custom_php_deinstall_command>
+ <![CDATA[
+ include_once("/usr/local/www/suricata/suricata_uninstall.php");
+ ]]>
+ </custom_php_deinstall_command>
+ <custom_php_resync_config_command>
+ sync_suricata_package_config();
+ </custom_php_resync_config_command>
+ <custom_php_validation_command>
+ </custom_php_validation_command>
+</packagegui>
diff --git a/config/suricata/suricata_alerts.php b/config/suricata/suricata_alerts.php
new file mode 100644
index 00000000..c36c0dd7
--- /dev/null
+++ b/config/suricata/suricata_alerts.php
@@ -0,0 +1,578 @@
+<?php
+/*
+ * suricata_alerts.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");
+
+$supplist = array();
+
+function suricata_is_alert_globally_suppressed($list, $gid, $sid) {
+
+ /************************************************/
+ /* Checks the passed $gid:$sid to see if it has */
+ /* been globally suppressed. If true, then any */
+ /* "track by_src" or "track by_dst" options are */
+ /* disabled since they are overridden by the */
+ /* global suppression of the $gid:$sid. */
+ /************************************************/
+
+ /* If entry has a child array, then it's by src or dst ip. */
+ /* So if there is a child array or the keys are not set, */
+ /* then this gid:sid is not globally suppressed. */
+ if (is_array($list[$gid][$sid]))
+ return false;
+ elseif (!isset($list[$gid][$sid]))
+ return false;
+ else
+ return true;
+}
+
+function suricata_add_supplist_entry($suppress) {
+
+ /************************************************/
+ /* Adds the passed entry to the Suppress List */
+ /* for the active interface. If a Suppress */
+ /* List is defined for the interface, it is */
+ /* used. If no list is defined, a new default */
+ /* list is created using the interface name. */
+ /* */
+ /* On Entry: */
+ /* $suppress --> suppression entry text */
+ /* */
+ /* Returns: */
+ /* TRUE if successful or FALSE on failure */
+ /************************************************/
+
+ global $config, $a_instance, $instanceid;
+
+ if (!is_array($config['installedpackages']['suricata']['suppress']))
+ $config['installedpackages']['suricata']['suppress'] = array();
+ if (!is_array($config['installedpackages']['suricata']['suppress']['item']))
+ $config['installedpackages']['suricata']['suppress']['item'] = array();
+ $a_suppress = &$config['installedpackages']['suricata']['suppress']['item'];
+
+ $found_list = false;
+
+ /* If no Suppress List is set for the interface, then create one with the interface name */
+ if (empty($a_instance[$instanceid]['suppresslistname']) || $a_instance[$instanceid]['suppresslistname'] == 'default') {
+ $s_list = array();
+ $s_list['uuid'] = uniqid();
+ $s_list['name'] = $a_instance[$instanceid]['interface'] . "suppress" . "_" . $s_list['uuid'];
+ $s_list['descr'] = "Auto-generated list for Alert suppression";
+ $s_list['suppresspassthru'] = base64_encode($suppress);
+ $a_suppress[] = $s_list;
+ $a_instance[$instanceid]['suppresslistname'] = $s_list['name'];
+ $found_list = true;
+ } else {
+ /* If we get here, a Suppress List is defined for the interface so see if we can find it */
+ foreach ($a_suppress as $a_id => $alist) {
+ if ($alist['name'] == $a_instance[$instanceid]['suppresslistname']) {
+ $found_list = true;
+ if (!empty($alist['suppresspassthru'])) {
+ $tmplist = base64_decode($alist['suppresspassthru']);
+ $tmplist .= "\n{$suppress}";
+ $alist['suppresspassthru'] = base64_encode($tmplist);
+ $a_suppress[$a_id] = $alist;
+ }
+ else {
+ $alist['suppresspassthru'] = base64_encode($suppress);
+ $a_suppress[$a_id] = $alist;
+ }
+ }
+ }
+ }
+
+ /* If we created a new list or updated an existing one, save the change, */
+ /* tell Snort to load it, and return true; otherwise return false. */
+ if ($found_list) {
+ write_config();
+ sync_suricata_package_config();
+ suricata_reload_config($a_instance[$instanceid]);
+ return true;
+ }
+ else
+ return false;
+}
+
+if ($_GET['instance'])
+ $instanceid = $_GET['instance'];
+if ($_POST['instance'])
+ $instanceid = $_POST['instance'];
+if (empty($instanceid))
+ $instanceid = 0;
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_instance = &$config['installedpackages']['suricata']['rule'];
+$suricata_uuid = $a_instance[$instanceid]['uuid'];
+$if_real = get_real_interface($a_instance[$instanceid]['interface']);
+$suricatalogdir = SURICATALOGDIR;
+
+// Load up the arrays of force-enabled and force-disabled SIDs
+$enablesid = suricata_load_sid_mods($a_instance[$instanceid]['rule_sid_on']);
+$disablesid = suricata_load_sid_mods($a_instance[$instanceid]['rule_sid_off']);
+
+$pconfig = array();
+if (is_array($config['installedpackages']['suricata']['alertsblocks'])) {
+ $pconfig['arefresh'] = $config['installedpackages']['suricata']['alertsblocks']['arefresh'];
+ $pconfig['alertnumber'] = $config['installedpackages']['suricata']['alertsblocks']['alertnumber'];
+}
+
+if (empty($pconfig['alertnumber']))
+ $pconfig['alertnumber'] = '250';
+if (empty($pconfig['arefresh']))
+ $pconfig['arefresh'] = 'off';
+$anentries = $pconfig['alertnumber'];
+
+if ($_POST['save']) {
+ if (!is_array($config['installedpackages']['suricata']['alertsblocks']))
+ $config['installedpackages']['suricata']['alertsblocks'] = array();
+ $config['installedpackages']['suricata']['alertsblocks']['arefresh'] = $_POST['arefresh'] ? 'on' : 'off';
+ $config['installedpackages']['suricata']['alertsblocks']['alertnumber'] = $_POST['alertnumber'];
+
+ write_config();
+
+ header("Location: /suricata/suricata_alerts.php?instance={$instanceid}");
+ exit;
+}
+
+//if ($_POST['todelete'] || $_GET['todelete']) {
+// $ip = "";
+// if($_POST['todelete'])
+// $ip = $_POST['todelete'];
+// else if($_GET['todelete'])
+// $ip = $_GET['todelete'];
+// if (is_ipaddr($ip)) {
+// exec("/sbin/pfctl -t snort2c -T delete {$ip}");
+// $savemsg = gettext("Host IP address {$ip} has been removed from the Blocked Table.");
+// }
+//}
+
+if ($_GET['act'] == "addsuppress" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) {
+ if (empty($_GET['descr']))
+ $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n";
+ else
+ $suppress = "#{$_GET['descr']}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n";
+
+ /* Add the new entry to the Suppress List */
+ if (suricata_add_supplist_entry($suppress))
+ $savemsg = gettext("An entry for 'suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}' has been added to the Suppress List.");
+ else
+ $input_errors[] = gettext("Suppress List '{$a_instance[$instanceid]['suppresslistname']}' is defined for this interface, but it could not be found!");
+}
+
+if (($_GET['act'] == "addsuppress_srcip" || $_GET['act'] == "addsuppress_dstip") && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) {
+ if ($_GET['act'] == "addsuppress_srcip")
+ $method = "by_src";
+ else
+ $method = "by_dst";
+
+ /* Check for valid IP addresses, exit if not valid */
+ if (is_ipaddr($_GET['ip']) || is_ipaddrv6($_GET['ip'])) {
+ if (empty($_GET['descr']))
+ $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}\n";
+ else
+ $suppress = "#{$_GET['descr']}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}\n";
+ }
+ else {
+ header("Location: /suricata/suricata_alerts.php?instance={$instanceid}");
+ exit;
+ }
+
+ /* Add the new entry to the Suppress List */
+ if (suricata_add_supplist_entry($suppress))
+ $savemsg = gettext("An entry for 'suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}' has been added to the Suppress List.");
+ else
+ /* We did not find the defined list, so notify the user with an error */
+ $input_errors[] = gettext("Suppress List '{$a_instance[$instanceid]['suppresslistname']}' is defined for this interface, but it could not be found!");
+}
+
+if ($_GET['act'] == "togglesid" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) {
+ // Get the GID tag embedded in the clicked rule icon.
+ $gid = $_GET['gen_id'];
+
+ // Get the SID tag embedded in the clicked rule icon.
+ $sid= $_GET['sidid'];
+
+ // See if the target SID is in our list of modified SIDs,
+ // and toggle it if present.
+ if (isset($enablesid[$gid][$sid]))
+ unset($enablesid[$gid][$sid]);
+ if (isset($disablesid[$gid][$sid]))
+ unset($disablesid[$gid][$sid]);
+ elseif (!isset($disablesid[$gid][$sid]))
+ $disablesid[$gid][$sid] = "disablesid";
+
+ // Write the updated enablesid and disablesid values to the config file.
+ $tmp = "";
+ foreach (array_keys($enablesid) as $k1) {
+ foreach (array_keys($enablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_instance[$instanceid]['rule_sid_on'] = $tmp;
+ else
+ unset($a_instance[$instanceid]['rule_sid_on']);
+
+ $tmp = "";
+ foreach (array_keys($disablesid) as $k1) {
+ foreach (array_keys($disablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_instance[$instanceid]['rule_sid_off'] = $tmp;
+ else
+ unset($a_instance[$instanceid]['rule_sid_off']);
+
+ /* Update the config.xml file. */
+ write_config();
+
+ /*************************************************/
+ /* Update the suricata.yaml file and rebuild the */
+ /* rules for this interface. */
+ /*************************************************/
+ $rebuild_rules = true;
+ suricata_generate_yaml($a_instance[$instanceid]);
+ $rebuild_rules = false;
+
+ /* Signal Suricata to live-load the new rules */
+ suricata_reload_config($a_instance[$instanceid]);
+
+ $savemsg = gettext("The state for rule {$gid}:{$sid} has been modified. Suricata is 'live-reloading' the new rules list. Please wait at least 30 secs for the process to complete before toggling additional rules.");
+}
+
+if ($_GET['action'] == "clear" || $_POST['delete']) {
+ conf_mount_rw();
+ suricata_post_delete_logs($suricata_uuid);
+ $fd = @fopen("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/alerts.log", "w+");
+ if ($fd)
+ fclose($fd);
+ conf_mount_ro();
+ /* XXX: This is needed if suricata is run as suricata user */
+ mwexec('/bin/chmod 660 {$suricatalogdir}*', true);
+ if (file_exists("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid"))
+ mwexec("/bin/pkill -HUP -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid -a");
+ header("Location: /suricata/suricata_alerts.php?instance={$instanceid}");
+ exit;
+}
+
+if ($_POST['download']) {
+ $save_date = exec('/bin/date "+%Y-%m-%d-%H-%M-%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} *");
+
+ 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("/tmp/{$file_name}");
+ }
+ else
+ $savemsg = gettext("An error occurred while creating archive");
+}
+
+/* Load up an array with the current Suppression List GID,SID values */
+$supplist = suricata_load_suppress_sigs($a_instance[$instanceid], true);
+
+$pgtitle = gettext("Suricata: Alerts");
+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");
+
+/* refresh every 60 secs */
+if ($pconfig['arefresh'] == 'on')
+ echo "<meta http-equiv=\"refresh\" content=\"60;url=/suricata/suricata_alerts.php?instance={$instanceid}\" />\n";
+?>
+
+<?php if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+ /* Display Alert message */
+ if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+ }
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+?>
+<form action="/suricata/suricata_alerts.php" method="post" id="formalert">
+<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("Global Settings"), false, "/suricata/suricata_global.php");
+ $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), true, "/suricata/suricata_alerts.php?instance={$instanceid}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr>
+ <td><div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Alert Log View Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" class="vncell"><?php echo gettext('Instance to Inspect'); ?></td>
+ <td width="78%" class="vtable">
+ <select name="instance" id="instance" class="formselect" onChange="document.getElementById('formalert').method='get';document.getElementById('formalert').submit()">
+ <?php
+ foreach ($a_instance as $id => $instance) {
+ $selected = "";
+ if ($id == $instanceid)
+ $selected = "selected";
+ echo "<option value='{$id}' {$selected}> (" . suricata_get_friendly_interface($instance['interface']) . "){$instance['descr']}</option>\n";
+ }
+ ?>
+ </select>&nbsp;&nbsp;<?php echo gettext('Choose which instance alerts you want to inspect.'); ?>
+ </td>
+ <tr>
+ <td width="22%" class="vncell"><?php echo gettext('Save or Remove Logs'); ?></td>
+ <td width="78%" class="vtable">
+ <input name="download" type="submit" class="formbtns" value="Download"> <?php echo gettext('All ' .
+ 'log files will be saved.'); ?>&nbsp;&nbsp;<a href="/suricata/suricata_alerts.php?action=clear&instance=<?=$instanceid;?>">
+ <input name="delete" type="submit" class="formbtns" value="Clear"
+ onclick="return confirm('Do you really want to remove all instance logs?')"></a>
+ <span class="red"><strong><?php echo gettext('Warning:'); ?></strong></span> <?php echo ' ' . gettext('all log files will be deleted.'); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" class="vncell"><?php echo gettext('Auto Refresh and Log View'); ?></td>
+ <td width="78%" class="vtable">
+ <input name="save" type="submit" class="formbtns" value="Save">
+ <?php echo gettext('Refresh'); ?> <input name="arefresh" type="checkbox" value="on"
+ <?php if ($config['installedpackages']['suricata']['alertsblocks']['arefresh']=="on") echo "checked"; ?>>
+ <?php printf(gettext('%sDefault%s is %sON%s.'), '<strong>', '</strong>', '<strong>', '</strong>'); ?>&nbsp;&nbsp;
+ <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 printf(gettext("Last %s Alert Entries"), $anentries); ?>&nbsp;&nbsp;
+ <?php echo gettext("(Most recent entries are listed first)"); ?></td>
+ </tr>
+ <tr>
+ <td width="100%" colspan="2">
+ <table id="myTable" style="table-layout: fixed;" width="100%" class="sortable" border="1" cellpadding="0" cellspacing="0">
+ <colgroup>
+ <col width="10%" align="center" axis="date">
+ <col width="41" align="center" axis="number">
+ <col width="64" align="center" axis="string">
+ <col width="10%" axis="string">
+ <col width="13%" align="center" axis="string">
+ <col width="8%" align="center" axis="string">
+ <col width="13%" align="center" axis="string">
+ <col width="8%" align="center" axis="string">
+ <col width="9%" align="center" axis="number">
+ <col axis="string">
+ </colgroup>
+ <thead>
+ <tr>
+ <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>
+ <th class="listhdrr" axis="string"><?php echo gettext("CLASS"); ?></th>
+ <th class="listhdrr" axis="string"><?php echo gettext("SRC"); ?></th>
+ <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="string"><?php echo gettext("DESCRIPTION"); ?></th>
+ </tr>
+ </thead>
+ <tbody>
+ <?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_uuid}");
+ if (file_exists("/tmp/alerts_{$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_uuid}", "r");
+ while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) {
+ if(count($fields) < 12)
+ continue;
+
+ /* Time */
+ $alert_time = substr($fields[0], strpos($fields[0], '-')+1, -7);
+ /* Date */
+ $alert_date = trim(substr($fields[0], 0, strpos($fields[0], '-')));
+ /* Description */
+ $alert_descr = $fields[5];
+ $alert_descr_url = urlencode($fields[5]);
+ /* Priority */
+ $alert_priority = $fields[7];
+ /* Protocol */
+ $alert_proto = $fields[8];
+ /* 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(":", ":&#8203;", $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>&nbsp;";
+ $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 .= "&nbsp;&nbsp;<a href='?instance={$instanceid}&act=addsuppress_srcip&sidid={$fields[3]}&gen_id={$fields[2]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[9])) . "'>";
+ $alert_ip_src .= "<img 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") . "'></a>";
+ }
+ elseif (isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) {
+ $alert_ip_src .= "&nbsp;&nbsp;<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[9]])) {
+ $alert_ip_src .= "&nbsp;";
+ $alert_ip_src .= "<a href='?instance={$instanceid}&todelete=" . trim(urlencode($fields[9])) . "'>
+ <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"></a>";
+ }
+ /* 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(":", ":&#8203;", $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>&nbsp;";
+ $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[1]])) {
+ $alert_ip_dst .= "&nbsp;&nbsp;<a href='?instance={$instanceid}&act=addsuppress_dstip&sidid={$fields[3]}&gen_id={$fields[2]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[11])) . "'>";
+ $alert_ip_dst .= "<img 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") . "'></a>";
+ }
+ elseif (isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) {
+ $alert_ip_dst .= "&nbsp;&nbsp;<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[11]])) {
+ $alert_ip_dst .= "&nbsp;";
+ $alert_ip_dst .= "<a href='?instance={$instanceid}&todelete=" . trim(urlencode($fields[11])) . "'>
+ <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"></a>";
+ }
+ /* IP DST Port */
+ $alert_dst_p = $fields[12];
+ /* SID */
+ $alert_sid_str = "{$fields[2]}:{$fields[3]}";
+ if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3])) {
+ $sidsupplink = "<a href='?instance={$instanceid}&act=addsuppress&sidid={$fields[3]}&gen_id={$fields[2]}&descr={$alert_descr_url}'>";
+ $sidsupplink .= "<img 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") . "'></a>";
+ }
+ else {
+ $sidsupplink = "<img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' ";
+ $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 = "<a href='?instance={$instanceid}&act=togglesid&sidid={$fields[3]}&gen_id={$fields[2]}'>";
+ $sid_dsbl_link .= "<img 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.") . "'></a>";
+ }
+ else {
+ $sid_dsbl_link = "<a href='?instance={$instanceid}&act=togglesid&sidid={$fields[3]}&gen_id={$fields[2]}'>";
+ $sid_dsbl_link .= "<img 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.") . "'></a>";
+ }
+ /* DESCRIPTION */
+ $alert_class = $fields[6];
+
+ 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'>{$alert_ip_src}</td>
+ <td class='listr' align='center'>{$alert_src_p}</td>
+ <td class='listr' align='center'>{$alert_ip_dst}</td>
+ <td class='listr' align='center'>{$alert_dst_p}</td>
+ <td class='listr' align='center'>{$alert_sid_str}<br/>{$sidsupplink}&nbsp;&nbsp;{$sid_dsbl_link}</td>
+ <td class='listr' style=\"word-wrap:break-word;\">{$alert_descr}</td>
+ </tr>\n";
+
+ $counter++;
+ }
+ fclose($fd);
+ @unlink("/tmp/alerts_{$suricata_uuid}");
+ }
+}
+?>
+ </tbody>
+ </table>
+ </td>
+</tr>
+</table>
+</div>
+</td></tr>
+</table>
+</form>
+<?php
+include("fend.inc");
+?>
+
+</body>
+</html>
diff --git a/config/suricata/suricata_app_parsers.php b/config/suricata/suricata_app_parsers.php
new file mode 100644
index 00000000..0be45c32
--- /dev/null
+++ b/config/suricata/suricata_app_parsers.php
@@ -0,0 +1,303 @@
+<?php
+/*
+ * suricata_app_parsers.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;
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (!is_array($config['installedpackages']['suricata']))
+ $config['installedpackages']['suricata'] = array();
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+
+// Initialize HTTP libhtp engine arrays if necessary
+if (!is_array($config['installedpackages']['suricata']['rule'][$id]['libhtp_policy']['item']))
+ $config['installedpackages']['suricata']['rule'][$id]['libhtp_policy']['item'] = array();
+
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+$libhtp_engine_next_id = count($a_nat[$id]['libhtp_policy']['item']);
+
+$pconfig = array();
+if (isset($id) && $a_nat[$id]) {
+ /* Get current values from config for page form fields */
+ $pconfig = $a_nat[$id];
+
+ // See if Host-OS policy engine array is configured and use
+ // it; otherwise create a default engine configuration.
+ 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" );
+ $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();
+ $libhtp_engine_next_id++;
+ }
+ else
+ $pconfig['libhtp_policy'] = $a_nat[$id]['libhtp_policy'];
+}
+
+// Check for returned "selected alias" if action is import
+if ($_GET['act'] == "import" && isset($_GET['varname']) && !empty($_GET['varvalue'])) {
+ $pconfig[$_GET['varname']] = $_GET['varvalue'];
+}
+
+if ($_GET['act'] && isset($_GET['eng_id'])) {
+
+ $natent = array();
+ $natent = $pconfig;
+
+ if ($_GET['act'] == "del_libhtp_policy")
+ unset($natent['libhtp_policy']['item'][$_GET['eng_id']]);
+
+ if (isset($id) && $a_nat[$id]) {
+ $a_nat[$id] = $natent;
+ write_config();
+ }
+
+ header("Location: /suricata/suricata_app_parsers.php?id=$id");
+ exit;
+}
+
+if ($_POST['ResetAll']) {
+
+ /* Reset all the settings to defaults */
+ $pconfig['asn1_max_frames'] = "256";
+
+ /* 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.");
+}
+elseif ($_POST['Submit']) {
+ $natent = array();
+ $natent = $pconfig;
+
+ // TODO: validate input values
+ 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 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 we have a valid rule ID, save configuration */
+ /* then update the suricata.conf file and rebuild */
+ /* the rules for this interface. */
+ /**************************************************/
+ if (isset($id) && $a_nat[$id]) {
+ $a_nat[$id] = $natent;
+ write_config();
+ $rebuild_rules = true;
+ suricata_generate_yaml($natent);
+ $rebuild_rules = false;
+ }
+
+ 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_app_parsers.php?id=$id");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Layer 7 Application Parsers");
+include_once("head.inc");
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php include("fbegin.inc"); ?>
+<?php if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+
+
+ /* Display Alert message */
+
+ if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+ }
+
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+
+?>
+
+<script type="text/javascript" src="/javascript/autosuggest.js">
+</script>
+<script type="text/javascript" src="/javascript/suggestions.js">
+</script>
+
+<form action="suricata_app_parsers.php" method="post"
+ enctype="multipart/form-data" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ echo '</td></tr>';
+ echo '<tr><td>';
+ $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface ");
+ $tab_array = array();
+ $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"), 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}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr><td><div id="mainarea">
+<table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Abstract Syntax One Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Asn1 Max Frames"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="asn1_max_frames" type="text" class="formfld unknown" id="asn1_max_frames" size="9"
+ value="<?=htmlspecialchars($pconfig['asn1_max_frames']);?>">&nbsp;
+ <?php echo gettext("Limit for max number of asn1 frames to decode. Default is ") .
+ "<strong>" . gettext("256") . "</strong>" . gettext(" frames."); ?><br/><br/>
+ <?php echo gettext("To protect itself, Suricata will inspect only the maximum asn1 frames specified. ") .
+ gettext("Application layer protocols such as X.400 electronic mail, X.500 and LDAP directory services, ") .
+ 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("Host-Specific HTTP Server Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Server Configuration"); ?></td>
+ <td width="78%" class="vtable">
+ <table width="95%" align="left" id="libhtpEnginesTable" style="table-layout: fixed;" border="0" cellspacing="0" cellpadding="0">
+ <colgroup>
+ <col width="45%" align="left">
+ <col width="45%" align="center">
+ <col width="10%" align="right">
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="listhdrr" axis="string"><?php echo gettext("Name");?></th>
+ <th class="listhdrr" axis="string"><?php echo gettext("Bind-To Address Alias");?></th>
+ <th class="list" align="right"><a href="suricata_import_aliases.php?id=<?=$id?>&eng=libhtp_policy">
+ <img src="../themes/<?= $g['theme'];?>/images/icons/icon_import_alias.gif" width="17"
+ height="17" border="0" title="<?php echo gettext("Import server configuration from existing Aliases");?>"></a>
+ <a href="suricata_libhtp_policy_engine.php?id=<?=$id?>&eng_id=<?=$libhtp_engine_next_id?>">
+ <img src="../themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" width="17"
+ height="17" border="0" title="<?php echo gettext("Add a new server configuration");?>"></a></th>
+ </tr>
+ </thead>
+ <?php foreach ($pconfig['libhtp_policy']['item'] as $f => $v): ?>
+ <tr>
+ <td class="listlr" align="left"><?=gettext($v['name']);?></td>
+ <td class="listbg" align="center"><?=gettext($v['bind_to']);?></td>
+ <td class="listt" align="right"><a href="suricata_libhtp_policy_engine.php?id=<?=$id;?>&eng_id=<?=$f;?>">
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_e.gif"
+ width="17" height="17" border="0" title="<?=gettext("Edit this server configuration");?>"></a>
+ <?php if ($v['bind_to'] <> "all") : ?>
+ <a href="suricata_app_parsers.php?id=<?=$id;?>&eng_id=<?=$f;?>&act=del_libhtp_policy" onclick="return confirm('Are you sure you want to delete this entry?');">
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_x.gif" width="17" height="17" border="0"
+ title="<?=gettext("Delete this server configuration");?>"></a>
+ <?php else : ?>
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_x_d.gif" width="17" height="17" border="0"
+ title="<?=gettext("Default server configuration cannot be deleted");?>">
+ <?php endif ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="Save" title="<?php echo
+ gettext("Save flow and stream settings"); ?>">
+ <input name="id" type="hidden" value="<?=$id;?>">&nbsp;&nbsp;&nbsp;&nbsp;
+ <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>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Note: "); ?></strong></span></span>
+ <?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>
+</table>
+</div>
+</td></tr></table>
+</form>
+<script type="text/javascript">
+function wopen(url, name, w, h)
+{
+ // Fudge factors for window decoration space.
+ // In my tests these work well on all platforms & browsers.
+ w += 32;
+ h += 96;
+ var win = window.open(url,
+ name,
+ 'width=' + w + ', height=' + h + ', ' +
+ 'location=no, menubar=no, ' +
+ 'status=no, toolbar=no, scrollbars=yes, resizable=yes');
+ win.resizeTo(w, h);
+ win.focus();
+}
+
+</script>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_barnyard.php b/config/suricata/suricata_barnyard.php
new file mode 100644
index 00000000..f0bdbd17
--- /dev/null
+++ b/config/suricata/suricata_barnyard.php
@@ -0,0 +1,503 @@
+<?php
+/*
+ * suricata_barnyard.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;
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+$pconfig = array();
+if (isset($id) && $a_nat[$id]) {
+ /* old options */
+ $pconfig = $a_nat[$id];
+ if (!empty($a_nat[$id]['barnconfigpassthru']))
+ $pconfig['barnconfigpassthru'] = base64_decode($a_nat[$id]['barnconfigpassthru']);
+ if (!empty($a_nat[$id]['barnyard_dbpwd']))
+ $pconfig['barnyard_dbpwd'] = base64_decode($a_nat[$id]['barnyard_dbpwd']);
+ if (empty($a_nat[$id]['barnyard_show_year']))
+ $pconfig['barnyard_show_year'] = "on";
+ if (empty($a_nat[$id]['barnyard_archive_enable']))
+ $pconfig['barnyard_archive_enable'] = "on";
+ if (empty($a_nat[$id]['barnyard_obfuscate_ip']))
+ $pconfig['barnyard_obfuscate_ip'] = "off";
+ if (empty($a_nat[$id]['barnyard_syslog_dport']))
+ $pconfig['barnyard_syslog_dport'] = "514";
+ if (empty($a_nat[$id]['barnyard_syslog_proto']))
+ $pconfig['barnyard_syslog_proto'] = "udp";
+ 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";
+ if (empty($a_nat[$id]['barnyard_syslog_priority']))
+ $pconfig['barnyard_syslog_priority'] = "LOG_INFO";
+ if (empty($a_nat[$id]['barnyard_sensor_name']))
+ $pconfig['barnyard_sensor_name'] = php_uname("n");
+}
+
+if (isset($_GET['dup']))
+ unset($id);
+
+if ($_POST) {
+
+ foreach ($a_nat as $natent) {
+ if (isset($id) && ($a_nat[$id]) && ($a_nat[$id] === $natent))
+ continue;
+ if ($natent['interface'] != $_POST['interface'])
+ $input_error[] = "This interface has already an instance defined";
+ }
+
+ // Check that at least one output plugin is enabled
+ if ($_POST['barnyard_mysql_enable'] != 'on' && $_POST['barnyard_syslog_enable'] != 'on')
+ $input_errors[] = gettext("You must enable at least one output option when using Barnyard2.");
+
+ // Validate inputs if MySQL database loggging enabled
+ if ($_POST['barnyard_mysql_enable'] == 'on') {
+ if (empty($_POST['barnyard_dbhost']))
+ $input_errors[] = gettext("Please provide a valid hostname or IP address for the MySQL database host.");
+ if (empty($_POST['barnyard_dbname']))
+ $input_errors[] = gettext("You must provide a DB instance name when logging to a MySQL database.");
+ if (empty($_POST['barnyard_dbuser']))
+ $input_errors[] = gettext("You must provide a DB user login name when logging to a MySQL database.");
+ }
+
+ // Validate inputs if syslog output enabled
+ if ($_POST['barnyard_syslog_enable'] == 'on' && $_POST['barnyard_syslog_local'] <> 'on') {
+ if (empty($_POST['barnyard_syslog_dport']) || !is_numeric($_POST['barnyard_syslog_dport']))
+ $input_errors[] = gettext("Please provide a valid number between 1 and 65535 for the Syslog Remote Port.");
+ if (empty($_POST['barnyard_syslog_rhost']))
+ $input_errors[] = gettext("Please provide a valid hostname or IP address for the Syslog Remote Host.");
+ }
+
+ // if no errors write to conf
+ if (!$input_errors) {
+ $natent = array();
+ /* repost the options already in conf */
+ $natent = $pconfig;
+
+ $natent['barnyard_enable'] = $_POST['barnyard_enable'] ? 'on' : 'off';
+ $natent['barnyard_show_year'] = $_POST['barnyard_show_year'] ? 'on' : 'off';
+ $natent['barnyard_archive_enable'] = $_POST['barnyard_archive_enable'] ? 'on' : 'off';
+ $natent['barnyard_dump_payload'] = $_POST['barnyard_dump_payload'] ? 'on' : 'off';
+ $natent['barnyard_obfuscate_ip'] = $_POST['barnyard_obfuscate_ip'] ? 'on' : 'off';
+ $natent['barnyard_mysql_enable'] = $_POST['barnyard_mysql_enable'] ? 'on' : 'off';
+ $natent['barnyard_syslog_enable'] = $_POST['barnyard_syslog_enable'] ? 'on' : 'off';
+ $natent['barnyard_syslog_local'] = $_POST['barnyard_syslog_local'] ? 'on' : 'off';
+ $natent['barnyard_syslog_opmode'] = $_POST['barnyard_syslog_opmode'];
+ $natent['barnyard_syslog_proto'] = $_POST['barnyard_syslog_proto'];
+
+ if ($_POST['barnyard_sensor_name']) $natent['barnyard_sensor_name'] = $_POST['barnyard_sensor_name']; else unset($natent['barnyard_sensor_name']);
+ if ($_POST['barnyard_dbhost']) $natent['barnyard_dbhost'] = $_POST['barnyard_dbhost']; else unset($natent['barnyard_dbhost']);
+ if ($_POST['barnyard_dbname']) $natent['barnyard_dbname'] = $_POST['barnyard_dbname']; else unset($natent['barnyard_dbname']);
+ if ($_POST['barnyard_dbuser']) $natent['barnyard_dbuser'] = $_POST['barnyard_dbuser']; else unset($natent['barnyard_dbuser']);
+ if ($_POST['barnyard_dbpwd']) $natent['barnyard_dbpwd'] = base64_encode($_POST['barnyard_dbpwd']); else unset($natent['barnyard_dbpwd']);
+ if ($_POST['barnyard_syslog_rhost']) $natent['barnyard_syslog_rhost'] = $_POST['barnyard_syslog_rhost']; else unset($natent['barnyard_syslog_rhost']);
+ if ($_POST['barnyard_syslog_dport']) $natent['barnyard_syslog_dport'] = $_POST['barnyard_syslog_dport']; else $natent['barnyard_syslog_dport'] = '514';
+ if ($_POST['barnyard_syslog_facility']) $natent['barnyard_syslog_facility'] = $_POST['barnyard_syslog_facility']; else $natent['barnyard_syslog_facility'] = 'LOG_USER';
+ if ($_POST['barnyard_syslog_priority']) $natent['barnyard_syslog_priority'] = $_POST['barnyard_syslog_priority']; else $natent['barnyard_syslog_priority'] = 'LOG_INFO';
+ if ($_POST['barnconfigpassthru']) $natent['barnconfigpassthru'] = base64_encode($_POST['barnconfigpassthru']); else unset($natent['barnconfigpassthru']);
+
+ if (isset($id) && $a_nat[$id])
+ $a_nat[$id] = $natent;
+ else {
+ $a_nat[] = $natent;
+ }
+
+ write_config();
+
+ // No need to rebuild rules if just toggling Barnyard2 on or off
+ $rebuild_rules = false;
+ sync_suricata_package_config();
+
+ // Signal any running barnyard2 instance on this interface to
+ // reload its configuration to pick up any changes made.
+ suricata_barnyard_reload_config($a_nat[$id], "HUP");
+
+ // 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' );
+ 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_barnyard.php?id=$id");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Barnyard2 Settings");
+include_once("head.inc");
+
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php include("fbegin.inc"); ?>
+<?if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}?>
+
+<?php
+ /* Display Alert message */
+ if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+ }
+
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+
+ ?>
+
+<form action="suricata_barnyard.php" method="post"
+ enctype="multipart/form-data" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ 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"), true, "/suricata/suricata_barnyard.php?id={$id}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+ <tr>
+ <td><div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("General Barnyard2 " .
+ "Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncellreq"><?php echo gettext("Enable"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_enable" type="checkbox" value="on" <?php if ($pconfig['barnyard_enable'] == "on") echo "checked"; ?> onClick="enable_change(false)"/>
+ <strong><?php echo gettext("Enable Barnyard2"); ?></strong><br/>
+ <?php echo gettext("This will enable barnyard2 for this interface. You will also to enable at least one logging destination below."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Show Year"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_show_year" type="checkbox" value="on" <?php if ($pconfig['barnyard_show_year'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Enable the year being shown in timestamps. Default value is ") . "<strong>" . gettext("Checked") . "</strong>"; ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Archive Unified2 Logs"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_archive_enable" type="checkbox" value="on" <?php if ($pconfig['barnyard_archive_enable'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Enable the archiving of processed unified2 log files. Default value is ") . "<strong>" . gettext("Checked") . "</strong>"; ?><br/>
+ <?php echo gettext("Unified2 log files will be moved to an archive folder for subsequent cleanup when processed."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Dump Payload"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_dump_payload" type="checkbox" value="on" <?php if ($pconfig['barnyard_dump_payload'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Enable dumping of application data from unified2 files. Default value is ") . "<strong>" . gettext("Not Checked") . "</strong>"; ?><br/>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Obfuscate IP Addresses"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_obfuscate_ip" type="checkbox" value="on" <?php if ($pconfig['barnyard_obfuscate_ip'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Enable obfuscation of logged IP addresses. Default value is ") . "<strong>" . gettext("Not Checked") . "</strong>"; ?>
+ </td>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Sensor Name"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_sensor_name" type="text" class="formfld unknown"
+ id="barnyard_sensor_name" size="25" value="<?=htmlspecialchars($pconfig['barnyard_sensor_name']);?>"/>
+ &nbsp;<?php echo gettext("Unique name to use for this sensor."); ?>
+ </td>
+ </tr>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("MySQL Database Output Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable MySQL Database"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_mysql_enable" type="checkbox" value="on" <?php if ($pconfig['barnyard_mysql_enable'] == "on") echo "checked"; ?>
+ onClick="toggle_mySQL()"/><?php echo gettext("Enable logging of alerts to a MySQL database instance"); ?><br/>
+ <?php echo gettext("You will also have to provide the database credentials in the fields below."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Database Host"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_dbhost" type="text" class="formfld host"
+ id="barnyard_dbhost" size="25" value="<?=htmlspecialchars($pconfig['barnyard_dbhost']);?>"/>
+ &nbsp;<?php echo gettext("Hostname or IP address of the MySQL database server"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Database Name"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_dbname" type="text" class="formfld unknown"
+ id="barnyard_dbname" size="25" value="<?=htmlspecialchars($pconfig['barnyard_dbname']);?>"/>
+ &nbsp;<?php echo gettext("Instance or DB name of the MySQL database"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Database User Name"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_dbuser" type="text" class="formfld user"
+ id="barnyard_dbuser" size="25" value="<?=htmlspecialchars($pconfig['barnyard_dbuser']);?>"/>
+ &nbsp;<?php echo gettext("Username for the MySQL database"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Database User Password"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_dbpwd" type="password" class="formfld pwd"
+ id="barnyard_dbpwd" size="25" value="<?=htmlspecialchars($pconfig['barnyard_dbpwd']);?>"/>
+ &nbsp;<?php echo gettext("Password for the MySQL database user"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Syslog Output Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Syslog"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_syslog_enable" type="checkbox" value="on" <?php if ($pconfig['barnyard_syslog_enable'] == "on") echo "checked"; ?>
+ onClick="toggle_syslog()"/>
+ <?php echo gettext("Enable logging of alerts to a syslog receiver"); ?><br/>
+ <?php echo gettext("This will send alert data to either a local or remote syslog receiver."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Operation Mode"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_syslog_opmode" type="radio" id="barnyard_syslog_opmode_default"
+ value="default" <?php if ($pconfig['barnyard_syslog_opmode'] == 'default') echo "checked";?>/>
+ <?php echo gettext("DEFAULT"); ?>&nbsp;<input name="barnyard_syslog_opmode" type="radio" id="barnyard_syslog_opmode_complete"
+ value="complete" <?php if ($pconfig['barnyard_syslog_opmode'] == 'complete') echo "checked";?>/>
+ <?php echo gettext("COMPLETE"); ?>&nbsp;&nbsp;
+ <?php echo gettext("Select the level of detail to include when reporting"); ?><br/><br/>
+ <?php echo gettext("DEFAULT mode is compatible with the standard Snort syslog format. COMPLETE mode includes additional information such as the raw packet data (displayed in hex format)."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Local Only"); ?></td>
+ <td width="78%" class="vtable">
+ <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>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Remote Host"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_syslog_rhost" type="text" class="formfld host"
+ id="barnyard_syslog_rhost" size="25" value="<?=htmlspecialchars($pconfig['barnyard_syslog_rhost']);?>"/>
+ &nbsp;<?php echo gettext("Hostname or IP address of remote syslog host"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Remote Port"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_syslog_dport" type="text" class="formfld unknown"
+ id="barnyard_syslog_dport" size="25" value="<?=htmlspecialchars($pconfig['barnyard_syslog_dport']);?>"/>
+ &nbsp;<?php echo gettext("Port number for syslog on remote host. Default is ") . "<strong>" . gettext("514") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Protocol"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="barnyard_syslog_proto" type="radio" id="barnyard_syslog_proto_udp"
+ value="udp" <?php if ($pconfig['barnyard_syslog_proto'] == 'udp') echo "checked";?>/>
+ <?php echo gettext("UDP"); ?>&nbsp;<input name="barnyard_syslog_proto" type="radio" id="barnyard_syslog_proto_tcp"
+ value="tcp" <?php if ($pconfig['barnyard_syslog_proto'] == 'tcp') echo "checked";?>/>
+ <?php echo gettext("TCP"); ?>&nbsp;&nbsp;
+ <?php echo gettext("Select IP protocol to use for remote reporting. Default is ") . "<strong>" . gettext("UDP") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Facility"); ?></td>
+ <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" );
+ foreach ($log_facility as $facility) {
+ $selected = "";
+ if ($facility == $pconfig['barnyard_syslog_facility'])
+ $selected = " selected";
+ echo "<option value='{$facility}'{$selected}>" . $facility . "</option>\n";
+ }
+ ?></select>&nbsp;&nbsp;
+ <?php echo gettext("Select Syslog Facility to use for remote reporting. Default is ") . "<strong>" . gettext("LOG_USER") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Priority"); ?></td>
+ <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" );
+ foreach ($log_priority as $priority) {
+ $selected = "";
+ if ($priority == $pconfig['barnyard_syslog_priority'])
+ $selected = " selected";
+ echo "<option value='{$priority}'{$selected}>" . $priority . "</option>\n";
+ }
+ ?></select>&nbsp;&nbsp;
+ <?php echo gettext("Select Syslog Priority (Level) to use for remote reporting. Default is ") . "<strong>" . gettext("LOG_INFO") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Advanced Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Advanced configuration " .
+ "pass through"); ?></td>
+ <td width="78%" class="vtable"><textarea name="barnconfigpassthru" style="width:95%;"
+ cols="65" rows="7" id="barnconfigpassthru" ><?=htmlspecialchars($pconfig['barnconfigpassthru']);?></textarea>
+ <br/>
+ <?php echo gettext("Arguments entered here will be automatically inserted into the running " .
+ "barnyard2 configuration."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="Save">
+ <input name="id" type="hidden" value="<?=$id;?>"> </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Note:"); ?></strong></span></span>
+ <br/>
+ <?php echo gettext("Please save your settings before you click start."); ?> </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<script language="JavaScript">
+
+function toggle_mySQL() {
+ var endis = !document.iform.barnyard_mysql_enable.checked;
+
+ document.iform.barnyard_dbhost.disabled = endis;
+ document.iform.barnyard_dbname.disabled = endis;
+ document.iform.barnyard_dbuser.disabled = endis;
+ document.iform.barnyard_dbpwd.disabled = endis;
+}
+
+function toggle_syslog() {
+ var endis = !document.iform.barnyard_syslog_enable.checked;
+
+ document.iform.barnyard_syslog_opmode_default.disabled = endis;
+ document.iform.barnyard_syslog_opmode_complete.disabled = endis;
+ document.iform.barnyard_syslog_local.disabled = endis;
+ document.iform.barnyard_syslog_rhost.disabled = endis;
+ 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;
+}
+
+function toggle_local_syslog() {
+ var endis = document.iform.barnyard_syslog_local.checked;
+
+ if (document.iform.barnyard_syslog_enable.checked) {
+ document.iform.barnyard_syslog_rhost.disabled = endis;
+ 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;
+ }
+}
+
+function enable_change(enable_change) {
+ endis = !(document.iform.barnyard_enable.checked || enable_change);
+ // make sure a default answer is called if this is invoked.
+ endis2 = (document.iform.barnyard_enable);
+ document.iform.barnyard_archive_enable.disabled = endis;
+ document.iform.barnyard_show_year.disabled = endis;
+ document.iform.barnyard_dump_payload.disabled = endis;
+ document.iform.barnyard_obfuscate_ip.disabled = endis;
+ document.iform.barnyard_sensor_name.disabled = endis;
+ document.iform.barnyard_mysql_enable.disabled = endis;
+ document.iform.barnyard_dbhost.disabled = endis;
+ document.iform.barnyard_dbname.disabled = endis;
+ document.iform.barnyard_dbuser.disabled = endis;
+ document.iform.barnyard_dbpwd.disabled = endis;
+ document.iform.barnyard_syslog_enable.disabled = endis;
+ document.iform.barnyard_syslog_local.disabled = endis;
+ document.iform.barnyard_syslog_opmode_default.disabled = endis;
+ document.iform.barnyard_syslog_opmode_complete.disabled = endis;
+ document.iform.barnyard_syslog_rhost.disabled = endis;
+ 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;
+ document.iform.barnconfigpassthru.disabled = endis;
+}
+
+enable_change(false);
+toggle_mySQL();
+toggle_syslog();
+toggle_local_syslog();
+
+</script>
+
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_check_cron_misc.inc b/config/suricata/suricata_check_cron_misc.inc
new file mode 100644
index 00000000..88dfd5ff
--- /dev/null
+++ b/config/suricata/suricata_check_cron_misc.inc
@@ -0,0 +1,109 @@
+<?php
+/*
+ * suricata_check_cron_misc.inc
+ * 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("/usr/local/pkg/suricata/suricata.inc");
+
+// 'B' => 1,
+// 'KB' => 1024,
+// 'MB' => 1024 * 1024,
+// 'GB' => 1024 * 1024 * 1024,
+// 'TB' => 1024 * 1024 * 1024 * 1024,
+// 'PB' => 1024 * 1024 * 1024 * 1024 * 1024,
+
+
+/* chk if snort log dir is full if so clear it */
+$suricataloglimit = $config['installedpackages']['suricata']['config'][0]['suricataloglimit'];
+$suricataloglimitsize = $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'];
+
+if ($g['booting']==true)
+ return;
+
+if ($suricataloglimit == 'off')
+ return;
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ return;
+
+/* Convert Log Limit Size setting from MB to KB */
+$suricataloglimitsizeKB = round($suricataloglimitsize * 1024);
+$suricatalogdirsizeKB = suricata_Getdirsize(SURICATALOGDIR);
+if ($suricatalogdirsizeKB > 0 && $suricatalogdirsizeKB > $suricataloglimitsizeKB) {
+ log_error(gettext("[Suricata] Log directory size exceeds configured limit of " . number_format($suricataloglimitsize) . " MB set on Global Settings tab. All Suricata log files will be truncated."));
+ conf_mount_rw();
+
+ /* Truncate the Rules Update Log file if it exists */
+ if (file_exists(RULES_UPD_LOGFILE)) {
+ log_error(gettext("[Suricata] Truncating the Rules Update Log file..."));
+ $fd = @fopen(RULES_UPD_LOGFILE, "w+");
+ if ($fd)
+ fclose($fd);
+ }
+
+ /* Clean-up the logs for each configured Suricata instance */
+ foreach ($config['installedpackages']['suricata']['rule'] as $value) {
+ $if_real = suricata_get_real_interface($value['interface']);
+ $suricata_uuid = $value['uuid'];
+ $suricata_log_dir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}";
+ log_error(gettext("[Suricata] Truncating logs for {$value['descr']} ({$if_real})..."));
+ suricata_post_delete_logs($suricata_uuid);
+
+ // Initialize an array of the log files we want to prune
+ $logs = array ( "alerts.log", "http.log", "files-json.log", "tls.log", "stats.log" );
+
+ foreach ($logs as $file) {
+ // Truncate the log file if it exists
+ if (file_exists("{$suricata_log_dir}/$file")) {
+ $fd = @fopen("{$suricata_log_dir}/$file", "w+");
+ if ($fd)
+ fclose($fd);
+ }
+ }
+
+ // Check for any captured stored files and clean them up
+ $filelist = glob("{$suricata_log_dir}/files/*");
+ if (!empty($filelist)) {
+ foreach ($filelist as $file)
+ @unlink($file);
+ }
+
+ // This is needed if suricata is run as suricata user
+ mwexec('/bin/chmod 660 /var/log/suricata/*', true);
+
+ // Soft-restart Suricata process to resync logging
+ if (file_exists("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid")) {
+ log_error(gettext("[Suricata] Restarting logging on {$value['descr']} ({$if_real})..."));
+ mwexec("/bin/pkill -HUP -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid -a");
+ }
+ }
+ conf_mount_ro();
+ log_error(gettext("[Suricata] Automatic clean-up of Suricata logs completed."));
+}
+
+?>
diff --git a/config/suricata/suricata_check_for_rule_updates.php b/config/suricata/suricata_check_for_rule_updates.php
new file mode 100644
index 00000000..9aa14f6e
--- /dev/null
+++ b/config/suricata/suricata_check_for_rule_updates.php
@@ -0,0 +1,683 @@
+<?php
+/*
+ * suricata_check_for_rule_updates.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("functions.inc");
+require_once("service-utils.inc");
+require_once("/usr/local/pkg/suricata/suricata.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;
+
+/* Save the state of $pkg_interface so we can restore it */
+$pkg_interface_orig = $pkg_interface;
+if ($suricata_gui_include)
+ $pkg_interface = "";
+else
+ $pkg_interface = "console";
+
+/* define checks */
+$oinkid = $config['installedpackages']['suricata']['config'][0]['oinkcode'];
+$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';
+$eto = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules'] == 'on' ? 'on' : 'off';
+$vrt_enabled = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'] == 'on' ? 'on' : 'off';
+$snortcommunityrules = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules'] == 'on' ? 'on' : 'off';
+
+/* Working directory for downloaded rules tarballs */
+$tmpfname = "/tmp/suricata_rules_up";
+
+/* Snort Edge VRT Rules filenames and URL */
+$snort_filename = VRT_DNLD_FILENAME;
+$snort_filename_md5 = "{$snort_filename}.md5";
+$snort_rule_url = VRT_DNLD_URL;
+
+/* Snort GPLv2 Community Rules filenames and URL */
+$snort_community_rules_filename = GPLV2_DNLD_FILENAME;
+$snort_community_rules_filename_md5 = GPLV2_DNLD_FILENAME . ".md5";
+$snort_community_rules_url = GPLV2_DNLD_URL;
+
+/* Set up Emerging Threats rules filenames and URL */
+if ($etpro == "on") {
+ $emergingthreats_filename = ETPRO_DNLD_FILENAME;
+ $emergingthreats_filename_md5 = ETPRO_DNLD_FILENAME . ".md5";
+ $emergingthreats_url = ETPRO_BASE_DNLD_URL;
+ $emergingthreats_url .= "{$etproid}/suricata/";
+ $et_name = "Emerging Threats Pro";
+ $et_md5_remove = ET_DNLD_FILENAME . ".md5";
+ @unlink("{$suricatadir}{$et_md5_remove}");
+}
+else {
+ $emergingthreats_filename = ET_DNLD_FILENAME;
+ $emergingthreats_filename_md5 = ET_DNLD_FILENAME . ".md5";
+ $emergingthreats_url = ET_BASE_DNLD_URL;
+ // If using Sourcefire VRT rules with ET, then we should use the open-nogpl ET rules
+ $emergingthreats_url .= $vrt_enabled == "on" ? "open-nogpl/" : "open/";
+ $emergingthreats_url .= "suricata/";
+ $et_name = "Emerging Threats Open";
+ $et_md5_remove = ETPRO_DNLD_FILENAME . ".md5";
+ @unlink("{$suricatadir}{$et_md5_remove}");
+}
+
+// Set a common flag for all Emerging Threats rules (open and pro).
+if ($etpro == 'on' || $eto == 'on')
+ $emergingthreats = 'on';
+else
+ $emergingthreats = 'off';
+
+function suricata_download_file_url($url, $file_out) {
+
+ /************************************************/
+ /* This function downloads the file specified */
+ /* by $url using the CURL library functions and */
+ /* saves the content to the file specified by */
+ /* $file. */
+ /* */
+ /* This is needed so console output can be */
+ /* suppressed to prevent XMLRPC sync errors. */
+ /* */
+ /* It provides logging of returned CURL errors. */
+ /************************************************/
+
+ global $g, $config, $pkg_interface, $last_curl_error, $fout, $ch, $file_size, $downloaded, $first_progress_update;
+
+ // Initialize required variables for the pfSense "read_body()" function
+ $file_size = 1;
+ $downloaded = 1;
+ $first_progress_update = TRUE;
+
+
+ // Array of message strings for HTTP Response Codes
+ $http_resp_msg = array( 200 => "OK", 202 => "Accepted", 204 => "No Content", 205 => "Reset Content",
+ 206 => "Partial Content", 301 => "Moved Permanently", 302 => "Found",
+ 305 => "Use Proxy", 307 => "Temporary Redirect", 400 => "Bad Request",
+ 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden",
+ 404 => "Not Found", 405 => "Method Not Allowed", 407 => "Proxy Authentication Required",
+ 408 => "Request Timeout", 410 => "Gone", 500 => "Internal Server Error",
+ 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable",
+ 504 => "Gateway Timeout", 505 => "HTTP Version Not Supported" );
+
+ $last_curl_error = "";
+
+ $fout = fopen($file_out, "wb");
+ if ($fout) {
+ $ch = curl_init($url);
+ if (!$ch)
+ return false;
+ curl_setopt($ch, CURLOPT_FILE, $fout);
+
+ // NOTE: required to suppress errors from XMLRPC due to progress bar output
+ if ($g['suricata_sync_in_progress'])
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ else {
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
+ curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'read_body');
+ }
+
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Win64; x64; Trident/6.0)");
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 0);
+
+ // Use the system proxy server setttings if configured
+ 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']}");
+ }
+ }
+
+ $counter = 0;
+ $rc = true;
+ // Try up to 4 times to download the file before giving up
+ while ($counter < 4) {
+ $counter++;
+ $rc = curl_exec($ch);
+ if ($rc === true)
+ break;
+ log_error(gettext("[Suricata] Rules download error: " . curl_error($ch)));
+ log_error(gettext("[Suricata] Will retry in 15 seconds..."));
+ sleep(15);
+ }
+ if ($rc === false)
+ $last_curl_error = curl_error($ch);
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ if (isset($http_resp_msg[$http_code]))
+ $last_curl_error = $http_resp_msg[$http_code];
+ curl_close($ch);
+ fclose($fout);
+
+ // If we had to try more than once, log it
+ if ($counter > 1)
+ log_error(gettext("File '" . basename($file_out) . "' download attempts: {$counter} ..."));
+ return ($http_code == 200) ? true : $http_code;
+ }
+ else {
+ $last_curl_error = gettext("Failed to create file " . $file_out);
+ log_error(gettext("[Suricata] Failed to create file {$file_out} ..."));
+ return false;
+ }
+}
+
+function suricata_check_rule_md5($file_url, $file_dst, $desc = "") {
+
+ /**********************************************************/
+ /* This function attempts to download the passed MD5 hash */
+ /* file and compare its contents to the currently stored */
+ /* hash file to see if a new rules file has been posted. */
+ /* */
+ /* On Entry: $file_url = URL for md5 hash file */
+ /* $file_dst = Temp destination to store the */
+ /* downloaded hash file */
+ /* $desc = Short text string used to label */
+ /* log messages with rules type */
+ /* */
+ /* Returns: TRUE if new rule file download required. */
+ /* FALSE if rule download not required or an */
+ /* error occurred. */
+ /**********************************************************/
+
+ global $pkg_interface, $suricata_rules_upd_log, $last_curl_error;
+
+ $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);
+ $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);
+
+ // check md5 hash in new file against current file to see if new download is posted
+ if (file_exists("{$suricatadir}{$filename_md5}")) {
+ $md5_check_new = file_get_contents($file_dst);
+ $md5_check_old = file_get_contents("{$suricatadir}{$filename_md5}");
+ if ($md5_check_new == $md5_check_old) {
+ 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);
+ return false;
+ }
+ else
+ return true;
+ }
+ return true;
+ }
+ else {
+ error_log(gettext("\t{$desc} md5 download failed.\n"), 3, $suricata_rules_upd_log);
+ $suricata_err_msg = gettext("Server returned error code {$rc}.");
+ if ($pkg_interface <> "console") {
+ update_status(gettext("{$desc} md5 error ... Server returned error code {$rc} ..."));
+ update_output_window(gettext("{$desc} will not be updated.\n\t{$suricata_err_msg}"));
+ }
+ 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);
+ 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);
+ return false;
+ }
+}
+
+function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") {
+
+ /**********************************************************/
+ /* This function downloads the passed rules file and */
+ /* compares its computed md5 hash to the passed md5 hash */
+ /* to verify the file's integrity. */
+ /* */
+ /* On Entry: $file_url = URL of rules file */
+ /* $file_dst = Temp destination to store the */
+ /* downloaded rules file */
+ /* $file_md5 = Expected md5 hash for the new */
+ /* downloaded rules file */
+ /* $desc = Short text string for use in */
+ /* log messages */
+ /* */
+ /* Returns: TRUE if download was successful. */
+ /* FALSE if download was not successful. */
+ /**********************************************************/
+
+ global $pkg_interface, $suricata_rules_upd_log, $last_curl_error;
+
+ $suricatadir = SURICATADIR;
+ $filename = basename($file_dst);
+
+ 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);
+ $rc = suricata_download_file_url($file_url, $file_dst);
+
+ // See if the download from the URL was successful
+ if ($rc === true) {
+ 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);
+
+ // Test integrity of the rules file. Turn off update if file has wrong md5 hash
+ if ($file_md5 != trim(md5_file($file_dst))){
+ if ($pkg_interface <> "console")
+ update_output_window(gettext("{$desc} file MD5 checksum failed..."));
+ 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);
+ return false;
+ }
+ return true;
+ }
+ else {
+ 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);
+ 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);
+ return false;
+ }
+
+}
+
+/* Start of main code */
+conf_mount_rw();
+
+/* remove old $tmpfname files if present */
+if (is_dir("{$tmpfname}"))
+ exec("/bin/rm -r {$tmpfname}");
+
+/* Make sure required suricatadirs exsist */
+exec("/bin/mkdir -p {$suricatadir}rules");
+exec("/bin/mkdir -p {$tmpfname}");
+exec("/bin/mkdir -p {$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}");
+}
+
+/* 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);
+$last_curl_error = "";
+
+/* Check for and download any new Emerging Threats Rules sigs */
+if ($emergingthreats == 'on') {
+ if (suricata_check_rule_md5("{$emergingthreats_url}{$emergingthreats_filename_md5}", "{$tmpfname}/{$emergingthreats_filename_md5}", "{$et_name} rules")) {
+ /* download Emerging Threats rules file */
+ $file_md5 = trim(file_get_contents("{$tmpfname}/{$emergingthreats_filename_md5}"));
+ if (!suricata_fetch_new_rules("{$emergingthreats_url}{$emergingthreats_filename}", "{$tmpfname}/{$emergingthreats_filename}", $file_md5, "{$et_name} rules"))
+ $emergingthreats = 'off';
+ }
+ else
+ $emergingthreats = 'off';
+}
+
+/* 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")) {
+ /* 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"))
+ $snortdownload = 'off';
+ }
+ else
+ $snortdownload = 'off';
+}
+
+/* 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")) {
+ /* 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"))
+ $snortcommunityrules = 'off';
+ }
+ else
+ $snortcommunityrules = 'off';
+}
+
+/* Untar Emerging Threats rules file to tmp if downloaded */
+if ($emergingthreats == 'on') {
+ safe_mkdir("{$tmpfname}/emerging");
+ if (file_exists("{$tmpfname}/{$emergingthreats_filename}")) {
+ if ($pkg_interface <> "console") {
+ 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);
+ exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$tmpfname}/emerging rules/");
+
+ /* Remove the old Emerging Threats rules files */
+ $eto_prefix = ET_OPEN_FILE_PREFIX;
+ $etpro_prefix = ET_PRO_FILE_PREFIX;
+ array_map('unlink', glob("{$suricatadir}rules/{$eto_prefix}*.rules"));
+ array_map('unlink', glob("{$suricatadir}rules/{$etpro_prefix}*.rules"));
+ array_map('unlink', glob("{$suricatadir}rules/{$eto_prefix}*ips.txt"));
+ array_map('unlink', glob("{$suricatadir}rules/{$etpro_prefix}*ips.txt"));
+
+ // The code below renames ET-Pro files with a prefix, so we
+ // skip renaming the Suricata default events rule files
+ // that are also bundled in the ET-Pro rules.
+ $default_rules = array( "decoder-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules" );
+ $files = glob("{$tmpfname}/emerging/rules/*.rules");
+ foreach ($files as $file) {
+ $newfile = basename($file);
+ if ($etpro == "on" && !in_array($newfile, $default_rules))
+ @copy($file, "{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "{$newfile}");
+ else
+ @copy($file, "{$suricatadir}rules/{$newfile}");
+ }
+ /* IP lists for Emerging Threats rules */
+ $files = glob("{$tmpfname}/emerging/rules/*ips.txt");
+ foreach ($files as $file) {
+ $newfile = basename($file);
+ if ($etpro == "on")
+ @copy($file, "{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "{$newfile}");
+ else
+ @copy($file, "{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "{$newfile}");
+ }
+ /* base etc files for Emerging Threats rules */
+ foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) {
+ if (file_exists("{$tmpfname}/emerging/rules/{$file}"))
+ @copy("{$tmpfname}/emerging/rules/{$file}", "{$tmpfname}/ET_{$file}");
+ }
+
+ /* Copy emergingthreats md5 sig to Suricata dir */
+ if (file_exists("{$tmpfname}/{$emergingthreats_filename_md5}")) {
+ if ($pkg_interface <> "console")
+ update_status(gettext("Copying md5 signature to Suricata directory..."));
+ @copy("{$tmpfname}/{$emergingthreats_filename_md5}", "{$suricatadir}{$emergingthreats_filename_md5}");
+ }
+ if ($pkg_interface <> "console") {
+ 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");
+ }
+}
+
+/* Untar Snort rules file to tmp */
+if ($snortdownload == 'on') {
+ if (file_exists("{$tmpfname}/{$snort_filename}")) {
+ /* Remove the old Snort rules files */
+ $vrt_prefix = VRT_FILE_PREFIX;
+ array_map('unlink', glob("{$suricatadir}rules/{$vrt_prefix}*.rules"));
+
+ if ($pkg_interface <> "console") {
+ 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);
+
+ /* extract snort.org rules and add prefix to all snort.org files */
+ safe_mkdir("{$tmpfname}/snortrules");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname}/snortrules rules/");
+ $files = glob("{$tmpfname}/snortrules/rules/*.rules");
+ foreach ($files as $file) {
+ $newfile = basename($file);
+ @copy($file, "{$suricatadir}rules/" . VRT_FILE_PREFIX . "{$newfile}");
+ }
+
+ /* IP lists */
+ $files = glob("{$tmpfname}/snortrules/rules/*.txt");
+ foreach ($files as $file) {
+ $newfile = basename($file);
+ @copy($file, "{$suricatadir}rules/{$newfile}");
+ }
+ exec("rm -r {$tmpfname}/snortrules");
+
+ /* extract base etc files */
+ if ($pkg_interface <> "console") {
+ update_status(gettext("Extracting Snort VRT config and map files..."));
+ update_output_window(gettext("Copying config and map files..."));
+ }
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} etc/");
+ foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) {
+ if (file_exists("{$tmpfname}/etc/{$file}"))
+ @copy("{$tmpfname}/etc/{$file}", "{$tmpfname}/VRT_{$file}");
+ }
+ exec("rm -r {$tmpfname}/etc");
+ if (file_exists("{$tmpfname}/{$snort_filename_md5}")) {
+ if ($pkg_interface <> "console")
+ update_status(gettext("Copying md5 signature to Suricata directory..."));
+ @copy("{$tmpfname}/{$snort_filename_md5}", "{$suricatadir}{$snort_filename_md5}");
+ }
+ if ($pkg_interface <> "console") {
+ 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);
+ }
+}
+
+/* Untar Snort GPLv2 Community rules file to tmp */
+if ($snortcommunityrules == 'on') {
+ safe_mkdir("{$tmpfname}/community");
+ if (file_exists("{$tmpfname}/{$snort_community_rules_filename}")) {
+ if ($pkg_interface <> "console") {
+ 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);
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_community_rules_filename} -C {$tmpfname}/community/");
+
+ $files = glob("{$tmpfname}/community/community-rules/*.rules");
+ foreach ($files as $file) {
+ $newfile = basename($file);
+ @copy($file, "{$suricatadir}rules/" . GPL_FILE_PREFIX . "{$newfile}");
+ }
+ /* base etc files for Snort GPLv2 Community rules */
+ foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) {
+ if (file_exists("{$tmpfname}/community/community-rules/{$file}"))
+ @copy("{$tmpfname}/community/community-rules/{$file}", "{$tmpfname}/" . GPL_FILE_PREFIX . "{$file}");
+ }
+ /* Copy snort community md5 sig to suricata dir */
+ if (file_exists("{$tmpfname}/{$snort_community_rules_filename_md5}")) {
+ if ($pkg_interface <> "console")
+ update_status(gettext("Copying md5 signature to suricata directory..."));
+ @copy("{$tmpfname}/{$snort_community_rules_filename_md5}", "{$suricatadir}{$snort_community_rules_filename_md5}");
+ }
+ if ($pkg_interface <> "console") {
+ 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");
+ }
+}
+
+function suricata_apply_customizations($suricatacfg, $if_real) {
+
+ global $vrt_enabled, $rebuild_rules;
+ $suricatadir = SURICATADIR;
+
+ suricata_prepare_rule_files($suricatacfg, "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}");
+
+ /* Copy the master config and map files to the interface directory */
+ @copy("{$suricatadir}classification.config", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/classification.config");
+ @copy("{$suricatadir}reference.config", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/reference.config");
+ @copy("{$suricatadir}gen-msg.map", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/gen-msg.map");
+ @copy("{$suricatadir}unicode.map", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/unicode.map");
+}
+
+if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules == 'on') {
+
+ 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);
+
+ /******************************************************************/
+ /* Build the classification.config and reference.config files */
+ /* using the ones from all the downloaded rules plus the default */
+ /* files installed with Suricata. */
+ /******************************************************************/
+ $cfgs = glob("{$tmpfname}/*reference.config");
+ $cfgs[] = "{$suricatadir}reference.config";
+ suricata_merge_reference_configs($cfgs, "{$suricatadir}reference.config");
+ $cfgs = glob("{$tmpfname}/*classification.config");
+ $cfgs[] = "{$suricatadir}classification.config";
+ suricata_merge_classification_configs($cfgs, "{$suricatadir}classification.config");
+
+ /* Determine which map files to use for the master copy. */
+ /* The Snort VRT ones are preferred, if available. */
+ if ($snortdownload == 'on')
+ $prefix = "VRT_";
+ elseif ($emergingthreats == 'on')
+ $prefix = "ET_";
+ elseif ($snortcommunityrules == 'on')
+ $prefix = GPL_FILE_PREFIX;
+ if (file_exists("{$tmpfname}/{$prefix}unicode.map"))
+ @copy("{$tmpfname}/{$prefix}unicode.map", "{$suricatadir}unicode.map");
+ if (file_exists("{$tmpfname}/{$prefix}gen-msg.map"))
+ @copy("{$tmpfname}/{$prefix}gen-msg.map", "{$suricatadir}gen-msg.map");
+
+ /* Start the rules rebuild proccess for each configured interface */
+ if (is_array($config['installedpackages']['suricata']['rule']) &&
+ !empty($config['installedpackages']['suricata']['rule'])) {
+
+ /* Set the flag to force rule rebuilds since we downloaded new rules */
+ $rebuild_rules = true;
+
+ /* Create configuration for each active Suricata interface */
+ foreach ($config['installedpackages']['suricata']['rule'] as $value) {
+ $if_real = get_real_interface($value['interface']);
+ // Make sure the interface subdirectory exists. We need to re-create
+ // it during a pkg reinstall on the intial rules set download.
+ if (!is_dir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}"))
+ safe_mkdir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}");
+ if (!is_dir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}/rules"))
+ safe_mkdir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}/rules");
+ $tmp = "Updating rules configuration for: " . convert_friendly_interface_to_friendly_descr($value['interface']) . " ...";
+ if ($pkg_interface <> "console"){
+ update_status(gettext($tmp));
+ update_output_window(gettext("Please wait while Suricata interface files are being updated..."));
+ }
+ suricata_apply_customizations($value, $if_real);
+ $tmp = "\t" . $tmp . "\n";
+ error_log($tmp, 3, $suricata_rules_upd_log);
+ }
+ }
+ else {
+ if ($pkg_interface <> "console") {
+ 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);
+ }
+
+ /* 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']) {
+ 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);
+ 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);
+ }
+ else {
+ if ($pkg_interface <> "console")
+ update_output_window(gettext("The rules update task is complete..."));
+ }
+}
+
+// Remove old $tmpfname files
+if (is_dir("{$tmpfname}")) {
+ if ($pkg_interface <> "console")
+ update_status(gettext("Cleaning up after rules extraction..."));
+ exec("/bin/rm -r {$tmpfname}");
+}
+
+if ($pkg_interface <> "console")
+ update_status(gettext("The Rules update has finished..."));
+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();
+
+// Restore the state of $pkg_interface
+$pkg_interface = $pkg_interface_orig;
+
+?>
diff --git a/config/suricata/suricata_define_vars.php b/config/suricata/suricata_define_vars.php
new file mode 100644
index 00000000..b1cbfee9
--- /dev/null
+++ b/config/suricata/suricata_define_vars.php
@@ -0,0 +1,268 @@
+<?php
+/*
+ * suricata_define_vars.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("globals.inc");
+require_once("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (!is_array($config['installedpackages']['suricata']['rule'])) {
+ $config['installedpackages']['suricata']['rule'] = array();
+}
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+/* define servers and ports */
+$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",
+ "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"
+);
+
+/* if user has defined a custom ssh port, use it */
+if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port']))
+ $ssh_port = $config['system']['ssh']['port'];
+else
+ $ssh_port = "22";
+$suricata_ports = array(
+ "http_ports" => "80",
+ "oracle_ports" => "1521",
+ "ssh_ports" => $ssh_port,
+ "shellcode_ports" => "!80",
+ "DNP3_PORTS" => "20000", "file_data_ports" => "\$HTTP_PORTS,110,143"
+);
+
+// Sort our SERVERS and PORTS arrays to make values
+// easier to locate by the the user.
+ksort($suricata_servers);
+ksort($suricata_ports);
+
+$pconfig = $a_nat[$id];
+
+/* convert fake interfaces to real */
+$if_real = get_real_interface($pconfig['interface']);
+$suricata_uuid = $config['installedpackages']['suricata']['rule'][$id]['uuid'];
+
+if ($_POST) {
+
+ $natent = array();
+ $natent = $pconfig;
+
+ foreach ($suricata_servers as $key => $server) {
+ if ($_POST["def_{$key}"] && !is_alias($_POST["def_{$key}"]))
+ $input_errors[] = "Only aliases are allowed";
+ }
+ foreach ($suricata_ports as $key => $server) {
+ if ($_POST["def_{$key}"] && !is_alias($_POST["def_{$key}"]))
+ $input_errors[] = "Only aliases are allowed";
+ }
+ /* if no errors write to suricata.yaml */
+ if (!$input_errors) {
+ /* post new options */
+ foreach ($suricata_servers as $key => $server) {
+ if ($_POST["def_{$key}"])
+ $natent["def_{$key}"] = $_POST["def_{$key}"];
+ else
+ unset($natent["def_{$key}"]);
+ }
+ foreach ($suricata_ports as $key => $server) {
+ if ($_POST["def_{$key}"])
+ $natent["def_{$key}"] = $_POST["def_{$key}"];
+ else
+ unset($natent["def_{$key}"]);
+ }
+
+ $a_nat[$id] = $natent;
+
+ write_config();
+
+ /* Update the suricata.yaml file for this interface. */
+ $rebuild_rules = false;
+ suricata_generate_yaml($a_nat[$id]);
+
+ /* Soft-restart Suricaa to live-load new variables. */
+ suricata_reload_config($a_nat[$id]);
+
+ /* 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' );
+ 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_define_vars.php?id=$id");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} Variables - Servers and Ports");
+include_once("head.inc");
+
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php
+include("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+/* Display Alert message */
+if ($input_errors)
+ print_input_errors($input_errors); // TODO: add checks
+if ($savemsg)
+ print_info_box($savemsg);
+?>
+
+<script type="text/javascript" src="/javascript/autosuggest.js">
+</script>
+<script type="text/javascript" src="/javascript/suggestions.js">
+</script>
+<form action="suricata_define_vars.php" method="post" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ 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"), true, "/suricata/suricata_define_vars.php?id={$id}");
+ $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr>
+ <td><div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Define Servers (IP variables)"); ?></td>
+ </tr>
+<?php
+ foreach ($suricata_servers as $key => $server):
+ if (strlen($server) > 40)
+ $server = substr($server, 0, 40) . "...";
+ $label = strtoupper($key);
+ $value = "";
+ $title = "";
+ if (!empty($pconfig["def_{$key}"])) {
+ $value = htmlspecialchars($pconfig["def_{$key}"]);
+ $title = trim(filter_expand_alias($pconfig["def_{$key}"]));
+ }
+?>
+ <tr>
+ <td width='30%' valign='top' class='vncell'><?php echo gettext("Define"); ?> <?=$label;?></td>
+ <td width="70%" class="vtable">
+ <input name="def_<?=$key;?>" size="40"
+ type="text" autocomplete="off" class="formfldalias" id="def_<?=$key;?>"
+ value="<?=$value;?>" title="<?=$title;?>"> <br/>
+ <span class="vexpl"><?php echo gettext("Default value:"); ?> "<?=$server;?>" <br/><?php echo gettext("Leave " .
+ "blank for default value."); ?></span>
+ </td>
+ </tr>
+<?php endforeach; ?>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Define Ports (port variables)"); ?></td>
+ </tr>
+<?php
+ foreach ($suricata_ports as $key => $server):
+ if (strlen($server) > 40)
+ $server = substr($server, 0, 40) . "...";
+ $label = strtoupper($key);
+ $value = "";
+ $title = "";
+ if (!empty($pconfig["def_{$key}"])) {
+ $value = htmlspecialchars($pconfig["def_{$key}"]);
+ $title = trim(filter_expand_alias($pconfig["def_{$key}"]));
+ }
+?>
+ <tr>
+ <td width='30%' valign='top' class='vncell'><?php echo gettext("Define"); ?> <?=$label;?></td>
+ <td width="70%" class="vtable">
+ <input name="def_<?=$key;?>" type="text" size="40" autocomplete="off" class="formfldalias" id="def_<?=$key;?>"
+ value="<?=$value;?>" title="<?=$title;?>"> <br/>
+ <span class="vexpl"><?php echo gettext("Default value:"); ?> "<?=$server;?>" <br/> <?php echo gettext("Leave " .
+ "blank for default value."); ?></span>
+ </td>
+ </tr>
+<?php endforeach; ?>
+ <tr>
+ <td width="30%" valign="top">&nbsp;</td>
+ <td width="70%">
+ <input name="Submit" type="submit" class="formbtn" value="Save">
+ <input name="id" type="hidden" value="<?=$id;?>">
+ </td>
+ </tr>
+ </table>
+</div>
+</td></tr>
+</table>
+</form>
+<script type="text/javascript">
+//<![CDATA[
+ var addressarray = <?= json_encode(get_alias_list(array("host", "network"))) ?>;
+ var portsarray = <?= json_encode(get_alias_list("port")) ?>;
+
+ function createAutoSuggest() {
+ <?php
+ foreach ($suricata_servers as $key => $server)
+ echo " var objAlias{$key} = new AutoSuggestControl(document.getElementById('def_{$key}'), new StateSuggestions(addressarray));\n";
+ foreach ($suricata_ports as $key => $server)
+ echo "var pobjAlias{$key} = new AutoSuggestControl(document.getElementById('def_{$key}'), new StateSuggestions(portsarray));\n";
+ ?>
+ }
+
+setTimeout("createAutoSuggest();", 500);
+
+//]]>
+</script>
+
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_download_rules.php b/config/suricata/suricata_download_rules.php
new file mode 100644
index 00000000..26737dcf
--- /dev/null
+++ b/config/suricata/suricata_download_rules.php
@@ -0,0 +1,97 @@
+<?php
+/*
+ * suricata_download_rules.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("guiconfig.inc");
+require_once("functions.inc");
+require_once("service-utils.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g;
+
+$pgtitle = "Services: Suricata - Update Rules";
+include("head.inc");
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php include("fbegin.inc"); ?>
+<?if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}?>
+
+<form action="/suricata/suricata_download_updates.php" method="GET">
+
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td align="center"><div id="boxarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td class="tabcont" align="center">
+ <table width="420" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td style="background:url('../themes/<?= $g['theme']; ?>/images/misc/bar_left.gif')" height="15" width="5"></td>
+ <td style="background:url('../themes/<?= $g['theme']; ?>/images/misc/bar_gray.gif')" height="15" width="410">
+ <table id="progholder" width='410' cellpadding='0' cellspacing='0'>
+ <tr>
+ <td align="left"><img border='0' src='../themes/<?= $g['theme']; ?>/images/misc/bar_blue.gif'
+ width='0' height='15' name='progressbar' id='progressbar' alt='' /></td
+ </tr>
+ </table></td>
+ <td style="background:url('../themes/<?= $g['theme']; ?>/images/misc/bar_right.gif')" height="15" width="5"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="tabcont" align="center">
+ <!-- status box -->
+ <textarea cols="85" rows="1" name="status" id="status" wrap="soft"><?=gettext("Initializing..."); ?>.</textarea>
+ <!-- command output box -->
+ <textarea cols="85" rows="12" name="output" id="output" wrap="soft"></textarea>
+ </td>
+ </tr>
+ <tr>
+ <td class="tabcont" align="center" valign="middle"><input type="submit" name="return" id="return" Value="Return"></td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+<?php include("fend.inc");?>
+</body>
+</html>
+<?php
+
+$suricata_gui_include = true;
+include("/usr/local/www/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
new file mode 100644
index 00000000..ecfd5f8b
--- /dev/null
+++ b/config/suricata/suricata_download_updates.php
@@ -0,0 +1,220 @@
+<?php
+/*
+ * suricata_download_updates.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");
+
+/* Define some locally required variables from Suricata constants */
+$suricatadir = SURICATADIR;
+$suricata_rules_upd_log = RULES_UPD_LOGFILE;
+
+/* load only javascript that is needed */
+$suricata_load_jquery = 'yes';
+$suricata_load_jquery_colorbox = 'yes';
+$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 = VRT_DNLD_FILENAME;
+$snort_community_rules_filename = GPLV2_DNLD_FILENAME;
+
+if ($etpro == "on") {
+ $emergingthreats_filename = ETPRO_DNLD_FILENAME;
+ $et_name = "EMERGING THREATS PRO RULES";
+}
+else {
+ $emergingthreats_filename = ET_DNLD_FILENAME;
+ $et_name = "EMERGING THREATS RULES";
+}
+
+/* quick md5 chk of downloaded rules */
+$snort_org_sig_chk_local = 'N/A';
+if (file_exists("{$suricatadir}{$snort_rules_file}.md5"))
+ $snort_org_sig_chk_local = file_get_contents("{$suricatadir}{$snort_rules_file}.md5");
+
+$emergingt_net_sig_chk_local = 'N/A';
+if (file_exists("{$suricatadir}{$emergingthreats_filename}.md5"))
+ $emergingt_net_sig_chk_local = file_get_contents("{$suricatadir}{$emergingthreats_filename}.md5");
+
+$snort_community_sig_chk_local = 'N/A';
+if (file_exists("{$suricatadir}{$snort_community_rules_filename}.md5"))
+ $snort_community_sig_chk_local = file_get_contents("{$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}");
+}
+
+if ($_POST['update']) {
+ header("Location: /suricata/suricata_download_rules.php");
+ exit;
+}
+
+/* check for logfile */
+if (file_exists("{$suricata_rules_upd_log}"))
+ $suricata_rules_upd_log_chk = 'yes';
+else
+ $suricata_rules_upd_log_chk = 'no';
+
+if ($_POST['view']&& $suricata_rules_upd_log_chk == 'yes') {
+ $contents = @file_get_contents($suricata_rules_upd_log);
+ if (empty($contents))
+ $input_errors[] = gettext("Unable to read log file: {$suricata_rules_upd_log}");
+}
+
+$pgtitle = gettext("Suricata: Update Rules Set Files");
+include_once("head.inc");
+?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?php include("fbegin.inc"); ?>
+<?php
+ /* Display Alert message */
+ if ($input_errors) {
+ print_input_errors($input_errors);
+ }
+
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+?>
+<form action="suricata_download_updates.php" method="post" name="iform" id="iform">
+
+<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("Global Settings"), false, "/suricata/suricata_global.php");
+ $tab_array[] = array(gettext("Update Rules"), true, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr>
+ <td>
+ <div id="mainarea">
+ <table id="maintable4" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td valign="top" class="listtopic" align="center"><?php echo gettext("INSTALLED RULE SET MD5 SIGNATURES");?></td>
+ </tr>
+ <tr>
+ <td align="center"><br/>
+ <table width="100%" border="0" cellpadding="2" cellspacing="2">
+ <tr>
+ <td align="right" class="vexpl"><b><?=$et_name;?>&nbsp;&nbsp;---></b></td>
+ <td class="vexpl"><? echo $emergingt_net_sig_chk_local; ?></td>
+ </tr>
+ <tr>
+ <td align="right" class="vexpl"><b>SNORT VRT RULES&nbsp;&nbsp;---></b></td>
+ <td class="vexpl"><? echo $snort_org_sig_chk_local; ?></td>
+ </tr>
+ <td align="right" class="vexpl"><b>SNORT GPLv2 COMMUNITY RULES&nbsp;&nbsp;---></b></td>
+ <td class="vexpl"><? echo $snort_community_sig_chk_local; ?></td>
+ </tr>
+ </table><br/>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="listtopic" align="center"><?php echo gettext("UPDATE YOUR RULE SET");?></td>
+ </tr>
+ <tr>
+ <td align="center">
+ <?php if ($snortdownload != 'on' && $emergingthreats != 'on' && $etpro != 'on'): ?>
+ <br/><button disabled="disabled"><?php echo gettext("Update Rules"); ?></button><br/>
+ <p style="text-align:left;">
+ <font color="red" size="2px"><b><?php echo gettext("WARNING:");?></b></font><font size="1px" color="#000000">&nbsp;&nbsp;
+ <?php echo gettext('No rule types have been selected for download. ') .
+ gettext('Visit the ') . '<a href="/suricata/suricata_global.php">Global Settings Tab</a>' . gettext(' to select rule types.'); ?>
+ </font><br/></p>
+ <?php else: ?>
+ <br/>
+ <input type="submit" value="<?php echo gettext(" Update "); ?>" name="update" id="submit" class="formbtn"
+ title="<?php echo gettext("Check for new updates to configured rulesets"); ?>"/><br/><br/>
+ <?php endif; ?>
+ </td>
+ </tr>
+
+ <tr>
+ <td valign="top" class="listtopic" align="center"><?php echo gettext("MANAGE RULE SET LOG");?></td>
+ </tr>
+ <tr>
+ <td align="center" valign="middle" class="vexpl">
+ <?php if ($suricata_rules_upd_log_chk == 'yes'): ?>
+ <br/>
+ <input type="submit" value="<?php echo gettext("View Log"); ?>" name="view" id="view" class="formbtn"
+ title="<?php echo gettext("View rules update log contents"); ?>"/>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ <input type="submit" value="<?php echo gettext("Clear Log"); ?>" name="clear" id="clear" class="formbtn"
+ title="<?php echo gettext("Clear rules update log contents"); ?>" onClick="return confirm('Are you sure?\nOK to confirm, or CANCEL to quit');"/>
+ <br/>
+ <?php else: ?>
+ <br/>
+ <button disabled='disabled'><?php echo gettext("View Log"); ?></button>&nbsp;&nbsp;&nbsp;<?php echo gettext("Log is empty."); ?><br/>
+ <?php endif; ?>
+ <br/><?php echo gettext("The log file is limited to 1024K in size and automatically clears when the limit is exceeded."); ?><br/><br/>
+ </td>
+ </tr>
+ <?php if (!empty($contents)): ?>
+ <tr>
+ <td valign="top" class="listtopic" align="center"><?php echo gettext("RULE SET UPDATE LOG");?></td>
+ </tr>
+ <tr>
+ <td align="center">
+ <div style="background: #eeeeee; width:100%; height:100%;" id="textareaitem"><!-- NOTE: The opening *and* the closing textarea tag must be on the same line. -->
+ <textarea style="width:100%; height:100%;" readonly wrap="off" rows="24" cols="80" name="logtext"><?=$contents;?></textarea>
+ </div>
+ </td>
+ </tr>
+ <?php endif; ?>
+ <tr>
+ <td align="center">
+ <span class="vexpl"><br/><br/>
+ <span class="red"><b><?php echo gettext("NOTE:"); ?></b></span>
+ &nbsp;&nbsp;<a href="http://www.snort.org/" target="_blank"><?php echo gettext("Snort.org") . "</a>" .
+ gettext(" and ") . "<a href=\"http://www.emergingthreats.net/\" target=\"_blank\">" . gettext("EmergingThreats.net") . "</a>" .
+ gettext(" will go down from time to time. Please be patient."); ?></span><br/>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+</tr>
+</table>
+<!-- end of final table -->
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_flow_stream.php b/config/suricata/suricata_flow_stream.php
new file mode 100644
index 00000000..3a677d3a
--- /dev/null
+++ b/config/suricata/suricata_flow_stream.php
@@ -0,0 +1,644 @@
+<?php
+/*
+ * suricata_flow_stream.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;
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (!is_array($config['installedpackages']['suricata']))
+ $config['installedpackages']['suricata'] = array();
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+
+// Initialize Host-OS Policy engine arrays if necessary
+if (!is_array($config['installedpackages']['suricata']['rule'][$id]['host_os_policy']['item']))
+ $config['installedpackages']['suricata']['rule'][$id]['host_os_policy']['item'] = array();
+
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+$host_os_policy_engine_next_id = count($a_nat[$id]['host_os_policy']['item']);
+
+$pconfig = array();
+if (isset($id) && $a_nat[$id]) {
+ /* Get current values from config for page form fields */
+ $pconfig = $a_nat[$id];
+
+ // See if Host-OS policy engine array is configured and use
+ // it; otherwise create a default engine configuration.
+ if (empty($pconfig['host_os_policy']['item'])) {
+ $default = array( "name" => "default", "bind_to" => "all", "policy" => "bsd" );
+ $pconfig['host_os_policy']['item'] = array();
+ $pconfig['host_os_policy']['item'][] = $default;
+ if (!is_array($a_nat[$id]['host_os_policy']['item']))
+ $a_nat[$id]['host_os_policy']['item'] = array();
+ $a_nat[$id]['host_os_policy']['item'][] = $default;
+ write_config();
+ $host_os_policy_engine_next_id++;
+ }
+ else
+ $pconfig['host_os_policy'] = $a_nat[$id]['host_os_policy'];
+}
+
+// Check for returned "selected alias" if action is import
+if ($_GET['act'] == "import" && isset($_GET['varname']) && !empty($_GET['varvalue'])) {
+ $pconfig[$_GET['varname']] = $_GET['varvalue'];
+}
+
+if ($_GET['act'] && isset($_GET['eng_id'])) {
+
+ $natent = array();
+ $natent = $pconfig;
+
+ if ($_GET['act'] == "del_host_os_policy")
+ unset($natent['host_os_policy']['item'][$_GET['eng_id']]);
+
+ if (isset($id) && $a_nat[$id]) {
+ $a_nat[$id] = $natent;
+ write_config();
+ }
+
+ header("Location: /suricata/suricata_flow_stream.php?id=$id");
+ exit;
+}
+
+if ($_POST['ResetAll']) {
+
+ /* Reset all the settings to defaults */
+ $pconfig['ip_max_frags'] = "65535";
+ $pconfig['ip_frag_timeout'] = "60";
+ $pconfig['frag_memcap'] = '33554432';
+ $pconfig['ip_max_trackers'] = '65535';
+ $pconfig['frag_hash_size'] = '65536';
+
+ $pconfig['flow_memcap'] = '33554432';
+ $pconfig['flow_prealloc'] = '10000';
+ $pconfig['flow_hash_size'] = '65536';
+ $pconfig['flow_emerg_recovery'] = '30';
+ $pconfig['flow_prune'] = '5';
+
+ $pconfig['flow_tcp_new_timeout'] = '60';
+ $pconfig['flow_tcp_established_timeout'] = '3600';
+ $pconfig['flow_tcp_closed_timeout'] = '120';
+ $pconfig['flow_tcp_emerg_new_timeout'] = '10';
+ $pconfig['flow_tcp_emerg_established_timeout'] = '300';
+ $pconfig['flow_tcp_emerg_closed_timeout'] = '20';
+
+ $pconfig['flow_udp_new_timeout'] = '30';
+ $pconfig['flow_udp_established_timeout'] = '300';
+ $pconfig['flow_udp_emerg_new_timeout'] = '10';
+ $pconfig['flow_udp_emerg_established_timeout'] = '100';
+
+ $pconfig['flow_icmp_new_timeout'] = '30';
+ $pconfig['flow_icmp_established_timeout'] = '300';
+ $pconfig['flow_icmp_emerg_new_timeout'] = '10';
+ $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';
+ $pconfig['reassembly_to_server_chunk'] = '2560';
+ $pconfig['reassembly_to_client_chunk'] = '2560';
+ $pconfig['enable_midstream_sessions'] = 'off';
+ $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.");
+}
+elseif ($_POST['Submit']) {
+ $natent = array();
+ $natent = $pconfig;
+
+ // TODO: validate input values
+
+ /* if no errors write to conf */
+ if (!$input_errors) {
+ if ($_POST['ip_max_frags'] != "") { $natent['ip_max_frags'] = $_POST['ip_max_frags']; }else{ $natent['ip_max_frags'] = "65535"; }
+ if ($_POST['ip_frag_timeout'] != "") { $natent['ip_frag_timeout'] = $_POST['ip_frag_timeout']; }else{ $natent['ip_frag_timeout'] = "60"; }
+ if ($_POST['frag_memcap'] != "") { $natent['frag_memcap'] = $_POST['frag_memcap']; }else{ $natent['frag_memcap'] = "33554432"; }
+ if ($_POST['ip_max_trackers'] != "") { $natent['ip_max_trackers'] = $_POST['ip_max_trackers']; }else{ $natent['ip_max_trackers'] = "65535"; }
+ if ($_POST['frag_hash_size'] != "") { $natent['frag_hash_size'] = $_POST['frag_hash_size']; }else{ $natent['frag_hash_size'] = "65536"; }
+ if ($_POST['flow_memcap'] != "") { $natent['flow_memcap'] = $_POST['flow_memcap']; }else{ $natent['flow_memcap'] = "33554432"; }
+ if ($_POST['flow_prealloc'] != "") { $natent['flow_prealloc'] = $_POST['flow_prealloc']; }else{ $natent['flow_prealloc'] = "10000"; }
+ if ($_POST['flow_hash_size'] != "") { $natent['flow_hash_size'] = $_POST['flow_hash_size']; }else{ $natent['flow_hash_size'] = "65536"; }
+ if ($_POST['flow_emerg_recovery'] != "") { $natent['flow_emerg_recovery'] = $_POST['flow_emerg_recovery']; }else{ $natent['flow_emerg_recovery'] = "30"; }
+ if ($_POST['flow_prune'] != "") { $natent['flow_prune'] = $_POST['flow_prune']; }else{ $natent['flow_prune'] = "5"; }
+
+ if ($_POST['flow_tcp_new_timeout'] != "") { $natent['flow_tcp_new_timeout'] = $_POST['flow_tcp_new_timeout']; }else{ $natent['flow_tcp_new_timeout'] = "60"; }
+ if ($_POST['flow_tcp_established_timeout'] != "") { $natent['flow_tcp_established_timeout'] = $_POST['flow_tcp_established_timeout']; }else{ $natent['flow_tcp_established_timeout'] = "3600"; }
+ if ($_POST['flow_tcp_closed_timeout'] != "") { $natent['flow_tcp_closed_timeout'] = $_POST['flow_tcp_closed_timeout']; }else{ $natent['flow_tcp_closed_timeout'] = "120"; }
+ if ($_POST['flow_tcp_emerg_new_timeout'] != "") { $natent['flow_tcp_emerg_new_timeout'] = $_POST['flow_tcp_emerg_new_timeout']; }else{ $natent['flow_tcp_emerg_new_timeout'] = "10"; }
+ if ($_POST['flow_tcp_emerg_established_timeout'] != "") { $natent['flow_tcp_emerg_established_timeout'] = $_POST['flow_tcp_emerg_established_timeout']; }else{ $natent['flow_tcp_emerg_established_timeout'] = "300"; }
+ if ($_POST['flow_tcp_emerg_closed_timeout'] != "") { $natent['flow_tcp_emerg_closed_timeout'] = $_POST['flow_tcp_emerg_closed_timeout']; }else{ $natent['flow_tcp_emerg_closed_timeout'] = "20"; }
+
+ if ($_POST['flow_udp_new_timeout'] != "") { $natent['flow_udp_new_timeout'] = $_POST['flow_udp_new_timeout']; }else{ $natent['flow_udp_new_timeout'] = "30"; }
+ if ($_POST['flow_udp_established_timeout'] != "") { $natent['flow_udp_established_timeout'] = $_POST['flow_udp_established_timeout']; }else{ $natent['flow_udp_established_timeout'] = "300"; }
+ if ($_POST['flow_udp_emerg_new_timeout'] != "") { $natent['flow_udp_emerg_new_timeout'] = $_POST['flow_udp_emerg_new_timeout']; }else{ $natent['flow_udp_emerg_new_timeout'] = "10"; }
+ if ($_POST['flow_udp_emerg_established_timeout'] != "") { $natent['flow_udp_emerg_established_timeout'] = $_POST['flow_udp_emerg_established_timeout']; }else{ $natent['flow_udp_emerg_established_timeout'] = "100"; }
+
+ if ($_POST['flow_icmp_new_timeout'] != "") { $natent['flow_icmp_new_timeout'] = $_POST['flow_icmp_new_timeout']; }else{ $natent['flow_icmp_new_timeout'] = "30"; }
+ if ($_POST['flow_icmp_established_timeout'] != "") { $natent['flow_icmp_established_timeout'] = $_POST['flow_icmp_established_timeout']; }else{ $natent['flow_icmp_established_timeout'] = "300"; }
+ if ($_POST['flow_icmp_emerg_new_timeout'] != "") { $natent['flow_icmp_emerg_new_timeout'] = $_POST['flow_icmp_emerg_new_timeout']; }else{ $natent['flow_icmp_emerg_new_timeout'] = "10"; }
+ 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'; }
+ if ($_POST['reassembly_memcap'] != "") { $natent['reassembly_memcap'] = $_POST['reassembly_memcap']; }else{ $natent['reassembly_memcap'] = "67108864"; }
+ if ($_POST['reassembly_depth'] != "") { $natent['reassembly_depth'] = $_POST['reassembly_depth']; }else{ $natent['reassembly_depth'] = "1048576"; }
+ if ($_POST['reassembly_to_server_chunk'] != "") { $natent['reassembly_to_server_chunk'] = $_POST['reassembly_to_server_chunk']; }else{ $natent['reassembly_to_server_chunk'] = "2560"; }
+ if ($_POST['reassembly_to_client_chunk'] != "") { $natent['reassembly_to_client_chunk'] = $_POST['reassembly_to_client_chunk']; }else{ $natent['reassembly_to_client_chunk'] = "2560"; }
+
+ /**************************************************/
+ /* If we have a valid rule ID, save configuration */
+ /* then update the suricata.conf file and rebuild */
+ /* the rules for this interface. */
+ /**************************************************/
+ if (isset($id) && $a_nat[$id]) {
+ $a_nat[$id] = $natent;
+ write_config();
+ $rebuild_rules = true;
+ suricata_generate_yaml($natent);
+ $rebuild_rules = false;
+ }
+
+ 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_flow_stream.php?id=$id");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Flow and Stream");
+include_once("head.inc");
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php include("fbegin.inc"); ?>
+<?php if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+
+
+ /* Display Alert message */
+
+ if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+ }
+
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+
+?>
+
+<script type="text/javascript" src="/javascript/autosuggest.js">
+</script>
+<script type="text/javascript" src="/javascript/suggestions.js">
+</script>
+
+<form action="suricata_flow_stream.php" method="post"
+ enctype="multipart/form-data" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ echo '</td></tr>';
+ echo '<tr><td>';
+ $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface ");
+ $tab_array = array();
+ $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"), true, "/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}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr><td><div id="mainarea">
+<table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Host-Specific Defrag and Stream Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Host OS Policy Assignment"); ?></td>
+ <td width="78%" class="vtable">
+ <table width="95%" align="left" id="hostOSEnginesTable" style="table-layout: fixed;" border="0" cellspacing="0" cellpadding="0">
+ <colgroup>
+ <col width="45%" align="left">
+ <col width="45%" align="center">
+ <col width="10%" align="right">
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="listhdrr" axis="string"><?php echo gettext("Name");?></th>
+ <th class="listhdrr" axis="string"><?php echo gettext("Bind-To Address Alias");?></th>
+ <th class="list" align="right"><a href="suricata_import_aliases.php?id=<?=$id?>&eng=host_os_policy">
+ <img src="../themes/<?= $g['theme'];?>/images/icons/icon_import_alias.gif" width="17"
+ height="17" border="0" title="<?php echo gettext("Import policy configuration from existing Aliases");?>"></a>
+ <a href="suricata_os_policy_engine.php?id=<?=$id?>&eng_id=<?=$host_os_policy_engine_next_id?>">
+ <img src="../themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" width="17"
+ height="17" border="0" title="<?php echo gettext("Add a new policy configuration");?>"></a></th>
+ </tr>
+ </thead>
+ <?php foreach ($pconfig['host_os_policy']['item'] as $f => $v): ?>
+ <tr>
+ <td class="listlr" align="left"><?=gettext($v['name']);?></td>
+ <td class="listbg" align="center"><?=gettext($v['bind_to']);?></td>
+ <td class="listt" align="right"><a href="suricata_os_policy_engine.php?id=<?=$id;?>&eng_id=<?=$f;?>">
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_e.gif"
+ width="17" height="17" border="0" title="<?=gettext("Edit this policy configuration");?>"></a>
+ <?php if ($v['bind_to'] <> "all") : ?>
+ <a href="suricata_flow_stream.php?id=<?=$id;?>&eng_id=<?=$f;?>&act=del_host_os_policy" onclick="return confirm('Are you sure you want to delete this entry?');">
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_x.gif" width="17" height="17" border="0"
+ title="<?=gettext("Delete this policy configuration");?>"></a>
+ <?php else : ?>
+ <img src="/themes/<?=$g['theme'];?>/images/icons/icon_x_d.gif" width="17" height="17" border="0"
+ title="<?=gettext("Default policy configuration cannot be deleted");?>">
+ <?php endif ?>
+ </td>
+ </tr>
+ <?php endforeach; ?>
+ </table>
+ </td>
+ </tr>
+ <tr>
+
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("IP Defragmentation"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Fragmentation Memory Cap"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="frag_memcap" type="text" class="formfld unknown" id="frag_memcap" size="9"
+ value="<?=htmlspecialchars($pconfig['frag_memcap']);?>">&nbsp;
+ <?php echo gettext("Max memory to be used for defragmentation. Default is ") .
+ "<strong>" . gettext("33,554,432") . "</strong>" . gettext(" bytes (32 MB)."); ?><br/><br/>
+ <?php echo gettext("Sets the maximum amount of memory, in bytes, to be used by the IP defragmentation engine."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Trackers");?></td>
+ <td width="78%" class="vtable"><input name="ip_max_trackers" type="text" class="formfld unknown" id="ip_max_trackers" size="9" value="<?=htmlspecialchars($pconfig['ip_max_trackers']);?>">&nbsp;
+ <?php echo gettext("Number of defragmented flows to follow. Default is ") .
+ "<strong>" . gettext("65,535") . "</strong>" . gettext(" fragments.");?><br/><br/>
+ <?php echo gettext("Sets the number of defragmented flows to follow for reassembly."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Fragments");?></td>
+ <td width="78%" class="vtable"><input name="ip_max_frags" type="text" class="formfld unknown" id="ip_max_frags" size="9" value="<?=htmlspecialchars($pconfig['ip_max_frags']);?>">&nbsp;
+ <?php echo gettext("Maximum number of IP fragments to hold. Default is ") . "<strong>" . gettext("65,535") . "</strong>" . gettext(" fragments.");?><br/><br/>
+ <?php echo gettext("Sets the maximum number of IP fragments to retain in memory while awaiting reassembly."); ?><br/><br/>
+ <span class="red"><strong><?php echo gettext("Note: ") . "</strong></span>" . gettext("This must be equal to or greater than the Max Trackers value specified above."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Fragmentation Hash Table Size"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="frag_hash_size" type="text" class="formfld unknown" id="frag_hash_size" size="9"
+ value="<?=htmlspecialchars($pconfig['frag_hash_size']);?>">&nbsp;
+ <?php echo gettext("Hash Table size. Default is ") . "<strong>" . gettext("65,536") . "</strong>" . gettext(" entries."); ?><br/><br/>
+ <?php echo gettext("Sets the size of the Hash Table used by the defragmentation engine."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Timeout");?></td>
+ <td width="78%" class="vtable"><input name="ip_frag_timeout" type="text" class="formfld unknown" id="ip_frag_timeout" size="9" value="<?=htmlspecialchars($pconfig['ip_frag_timeout']);?>">&nbsp;
+ <?php echo gettext("Max seconds to hold an IP fragement. Default is ") .
+ "<strong>" . gettext("60") . "</strong>" . gettext(" seconds.");?><br/><br/>
+ <?php echo gettext("Sets the number of seconds to hold an IP fragment in memory while awaiting the remainder of the packet to arrive."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Flow Manager Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Flow Memory Cap"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="flow_memcap" type="text" class="formfld unknown" id="flow_memcap" size="9"
+ value="<?=htmlspecialchars($pconfig['flow_memcap']);?>">&nbsp;
+ <?php echo gettext("Max memory, in bytes, to be used by the flow engine. Default is ") .
+ "<strong>" . gettext("33,554,432") . "</strong>" . gettext(" bytes (32 MB)"); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Flow Hash Table Size"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="flow_hash_size" type="text" class="formfld unknown" id="flow_hash_size" size="9"
+ value="<?=htmlspecialchars($pconfig['flow_hash_size']);?>">&nbsp;
+ <?php echo gettext("Hash Table size used by the flow engine. Default is ") .
+ "<strong>" . gettext("65,536") . "</strong>" . gettext(" entries."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Preallocated Flows"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="flow_prealloc" type="text" class="formfld unknown" id="flow_prealloc" size="9"
+ value="<?=htmlspecialchars($pconfig['flow_prealloc']);?>">&nbsp;
+ <?php echo gettext("Number of preallocated flows ready for use. Default is ") .
+ "<strong>" . gettext("10,000") . "</strong>" . gettext(" flows."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Emergency Recovery"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="flow_emerg_recovery" type="text" class="formfld unknown" id="flow_emerg_recovery" size="9"
+ value="<?=htmlspecialchars($pconfig['flow_emerg_recovery']);?>">&nbsp;
+ <?php echo gettext("Percentage of preallocated flows to complete before exiting Emergency Mode. Default is ") .
+ "<strong>" . gettext("30%") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Prune Flows"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="flow_prune" type="text" class="formfld unknown" id="flow_prune" size="9"
+ value="<?=htmlspecialchars($pconfig['flow_prune']);?>">&nbsp;
+ <?php echo gettext("Number of flows to prune in Emergency Mode when allocating a new flow. Default is ") .
+ "<strong>" . gettext("5") . "</strong>" . gettext(" flows."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Flow Timeout Settings"); ?></td>
+ </tr>
+ <tr>
+ <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">
+ <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']);?>">&nbsp;
+ <?php echo gettext("New TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("60") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_tcp_established_timeout" type="text" class="formfld unknown" id="flow_tcp_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Established TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("3600") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_tcp_closed_timeout" type="text" class="formfld unknown" id="flow_tcp_closed_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_closed_timeout']);?>">&nbsp;
+ <?php echo gettext("Closed TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("120") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_tcp_emerg_new_timeout" type="text" class="formfld unknown" id="flow_tcp_emerg_new_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_emerg_new_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency New TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("10") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_tcp_emerg_established_timeout" type="text" class="formfld unknown" id="flow_tcp_emerg_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_emerg_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency Established TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("300") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_tcp_emerg_closed_timeout" type="text" class="formfld unknown" id="flow_tcp_emerg_closed_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_tcp_emerg_closed_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency Closed TCP connection timeout in seconds. Default is ") . "<strong>" . gettext("20") . "</strong>."; ?>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <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">
+ <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']);?>">&nbsp;
+ <?php echo gettext("New UDP connection timeout in seconds. Default is ") . "<strong>" . gettext("30") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_udp_established_timeout" type="text" class="formfld unknown" id="flow_udp_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_udp_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Established UDP connection timeout in seconds. Default is ") . "<strong>" . gettext("300") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_udp_emerg_new_timeout" type="text" class="formfld unknown" id="flow_udp_emerg_new_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_udp_emerg_new_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency New UDP connection timeout in seconds. Default is ") . "<strong>" . gettext("10") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_udp_emerg_established_timeout" type="text" class="formfld unknown" id="flow_udp_emerg_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_udp_emerg_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency Established UDP connection timeout in seconds. Default is ") . "<strong>" . gettext("100") . "</strong>."; ?>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <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">
+ <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']);?>">&nbsp;
+ <?php echo gettext("New ICMP connection timeout in seconds. Default is ") . "<strong>" . gettext("30") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_icmp_established_timeout" type="text" class="formfld unknown" id="flow_icmp_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_icmp_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Established ICMP connection timeout in seconds. Default is ") . "<strong>" . gettext("300") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_icmp_emerg_new_timeout" type="text" class="formfld unknown" id="flow_icmp_emerg_new_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_icmp_emerg_new_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency New ICMP connection timeout in seconds. Default is ") . "<strong>" . gettext("10") . "</strong>."; ?>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><input name="flow_icmp_emerg_established_timeout" type="text" class="formfld unknown" id="flow_icmp_emerg_established_timeout"
+ size="9" value="<?=htmlspecialchars($pconfig['flow_icmp_emerg_established_timeout']);?>">&nbsp;
+ <?php echo gettext("Emergency Established ICMP connection timeout in seconds. Default is ") . "<strong>" . gettext("100") . "</strong>."; ?>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Stream Engine Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Stream Memory Cap"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="stream_memcap" type="text" class="formfld unknown" id="stream_memcap" size="9"
+ value="<?=htmlspecialchars($pconfig['stream_memcap']);?>">&nbsp;
+ <?php echo gettext("Max memory to be used by stream engine. Default is ") .
+ "<strong>" . gettext("33,554,432") . "</strong>" . gettext(" bytes (32MB)"); ?><br/><br/>
+ <?php echo gettext("Sets the maximum amount of memory, in bytes, to be used by the stream engine."); ?>
+ </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']);?>">&nbsp;
+ <?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"
+ value="<?=htmlspecialchars($pconfig['stream_prealloc_sessions']);?>">&nbsp;
+ <?php echo gettext("Number of preallocated stream engine sessions. Default is ") .
+ "<strong>" . gettext("32,768") . "</strong>" . gettext(" sessions."); ?><br/><br/>
+ <?php echo gettext("Sets the number of stream engine sessions to preallocate. This can be a performance enhancement."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Mid-Stream Sessions"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_midstream_sessions" type="checkbox" value="on" <?php if ($pconfig['enable_midstream_sessions'] == "on") echo "checked"; ?>>
+ <?php echo gettext("Suricata will pick up and track sessions mid-stream. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Async Streams"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_async_sessions" type="checkbox" value="on" <?php if ($pconfig['enable_async_sessions'] == "on") echo "checked"; ?>>
+ <?php echo gettext("Suricata will track asynchronous one-sided streams. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Reassembly Memory Cap"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="reassembly_memcap" type="text" class="formfld unknown" id="reassembly_memcap" size="9"
+ value="<?=htmlspecialchars($pconfig['reassembly_memcap']);?>">&nbsp;
+ <?php echo gettext("Max memory to be used for stream reassembly. Default is ") .
+ "<strong>" . gettext("67,108,864") . "</strong>" . gettext(" bytes (64MB)."); ?><br/><br/>
+ <?php echo gettext("Sets the maximum amount of memory, in bytes, to be used for stream reassembly."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Reassembly Depth"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="reassembly_depth" type="text" class="formfld unknown" id="reassembly_depth" size="9"
+ value="<?=htmlspecialchars($pconfig['reassembly_depth']);?>">&nbsp;
+ <?php echo gettext("Amount of a stream to reassemble. Default is ") .
+ "<strong>" . gettext("1,048,576") . "</strong>" . gettext(" bytes (1MB)."); ?><br/><br/>
+ <?php echo gettext("Sets the depth, in bytes, of a stream to be reassembled by the stream engine.") . "<br/>" .
+ "<span class=\"red\"><strong>" . gettext("Note: ") . "</strong></span>" . gettext("Set to 0 (unlimited) to reassemble entire stream. This is required for file extraction."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("To-Server Chunk Size"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="reassembly_to_server_chunk" type="text" class="formfld unknown" id="reassembly_to_server_chunk" size="9"
+ value="<?=htmlspecialchars($pconfig['reassembly_to_server_chunk']);?>">&nbsp;
+ <?php echo gettext("Size of raw stream chunks to inspect. Default is ") .
+ "<strong>" . gettext("2,560") . "</strong>" . gettext(" bytes."); ?><br/><br/>
+ <?php echo gettext("Sets the chunk size, in bytes, for raw stream inspection performed for 'to-server' traffic."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("To-Client Chunk Size"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="reassembly_to_client_chunk" type="text" class="formfld unknown" id="reassembly_to_client_chunk" size="9"
+ value="<?=htmlspecialchars($pconfig['reassembly_to_client_chunk']);?>">&nbsp;
+ <?php echo gettext("Amount of a stream to reassemble. Default is ") .
+ "<strong>" . gettext("2,560") . "</strong>" . gettext(" bytes."); ?><br/><br/>
+ <?php echo gettext("Sets the chunk size, in bytes, for raw stream inspection performed for 'to-client' traffic."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="Save" title="<?php echo
+ gettext("Save flow and stream settings"); ?>">
+ <input name="id" type="hidden" value="<?=$id;?>">&nbsp;&nbsp;&nbsp;&nbsp;
+ <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 flow and stream settings to their defaults. Click OK to continue or CANCEL to quit.") .
+ "');\""; ?>></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Note: "); ?></strong></span></span>
+ <?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>
+</table>
+</div>
+</td></tr></table>
+</form>
+<script type="text/javascript">
+
+function wopen(url, name, w, h)
+{
+ // Fudge factors for window decoration space.
+ // In my tests these work well on all platforms & browsers.
+ w += 32;
+ h += 96;
+ var win = window.open(url,
+ name,
+ 'width=' + w + ', height=' + h + ', ' +
+ 'location=no, menubar=no, ' +
+ 'status=no, toolbar=no, scrollbars=yes, resizable=yes');
+ win.resizeTo(w, h);
+ win.focus();
+}
+
+</script>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_generate_yaml.php b/config/suricata/suricata_generate_yaml.php
new file mode 100644
index 00000000..0614adf8
--- /dev/null
+++ b/config/suricata/suricata_generate_yaml.php
@@ -0,0 +1,515 @@
+<?php
+/*
+ suricata_generate_yaml.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.
+*/
+
+// Create required Suricata directories if they don't exist
+$suricata_dirs = array( $suricatadir, $suricatacfgdir, "{$suricatacfgdir}/rules",
+ "{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}" );
+foreach ($suricata_dirs as $dir) {
+ if (!is_dir($dir))
+ safe_mkdir($dir);
+}
+
+// Copy required generic files to the interface sub-directory
+$config_files = array( "classification.config", "reference.config", "gen-msg.map", "unicode.map" );
+foreach ($config_files as $file) {
+ if (file_exists("{$suricatadir}{$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.
+
+// Set HOME_NET and EXTERNAL_NET for the interface
+$home_net_list = suricata_build_list($suricatacfg, $suricatacfg['homelistname']);
+$home_net = implode(",", $home_net_list);
+$home_net = trim($home_net);
+$external_net = '!$HOME_NET';
+if (!empty($suricatacfg['externallistname']) && $suricatacfg['externallistname'] != 'default') {
+ $external_net_list = suricata_build_list($suricatacfg, $suricatacfg['externallistname']);
+ $external_net = implode(",", $external_net_list);
+ $external_net = trim($external_net);
+}
+
+// Set default and user-defined variables for SERVER_VARS and PORT_VARS
+$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",
+ "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 = "";
+ foreach ($suricata_servers as $alias => $avalue) {
+ if (!empty($suricatacfg["def_{$alias}"]) && is_alias($suricatacfg["def_{$alias}"])) {
+ $avalue = trim(filter_expand_alias($suricatacfg["def_{$alias}"]));
+ $avalue = preg_replace('/\s+/', ',', trim($avalue));
+ }
+ $addr_vars .= " " . strtoupper($alias) . ": \"{$avalue}\"\n";
+ }
+$addr_vars = trim($addr_vars);
+if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port']))
+ $ssh_port = $config['system']['ssh']['port'];
+else
+ $ssh_port = "22";
+$suricata_ports = array(
+ "http_ports" => "80",
+ "oracle_ports" => "1521",
+ "ssh_ports" => $ssh_port,
+ "shellcode_ports" => "!80",
+ "DNP3_PORTS" => "20000", "file_data_ports" => "\$HTTP_PORTS,110,143"
+);
+$port_vars = "";
+ foreach ($suricata_ports as $alias => $avalue) {
+ if (!empty($suricatacfg["def_{$alias}"]) && is_alias($suricatacfg["def_{$alias}"])) {
+ $avalue = trim(filter_expand_alias($suricatacfg["def_{$alias}"]));
+ $avalue = preg_replace('/\s+/', ',', trim($avalue));
+ }
+ $port_vars .= " " . strtoupper($alias) . ": \"{$avalue}\"\n";
+ }
+$port_vars = trim($port_vars);
+
+// Define a Suppress List (Threshold) if one is configured
+$suppress = suricata_find_list($suricatacfg['suppresslistname'], 'suppress');
+if (!empty($suppress)) {
+ $suppress_data = str_replace("\r", "", base64_decode($suppress['suppresspassthru']));
+ @file_put_contents("{$suricatacfgdir}/threshold.config", $suppress_data);
+}
+else
+ @file_put_contents("{$suricatacfgdir}/threshold.config", "");
+
+// Add interface-specific detection engine settings
+if (!empty($suricatacfg['max_pending_packets']))
+ $max_pend_pkts = $suricatacfg['max_pending_packets'];
+else
+ $max_pend_pkts = 1024;
+
+if (!empty($suricatacfg['detect_eng_profile']))
+ $detect_eng_profile = $suricatacfg['detect_eng_profile'];
+else
+ $detect_eng_profile = "medium";
+
+if (!empty($suricatacfg['sgh_mpm_context']))
+ $sgh_mpm_ctx = $suricatacfg['sgh_mpm_context'];
+else
+ $sgh_mpm_ctx = "auto";
+
+if (!empty($suricatacfg['mpm_algo']))
+ $mpm_algo = $suricatacfg['mpm_algo'];
+else
+ $mpm_algo = "ac";
+
+if (!empty($suricatacfg['inspect_recursion_limit']) || $suricatacfg['inspect_recursion_limit'] == '0')
+ $inspection_recursion_limit = $suricatacfg['inspect_recursion_limit'];
+else
+ $inspection_recursion_limit = "";
+
+// Add interface-specific logging settings
+if ($suricatacfg['alertsystemlog'] == 'on')
+ $alert_syslog = "yes";
+else
+ $alert_syslog = "no";
+
+if ($suricatacfg['enable_stats_log'] == 'on')
+ $stats_log_enabled = "yes";
+else
+ $stats_log_enabled = "no";
+
+if (!empty($suricatacfg['stats_upd_interval']))
+ $stats_upd_interval = $suricatacfg['stats_upd_interval'];
+else
+ $stats_upd_interval = "10";
+
+if ($suricatacfg['append_stats_log'] == 'on')
+ $stats_log_append = "yes";
+else
+ $stats_log_append = "no";
+
+if ($suricatacfg['enable_http_log'] == 'on')
+ $http_log_enabled = "yes";
+else
+ $http_log_enabled = "no";
+
+if ($suricatacfg['append_http_log'] == 'on')
+ $http_log_append = "yes";
+else
+ $http_log_append = "no";
+
+if ($suricatacfg['enable_tls_log'] == 'on')
+ $tls_log_enabled = "yes";
+else
+ $tls_log_enabled = "no";
+
+if ($suricatacfg['tls_log_extended'] == 'on')
+ $tls_log_extended = "yes";
+else
+ $tls_log_extended = "no";
+
+if ($suricatacfg['enable_json_file_log'] == 'on')
+ $json_log_enabled = "yes";
+else
+ $json_log_enabled = "no";
+
+if ($suricatacfg['append_json_file_log'] == 'on')
+ $json_log_append = "yes";
+else
+ $json_log_append = "no";
+
+if ($suricatacfg['enable_tracked_files_magic'] == 'on')
+ $json_log_magic = "yes";
+else
+ $json_log_magic = "no";
+
+if ($suricatacfg['enable_tracked_files_md5'] == 'on')
+ $json_log_md5 = "yes";
+else
+ $json_log_md5 = "no";
+
+if ($suricatacfg['enable_file_store'] == 'on') {
+ $file_store_enabled = "yes";
+ if (!file_exists("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/file.waldo"))
+ @file_put_contents("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/file.waldo", "");
+}
+else
+ $file_store_enabled = "no";
+
+if ($suricatacfg['enable_pcap_log'] == 'on')
+ $pcap_log_enabled = "yes";
+else
+ $pcap_log_enabled = "no";
+
+if (!empty($suricatacfg['max_pcap_log_size']))
+ $pcap_log_limit_size = $suricatacfg['max_pcap_log_size'];
+else
+ $pcap_log_limit_size = "32";
+
+if (!empty($suricatacfg['max_pcap_log_files']))
+ $pcap_log_max_files = $suricatacfg['max_pcap_log_files'];
+else
+ $pcap_log_max_files = "1000";
+
+if ($suricatacfg['barnyard_enable'] == 'on')
+ $barnyard2_enabled = "yes";
+else
+ $barnyard2_enabled = "no";
+
+// Add interface-specific IP defrag settings
+if (!empty($suricatacfg['frag_memcap']))
+ $frag_memcap = $suricatacfg['frag_memcap'];
+else
+ $frag_memcap = "33554432";
+
+if (!empty($suricatacfg['ip_max_trackers']))
+ $ip_max_trackers = $suricatacfg['ip_max_trackers'];
+else
+ $ip_max_trackers = "65535";
+
+if (!empty($suricatacfg['ip_max_frags']))
+ $ip_max_frags = $suricatacfg['ip_max_frags'];
+else
+ $ip_max_frags = "65535";
+
+if (!empty($suricatacfg['frag_hash_size']))
+ $frag_hash_size = $suricatacfg['frag_hash_size'];
+else
+ $frag_hash_size = "65536";
+
+if (!empty($suricatacfg['ip_frag_timeout']))
+ $ip_frag_timeout = $suricatacfg['ip_frag_timeout'];
+else
+ $ip_frag_timeout = "60";
+
+// Add interface-specific flow manager setttings
+if (!empty($suricatacfg['flow_memcap']))
+ $flow_memcap = $suricatacfg['flow_memcap'];
+else
+ $flow_memcap = "33554432";
+
+if (!empty($suricatacfg['flow_hash_size']))
+ $flow_hash_size = $suricatacfg['flow_hash_size'];
+else
+ $flow_hash_size = "65536";
+
+if (!empty($suricatacfg['flow_prealloc']))
+ $flow_prealloc = $suricatacfg['flow_prealloc'];
+else
+ $flow_prealloc = "10000";
+
+if (!empty($suricatacfg['flow_emerg_recovery']))
+ $flow_emerg_recovery = $suricatacfg['flow_emerg_recovery'];
+else
+ $flow_emerg_recovery = "30";
+
+if (!empty($suricatacfg['flow_prune']))
+ $flow_prune = $suricatacfg['flow_prune'];
+else
+ $flow_prune = "5";
+
+// Add interface-specific flow timeout setttings
+if (!empty($suricatacfg['flow_tcp_new_timeout']))
+ $flow_tcp_new_timeout = $suricatacfg['flow_tcp_new_timeout'];
+else
+ $flow_tcp_new_timeout = "60";
+
+if (!empty($suricatacfg['flow_tcp_established_timeout']))
+ $flow_tcp_established_timeout = $suricatacfg['flow_tcp_established_timeout'];
+else
+ $flow_tcp_established_timeout = "3600";
+
+if (!empty($suricatacfg['flow_tcp_closed_timeout']))
+ $flow_tcp_closed_timeout = $suricatacfg['flow_tcp_closed_timeout'];
+else
+ $flow_tcp_closed_timeout = "120";
+
+if (!empty($suricatacfg['flow_tcp_emerg_new_timeout']))
+ $flow_tcp_emerg_new_timeout = $suricatacfg['flow_tcp_emerg_new_timeout'];
+else
+ $flow_tcp_emerg_new_timeout = "10";
+
+if (!empty($suricatacfg['flow_tcp_emerg_established_timeout']))
+ $flow_tcp_emerg_established_timeout = $suricatacfg['flow_tcp_emerg_established_timeout'];
+else
+ $flow_tcp_emerg_established_timeout = "300";
+
+if (!empty($suricatacfg['flow_tcp_emerg_closed_timeout']))
+ $flow_tcp_emerg_closed_timeout = $suricatacfg['flow_tcp_emerg_closed_timeout'];
+else
+ $flow_tcp_emerg_closed_timeout = "20";
+
+if (!empty($suricatacfg['flow_udp_new_timeout']))
+ $flow_udp_new_timeout = $suricatacfg['flow_udp_new_timeout'];
+else
+ $flow_udp_new_timeout = "30";
+
+if (!empty($suricatacfg['flow_udp_established_timeout']))
+ $flow_udp_established_timeout = $suricatacfg['flow_udp_established_timeout'];
+else
+ $flow_udp_established_timeout = "300";
+
+if (!empty($suricatacfg['flow_udp_emerg_new_timeout']))
+ $flow_udp_emerg_new_timeout = $suricatacfg['flow_udp_emerg_new_timeout'];
+else
+ $flow_udp_emerg_new_timeout = "10";
+
+if (!empty($suricatacfg['flow_udp_emerg_established_timeout']))
+ $flow_udp_emerg_established_timeout = $suricatacfg['flow_udp_emerg_established_timeout'];
+else
+ $flow_udp_emerg_established_timeout = "100";
+
+if (!empty($suricatacfg['flow_icmp_new_timeout']))
+ $flow_icmp_new_timeout = $suricatacfg['flow_icmp_new_timeout'];
+else
+ $flow_icmp_new_timeout = "30";
+
+if (!empty($suricatacfg['flow_icmp_established_timeout']))
+ $flow_icmp_established_timeout = $suricatacfg['flow_icmp_established_timeout'];
+else
+ $flow_icmp_established_timeout = "300";
+
+if (!empty($suricatacfg['flow_icmp_emerg_new_timeout']))
+ $flow_icmp_emerg_new_timeout = $suricatacfg['flow_icmp_emerg_new_timeout'];
+else
+ $flow_icmp_emerg_new_timeout = "10";
+
+if (!empty($suricatacfg['flow_icmp_emerg_established_timeout']))
+ $flow_icmp_emerg_established_timeout = $suricatacfg['flow_icmp_emerg_established_timeout'];
+else
+ $flow_icmp_emerg_established_timeout = "100";
+
+// Add interface-specific stream settings
+if (!empty($suricatacfg['stream_memcap']))
+ $stream_memcap = $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
+ $stream_prealloc_sessions = "32768";
+
+if (!empty($suricatacfg['reassembly_memcap']))
+ $reassembly_memcap = $suricatacfg['reassembly_memcap'];
+else
+ $reassembly_memcap = "67108864";
+
+if (!empty($suricatacfg['reassembly_depth']) || $suricatacfg['reassembly_depth'] == '0')
+ $reassembly_depth = $suricatacfg['reassembly_depth'];
+else
+ $reassembly_depth = "1048576";
+
+if (!empty($suricatacfg['reassembly_to_server_chunk']))
+ $reassembly_to_server_chunk = $suricatacfg['reassembly_to_server_chunk'];
+else
+ $reassembly_to_server_chunk = "2560";
+
+if (!empty($suricatacfg['reassembly_to_client_chunk']))
+ $reassembly_to_client_chunk = $suricatacfg['reassembly_to_client_chunk'];
+else
+ $reassembly_to_client_chunk = "2560";
+
+if ($suricatacfg['enable_midstream_sessions'] == 'on')
+ $stream_enable_midstream = "true";
+else
+ $stream_enable_midstream = "false";
+
+if ($suricatacfg['enable_async_sessions'] == 'on')
+ $stream_enable_async = "true";
+else
+ $stream_enable_async = "false";
+
+// Add the OS-specific host policies if configured, otherwise
+// just set default to BSD for all networks.
+if (!is_array($suricatacfg['host_os_policy']['item']))
+ $suricatacfg['host_os_policy']['item'] = array();
+if (empty($suricatacfg['host_os_policy']['item']))
+ $host_os_policy = "bsd: [0.0.0.0/0]";
+else {
+ foreach ($suricatacfg['host_os_policy']['item'] as $k => $v) {
+ $engine = "{$v['policy']}: ";
+ if ($v['bind_to'] <> "all") {
+ $tmp = trim(filter_expand_alias($v['bind_to']));
+ if (!empty($tmp)) {
+ $engine .= "[";
+ $tmp = preg_replace('/\s+/', ',', $tmp);
+ $list = explode(',', $tmp);
+ foreach ($list as $addr) {
+ if (is_ipaddrv6($addr) || is_subnetv6($addr))
+ $engine .= "\"{$addr}\", ";
+ elseif (is_ipaddrv4($addr) || is_subnetv4($addr))
+ $engine .= "{$addr}, ";
+ else
+ log_error("[suricata] WARNING: invalid IP address value '{$addr}' in Alias {$v['bind_to']} will be ignored.");
+ }
+ $engine = trim($engine, ' ,');
+ $engine .= "]";
+ }
+ else {
+ log_error("[suricata] WARNING: unable to resolve IP List Alias '{$v['bind_to']}' for Host OS Policy '{$v['name']}' ... ignoring this entry.");
+ continue;
+ }
+ }
+ else
+ $engine .= "[0.0.0.0/0]";
+
+ $host_os_policy .= " {$engine}\n";
+ }
+ // Remove trailing newline
+ $host_os_policy = trim($host_os_policy);
+}
+
+// Add the HTTP Server-specific policies if configured, otherwise
+// just set default to IDS for all networks.
+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";
+}
+else {
+ foreach ($suricatacfg['libhtp_policy']['item'] as $k => $v) {
+ if ($v['bind_to'] <> "all") {
+ $engine = "server-config:\n - {$v['name']}:\n";
+ $tmp = trim(filter_expand_alias($v['bind_to']));
+ if (!empty($tmp)) {
+ $engine .= " address: [";
+ $tmp = preg_replace('/\s+/', ',', $tmp);
+ $list = explode(',', $tmp);
+ foreach ($list as $addr) {
+ if (is_ipaddrv6($addr) || is_subnetv6($addr))
+ $engine .= "\"{$addr}\", ";
+ elseif (is_ipaddrv4($addr) || is_subnetv4($addr))
+ $engine .= "{$addr}, ";
+ else {
+ log_error("[suricata] WARNING: invalid IP address value '{$addr}' in Alias {$v['bind_to']} will be ignored.");
+ continue;
+ }
+ }
+ $engine = trim($engine, ' ,');
+ $engine .= "]\n";
+ $engine .= " personality: {$v['personality']}\n request-body-limit: {$v['request-body-limit']}\n";
+ $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";
+ $http_hosts_policy .= " {$engine}\n";
+ }
+ else {
+ log_error("[suricata] WARNING: unable to resolve IP List Alias '{$v['bind_to']}' for Host OS Policy '{$v['name']}' ... ignoring this entry.");
+ continue;
+ }
+ }
+ else {
+ $http_hosts_default_policy = " personality: {$v['personality']}\n request-body-limit: {$v['request-body-limit']}\n";
+ $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";
+ }
+ }
+ // Remove trailing newline
+ $http_hosts_default_policy = trim($http_hosts_default_policy);
+ $http_hosts_policy = trim($http_hosts_policy);
+}
+
+// Configure ASN1 max frames value
+if (!empty($suricatacfg['asn1_max_frames']))
+ $asn1_max_frames = $suricatacfg['asn1_max_frames'];
+else
+ $asn1_max_frames = "256";
+
+// 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/".FLOWBITS_FILENAME) > 0)
+ $rules_files .= "\n - " . FLOWBITS_FILENAME;
+if (filesize("{$suricatacfgdir}/rules/custom.rules") > 0)
+ $rules_files .= "\n - custom.rules";
+$rules_files = ltrim($rules_files, '\n -');
+
+// Add the general logging settings to the configuration (non-interface specific)
+if ($config['installedpackages']['suricata']['config'][0]['log_to_systemlog'] == 'on')
+ $suricata_use_syslog = "yes";
+else
+ $suricata_use_syslog = "no";
+
+?>
diff --git a/config/suricata/suricata_global.php b/config/suricata/suricata_global.php
new file mode 100644
index 00000000..f6b5d83d
--- /dev/null
+++ b/config/suricata/suricata_global.php
@@ -0,0 +1,456 @@
+<?php
+/*
+ * suricata_global.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;
+
+$suricatadir = SURICATADIR;
+
+$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['suricataloglimit'] = $config['installedpackages']['suricata']['config'][0]['suricataloglimit'];
+$pconfig['suricataloglimitsize'] = $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'];
+$pconfig['autoruleupdate'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdate'];
+$pconfig['autoruleupdatetime'] = $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'];
+$pconfig['log_to_systemlog'] = $config['installedpackages']['suricata']['config'][0]['log_to_systemlog'];
+$pconfig['clearlogs'] = $config['installedpackages']['suricata']['config'][0]['clearlogs'];
+$pconfig['forcekeepsettings'] = $config['installedpackages']['suricata']['config'][0]['forcekeepsettings'];
+$pconfig['snortcommunityrules'] = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules'];
+
+if (empty($pconfig['suricataloglimit']))
+ $pconfig['suricataloglimit'] = 'on';
+if (empty($pconfig['autoruleupdatetime']))
+ $pconfig['autoruleupdatetime'] = '00:30';
+if (empty($pconfig['suricataloglimitsize']))
+ // Set limit to 20% of slice that is unused */
+ $pconfig['suricataloglimitsize'] = round(exec('df -k /var | grep -v "Filesystem" | awk \'{print $4}\'') * .20 / 1024);
+
+
+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']))
+ $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']))
+ $input_errors[] = "You must supply a subscription code in the box provided in order to enable Emerging Threats Pro rules!";
+
+/* if no errors move foward with save */
+if (!$input_errors) {
+ if ($_POST["Submit"]) {
+
+ $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'] = $_POST['enable_vrt_rules'] ? 'on' : 'off';
+ $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';
+
+ // If any rule sets are being turned off, then remove them
+ // from the active rules section of each interface. Start
+ // by building an arry of prefixes for the disabled rules.
+ $disabled_rules = array();
+ $disable_ips_policy = false;
+ if ($config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'] == 'off') {
+ $disabled_rules[] = VRT_FILE_PREFIX;
+ $disable_ips_policy = true;
+ }
+ if ($config['installedpackages']['suricata']['config'][0]['snortcommunityrules'] == 'off')
+ $disabled_rules[] = GPL_FILE_PREFIX;
+ if ($config['installedpackages']['suricata']['config'][0]['enable_etopen_rules'] == 'off')
+ $disabled_rules[] = ET_OPEN_FILE_PREFIX;
+ if ($config['installedpackages']['suricata']['config'][0]['enable_etpro_rules'] == 'off')
+ $disabled_rules[] = ET_PRO_FILE_PREFIX;
+
+ // Now walk all the configured interface rulesets and remove
+ // any matching the disabled ruleset prefixes.
+ if (is_array($config['installedpackages']['suricata']['rule'])) {
+ foreach ($config['installedpackages']['suricata']['rule'] as &$iface) {
+ // Disable Snort IPS policy if VRT rules are disabled
+ if ($disable_ips_policy) {
+ $iface['ips_policy_enable'] = 'off';
+ unset($iface['ips_policy']);
+ }
+ $enabled_rules = explode("||", $iface['rulesets']);
+ foreach ($enabled_rules as $k => $v) {
+ foreach ($disabled_rules as $d)
+ if (strpos(trim($v), $d) !== false)
+ unset($enabled_rules[$k]);
+ }
+ $iface['rulesets'] = implode("||", $enabled_rules);
+ }
+ }
+
+ $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'];
+ if ($_POST['suricataloglimitsize']) {
+ $config['installedpackages']['suricata']['config'][0]['suricataloglimit'] = $_POST['suricataloglimit'];
+ $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'] = $_POST['suricataloglimitsize'];
+ } else {
+ $config['installedpackages']['suricata']['config'][0]['suricataloglimit'] = 'on';
+
+ /* code will set limit to 21% of slice that is unused */
+ $suricataloglimitDSKsize = round(exec('df -k /var | grep -v "Filesystem" | awk \'{print $4}\'') * .22 / 1024);
+ $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'] = $suricataloglimitDSKsize;
+ }
+ $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);
+ }
+ $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]['clearlogs'] = $_POST['clearlogs'] ? 'on' : 'off';
+ $config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] = $_POST['forcekeepsettings'] ? 'on' : 'off';
+
+ $retval = 0;
+
+ /* create whitelist and homenet file, then sync files */
+ sync_suricata_package_config();
+
+ write_config();
+
+ /* 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_global.php");
+ exit;
+ }
+}
+
+$pgtitle = gettext("Suricata: Global Settings");
+include_once("head.inc");
+
+?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?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);
+
+?>
+
+<form action="suricata_global.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<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("Global Settings"), true, "/suricata/suricata_global.php");
+ $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$instanceid}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr>
+ <td>
+ <div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Please Choose The Type Of Rules You Wish To Download");?></td>
+</tr>
+<tr>
+ <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">
+ <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>
+ <td><span class="vexpl"><?php echo gettext("ETOpen is an open source set of Snort rules whose coverage " .
+ "is more limited than ETPro."); ?></span></td>
+ </tr>
+ <tr>
+ <td valign="top" width="8%"><input name="enable_etpro_rules" type="checkbox" value="on" onclick="enable_pro_rules();"
+ <?php if ($config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']=="on") echo "checked"; ?>></td>
+ <td><span class="vexpl"><?php echo gettext("ETPro for Snort offers daily updates and extensive coverage of current malware threats."); ?></span></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td><a href="http://www.emergingthreats.net/solutions/etpro-ruleset/" target="_blank"><?php echo gettext("Sign Up for an ETPro Account"); ?> </a></td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td class="vexpl"><?php echo "<span class='red'><strong>" . gettext("Note:") . "</strong></span>" . "&nbsp;" .
+ 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>
+ </table>
+ <table id="etpro_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0">
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top"><b><span class="vexpl"><?php echo gettext("ETPro Subscription Configuration"); ?></span></b></td>
+ </tr>
+ <tr>
+ <td valign="top"><span class="vexpl"><strong><?php echo gettext("Code:"); ?></strong></span></td>
+ <td><input name="etprocode" type="text"
+ class="formfld unknown" id="etprocode" size="52"
+ value="<?=htmlspecialchars($pconfig['etprocode']);?>"><br/>
+ <?php echo gettext("Obtain an ETPro subscription code and paste it here."); ?></td>
+ </tr>
+ </table>
+ </td>
+</tr>
+<tr>
+ <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">
+ <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>&nbsp;</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">
+ <?php echo gettext("Sign Up for paid Sourcefire VRT Certified Subscriber Rules"); ?></a></td>
+ </tr>
+ </table>
+ <table id="snort_oink_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0">
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top"><b><span class="vexpl"><?php echo gettext("Snort VRT Oinkmaster Configuration"); ?></span></b></td>
+ </tr>
+ <tr>
+ <td valign="top"><span class="vexpl"><strong><?php echo gettext("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>
+ </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">
+ <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>
+ <td class="vexpl"><?php echo gettext("The Snort Community Ruleset is a GPLv2 VRT certified ruleset that is distributed free of charge " .
+ "without any VRT License restrictions. This ruleset is updated daily and is a subset of the subscriber ruleset.");?>
+ <br/><br/><?php echo "<span class=\"red\"><strong>" . gettext("Note: ") . "</strong></span>" .
+ 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>
+ </table></td>
+</tr>
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Rules Update Settings"); ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Update Interval"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="autoruleupdate" class="formselect" id="autoruleupdate" onchange="enable_change_rules_upd()">
+ <?php
+ $interfaces3 = array('never_up' => gettext('NEVER'), '6h_up' => gettext('6 HOURS'), '12h_up' => gettext('12 HOURS'), '1d_up' => gettext('1 DAY'), '4d_up' => gettext('4 DAYS'), '7d_up' => gettext('7 DAYS'), '28d_up' => gettext('28 DAYS'));
+ foreach ($interfaces3 as $iface3 => $ifacename3): ?>
+ <option value="<?=$iface3;?>"
+ <?php if ($iface3 == $pconfig['autoruleupdate']) echo "selected"; ?>>
+ <?=htmlspecialchars($ifacename3);?></option>
+ <?php endforeach; ?>
+ </select><span class="vexpl">&nbsp;&nbsp;<?php echo gettext("Please select the interval for rule updates. Choosing ") .
+ "<strong>" . gettext("NEVER") . "</strong>" . gettext(" disables auto-updates."); ?><br/><br/>
+ <?php echo "<span class=\"red\"><strong>" . gettext("Hint: ") . "</strong></span>" . gettext("in most cases, every 12 hours is a good choice."); ?></span></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Update Start Time"); ?></td>
+ <td width="78%" class="vtable"><input type="text" class="formfld time" name="autoruleupdatetime" id="autoruleupdatetime" size="4"
+ maxlength="5" value="<?=$pconfig['autoruleupdatetime'];?>" <?php if ($pconfig['autoruleupdate'] == "never_up") {echo "disabled";} ?>><span class="vexpl">&nbsp;&nbsp;
+ <?php echo gettext("Enter the rule update start time in 24-hour format (HH:MM). ") . "<strong>" .
+ gettext("Default") . "&nbsp;</strong>" . gettext("is ") . "<strong>" . gettext("00:03") . "</strong></span>"; ?>.<br/><br/>
+ <?php echo gettext("Rules will update at the interval chosen above starting at the time specified here. For example, using the default " .
+ "start time of 00:03 and choosing 12 Hours for the interval, the rules will update at 00:03 and 12:03 each day."); ?></td>
+</tr>
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("General Settings"); ?></td>
+</tr>
+<tr>
+<?php $suricatalogCurrentDSKsize = round(exec('df -k /var | grep -v "Filesystem" | awk \'{print $4}\'') / 1024); ?>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Directory Size " .
+ "Limit"); ?><br/>
+ <br/>
+ <br/>
+ <span class="red"><strong><?php echo gettext("Note:"); ?></strong></span><br/>
+ <?php echo gettext("Available space is"); ?> <strong><?php echo $suricatalogCurrentDSKsize; ?>&nbsp;MB</strong></td>
+ <td width="78%" class="vtable">
+ <table cellpadding="0" cellspacing="0">
+ <tr>
+ <td colspan="2"><input name="suricataloglimit" type="radio" id="suricataloglimit" value="on"
+ <?php if($pconfig['suricataloglimit']=='on') echo 'checked'; ?>><span class="vexpl">
+ <strong><?php echo gettext("Enable"); ?></strong> <?php echo gettext("directory size limit"); ?> (<strong><?php echo gettext("Default"); ?></strong>)</span></td>
+ </tr>
+ <tr>
+ <td colspan="2"><input name="suricataloglimit" type="radio" id="suricataloglimit" value="off"
+ <?php if($pconfig['suricataloglimit']=='off') echo 'checked'; ?>> <span class="vexpl"><strong><?php echo gettext("Disable"); ?></strong>
+ <?php echo gettext("directory size limit"); ?></span><br/>
+ <br/>
+ <span class="red"><strong><?php echo gettext("Warning:"); ?></strong></span> <?php echo gettext("Nanobsd " .
+ "should use no more than 10MB of space."); ?></td>
+ </tr>
+ </table>
+ <table width="100%" border="0" cellpadding="2" cellspacing="0">
+ <tr>
+ <td class="vexpl"><?php echo gettext("Size in ") . "<strong>" . gettext("MB:") . "</strong>";?>&nbsp;
+ <input name="suricataloglimitsize" type="text" class="formfld unknown" id="suricataloglimitsize" size="10" value="<?=htmlspecialchars($pconfig['suricataloglimitsize']);?>">
+ &nbsp;<?php echo gettext("Default is ") . "<strong>" . gettext("20%") . "</strong>" . gettext(" of available space.");?></td>
+ </tr>
+ </table>
+ </td>
+</tr>
+<tr style="display:none;">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Remove Blocked Hosts Interval"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="rm_blocked" class="formselect" id="rm_blocked">
+ <?php
+ $interfaces3 = array('never_b' => gettext('NEVER'), '15m_b' => gettext('15 MINS'), '30m_b' => gettext('30 MINS'), '1h_b' => gettext('1 HOUR'), '3h_b' => gettext('3 HOURS'), '6h_b' => gettext('6 HOURS'), '12h_b' => gettext('12 HOURS'), '1d_b' => gettext('1 DAY'), '4d_b' => gettext('4 DAYS'), '7d_b' => gettext('7 DAYS'), '28d_b' => gettext('28 DAYS'));
+ foreach ($interfaces3 as $iface3 => $ifacename3): ?>
+ <option value="<?=$iface3;?>"
+ <?php if ($iface3 == $pconfig['rm_blocked']) echo "selected"; ?>>
+ <?=htmlspecialchars($ifacename3);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;
+ <?php echo gettext("Please select the amount of time you would like hosts to be blocked."); ?><br/><br/>
+ <?php echo "<span class=\"red\"><strong>" . gettext("Hint:") . "</strong></span>" . gettext(" in most cases, 1 hour is a good choice.");?></td>
+</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"
+ <?php if ($config['installedpackages']['suricata']['config'][0]['log_to_systemlog']=="on") echo "checked"; ?>
+ >&nbsp;<?php echo gettext("Copy Suricata messages to the firewall system log."); ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Remove Suricata Log Files After Deinstall"); ?></td>
+ <td width="78%" class="vtable"><input name="clearlogs"
+ id="clearlogs" type="checkbox" value="yes"
+ <?php if ($config['installedpackages']['suricata']['config'][0]['clearlogs']=="on") echo "checked"; ?>
+ >&nbsp;<?php echo gettext("Suricata log files will be removed during package deinstallation."); ?></td>
+</tr>
+<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"
+ <?php if ($config['installedpackages']['suricata']['config'][0]['forcekeepsettings']=="on") echo "checked"; ?>
+ >&nbsp;<?php echo gettext("Settings will not be removed during package deinstallation."); ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top">
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="Save" >
+ </td>
+</tr>
+<tr>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%" class="vexpl"><span class="red"><strong><?php echo gettext("Note:");?></strong>&nbsp;
+ </span><?php echo gettext("Changing any settings on this page will affect all Suricata-configured interfaces.");?></td>
+</tr>
+ </table>
+</div><br/>
+</td></tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+
+<script language="JavaScript">
+<!--
+function enable_snort_vrt() {
+ var endis = !(document.iform.enable_vrt_rules.checked);
+ if (endis)
+ document.getElementById("snort_oink_code_tbl").style.display = "none";
+ else
+ document.getElementById("snort_oink_code_tbl").style.display = "table";
+}
+
+function enable_et_rules() {
+ var endis = document.iform.enable_etopen_rules.checked;
+ if (endis) {
+ document.iform.enable_etpro_rules.checked = !(endis);
+ document.getElementById("etpro_code_tbl").style.display = "none";
+ }
+}
+
+function enable_pro_rules() {
+ var endis = document.iform.enable_etpro_rules.checked;
+ if (endis) {
+ document.iform.enable_etopen_rules.checked = !(endis);
+ document.iform.etprocode.disabled = "";
+ document.getElementById("etpro_code_tbl").style.display = "table";
+ }
+ else {
+ document.iform.etprocode.disabled = "true";
+ document.getElementById("etpro_code_tbl").style.display = "none";
+ }
+}
+
+function enable_change_rules_upd() {
+ if (document.iform.autoruleupdate.selectedIndex == 0)
+ document.iform.autoruleupdatetime.disabled="true";
+ else
+ document.iform.autoruleupdatetime.disabled="";
+}
+
+// Initialize the form controls state based on saved settings
+enable_snort_vrt();
+enable_et_rules();
+enable_pro_rules();
+enable_change_rules_upd();
+
+//-->
+</script>
+
+</body>
+</html>
diff --git a/config/suricata/suricata_import_aliases.php b/config/suricata/suricata_import_aliases.php
new file mode 100644
index 00000000..c16ac65d
--- /dev/null
+++ b/config/suricata/suricata_import_aliases.php
@@ -0,0 +1,272 @@
+<?php
+/* $Id$ */
+/*
+ suricata_import_aliases.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("guiconfig.inc");
+require_once("functions.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+// Retrieve any passed QUERY STRING or POST variables
+$id = $_GET['id'];
+$eng = $_GET['eng'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (isset($_POST['eng']))
+ $eng = $_POST['eng'];
+
+// Make sure we have a valid rule ID and ENGINE name, or
+// else bail out to top-level menu.
+if (is_null($id) || is_null($eng)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+// Used to track if any selectable Aliases are found
+$selectablealias = false;
+
+// Initialize required array variables as necessary
+if (!is_array($config['aliases']['alias']))
+ $config['aliases']['alias'] = array();
+$a_aliases = $config['aliases']['alias'];
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+
+// The $eng variable points to the specific Suricata config section
+// engine we are importing values into. Initialize the config.xml
+// array if necessary.
+if (!is_array($config['installedpackages']['suricata']['rule'][$id][$eng]['item']))
+ $config['installedpackages']['suricata']['rule'][$id][$eng]['item'] = array();
+
+// Initialize a pointer to the Suricata config section engine we are
+// importing values into.
+$a_nat = &$config['installedpackages']['suricata']['rule'][$id][$eng]['item'];
+
+// Build a lookup array of currently used engine 'bind_to' Aliases
+// so we can screen matching Alias names from the list.
+$used = array();
+foreach ($a_nat as $v)
+ $used[$v['bind_to']] = true;
+
+// Construct the correct return URL based on the Suricata config section
+// engine we were called with. This lets us return to the page we were
+// called from.
+switch ($eng) {
+ case "host_os_policy":
+ $returl = "/suricata/suricata_flow_stream.php";
+ $multi_ip = true;
+ $title = "Host Operating System Policy";
+ break;
+ case "libhtp_policy":
+ $returl = "/suricata/suricata_app_parsers.php";
+ $multi_ip = true;
+ $title = "HTTP Server Policy";
+ break;
+ default:
+ $returl = "/suricata/suricata_interface_edit";
+ $multi_ip = true;
+ $title = "";
+}
+
+if ($_POST['cancel']) {
+ header("Location: {$returl}?id={$id}");
+ exit;
+}
+
+if ($_POST['save']) {
+
+ // Define default engine configurations for each of the supported engines.
+ $def_os_policy = array( "name" => "", "bind_to" => "", "policy" => "bsd" );
+
+ $def_libhtp_policy = array( "name" => "default", "bind_to" => "all", "personality" => "IDS",
+ "request-body-limit" => 4096, "response-body-limit" => 4096,
+ "double-decode-path" => "no", "double-decode-query" => "no" );
+
+ // Figure out which engine type we are importing and set up default engine array
+ $engine = array();
+ switch ($eng) {
+ case "host_os_policy":
+ $engine = $def_os_policy;
+ break;
+ case "libhtp_policy":
+ $engine = $def_libhtp_policy;
+ break;
+ default:
+ $engine = "";
+ $input_errors[] = gettext("Invalid ENGINE TYPE passed in query string. Aborting operation.");
+ }
+
+ // See if anything was checked to import
+ if (is_array($_POST['toimport']) && count($_POST['toimport']) > 0) {
+ foreach ($_POST['toimport'] as $item) {
+ $engine['name'] = strtolower($item);
+ $engine['bind_to'] = $item;
+ $a_nat[] = $engine;
+ }
+ }
+ else
+ $input_errors[] = gettext("No entries were selected for import. Please select one or more Aliases for import and click SAVE.");
+
+ // if no errors, write new entry to conf
+ if (!$input_errors) {
+ // Reorder the engine array to ensure the
+ // 'bind_to=all' entry is at the bottom if
+ // the array contains more than one entry.
+ if (count($a_nat) > 1) {
+ $i = -1;
+ foreach ($a_nat as $f => $v) {
+ if ($v['bind_to'] == "all") {
+ $i = $f;
+ break;
+ }
+ }
+ // Only relocate the entry if we
+ // found it, and it's not already
+ // at the end.
+ if ($i > -1 && ($i < (count($a_nat) - 1))) {
+ $tmp = $a_nat[$i];
+ unset($a_nat[$i]);
+ $a_nat[] = $tmp;
+ }
+ }
+
+ // Now write the new engine array to conf and return
+ write_config();
+
+ header("Location: {$returl}?id={$id}");
+ exit;
+ }
+}
+
+$pgtitle = gettext("Suricata: Import Host/Network Alias for {$title}");
+include("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php include("fbegin.inc"); ?>
+<form action="suricata_import_aliases.php" method="post">
+<input type="hidden" name="id" value="<?=$id;?>">
+<input type="hidden" name="eng" value="<?=$eng;?>">
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<div id="boxarea">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+ <td class="tabcont"><strong><?=gettext("Select one or more Aliases to use as {$title} targets from the list below.");?></strong><br/>
+ </td>
+</tr>
+<tr>
+ <td class="tabcont">
+ <table id="sortabletable1" style="table-layout: fixed;" class="sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <colgroup>
+ <col width="5%" align="center">
+ <col width="25%" align="left" axis="string">
+ <col width="35%" align="left" axis="string">
+ <col width="35%" align="left" axis="string">
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="listhdrr"></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>
+ </tr>
+ </thead>
+ <tbody>
+ <?php $i = 0; foreach ($a_aliases as $alias): ?>
+ <?php if ($alias['type'] <> "host" && $alias['type'] <> "network")
+ continue;
+ if (isset($used[$alias['name']]))
+ continue;
+ elseif (trim(filter_expand_alias($alias['name'])) == "") {
+ $textss = "<span class=\"gray\">";
+ $textse = "</span>";
+ $disable = true;
+ $tooltip = gettext("Aliases representing a FQDN host cannot be used in Suricata Host OS Policy configurations.");
+ }
+ else {
+ $textss = "";
+ $textse = "";
+ $disable = "";
+ $selectablealias = true;
+ $tooltip = gettext("Selected entries will be imported. Click to toggle selection of this entry.");
+ }
+ ?>
+ <?php if ($disable): ?>
+ <tr title="<?=$tooltip;?>">
+ <td class="listlr" align="center"><img src="../themes/<?=$g['theme'];?>/images/icons/icon_block_d.gif" width="11" height"11" border="0"/>
+ <?php else: ?>
+ <tr>
+ <td class="listlr" align="center"><input type="checkbox" name="toimport[]" value="<?=htmlspecialchars($alias['name']);?>" title="<?=$tooltip;?>"/></td>
+ <?php endif; ?>
+ <td class="listr" align="left"><?=$textss . htmlspecialchars($alias['name']) . $textse;?></td>
+ <td class="listr" align="left">
+ <?php
+ $tmpaddr = explode(" ", $alias['address']);
+ $addresses = implode(", ", array_slice($tmpaddr, 0, 10));
+ echo "{$textss}{$addresses}{$textse}";
+ if(count($tmpaddr) > 10) {
+ echo "...";
+ }
+ ?>
+ </td>
+ <td class="listbg" align="left">
+ <?=$textss . htmlspecialchars($alias['descr']) . $textse;?>&nbsp;
+ </td>
+ </tr>
+ <?php $i++; endforeach; ?>
+ </table>
+ </td>
+</tr>
+<?php if (!$selectablealias): ?>
+<tr>
+ <td class="tabcont" align="center"><b><?php echo gettext("There are currently no defined Aliases eligible for import.");?></b></td>
+</tr>
+<tr>
+ <td class="tabcont" align="center">
+ <input type="Submit" name="cancel" value="Cancel" id="cancel" class="formbtn" title="<?=gettext("Cancel import operation and return");?>"/>
+ </td>
+</tr>
+<?php else: ?>
+<tr>
+ <td class="tabcont" align="center">
+ <input type="Submit" name="save" value="Save" id="save" class="formbtn" title="<?=gettext("Import selected item and return");?>"/>&nbsp;&nbsp;&nbsp;
+ <input type="Submit" name="cancel" value="Cancel" id="cancel" class="formbtn" title="<?=gettext("Cancel import operation and return");?>"/>
+ </td>
+</tr>
+<?php endif; ?>
+<tr>
+ <td class="tabcont">
+ <span class="vexpl"><span class="red"><strong><?=gettext("Note:"); ?><br></strong></span><?=gettext("Fully-Qualified Domain Name (FQDN) host Aliases cannot be used as Suricata configuration parameters. Aliases resolving to a single FQDN value are disabled in the list above. In the case of nested Aliases where one or more of the nested values is a FQDN host, the FQDN host will not be included in the {$title} configuration.");?></span>
+ </td>
+</tr>
+</table>
+</div>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_interfaces.php b/config/suricata/suricata_interfaces.php
new file mode 100644
index 00000000..26ccada3
--- /dev/null
+++ b/config/suricata/suricata_interfaces.php
@@ -0,0 +1,474 @@
+<?php
+/*
+ * suricata_interfaces.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.
+ */
+
+$nocsrf = true;
+require_once("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+$suricatadir = SURICATADIR;
+$suricatalogdir = SURICATALOGDIR;
+$rcdir = RCFILEPREFIX;
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+$id_gen = count($config['installedpackages']['suricata']['rule']);
+
+if (isset($_POST['del_x'])) {
+ /* delete selected rules */
+ if (is_array($_POST['rule'])) {
+ conf_mount_rw();
+ foreach ($_POST['rule'] as $rulei) {
+ /* convert fake interfaces to real */
+ $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}");
+
+ // If interface had auto-generated Suppress List, then
+ // delete that along with the interface
+ $autolist = "{$a_nat[$rulei]['interface']}" . "suppress";
+ if (is_array($config['installedpackages']['suricata']['suppress']) &&
+ is_array($config['installedpackages']['suricata']['suppress']['item'])) {
+ $a_suppress = &$config['installedpackages']['suricata']['suppress']['item'];
+ foreach ($a_suppress as $k => $i) {
+ if ($i['name'] == $autolist) {
+ unset($config['installedpackages']['suricata']['suppress']['item'][$k]);
+ break;
+ }
+ }
+ }
+
+ // Finally delete the interface's config entry entirely
+ unset($a_nat[$rulei]);
+ }
+ conf_mount_ro();
+
+ /* If all the Suricata interfaces are removed, then unset the config array. */
+ if (empty($a_nat))
+ unset($a_nat);
+
+ write_config();
+ 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();
+ }
+
+ 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;
+ }
+
+}
+
+/* start/stop Barnyard2 */
+if ($_GET['act'] == 'bartoggle' && is_numeric($id)) {
+ $suricatacfg = $config['installedpackages']['suricata']['rule'][$id];
+ $if_real = get_real_interface($suricatacfg['interface']);
+ $if_friendly = convert_friendly_interface_to_friendly_descr($suricatacfg['interface']);
+
+ if (suricata_is_running($suricatacfg['uuid'], $if_real, 'barnyard2') == 'no') {
+ log_error("Toggle (barnyard starting) for {$if_friendly}({$suricatacfg['descr']})...");
+ sync_suricata_package_config();
+ suricata_barnyard_start($suricatacfg, $if_real);
+ } else {
+ log_error("Toggle (barnyard stopping) for {$if_friendly}({$suricatacfg['descr']})...");
+ suricata_barnyard_stop($suricatacfg, $if_real);
+ }
+
+ sleep(3); // So the GUI reports correctly
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+/* start/stop Suricata */
+if ($_GET['act'] == 'toggle' && is_numeric($id)) {
+ $suricatacfg = $config['installedpackages']['suricata']['rule'][$id];
+ $if_real = get_real_interface($suricatacfg['interface']);
+ $if_friendly = convert_friendly_interface_to_friendly_descr($suricatacfg['interface']);
+
+ if (suricata_is_running($suricatacfg['uuid'], $if_real) == 'yes') {
+ log_error("Toggle (suricata stopping) for {$if_friendly}({$suricatacfg['descr']})...");
+ suricata_stop($suricatacfg, $if_real);
+ } else {
+ log_error("Toggle (suricata starting) for {$if_friendly}({$suricatacfg['descr']})...");
+ // set flag to rebuild interface rules before starting Snort
+ $rebuild_rules = true;
+ sync_suricata_package_config();
+ $rebuild_rules = false;
+ suricata_start($suricatacfg, $if_real);
+ }
+ sleep(3); // So the GUI reports correctly
+ 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;
+}
+
+$pgtitle = "Services: Suricata Intrusion Detection System";
+include_once("head.inc");
+
+?>
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?php
+include_once("fbegin.inc");
+if ($pfsense_stable == 'yes')
+ echo '<p class="pgtitle">' . $pgtitle . '</p>';
+?>
+
+<form action="suricata_interfaces.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php
+ /* Display Alert message */
+ if ($input_errors)
+ print_input_errors($input_errors); // TODO: add checks
+
+ if ($savemsg)
+ 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"), 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("Alerts"), false, "/suricata/suricata_alerts.php");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ ?>
+ </td>
+</tr>
+<tr>
+ <td>
+ <div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr id="frheader">
+ <td width="3%" class="list">&nbsp;</td>
+ <td width="10%" class="listhdrr"><?php echo gettext("Interface"); ?></td>
+ <td width="13%" class="listhdrr"><?php echo gettext("Suricata"); ?></td>
+ <td width="10%" class="listhdrr"><?php echo gettext("Pattern Match"); ?></td>
+ <td width="10%" class="listhdrr"><?php echo gettext("Block"); ?></td>
+ <td width="12%" class="listhdrr"><?php echo gettext("Barnyard2"); ?></td>
+ <td width="30%" class="listhdr"><?php echo gettext("Description"); ?></td>
+ <td width="3%" class="list">
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td></td>
+ <td align="center" valign="middle"><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></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <?php $nnats = $i = 0;
+
+ // Turn on buffering to speed up rendering
+ ini_set('output_buffering','true');
+
+ // Start buffering to fix display lag issues in IE9 and IE10
+ ob_start(null, 0);
+
+ /* If no interfaces are defined, then turn off the "no rules" warning */
+ $no_rules_footnote = false;
+ if ($id_gen == 0)
+ $no_rules = false;
+ else
+ $no_rules = true;
+
+ foreach ($a_nat as $natent): ?>
+ <tr valign="top" id="fr<?=$nnats;?>">
+ <?php
+
+ /* convert fake interfaces to real and check if iface is up */
+ /* There has to be a smarter way to do this */
+ $if_real = get_real_interface($natent['interface']);
+ $natend_friendly= convert_friendly_interface_to_friendly_descr($natent['interface']);
+ $suricata_uuid = $natent['uuid'];
+ if (suricata_is_running($suricata_uuid, $if_real) == 'no'){
+ $iconfn = 'block';
+ $iconfn_msg1 = 'Suricata is not running on ';
+ $iconfn_msg2 = '. Click to start.';
+ }
+ else{
+ $iconfn = 'pass';
+ $iconfn_msg1 = 'Suricata is running on ';
+ $iconfn_msg2 = '. Click to stop.';
+ }
+ if (suricata_is_running($suricata_uuid, $if_real, 'barnyard2') == 'no'){
+ $biconfn = 'block';
+ $biconfn_msg1 = 'Barnyard2 is not running on ';
+ $biconfn_msg2 = '. Click to start.';
+ }
+ else{
+ $biconfn = 'pass';
+ $biconfn_msg1 = 'Barnyard2 is running on ';
+ $biconfn_msg2 = '. Click to stop.';
+ }
+
+ /* See if interface has any rules defined and set boolean flag */
+ $no_rules = true;
+ if (isset($natent['customrules']) && !empty($natent['customrules']))
+ $no_rules = false;
+ if (isset($natent['rulesets']) && !empty($natent['rulesets']))
+ $no_rules = false;
+ if (isset($natent['ips_policy']) && !empty($natent['ips_policy']))
+ $no_rules = false;
+ /* Do not display the "no rules" warning if interface disabled */
+ if ($natent['enable'] == "off")
+ $no_rules = false;
+ if ($no_rules)
+ $no_rules_footnote = true;
+ ?>
+ <td class="listt">
+ <input type="checkbox" id="frc<?=$nnats;?>" name="rule[]" value="<?=$i;?>" onClick="fr_bgcolor('<?=$nnats;?>')" style="margin: 0; padding: 0;">
+ </td>
+ <td class="listr"
+ id="frd<?=$nnats;?>" valign="middle"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <?php
+ echo $natend_friendly;
+ ?>
+ </td>
+ <td class="listr"
+ id="frd<?=$nnats;?>"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <?php
+ $check_suricata_info = $config['installedpackages']['suricata']['rule'][$nnats]['enable'];
+ if ($check_suricata_info == "on") {
+ echo gettext("ENABLED");
+ echo "<a href='?act=toggle&id={$i}'>
+ <img src='../themes/{$g['theme']}/images/icons/icon_{$iconfn}.gif'
+ width='13' height='13' border='0'
+ title='" . gettext($iconfn_msg1.$natend_friendly.$iconfn_msg2) . "'></a>";
+ echo ($no_rules) ? "&nbsp;<img src=\"../themes/{$g['theme']}/images/icons/icon_frmfld_imp.png\" width=\"15\" height=\"15\" border=\"0\">" : "";
+ } else
+ echo gettext("DISABLED");
+ ?>
+ </td>
+ <td class="listr"
+ id="frd<?=$nnats;?>" valign="middle"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <?php
+ $check_performance_info = $config['installedpackages']['suricata']['rule'][$nnats]['mpm_algo'];
+ if ($check_performance_info != "") {
+ $check_performance = $check_performance_info;
+ }else{
+ $check_performance = "unknown";
+ }
+ ?> <?=strtoupper($check_performance);?>
+ </td>
+ <td class="listr"
+ id="frd<?=$nnats;?>" valign="middle"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <?php
+ $check_blockoffenders_info = $config['installedpackages']['suricata']['rule'][$nnats]['blockoffenders'];
+ if ($check_blockoffenders_info == "on")
+ {
+ $check_blockoffenders = enabled;
+ } else {
+ $check_blockoffenders = disabled;
+ }
+ ?> <?=strtoupper($check_blockoffenders);?>
+ </td>
+ <td class="listr"
+ id="frd<?=$nnats;?>" valign="middle"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <?php
+ $check_suricatabarnyardlog_info = $config['installedpackages']['suricata']['rule'][$nnats]['barnyard_enable'];
+ if ($check_suricatabarnyardlog_info == "on") {
+ echo gettext("ENABLED");
+ echo "<a href='?act=bartoggle&id={$i}'>
+ <img src='../themes/{$g['theme']}/images/icons/icon_{$biconfn}.gif'
+ width='13' height='13' border='0'
+ title='" . gettext($biconfn_msg1.$natend_friendly.$biconfn_msg2) . "'></a>";
+ } else
+ echo gettext("DISABLED");
+ ?>
+ </td>
+ <td class="listbg" valign="middle"
+ ondblclick="document.location='suricata_interfaces_edit.php?id=<?=$nnats;?>';">
+ <font color="#ffffff"> <?=htmlspecialchars($natent['descr']);?>&nbsp;</font>
+ </td>
+ <td valign="middle" class="list" nowrap>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><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>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <?php $i++; $nnats++; endforeach; ob_end_flush(); ?>
+ <tr>
+ <td class="list"></td>
+ <td class="list" colspan="6">
+ <?php if ($no_rules_footnote): ?><br><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_frmfld_imp.png" width="15" height="15" border="0">
+ <span class="red">&nbsp;&nbsp <?php echo gettext("WARNING: Marked interface currently has no rules defined for Suricata"); ?></span>
+ <?php else: ?>&nbsp;
+ <?php endif; ?>
+ </td>
+ <td class="list" valign="middle" nowrap>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><?php if ($nnats == 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; ?></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="8">&nbsp;</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td colspan="6">
+ <table class="tabcont" width="100%" border="0" cellpadding="1" cellspacing="0">
+ <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 ") .
+ "</strong>" . gettext("where you can see an overview of all your interface settings. ");
+ if (empty($a_nat)) {
+ echo gettext("Please configure the parameters on the ") . "<strong>" . gettext("Global Settings") .
+ "</strong>" . gettext(" tab before adding an interface.");
+ }?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3" class="vexpl"><br>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3" class="vexpl"><span class="red"><strong><?php echo gettext("Warning:"); ?></strong></span><br>
+ <strong><?php echo gettext("New settings will not take effect until interface restart."); ?></strong>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3" class="vexpl"><br>
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><strong>Click</strong> on the <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif"
+ width="17" height="17" border="0" title="<?php echo gettext("Add Icon"); ?>"> icon to add
+ an interface.
+ </td>
+ <td width="3%" class="vexpl">&nbsp;
+ </td>
+ <td class="vexpl"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_pass.gif"
+ width="13" height="13" border="0" title="<?php echo gettext("Running"); ?>">
+ <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_block.gif"
+ width="13" height="13" border="0" title="<?php echo gettext("Not Running"); ?>"> icons will show current
+ suricata and barnyard2 status.
+ </td>
+ </tr>
+ <tr>
+ <td class="vexpl"><strong>Click</strong> on the <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_e.gif"
+ width="17" height="17" border="0" title="<?php echo gettext("Edit Icon"); ?>"> icon to edit
+ an interface and settings.
+ <td width="3%">&nbsp;
+ </td>
+ <td class="vexpl"><strong>Click</strong> on the status icons to <strong>toggle</strong> suricata and barnyard2 status.
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3" class="vexpl"><strong> Click</strong> on the <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_x.gif"
+ width="17" height="17" border="0" title="<?php echo gettext("Delete Icon"); ?>"> icon to
+ delete an interface and settings.
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>&nbsp;</td>
+ </tr>
+ </table>
+ </div>
+ </td>
+</tr>
+</table>
+</form>
+
+<script type="text/javascript">
+
+function intf_del() {
+ var isSelected = false;
+ var inputs = document.iform.elements;
+ for (var i = 0; i < inputs.length; i++) {
+ if (inputs[i].type == "checkbox") {
+ if (inputs[i].checked)
+ isSelected = true;
+ }
+ }
+ if (isSelected)
+ return confirm('Do you really want to delete the selected Suricata mapping?');
+ else
+ alert("There is no Suricata mapping selected for deletion. Click the checkbox beside the Suricata mapping(s) you wish to delete.");
+}
+
+</script>
+
+<?php
+include("fend.inc");
+?>
+</body>
+</html>
diff --git a/config/suricata/suricata_interfaces_edit.php b/config/suricata/suricata_interfaces_edit.php
new file mode 100644
index 00000000..5f644a55
--- /dev/null
+++ b/config/suricata/suricata_interfaces_edit.php
@@ -0,0 +1,911 @@
+<?php
+/*
+ * suricata_interfaces_edit.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+if (!is_array($config['installedpackages']['suricata']))
+ $config['installedpackages']['suricata'] = array();
+$suricataglob = $config['installedpackages']['suricata'];
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_rule = &$config['installedpackages']['suricata']['rule'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+$pconfig = array();
+if (empty($suricataglob['rule'][$id]['uuid'])) {
+ /* Adding new interface, so flag rules to build. */
+ $pconfig['uuid'] = suricata_generate_id();
+ $rebuild_rules = true;
+}
+else {
+ $pconfig['uuid'] = $a_rule[$id]['uuid'];
+ $pconfig['descr'] = $a_rule[$id]['descr'];
+ $rebuild_rules = false;
+}
+$suricata_uuid = $pconfig['uuid'];
+
+// Get the physical configured interfaces on the firewall
+if (function_exists('get_configured_interface_with_descr'))
+ $interfaces = get_configured_interface_with_descr();
+else {
+ $interfaces = array('wan' => 'WAN', 'lan' => 'LAN');
+ for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
+ $interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
+}
+
+// See if interface is already configured, and use its values
+if (isset($id) && $a_rule[$id]) {
+ $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])) {
+ $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;
+ break;
+ }
+ }
+ if (count($ifrules) == count($ifaces)) {
+ $input_errors[] = gettext("No more available interfaces to configure for Suricata!");
+ $interfaces = array();
+ $pconfig = array();
+ }
+}
+
+if (isset($_GET['dup']))
+ unset($id);
+
+// Set defaults for any empty key parameters
+if (empty($pconfig['blockoffendersip']))
+ $pconfig['blockoffendersip'] = "both";
+if (empty($pconfig['max_pending_packets']))
+ $pconfig['max_pending_packets'] = "1024";
+if (empty($pconfig['inspect_recursion_limit']))
+ $pconfig['inspect_recursion_limit'] = "3000";
+if (empty($pconfig['detect_eng_profile']))
+ $pconfig['detect_eng_profile'] = "medium";
+if (empty($pconfig['mpm_algo']))
+ $pconfig['mpm_algo'] = "ac";
+if (empty($pconfig['sgh_mpm_context']))
+ $pconfig['sgh_mpm_context'] = "auto";
+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['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_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 ($_POST["Submit"]) {
+ if (!$_POST['interface'])
+ $input_errors[] = gettext("Choosing an Interface is mandatory!");
+
+ if ($_POST['max_pending_packets'] < 1 || $_POST['max_pending_packets'] > 65535)
+ $input_errors[] = gettext("The value for Maximum-Pending-Packets must be between 1 and 65,535!");
+
+ if (!empty($_POST['max_pcap_log_size']) && !is_numeric($_POST['max_pcap_log_size']))
+ $input_errors[] = gettext("The value for 'Max Packet Log Size' must be numbers only. Do not include any alphabetic characters.");
+
+ if (!empty($_POST['max_pcap_log_files']) && !is_numeric($_POST['max_pcap_log_files']))
+ $input_errors[] = gettext("The value for 'Max Packet Log Files' must be numbers only.");
+
+ // if no errors write to suricata.yaml
+ if (!$input_errors) {
+ $natent = $a_rule[$id];
+ $natent['interface'] = $_POST['interface'];
+ $natent['enable'] = $_POST['enable'] ? 'on' : 'off';
+ $natent['uuid'] = $pconfig['uuid'];
+
+ // See if the HOME_NET, EXTERNAL_NET, or SUPPRESS LIST values were changed
+ $suricata_reload = false;
+ if ($_POST['homelistname'] && ($_POST['homelistname'] <> $natent['homelistname']))
+ $suricata_reload = true;
+ if ($_POST['externallistname'] && ($_POST['externallistname'] <> $natent['externallistname']))
+ $suricata_reload = true;
+ if ($_POST['suppresslistname'] && ($_POST['suppresslistname'] <> $natent['suppresslistname']))
+ $suricata_reload = true;
+
+ if ($_POST['descr']) $natent['descr'] = $_POST['descr']; else $natent['descr'] = strtoupper($natent['interface']);
+ if ($_POST['max_pcap_log_size']) $natent['max_pcap_log_size'] = $_POST['max_pcap_log_size']; else unset($natent['max_pcap_log_size']);
+ if ($_POST['max_pcap_log_files']) $natent['max_pcap_log_files'] = $_POST['max_pcap_log_files']; else unset($natent['max_pcap_log_files']);
+ if ($_POST['enable_stats_log'] == "on") { $natent['enable_stats_log'] = 'on'; }else{ $natent['enable_stats_log'] = 'off'; }
+ if ($_POST['append_stats_log'] == "on") { $natent['append_stats_log'] = 'on'; }else{ $natent['append_stats_log'] = 'off'; }
+ if ($_POST['stats_upd_interval']) $natent['stats_upd_interval'] = $_POST['stats_upd_interval']; else $natent['stats_upd_interval'] = "10";
+ 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['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'; }
+ if ($_POST['append_json_file_log'] == "on") { $natent['append_json_file_log'] = 'on'; }else{ $natent['append_json_file_log'] = 'off'; }
+ 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['max_pending_packets']) $natent['max_pending_packets'] = $_POST['max_pending_packets']; else unset($natent['max_pending_packets']);
+ if ($_POST['inspect_recursion_limit']) $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']);
+ if ($_POST['mpm_algo']) $natent['mpm_algo'] = $_POST['mpm_algo']; else unset($natent['mpm_algo']);
+ if ($_POST['sgh_mpm_context']) $natent['sgh_mpm_context'] = $_POST['sgh_mpm_context']; else unset($natent['sgh_mpm_context']);
+ if ($_POST['blockoffenders'] == "on") $natent['blockoffenders'] = 'on'; else $natent['blockoffenders'] = 'off';
+ if ($_POST['blockoffenderskill'] == "on") $natent['blockoffenderskill'] = 'on'; else unset($natent['blockoffenderskill']);
+ if ($_POST['blockoffendersip']) $natent['blockoffendersip'] = $_POST['blockoffendersip']; else unset($natent['blockoffendersip']);
+ if ($_POST['whitelistname']) $natent['whitelistname'] = $_POST['whitelistname']; else unset($natent['whitelistname']);
+ if ($_POST['homelistname']) $natent['homelistname'] = $_POST['homelistname']; else unset($natent['homelistname']);
+ 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['configpassthru']) $natent['configpassthru'] = base64_encode($_POST['configpassthru']); else unset($natent['configpassthru']);
+
+ $if_real = get_real_interface($natent['interface']);
+ if (isset($id) && $a_rule[$id]) {
+ if ($natent['interface'] != $a_rule[$id]['interface']) {
+ $oif_real = get_real_interface($a_rule[$id]['interface']);
+ suricata_stop($a_rule[$id], $oif_real);
+ exec("rm -r /var/log/suricata_{$oif_real}" . $a_rule[$id]['uuid']);
+ exec("mv -f {$suricatadir}/suricata_" . $a_rule[$id]['uuid'] . "_{$oif_real} {$suricatadir}/suricata_" . $a_rule[$id]['uuid'] . "_{$if_real}");
+ }
+ // Edits don't require a rules rebuild, so turn it "off"
+ $rebuild_rules = false;
+ $a_rule[$id] = $natent;
+ } else {
+ // Adding new interface, so set interface configuration parameter defaults
+ $natent['ip_max_frags'] = "65535";
+ $natent['ip_frag_timeout'] = "60";
+ $natent['frag_memcap'] = '33554432';
+ $natent['ip_max_trackers'] = '65535';
+ $natent['frag_hash_size'] = '65536';
+
+ $natent['flow_memcap'] = '33554432';
+ $natent['flow_prealloc'] = '10000';
+ $natent['flow_hash_size'] = '65536';
+ $natent['flow_emerg_recovery'] = '30';
+ $natent['flow_prune'] = '5';
+
+ $natent['flow_tcp_new_timeout'] = '60';
+ $natent['flow_tcp_established_timeout'] = '3600';
+ $natent['flow_tcp_closed_timeout'] = '120';
+ $natent['flow_tcp_emerg_new_timeout'] = '10';
+ $natent['flow_tcp_emerg_established_timeout'] = '300';
+ $natent['flow_tcp_emerg_closed_timeout'] = '20';
+
+ $natent['flow_udp_new_timeout'] = '30';
+ $natent['flow_udp_established_timeout'] = '300';
+ $natent['flow_udp_emerg_new_timeout'] = '10';
+ $natent['flow_udp_emerg_established_timeout'] = '100';
+
+ $natent['flow_icmp_new_timeout'] = '30';
+ $natent['flow_icmp_established_timeout'] = '300';
+ $natent['flow_icmp_emerg_new_timeout'] = '10';
+ $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';
+ $natent['reassembly_to_server_chunk'] = '2560';
+ $natent['reassembly_to_client_chunk'] = '2560';
+ $natent['enable_midstream_sessions'] = 'off';
+ $natent['enable_async_sessions'] = 'off';
+
+ $natent['asn1_max_frames'] = '256';
+
+ $default = array( "name" => "default", "bind_to" => "all", "policy" => "bsd" );
+ if (!is_array($natent['host_os_policy']['item']))
+ $natent['host_os_policy']['item'] = array();
+ $natent['host_os_policy']['item'][] = $default;
+
+ $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" );
+ 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";
+
+ // Adding a new interface, so set flag to build new rules
+ $rebuild_rules = true;
+
+ // Add the new interface configuration to the [rule] array in config
+ $a_rule[] = $natent;
+ }
+
+ // If Suricata is disabled on this interface, stop any running instance
+ if ($natent['enable'] != 'on')
+ suricata_stop($natent, $if_real);
+
+ // Save configuration changes
+ write_config();
+
+ // Update suricata.conf and suricata.sh files for this interface
+ sync_suricata_package_config();
+
+ /*******************************************************/
+ /* Signal Suricata to reload configuration if we changed */
+ /* HOME_NET, EXTERNAL_NET or Suppress list values. */
+ /* The function only signals a running Suricata instance */
+ /* to safely reload these parameters. */
+ /*******************************************************/
+ if ($suricata_reload == true)
+ suricata_reload_config($natent, "USR2");
+
+ 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;
+ } else
+ $pconfig = $_POST;
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Edit Settings");
+include_once("head.inc");
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php include("fbegin.inc"); ?>
+
+<?if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}?>
+
+<?php
+ /* Display Alert message */
+ if ($input_errors) {
+ print_input_errors($input_errors);
+ }
+
+ if ($savemsg) {
+ print_info_box($savemsg);
+ }
+?>
+
+<form action="suricata_interfaces_edit.php<?php echo "?id=$id";?>" method="post" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ 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"), true, "/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}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr><td><div id="mainarea">
+<table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("General Settings"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncellreq"><?php echo gettext("Enable"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="enable" type="checkbox" value="on" <?php if ($pconfig['enable'] == "on") echo "checked"; ?> onClick="enable_change(false)"/>
+ <?php echo gettext("Checking this box enables Suricata inspection on the interface."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncellreq"><?php echo gettext("Interface"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="interface" class="formselect" tabindex="0">
+ <?php
+ foreach ($interfaces as $iface => $ifacename): ?>
+ <option value="<?=$iface;?>"
+ <?php if ($iface == $pconfig['interface']) echo " selected"; ?>><?=htmlspecialchars($ifacename);?>
+ </option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;
+ <span class="vexpl"><?php echo gettext("Choose which interface this Suricata instance applies to."); ?><br/>
+ <span class="red"><?php echo gettext("Hint:"); ?></span>&nbsp;<?php echo gettext("In most cases, you'll want to use WAN here."); ?></span><br/></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncellreq"><?php echo gettext("Description"); ?></td>
+ <td width="78%" class="vtable"><input name="descr" type="text"
+ class="formfld unknown" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']); ?>"/> <br/>
+ <span class="vexpl"><?php echo gettext("Enter a meaningful description here for your reference."); ?></span><br/></td>
+ </tr>
+<tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Logging Settings"); ?></td>
+</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>
+ </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"; ?>
+ onClick="toggle_stats_log();" id="enable_stats_log"/>
+ <?php echo gettext("Suricata will periodically log statistics for the interface. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?>
+ <div id="stats_log_warning" style="display: none;"><br/><span class="red"><strong><?php echo gettext("Warning: ") . "</strong></span>" .
+ gettext("The stats log file can become quite large, especially when append mode is enabled!"); ?></div></td>
+ </tr>
+ <tr id="stats_interval_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Stats Update Interval"); ?></td>
+ <td width="78%" class="vtable"><input name="stats_upd_interval" type="text"
+ class="formfld unknown" id="stats_upd_interval" size="8" value="<?=htmlspecialchars($pconfig['stats_upd_interval']); ?>"/>&nbsp;
+ <?php echo gettext("Enter the update interval in ") . "<strong>" . gettext("seconds") . "</strong>" . gettext(" for stats updating. Default is ") . "<strong>" .
+ gettext("10") . "</strong>."; ?><br/><?php echo gettext("Sets the update interval, in seconds, for the collection and logging of statistics.") ?></td>
+ </tr>
+ <tr id="stats_log_append_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Append Stats Log"); ?></td>
+ <td width="78%" class="vtable"><input name="append_stats_log" type="checkbox" value="on" <?php if ($pconfig['append_stats_log'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Suricata will append-to instead of clearing statistics log file when restarting. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable HTTP Log"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_http_log" type="checkbox" value="on" <?php if ($pconfig['enable_http_log'] == "on") echo "checked"; ?>
+ onClick="toggle_http_log()" id="enable_http_log"/>
+ <?php echo gettext("Suricata will log decoded HTTP traffic for the interface. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr id="http_log_append_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Append HTTP Log"); ?></td>
+ <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>
+ <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"; ?>
+ onClick="toggle_tls_log()" id="enable_tls_log"/>
+ <?php echo gettext("Suricata will log TLS handshake traffic for the interface. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr id="tls_log_extended_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Log Extended TLS Info"); ?></td>
+ <td width="78%" class="vtable"><input name="tls_log_extended" type="checkbox" value="on" <?php if ($pconfig['tls_log_extended'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Suricata will log extended TLS info such as fingerprint. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Tracked-Files Log"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_json_file_log" type="checkbox" value="on" <?php if ($pconfig['enable_json_file_log'] == "on") echo "checked"; ?>
+ onClick="toggle_json_file_log()" id="enable_json_file_log"/>
+ <?php echo gettext("Suricata will log tracked files in JavaScript Object Notation (JSON) format. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr id="tracked_files_append_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Append Tracked-Files Log"); ?></td>
+ <td width="78%" class="vtable"><input name="append_json_file_log" type="checkbox" value="on" <?php if ($pconfig['append_json_file_log'] == "on") echo "checked"; ?>
+ id="append_json_file_log"/>
+ <?php echo gettext("Suricata will append-to instead of clearing Tracked Files log file when restarting. Default is ") . "<strong>" . gettext("Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr id="tracked_files_magic_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Logging Magic for Tracked-Files"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_tracked_files_magic" type="checkbox" value="on" <?php if ($pconfig['enable_tracked_files_magic'] == "on") echo "checked"; ?>
+ id="enable_tracked_files_magic"/>
+ <?php echo gettext("Suricata will force logging magic on all logged Tracked Files. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr id="tracked_files_md5_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable MD5 for Tracked-Files"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_tracked_files_md5" type="checkbox" value="on" <?php if ($pconfig['enable_tracked_files_md5'] == "on") echo "checked"; ?>
+ id="enable_tracked_files_md5"/>
+ <?php echo gettext("Suricata will generate MD5 checksums for all logged Tracked Files. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable File-Store"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_file_store" type="checkbox" value="on" <?php if ($pconfig['enable_file_store'] == "on") echo "checked"; ?>
+ onClick="toggle_file_store()" id="enable_file_store"/>
+ <?php echo gettext("Suricata will extract and store files from application layer streams. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?>
+ <div id="file_store_warning" style="display: none;"><br/><span class="red"><strong><?php echo gettext("Warning: ") . "</strong></span>" .
+ gettext("This will consume a significant amount of disk space on a busy network when enabled!"); ?></div>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable Packet Log"); ?></td>
+ <td width="78%" class="vtable"><input name="enable_pcap_log" id="enable_pcap_log" type="checkbox" value="on" <?php if ($pconfig['enable_pcap_log'] == "on") echo "checked"; ?>
+ onClick="toggle_pcap_log()"/>
+ <?php echo gettext("Suricata will log decoded packets for the interface in pcap-format. Default is ") . "<strong>" . gettext("Not Checked") . "</strong>."; ?>
+ <div id="file_pcap_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>
+ <tr id="pcap_log_size_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Packet Log File Size"); ?></td>
+ <td width="78%" class="vtable"><input name="max_pcap_log_size" type="text"
+ class="formfld unknown" id="max_pcap_log_size" size="8" value="<?=htmlspecialchars($pconfig['max_pcap_log_size']); ?>"/>&nbsp;
+ <?php echo gettext("Enter maximum size in ") . "<strong>" . gettext("MB") . "</strong>" . gettext(" for a packet log file. Default is ") . "<strong>" .
+ gettext("32") . "</strong>."; ?><br/><br/><?php echo gettext("When the packet log file size reaches the set limit, it will be rotated and a new one created.") ?></td>
+ </tr>
+ </tr>
+ <tr id="pcap_log_max_row">
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Packet Log Files"); ?></td>
+ <td width="78%" class="vtable"><input name="max_pcap_log_files" type="text"
+ class="formfld unknown" id="max_pcap_log_files" size="8" value="<?=htmlspecialchars($pconfig['max_pcap_log_files']); ?>"/>&nbsp;
+ <?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 colspan="2" class="listtopic"><?php echo gettext("Alert Settings"); ?></td>
+</tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Block Offenders"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="blockoffenders" id="blockoffenders" type="checkbox" value="on"
+ <?php if ($pconfig['blockoffenders'] == "on") echo "checked"; ?>
+ onClick="enable_blockoffenders()"/>
+ <?php echo gettext("Checking this option will automatically block hosts that generate a " . "Suricata alert."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Kill States"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="blockoffenderskill" id="blockoffenderskill" type="checkbox" value="on" <?php if ($pconfig['blockoffenderskill'] == "on") echo "checked"; ?>/>
+ <?php echo gettext("Checking this option will kill firewall states for the blocked IP."); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Which IP to Block"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="blockoffendersip" class="formselect" id="blockoffendersip">
+ <?php
+ foreach (array("src", "dst", "both") as $btype) {
+ if ($btype == $pconfig['blockoffendersip'])
+ echo "<option value='{$btype}' selected>";
+ else
+ echo "<option value='{$btype}'>";
+ echo htmlspecialchars($btype) . '</option>';
+ }
+ ?>
+ </select>&nbsp;&nbsp;
+ <?php echo gettext("Select which IP extracted from the packet you wish to block."); ?><br/>
+ <span class="red"><?php echo gettext("Hint:") . "</span>&nbsp;" . gettext("Choosing BOTH is suggested, and it is the default value."); ?></span><br/></td>
+ </td>
+ </tr>
+-->
+
+<tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Detection Engine Settings"); ?></td>
+</tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Max Pending Packets"); ?></td>
+ <td width="78%" class="vtable"><input name="max_pending_packets" type="text"
+ class="formfld unknown" id="max_pending_packets" size="8" value="<?=htmlspecialchars($pconfig['max_pending_packets']); ?>"/>&nbsp;
+ <?php echo gettext("Enter number of simultaneous packets to process. Default is ") . "<strong>" .
+ gettext("1024") . "</strong>."; ?><br/><br/><?php echo gettext("Minimum value is 1 and the maximum value is 65,535.") ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Detect-Engine Profile"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="detect_eng_profile" class="formselect" id="detect_eng_profile">
+ <?php
+ $interfaces2 = array('low' => 'Low', 'medium' => 'Medium', 'high' => 'High');
+ foreach ($interfaces2 as $iface2 => $ifacename2): ?>
+ <option value="<?=$iface2;?>"
+ <?php if ($iface2 == $pconfig['detect_eng_profile']) echo "selected"; ?>>
+ <?=htmlspecialchars($ifacename2);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;
+ <?php echo gettext("Choose a detection engine profile. ") . "<strong>" . gettext("Default") .
+ "</strong>" . gettext(" is ") . "<strong>" . gettext("Medium") . "</strong>"; ?>.<br/><br/>
+ <?php echo gettext("MEDIUM is recommended for most systems because it offers a good " .
+ "balance between memory consumption and performance. LOW uses less memory, but it offers lower performance. " .
+ "HIGH consumes a large amount of memory, but it offers the highest performance."); ?>
+ <br/></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Pattern Matcher Algorithm"); ?></td>
+ <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');
+ foreach ($interfaces2 as $iface2 => $ifacename2): ?>
+ <option value="<?=$iface2;?>"
+ <?php if ($iface2 == $pconfig['mpm_algo']) echo "selected"; ?>>
+ <?=htmlspecialchars($ifacename2);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;
+ <?php echo gettext("Choose a multi-pattern matcher (MPM) algorithm. ") . "<strong>" . gettext("Default") .
+ "</strong>" . gettext(" is ") . "<strong>" . gettext("AC") . "</strong>"; ?>.<br/><br/>
+ <?php echo gettext("AC is recommended for most systems. "); ?>
+ <br/></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Signature Group Header MPM Context"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="sgh_mpm_context" class="formselect" id="sgh_mpm_context">
+ <?php
+ $interfaces2 = array('auto' => 'Auto', 'full' => 'Full', 'single' => 'Single');
+ foreach ($interfaces2 as $iface2 => $ifacename2): ?>
+ <option value="<?=$iface2;?>"
+ <?php if ($iface2 == $pconfig['sgh_mpm_context']) echo "selected"; ?>>
+ <?=htmlspecialchars($ifacename2);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;
+ <?php echo gettext("Choose a Signature Group Header multi-pattern matcher context. ") . "<strong>" . gettext("Default") .
+ "</strong>" . gettext(" is ") . "<strong>" . gettext("Auto") . "</strong>"; ?>.<br/><br/>
+ <?php echo gettext("AUTO means Suricata selects between Full and Single based on the MPM algorithm " .
+ "chosen. FULL means every Signature Group has its own MPM context. SINGLE means all Signature Groups share a single MPM " .
+ "context. Using FULL can improve performance at the expense of significant memory consumption."); ?>
+ <br/></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Inspection Recursion Limit"); ?></td>
+ <td width="78%" class="vtable"><input name="inspect_recursion_limit" type="text"
+ class="formfld unknown" id="inspect_recursion_limit" size="8" value="<?=htmlspecialchars($pconfig['inspect_recursion_limit']); ?>"/>&nbsp;
+ <?php echo gettext("Enter limit for recursive calls in content inspection code. Default is ") . "<strong>" .
+ gettext("3000") . "</strong>."; ?><br/><br/><?php echo gettext("When set to 0 an internal default is used. When left blank there is no recursion limit.") ?></td>
+ </tr>
+ <tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Networks " . "Suricata Should Inspect and Whitelist"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Home Net"); ?></td>
+ <td width="78%" class="vtable">
+ <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) {
+ $ilistname = $value['name'];
+ if ($ilistname == $pconfig['homelistname'])
+ echo "<option value='$ilistname' selected>";
+ else
+ echo "<option value='$ilistname'>";
+ echo htmlspecialchars($ilistname) . '</option>';
+ }
+ }
+ ?>
+ </select>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="button" class="formbtns" value="View List"
+ 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>
+ <br/><br/>
+ <span class="red"><?php echo gettext("Note:"); ?></span>&nbsp;<?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>&nbsp;<?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/>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("External Net"); ?></td>
+ <td width="78%" class="vtable">
+ <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) {
+ $ilistname = $value['name'];
+ if ($ilistname == $pconfig['externallistname'])
+ echo "<option value='$ilistname' selected>";
+ else
+ echo "<option value='$ilistname'>";
+ echo htmlspecialchars($ilistname) . '</option>';
+ }
+ }
+ ?>
+ </select>&nbsp;&nbsp;
+ <?php echo gettext("Choose the External Net you want this interface " .
+ "to use."); ?>&nbsp;<br/><br/>
+ <span class="red"><?php echo gettext("Note:"); ?></span>&nbsp;<?php echo gettext("Default " .
+ "External Net is networks that are not Home Net."); ?><br/>
+ <span class="red"><?php echo gettext("Hint:"); ?></span>&nbsp;<?php echo gettext("Most users should leave this " .
+ "setting at default. Create an Alias for custom External Net settings."); ?><br/>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Whitelist"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="whitelistname" class="formselect" id="whitelistname">
+ <?php
+ /* find whitelist names and filter by type, make sure to track by uuid */
+ echo "<option value='default' >default</option>\n";
+ if (is_array($suricataglob['whitelist']['item'])) {
+ foreach ($suricataglob['whitelist']['item'] as $value) {
+ if ($value['name'] == $pconfig['whitelistname'])
+ echo "<option value='{$value['name']}' selected>";
+ else
+ echo "<option value='{$value['name']}'>";
+ echo htmlspecialchars($value['name']) . '</option>';
+ }
+ }
+ ?>
+ </select>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="button" class="formbtns" value="View List" onclick="viewList('<?=$id;?>','whitelistname','whitelist')"
+ id="btnWhitelist" title="<?php echo gettext("Click to view currently selected Whitelist contents"); ?>"/>
+ <br/>
+ <?php echo gettext("Choose the whitelist you want this interface to " .
+ "use."); ?> <br/><br/>
+ <span class="red"><?php echo gettext("Note:"); ?></span>&nbsp;<?php echo gettext("This option will only be used when block offenders is on."); ?><br/>
+ <span class="red"><?php echo gettext("Hint:"); ?></span>&nbsp;<?php echo gettext("Default " .
+ "whitelist adds local networks, WAN IPs, Gateways, VPNs and VIPs. Create an Alias to customize."); ?>
+ </td>
+ </tr>
+<tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Alert Suppression and Filtering"); ?></td>
+</tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Alert Suppression"); ?></td>
+ <td width="78%" class="vtable">
+ <select name="suppresslistname" class="formselect" id="suppresslistname">
+ <?php
+ echo "<option value='default' >default</option>\n";
+ if (is_array($suricataglob['suppress']['item'])) {
+ $slist_select = $suricataglob['suppress']['item'];
+ foreach ($slist_select as $value) {
+ $ilistname = $value['name'];
+ if ($ilistname == $pconfig['suppresslistname'])
+ echo "<option value='$ilistname' selected>";
+ else
+ echo "<option value='$ilistname'>";
+ echo htmlspecialchars($ilistname) . '</option>';
+ }
+ }
+ ?>
+ </select>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="button" class="formbtns" value="View List" onclick="viewList('<?=$id;?>','suppresslistname', 'suppress')"
+ id="btnSuppressList" title="<?php echo gettext("Click to view currently selected Suppression List contents"); ?>"/>
+ <br/>
+ <?php echo gettext("Choose the suppression or filtering file you " .
+ "want this interface to use."); ?> <br/>&nbsp;<br/><span class="red"><?php echo gettext("Note: ") . "</span>" .
+ gettext("Default option disables suppression and filtering."); ?>
+ </td>
+ </tr>
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Arguments here will " .
+ "be automatically inserted into the Suricata configuration"); ?></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Advanced configuration pass-through"); ?></td>
+ <td width="78%" class="vtable">
+ <textarea style="width:98%; height:100%;" wrap="off" name="configpassthru" cols="60" rows="8" id="configpassthru"><?=htmlspecialchars($pconfig['configpassthru']);?></textarea>
+ </td>
+</tr>
+<tr>
+ <td width="22%" valign="top"></td>
+ <td width="78%"><input name="Submit" 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>
+ <td width="22%" valign="top">&nbsp;</td>
+ <td width="78%"><span class="vexpl"><span class="red"><strong><?php echo gettext("Note: ") . "</strong></span></span>" .
+ gettext("Please save your settings before you attempt to start Suricata."); ?>
+ </td>
+</tr>
+</table>
+</div>
+</td></tr>
+</table>
+</form>
+
+<script language="JavaScript">
+
+function enable_blockoffenders() {
+// var endis = !(document.iform.blockoffenders.checked);
+// document.iform.blockoffenderskill.disabled=endis;
+// document.iform.blockoffendersip.disabled=endis;
+// document.iform.whitelistname.disabled=endis;
+// document.iform.btnWhitelist.disabled=endis;
+}
+
+function toggle_stats_log() {
+ var endis = !(document.iform.enable_stats_log.checked);
+ if (endis) {
+ document.getElementById("stats_log_append_row").style.display="none";
+ document.getElementById("stats_interval_row").style.display="none";
+ document.getElementById("stats_log_warning").style.display="none";
+ }
+ else {
+ document.getElementById("stats_log_append_row").style.display="table-row";
+ document.getElementById("stats_interval_row").style.display="table-row";
+ document.getElementById("stats_log_warning").style.display="inline";
+ }
+}
+
+function toggle_http_log() {
+ var endis = !(document.iform.enable_http_log.checked);
+ if (endis)
+ document.getElementById("http_log_append_row").style.display="none";
+ else
+ document.getElementById("http_log_append_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
+ document.getElementById("tls_log_extended_row").style.display="table-row";
+}
+
+function toggle_json_file_log() {
+ var endis = !(document.iform.enable_json_file_log.checked);
+ if (endis) {
+ document.getElementById("tracked_files_append_row").style.display="none";
+ document.getElementById("tracked_files_magic_row").style.display="none";
+ document.getElementById("tracked_files_md5_row").style.display="none";
+ }
+ else {
+ document.getElementById("tracked_files_append_row").style.display="table-row";
+ document.getElementById("tracked_files_magic_row").style.display="table-row";
+ document.getElementById("tracked_files_md5_row").style.display="table-row";
+ }
+}
+
+function toggle_file_store() {
+ var endis = !(document.iform.enable_file_store.checked);
+ if (endis) {
+ document.getElementById("file_store_warning").style.display="none";
+ }
+ else {
+ document.getElementById("file_store_warning").style.display="inline";
+ }
+}
+
+function toggle_pcap_log() {
+ var endis = !(document.iform.enable_pcap_log.checked);
+ if (endis) {
+ document.getElementById("pcap_log_size_row").style.display="none";
+ document.getElementById("pcap_log_max_row").style.display="none";
+ document.getElementById("file_pcap_warning").style.display="none";
+ }
+ else {
+ document.getElementById("pcap_log_size_row").style.display="table-row";
+ document.getElementById("pcap_log_max_row").style.display="table-row";
+ document.getElementById("file_pcap_warning").style.display="inline";
+ }
+}
+
+function enable_change(enable_change) {
+ endis = !(document.iform.enable.checked || enable_change);
+ // make sure a default answer is called if this is invoked.
+ endis2 = (document.iform.enable);
+ document.iform.enable_stats_log.disabled = endis;
+ document.iform.stats_upd_interval.disabled = endis;
+ document.iform.append_stats_log.disabled = endis;
+ document.iform.enable_http_log.disabled = endis;
+ document.iform.append_http_log.disabled = endis;
+ document.iform.enable_tls_log.disabled = endis;
+ document.iform.tls_log_extended.disabled = endis;
+ document.iform.enable_json_file_log.disabled = endis;
+ document.iform.append_json_file_log.disabled = endis;
+ document.iform.enable_tracked_files_magic.disabled = endis;
+ document.iform.enable_tracked_files_md5.disabled = endis;
+ document.iform.enable_file_store.disabled = endis;
+ 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.max_pending_packets.disabled = endis;
+ document.iform.detect_eng_profile.disabled = endis;
+ document.iform.mpm_algo.disabled = endis;
+ document.iform.sgh_mpm_context.disabled = endis;
+ document.iform.inspect_recursion_limit.disabled = endis;
+// document.iform.blockoffenders.disabled = endis;
+// document.iform.blockoffendersip.disabled=endis;
+// document.iform.blockoffenderskill.disabled=endis;
+ document.iform.alertsystemlog.disabled = endis;
+ document.iform.externallistname.disabled = endis;
+ document.iform.homelistname.disabled = endis;
+ document.iform.whitelistname.disabled=endis;
+ document.iform.suppresslistname.disabled = endis;
+ document.iform.configpassthru.disabled = endis;
+ document.iform.btnHomeNet.disabled=endis;
+ document.iform.btnWhitelist.disabled=endis;
+ document.iform.btnSuppressList.disabled=endis;
+}
+
+function wopen(url, name, w, h) {
+ // Fudge factors for window decoration space.
+ // In my tests these work well on all platforms & browsers.
+ w += 32;
+ h += 96;
+ var win = window.open(url,
+ name,
+ 'width=' + w + ', height=' + h + ', ' +
+ 'location=no, menubar=no, ' +
+ 'status=no, toolbar=no, scrollbars=yes, resizable=yes');
+ win.resizeTo(w, h);
+ win.focus();
+}
+
+function getSelectedValue(elemID) {
+ var ctrl = document.getElementById(elemID);
+ return ctrl.options[ctrl.selectedIndex].value;
+}
+
+function viewList(id, elemID, elemType) {
+ if (typeof elemType == "undefined") {
+ elemType = "whitelist";
+ }
+ var url = "suricata_list_view.php?id=" + id + "&wlist=";
+ url = url + getSelectedValue(elemID) + "&type=" + elemType;
+ wopen(url, 'WhitelistViewer', 640, 480);
+}
+
+enable_change(false);
+enable_blockoffenders();
+toggle_stats_log();
+toggle_http_log();
+toggle_tls_log();
+toggle_json_file_log();
+toggle_file_store();
+toggle_pcap_log();
+
+</script>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_libhtp_policy_engine.php b/config/suricata/suricata_libhtp_policy_engine.php
new file mode 100644
index 00000000..e7cf4135
--- /dev/null
+++ b/config/suricata/suricata_libhtp_policy_engine.php
@@ -0,0 +1,314 @@
+<?php
+/*
+ * suricata_libhtp_policy_engine.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g;
+
+// Grab the incoming QUERY STRING or POST variables
+$id = $_GET['id'];
+$eng_id = $_GET['eng_id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (isset($_POST['eng_id']))
+ $eng_id = $_POST['eng_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]['libhtp_policy']['item']))
+ $config['installedpackages']['suricata']['rule'][$id]['libhtp_policy']['item'] = array();
+$a_nat = &$config['installedpackages']['suricata']['rule'][$id]['libhtp_policy']['item'];
+
+$pconfig = array();
+if (empty($a_nat[$eng_id])) {
+ $def = array( "name" => "engine_{$eng_id}", "bind_to" => "", "personality" => "IDS",
+ "request-body-limit" => "4096", "response-body-limit" => "4096",
+ "double-decode-path" => "no", "double-decode-query" => "no" );
+
+ // See if this is initial entry and set to "default" if true
+ if ($eng_id < 1) {
+ $def['name'] = "default";
+ $def['bind_to'] = "all";
+ }
+ $pconfig = $def;
+}
+else {
+ $pconfig = $a_nat[$eng_id];
+
+ // Check for any empty values and set sensible defaults
+ if (empty($pconfig['personality']))
+ $pconfig['personality'] = "IDS";
+}
+
+if ($_POST['Cancel']) {
+ header("Location: /suricata/suricata_app_parsers.php?id={$id}");
+ exit;
+}
+
+// Check for returned "selected alias" if action is import
+if ($_GET['act'] == "import") {
+ if ($_GET['varname'] == "bind_to" && !empty($_GET['varvalue']))
+ $pconfig[$_GET['varname']] = $_GET['varvalue'];
+}
+
+if ($_POST['Submit']) {
+
+ /* Grab all the POST values and save in new temp array */
+ $engine = array();
+ if ($_POST['policy_name']) { $engine['name'] = trim($_POST['policy_name']); } else { $engine['name'] = "default"; }
+ if ($_POST['policy_bind_to']) {
+ if (is_alias($_POST['policy_bind_to']))
+ $engine['bind_to'] = $_POST['policy_bind_to'];
+ elseif (strtolower(trim($_POST['policy_bind_to'])) == "all")
+ $engine['bind_to'] = "all";
+ else
+ $input_errors[] = gettext("You must provide a valid Alias or the reserved keyword 'all' for the 'Bind-To IP Address' value.");
+ }
+ else {
+ $input_errors[] = gettext("The 'Bind-To IP Address' value cannot be blank. Provide a valid Alias or the reserved keyword 'all'.");
+ }
+
+ if ($_POST['personality']) { $engine['personality'] = $_POST['personality']; } else { $engine['personality'] = "IDS"; }
+ if (is_numeric($_POST['req_body_limit']) && $_POST['req_body_limit'] >= 0)
+ $engine['request-body-limit'] = $_POST['req_body_limit'];
+ else
+ $input_errors[] = gettext("The value for 'Request Body Limit' must be all numbers and greater than or equal to zero.");
+
+ if (is_numeric($_POST['resp_body_limit']) && $_POST['resp_body_limit'] >= 0)
+ $engine['response-body-limit'] = $_POST['resp_body_limit'];
+ else
+ $input_errors[] = gettext("The value for 'Response Body Limit' must be all numbers and greater than or equal to zero.");
+
+ 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'; }
+
+ /* Can only have one "all" Bind_To address */
+ if ($engine['bind_to'] == "all" && $engine['name'] <> "default") {
+ $input_errors[] = gettext("Only one default HTTP Server Policy Engine can be bound to all addresses.");
+ $pconfig = $engine;
+ }
+
+ /* if no errors, write new entry to conf */
+ if (!$input_errors) {
+ if (isset($eng_id) && $a_nat[$eng_id]) {
+ $a_nat[$eng_id] = $engine;
+ }
+ else
+ $a_nat[] = $engine;
+
+ /* Reorder the engine array to ensure the */
+ /* 'bind_to=all' entry is at the bottom */
+ /* if it contains more than one entry. */
+ if (count($a_nat) > 1) {
+ $i = -1;
+ foreach ($a_nat as $f => $v) {
+ if ($v['bind_to'] == "all") {
+ $i = $f;
+ break;
+ }
+ }
+ /* Only relocate the entry if we */
+ /* found it, and it's not already */
+ /* at the end. */
+ if ($i > -1 && ($i < (count($a_nat) - 1))) {
+ $tmp = $a_nat[$i];
+ unset($a_nat[$i]);
+ $a_nat[] = $tmp;
+ }
+ }
+
+ /* Now write the new engine array to conf */
+ write_config();
+
+ header("Location: /suricata/suricata_app_parsers.php?id={$id}");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($config['installedpackages']['suricata']['rule'][$id]['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} HTTP Server Policy Engine");
+include_once("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC" >
+
+<?php
+include("fbegin.inc");
+if ($input_errors) print_input_errors($input_errors);
+if ($savemsg)
+ print_info_box($savemsg);
+?>
+
+<form action="suricata_libhtp_policy_engine.php" method="post" name="iform" id="iform">
+<input name="id" type="hidden" value="<?=$id?>">
+<input name="eng_id" type="hidden" value="<?=$eng_id?>">
+<div id="boxarea">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+<td class="tabcont">
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="middle" class="listtopic"><?php echo gettext("Suricata Target-Based HTTP Server Policy Configuration"); ?></td>
+ </tr>
+ <tr>
+ <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($pconfig['name']);?>"<?php if (htmlspecialchars($pconfig['name']) == "default") echo "readonly";?>>&nbsp;
+ <?php if (htmlspecialchars($pconfig['name']) <> "default")
+ echo gettext("Name or description for this engine. (Max 25 characters)");
+ else
+ echo "<span class=\"red\">" . gettext("The name for the 'default' engine is read-only.") . "</span>";?><br/>
+ <?php echo gettext("Unique name or description for this engine configuration. Default value is ") .
+ "<strong>" . gettext("default") . "</strong>"; ?>.<br/>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="vncell"><?php echo gettext("Bind-To IP Address Alias"); ?></td>
+ <td class="vtable">
+ <?php if ($pconfig['name'] <> "default") : ?>
+ <table width="95%" border="0" cellpadding="2" cellspacing="0">
+ <tr>
+ <td class="vexpl"><input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32"
+ value="<?=htmlspecialchars($pconfig['bind_to']);?>" title="<?=trim(filter_expand_alias($pconfig['bind_to']));?>" autocomplete="off">&nbsp;
+ <?php echo gettext("IP List to bind this engine to. (Cannot be blank)"); ?></td>
+ <td class="vexpl" align="right"><input type="button" class="formbtns" value="Aliases" onclick="parent.location='suricata_select_alias.php?id=<?=$id;?>&eng_id=<?=$eng_id;?>&type=host|network&varname=bind_to&act=import&multi_ip=yes&returl=<?=urlencode($_SERVER['PHP_SELF']);?>'"
+ title="<?php echo gettext("Select an existing IP alias");?>"/></td>
+ </tr>
+ <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>
+ </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 : ?>
+ <input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32"
+ value="<?=htmlspecialchars($pconfig['bind_to']);?>" autocomplete="off" readonly>&nbsp;
+ <?php echo "<span class=\"red\">" . gettext("IP List for the default engine is read-only and must be 'all'.") . "</span>";?><br/>
+ <?php echo gettext("The default engine is required and will apply for packets with destination addresses not matching other engine IP Lists.");?><br/>
+ <?php endif ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Target Web Server Personality"); ?> </td>
+ <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' );
+ foreach ($profile as $val): ?>
+ <option value="<?=$val;?>"
+ <?php if ($val == $pconfig['personality']) echo "selected"; ?>>
+ <?=gettext($val);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;<?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/>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Inspection Limits"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Request Body Limit"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="req_body_limit" type="text" class="formfld unknown" id="req_body_limit" size="9"
+ value="<?=htmlspecialchars($pconfig['request-body-limit']);?>">&nbsp;
+ <?php echo gettext("Maximum number of HTTP request body bytes to inspect. Default is ") .
+ "<strong>" . gettext("4,096") . "</strong>" . gettext(" bytes."); ?><br/><br/>
+ <?php echo gettext("HTTP request bodies are often big, so they take a lot of time to process which has a significant impact ") .
+ gettext("on performance. This sets the limit (in bytes) of the client-body that will be inspected.") . "<br/><br/><span class=\"red\"><strong>" .
+ gettext("Note: ") . "</strong></span>" . gettext("Setting this parameter to 0 will inspect all of the client-body."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Response Body Limit"); ?></td>
+ <td width="78%" class="vtable">
+ <input name="resp_body_limit" type="text" class="formfld unknown" id="resp_body_limit" size="9"
+ value="<?=htmlspecialchars($pconfig['response-body-limit']);?>">&nbsp;
+ <?php echo gettext("Maximum number of HTTP response body bytes to inspect. Default is ") .
+ "<strong>" . gettext("4,096") . "</strong>" . gettext(" bytes."); ?><br/><br/>
+ <?php echo gettext("HTTP response bodies are often big, so they take a lot of time to process which has a significant impact ") .
+ gettext("on performance. This sets the limit (in bytes) of the server-body that will be inspected.") . "<br/><br/><span class=\"red\"><strong>" .
+ gettext("Note: ") . "</strong></span>" . gettext("Setting this parameter to 0 will inspect all of the server-body."); ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Decode Settings"); ?></td>
+ </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="on" <?php if ($pconfig['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="on" <?php if ($pconfig['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="bottom">&nbsp;</td>
+ <td width="78%" valign="bottom">
+ <input name="Submit" id="submit" type="submit" class="formbtn" value=" Save " title="<?php echo
+ gettext("Save web server policy engine settings and return to App Parsers tab"); ?>">
+ &nbsp;&nbsp;&nbsp;&nbsp;
+ <input name="Cancel" id="cancel" type="submit" class="formbtn" value="Cancel" title="<?php echo
+ gettext("Cancel changes and return to App Parsers tab"); ?>"></td>
+ </tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+<script type="text/javascript" src="/javascript/autosuggest.js">
+</script>
+<script type="text/javascript" src="/javascript/suggestions.js">
+</script>
+<script type="text/javascript">
+//<![CDATA[
+var addressarray = <?= json_encode(get_alias_list(array("host", "network"))) ?>;
+
+function createAutoSuggest() {
+<?php
+ echo "\tvar objAlias = new AutoSuggestControl(document.getElementById('policy_bind_to'), new StateSuggestions(addressarray));\n";
+?>
+}
+
+setTimeout("createAutoSuggest();", 500);
+
+</script>
+
+</html>
diff --git a/config/suricata/suricata_list_view.php b/config/suricata/suricata_list_view.php
new file mode 100644
index 00000000..2ff121f2
--- /dev/null
+++ b/config/suricata/suricata_list_view.php
@@ -0,0 +1,100 @@
+<?php
+/*
+ * suricata_list_view.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $config;
+
+$contents = '';
+
+$id = $_GET['id'];
+$wlist = $_GET['wlist'];
+$type = $_GET['type'];
+
+if (isset($id) && isset($wlist)) {
+ $a_rule = $config['installedpackages']['suricata']['rule'][$id];
+ if ($type == "homenet") {
+ $list = suricata_build_list($a_rule, $wlist);
+ $contents = implode("\n", $list);
+ }
+ elseif ($type == "whitelist") {
+ $list = suricata_build_list($a_rule, $wlist, true);
+ $contents = implode("\n", $list);
+ }
+ elseif ($type == "suppress") {
+ $list = suricata_find_list($wlist, $type);
+ $contents = str_replace("\r", "", base64_decode($list['suppresspassthru']));
+ }
+ else
+ $contents = gettext("\n\nERROR -- Requested List Type entity is not valid!");
+}
+else
+ $contents = gettext("\n\nERROR -- Supplied interface or List entity is not valid!");
+
+$pgtitle = array(gettext("Suricata"), gettext(ucfirst($type) . " Viewer"));
+?>
+
+<?php include("head.inc");?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+<?php if ($savemsg) print_info_box($savemsg); ?>
+<?php // include("fbegin.inc");?>
+
+<form action="suricata_list_view.php" method="post">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+ <td class="tabcont">
+ <table width="100%" cellpadding="0" cellspacing="6" bgcolor="#eeeeee">
+ <tr>
+ <td class="pgtitle" colspan="2">Suricata: <?php echo gettext(ucfirst($type) . " Viewer"); ?></td>
+ </tr>
+ <tr>
+ <td align="left" width="20%">
+ <input type="button" class="formbtn" value="Return" onclick="window.close()">
+ </td>
+ <td align="right">
+ <b><?php echo gettext(ucfirst($type) . ": ") . '</b>&nbsp;' . $_GET['wlist']; ?>&nbsp;&nbsp;&nbsp;&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" valign="top" class="label">
+ <div style="background: #eeeeee; width:100%; height:100%;" id="textareaitem"><!-- NOTE: The opening *and* the closing textarea tag must be on the same line. -->
+ <textarea style="width:100%; height:100%;" readonly wrap="off" rows="25" cols="80" name="code2"><?=$contents;?></textarea>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+</form>
+<?php // include("fend.inc");?>
+</body>
+</html>
diff --git a/config/suricata/suricata_logs_browser.php b/config/suricata/suricata_logs_browser.php
new file mode 100644
index 00000000..38310b9f
--- /dev/null
+++ b/config/suricata/suricata_logs_browser.php
@@ -0,0 +1,217 @@
+<?php
+/*
+ suricata_logs_browser.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+if ($_POST['instance'])
+ $instanceid = $_POST['instance'];
+if (empty($instanceid))
+ $instanceid = 0;
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_instance = $config['installedpackages']['suricata']['rule'];
+$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}";
+
+$logfile = $_POST['file'];
+
+if ($_POST['action'] == 'load') {
+ if(!is_file($_POST['file'])) {
+ echo "|3|" . gettext("Log file does not exist or that logging feature is not enabled") . ".|";
+ }
+ else {
+ $data = file_get_contents($_POST['file']);
+ if($data === false) {
+ echo "|1|" . gettext("Failed to read log file") . ".|";
+ } else {
+ $data = base64_encode($data);
+ echo "|0|{$_POST['file']}|{$data}|";
+ }
+ }
+ exit;
+}
+
+$pgtitle = gettext("Suricata: Logs Browser");
+include_once("head.inc");
+
+?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?php
+include_once("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+if ($input_errors) {
+ print_input_errors($input_errors);
+}
+
+?>
+<script type="text/javascript" src="/javascript/base64.js"></script>
+<script type="text/javascript">
+ function loadFile() {
+ jQuery("#fileStatus").html("<?=gettext("Loading file"); ?> ...");
+ jQuery("#fileStatusBox").show(500);
+ jQuery("#filePathBox").show(500);
+ jQuery("#fbTarget").html("");
+
+ jQuery.ajax(
+ "<?=$_SERVER['SCRIPT_NAME'];?>", {
+ type: 'POST',
+ data: "action=load&file=" + jQuery("#logFile").val(),
+ complete: loadComplete
+ }
+ );
+ }
+
+ function loadComplete(req) {
+ jQuery("#fileContent").show(1000);
+ var values = req.responseText.split("|");
+ values.shift(); values.pop();
+
+ if(values.shift() == "0") {
+ var file = values.shift();
+ var fileContent = Base64.decode(values.join("|"));
+ jQuery("#fileStatus").html("<?=gettext("File successfully loaded"); ?>.");
+ jQuery("#fbTarget").html(file);
+ jQuery("#fileContent").val(fileContent);
+ }
+ else {
+ jQuery("#fileStatus").html(values[0]);
+ jQuery("#fbTarget").html("");
+ jQuery("#fileContent").val("");
+ }
+ jQuery("#fileContent").show(1000);
+ }
+
+</script>
+
+<form action="/suricata/suricata_logs_browser.php" method="post" id="formbrowse">
+<input type="hidden" id="instance" value="<?=$instanceid;?>"/>
+<?php if ($savemsg) 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("Global Settings"), false, "/suricata/suricata_global.php");
+ $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$instanceid}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), true, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <td><div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="6">
+ <tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Logs Browser Selections"); ?></td>
+ </tr>
+ <tr>
+ <td width="22%" class="vncell"><?php echo gettext('Instance to View'); ?></td>
+ <td width="78%" class="vtable">
+ <select name="instance" id="instance" class="formselect" onChange="document.getElementById('formbrowse').method='post';document.getElementById('formbrowse').submit()">
+ <?php
+ foreach ($a_instance as $id => $instance) {
+ $selected = "";
+ if ($id == $instanceid)
+ $selected = "selected";
+ echo "<option value='{$id}' {$selected}> (" . convert_friendly_interface_to_friendly_descr($instance['interface']) . "){$instance['descr']}</option>\n";
+ }
+ ?>
+ </select>&nbsp;&nbsp;<?php echo gettext('Choose which instance logs you want to view.'); ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" class="vncell"><?php echo gettext('Log File to View'); ?></td>
+ <td width="78%" class="vtable">
+ <select name="logFile" id="logFile" class="formselect" onChange="loadFile();">
+ <?php
+ $logs = array( "alerts.log", "files-json.log", "http.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";
+ }
+ ?>
+ </select>&nbsp;&nbsp;<?php echo gettext('Choose which log you want to view.'); ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="listtopic"><?php echo gettext("Log Contents"); ?></td>
+ </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>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table width="100%">
+ <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>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<?php if(empty($logfile)): ?>
+<script type="text/javascript">
+ document.getElementById("logFile").selectedIndex=-1;
+</script>
+<?php endif; ?>
+
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_os_policy_engine.php b/config/suricata/suricata_os_policy_engine.php
new file mode 100644
index 00000000..61918e65
--- /dev/null
+++ b/config/suricata/suricata_os_policy_engine.php
@@ -0,0 +1,261 @@
+<?php
+/*
+ * suricata_os_policy_engine.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g;
+
+// Grab the incoming QUERY STRING or POST variables
+$id = $_GET['id'];
+$eng_id = $_GET['eng_id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (isset($_POST['eng_id']))
+ $eng_id = $_POST['eng_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]['host_os_policy']['item']))
+ $config['installedpackages']['suricata']['rule'][$id]['host_os_policy']['item'] = array();
+$a_nat = &$config['installedpackages']['suricata']['rule'][$id]['host_os_policy']['item'];
+
+$pconfig = array();
+if (empty($a_nat[$eng_id])) {
+ $def = array( "name" => "engine_{$eng_id}", "bind_to" => "", "policy" => "bsd" );
+ // See if this is initial entry and set to "default" if true
+ if ($eng_id < 1) {
+ $def['name'] = "default";
+ $def['bind_to'] = "all";
+ }
+ $pconfig = $def;
+}
+else {
+ $pconfig = $a_nat[$eng_id];
+
+ // Check for any empty values and set sensible defaults
+ if (empty($pconfig['policy']))
+ $pconfig['policy'] = "bsd";
+}
+
+if ($_POST['Cancel']) {
+ header("Location: /suricata/suricata_flow_stream.php?id={$id}");
+ exit;
+}
+
+// Check for returned "selected alias" if action is import
+if ($_GET['act'] == "import") {
+ if ($_GET['varname'] == "bind_to" && !empty($_GET['varvalue']))
+ $pconfig[$_GET['varname']] = $_GET['varvalue'];
+}
+
+if ($_POST['Submit']) {
+
+ /* Grab all the POST values and save in new temp array */
+ $engine = array();
+ if ($_POST['policy_name']) { $engine['name'] = trim($_POST['policy_name']); } else { $engine['name'] = "default"; }
+ if ($_POST['policy_bind_to']) {
+ if (is_alias($_POST['policy_bind_to']))
+ $engine['bind_to'] = $_POST['policy_bind_to'];
+ elseif (strtolower(trim($_POST['policy_bind_to'])) == "all")
+ $engine['bind_to'] = "all";
+ else
+ $input_errors[] = gettext("You must provide a valid Alias or the reserved keyword 'all' for the 'Bind-To IP Address' value.");
+ }
+ else {
+ $input_errors[] = gettext("The 'Bind-To IP Address' value cannot be blank. Provide a valid Alias or the reserved keyword 'all'.");
+ }
+
+ if ($_POST['policy']) { $engine['policy'] = $_POST['policy']; } else { $engine['policy'] = "bsd"; }
+
+ /* Can only have one "all" Bind_To address */
+ if ($engine['bind_to'] == "all" && $engine['name'] <> "default") {
+ $input_errors[] = gettext("Only one default OS-Policy Engine can be bound to all addresses.");
+ $pconfig = $engine;
+ }
+
+ /* if no errors, write new entry to conf */
+ if (!$input_errors) {
+ if (isset($eng_id) && $a_nat[$eng_id]) {
+ $a_nat[$eng_id] = $engine;
+ }
+ else
+ $a_nat[] = $engine;
+
+ /* Reorder the engine array to ensure the */
+ /* 'bind_to=all' entry is at the bottom */
+ /* if it contains more than one entry. */
+ if (count($a_nat) > 1) {
+ $i = -1;
+ foreach ($a_nat as $f => $v) {
+ if ($v['bind_to'] == "all") {
+ $i = $f;
+ break;
+ }
+ }
+ /* Only relocate the entry if we */
+ /* found it, and it's not already */
+ /* at the end. */
+ if ($i > -1 && ($i < (count($a_nat) - 1))) {
+ $tmp = $a_nat[$i];
+ unset($a_nat[$i]);
+ $a_nat[] = $tmp;
+ }
+ }
+
+ /* Now write the new engine array to conf */
+ write_config();
+
+ header("Location: /suricata/suricata_flow_stream.php?id={$id}");
+ exit;
+ }
+}
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($config['installedpackages']['suricata']['rule'][$id]['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} Operating System Policy Engine");
+include_once("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC" >
+
+<?php
+include("fbegin.inc");
+if ($input_errors) print_input_errors($input_errors);
+if ($savemsg)
+ print_info_box($savemsg);
+?>
+
+<form action="suricata_os_policy_engine.php" method="post" name="iform" id="iform">
+<input name="id" type="hidden" value="<?=$id?>">
+<input name="eng_id" type="hidden" value="<?=$eng_id?>">
+<div id="boxarea">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+<td class="tabcont">
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td colspan="2" valign="middle" class="listtopic"><?php echo gettext("Suricata Target-Based OS Policy Engine Configuration"); ?></td>
+ </tr>
+ <tr>
+ <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($pconfig['name']);?>"<?php if (htmlspecialchars($pconfig['name']) == "default") echo "readonly";?>>&nbsp;
+ <?php if (htmlspecialchars($pconfig['name']) <> "default")
+ echo gettext("Name or description for this engine. (Max 25 characters)");
+ else
+ echo "<span class=\"red\">" . gettext("The name for the 'default' engine is read-only.") . "</span>";?><br/>
+ <?php echo gettext("Unique name or description for this engine configuration. Default value is ") .
+ "<strong>" . gettext("default") . "</strong>"; ?>.<br/>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="vncell"><?php echo gettext("Bind-To IP Address Alias"); ?></td>
+ <td class="vtable">
+ <?php if ($pconfig['name'] <> "default") : ?>
+ <table width="95%" border="0" cellpadding="2" cellspacing="0">
+ <tr>
+ <td class="vexpl"><input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32"
+ value="<?=htmlspecialchars($pconfig['bind_to']);?>" title="<?=trim(filter_expand_alias($pconfig['bind_to']));?>" autocomplete="off">&nbsp;
+ <?php echo gettext("IP List to bind this engine to. (Cannot be blank)"); ?></td>
+ <td class="vexpl" align="right"><input type="button" class="formbtns" value="Aliases" onclick="parent.location='suricata_select_alias.php?id=<?=$id;?>&eng_id=<?=$eng_id;?>&type=host|network&varname=bind_to&act=import&multi_ip=yes&returl=<?=urlencode($_SERVER['PHP_SELF']);?>'"
+ title="<?php echo gettext("Select an existing IP alias");?>"/></td>
+ </tr>
+ <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>
+ </table>
+ <span class="red"><strong><?php echo gettext("Note: ") . "</strong></span>" . gettext("Supplied value must be a pre-configured Alias or the keyword 'all'.");?>
+ &nbsp;&nbsp;&nbsp;&nbsp;
+ <?php else : ?>
+ <input name="policy_bind_to" type="text" class="formfldalias" id="policy_bind_to" size="32"
+ value="<?=htmlspecialchars($pconfig['bind_to']);?>" autocomplete="off" readonly>&nbsp;
+ <?php echo "<span class=\"red\">" . gettext("IP List for the default engine is read-only and must be 'all'.") . "</span>";?><br/>
+ <?php echo gettext("The default engine is required and will apply for packets with destination addresses not matching other engine IP Lists.");?><br/>
+ <?php endif ?>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Target Policy"); ?> </td>
+ <td width="78%" class="vtable">
+ <select name="policy" class="formselect" id="policy">
+ <?php
+ $profile = array( 'BSD', 'BSD-Right', 'HPUX10', 'HPUX11', 'Irix', 'Linux', 'Mac-OS', 'Old-Linux', 'Old-Solaris', 'Solaris', 'Vista', 'Windows', 'Windows2k3' );
+ foreach ($profile as $val): ?>
+ <option value="<?=strtolower($val);?>"
+ <?php if (strtolower($val) == $pconfig['policy']) echo "selected"; ?>>
+ <?=gettext($val);?></option>
+ <?php endforeach; ?>
+ </select>&nbsp;&nbsp;<?php echo gettext("Choose the OS target policy appropriate for the protected hosts. The default is ") .
+ "<strong>" . gettext("BSD") . "</strong>"; ?>.<br/><br/>
+ <?php echo gettext("Available OS targets are BSD, BSD-Right, HPUX10, HPUX11, Irix, Linux, Mac-OS, Old-Linux, Old-Solaris, Solaris, Vista, 'Windows' and Windows2k3."); ?><br/>
+ </td>
+ </tr>
+ <tr>
+ <td width="22%" valign="bottom">&nbsp;</td>
+ <td width="78%" valign="bottom">
+ <input name="Submit" id="submit" type="submit" class="formbtn" value=" Save " title="<?php echo
+ gettext("Save OS policy engine settings and return to Flow/Stream tab"); ?>">
+ &nbsp;&nbsp;&nbsp;&nbsp;
+ <input name="Cancel" id="cancel" type="submit" class="formbtn" value="Cancel" title="<?php echo
+ gettext("Cancel changes and return to Flow/Stream tab"); ?>"></td>
+ </tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+<script type="text/javascript" src="/javascript/autosuggest.js">
+</script>
+<script type="text/javascript" src="/javascript/suggestions.js">
+</script>
+<script type="text/javascript">
+//<![CDATA[
+ var addressarray = <?= json_encode(get_alias_list(array("host", "network"))) ?>;
+
+function createAutoSuggest() {
+ <?php
+ echo "\tvar objAlias = new AutoSuggestControl(document.getElementById('policy_bind_to'), new StateSuggestions(addressarray));\n";
+ ?>
+}
+
+setTimeout("createAutoSuggest();", 500);
+//]]>
+
+</script>
+
+</html>
diff --git a/config/suricata/suricata_post_install.php b/config/suricata/suricata_post_install.php
new file mode 100644
index 00000000..653f47fd
--- /dev/null
+++ b/config/suricata/suricata_post_install.php
@@ -0,0 +1,132 @@
+<?php
+/*
+ * suricata_post_install.php
+ *
+ * Copyright (C) 2014 Bill Meeks
+ * part of pfSense
+ * 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 module is called once during the Suricata package installation to */
+/* perform required post-installation setup. It should only be executed */
+/* from the Package Manager process via the custom-post-install hook in */
+/* the snort.xml package configuration file. */
+/****************************************************************************/
+
+require_once("config.inc");
+require_once("functions.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $config, $g, $rebuild_rules, $pkg_interface, $suricata_gui_include;
+
+$suricatadir = SURICATADIR;
+$rcdir = RCFILEPREFIX;
+
+// Hard kill any running Suricata process that may have been started by any
+// of the pfSense scripts such as check_reload_status() or rc.start_packages
+if(is_process_running("suricata")) {
+ killbyname("suricata");
+ sleep(2);
+ // Delete any leftover suricata PID files in /var/run
+ array_map('@unlink', glob("/var/run/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
+ array_map('@unlink', glob("/var/run/barnyard2_*.pid"));
+}
+
+// Set flag for post-install in progress
+$g['suricata_postinstall'] = true;
+
+// Remove any previously installed script since we rebuild it
+@unlink("{$rcdir}/suricata.sh");
+
+// Create the top-tier log directory
+safe_mkdir(SURICATALOGDIR);
+
+// remake saved settings
+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..."));
+ 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');
+ update_status(gettext("Generating suricata.yaml configuration file from saved settings..."));
+ $rebuild_rules = true;
+
+ // 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']);
+
+ // 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);
+ }
+
+ // create Suricata bootup file suricata.sh
+ suricata_create_rc();
+
+ // Set Log Limit, Block Hosts Time and Rules Update Time
+ suricata_loglimit_install_cron($config['installedpackages']['suricata']['config'][0]['suricataloglimit'] == 'on' ? true : false);
+// 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();
+
+ $rebuild_rules = false;
+ 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..."));
+ }
+}
+
+// Update Suricata package version in configuration
+$config['installedpackages']['suricata']['config'][0]['suricata_config_ver'] = "0.1-BETA";
+write_config();
+
+// Done with post-install, so clear flag
+unset($g['suricata_postinstall']);
+log_error(gettext("[Suricata] Package post-installation tasks completed..."));
+return true;
+
+?>
diff --git a/config/suricata/suricata_rules.php b/config/suricata/suricata_rules.php
new file mode 100644
index 00000000..b848b4e8
--- /dev/null
+++ b/config/suricata/suricata_rules.php
@@ -0,0 +1,790 @@
+<?php
+/*
+ * suricata_rules.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+$suricatadir = SURICATADIR;
+$rules_map = array();
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+$a_rule = &$config['installedpackages']['suricata']['rule'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (isset($id) && $a_rule[$id]) {
+ $pconfig['enable'] = $a_rule[$id]['enable'];
+ $pconfig['interface'] = $a_rule[$id]['interface'];
+ $pconfig['rulesets'] = $a_rule[$id]['rulesets'];
+ if (!empty($a_rule[$id]['customrules']))
+ $pconfig['customrules'] = base64_decode($a_rule[$id]['customrules']);
+}
+
+function truncate($string, $length) {
+
+ /********************************
+ * This function truncates the *
+ * passed string to the length *
+ * specified adding ellipsis if *
+ * truncation was necessary. *
+ ********************************/
+ if (strlen($string) > $length)
+ $string = substr($string, 0, ($length - 2)) . "...";
+ return $string;
+}
+
+function add_title_attribute($tag, $title) {
+
+ /********************************
+ * This function adds a "title" *
+ * attribute to the passed tag *
+ * and sets the value to the *
+ * value specified by "$title". *
+ ********************************/
+ $result = "";
+ if (empty($tag)) {
+ // If passed an empty element tag, then
+ // just create a <span> tag with title
+ $result = "<span title=\"" . $title . "\">";
+ }
+ else {
+ // Find the ending ">" for the element tag
+ $pos = strpos($tag, ">");
+ if ($pos !== false) {
+ // We found the ">" delimter, so add "title"
+ // attribute and close the element tag
+ $result = substr($tag, 0, $pos) . " title=\"" . $title . "\">";
+ }
+ else {
+ // We did not find the ">" delimiter, so
+ // something is wrong, just return the
+ // tag "as-is"
+ $result = $tag;
+ }
+ }
+ return $result;
+}
+
+/* convert fake interfaces to real */
+$if_real = get_real_interface($pconfig['interface']);
+$suricata_uuid = $a_rule[$id]['uuid'];
+$suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}";
+$snortdownload = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules'];
+$emergingdownload = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules'];
+$etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules'];
+$categories = explode("||", $pconfig['rulesets']);
+
+if ($_GET['openruleset'])
+ $currentruleset = $_GET['openruleset'];
+else if ($_POST['openruleset'])
+ $currentruleset = $_POST['openruleset'];
+else
+ $currentruleset = $categories[0];
+
+if (empty($categories[0]) && ($currentruleset != "custom.rules") && ($currentruleset != "Auto-Flowbit Rules")) {
+ if (!empty($a_rule[$id]['ips_policy']))
+ $currentruleset = "IPS Policy - " . ucfirst($a_rule[$id]['ips_policy']);
+ else
+ $currentruleset = "custom.rules";
+}
+
+/* One last sanity check -- if the rules directory is empty, default to loading custom rules */
+$tmp = glob("{$suricatadir}rules/*.rules");
+if (empty($tmp))
+ $currentruleset = "custom.rules";
+
+$ruledir = "{$suricatadir}rules";
+$rulefile = "{$ruledir}/{$currentruleset}";
+if ($currentruleset != 'custom.rules') {
+ // Read the current rules file into our rules map array.
+ // If it is the auto-flowbits file, set the full path.
+ if ($currentruleset == "Auto-Flowbit Rules")
+ $rulefile = "{$suricatacfgdir}/rules/" . FLOWBITS_FILENAME;
+ // Test for the special case of an IPS Policy file.
+ if (substr($currentruleset, 0, 10) == "IPS Policy")
+ $rules_map = suricata_load_vrt_policy($a_rule[$id]['ips_policy']);
+ elseif (!file_exists($rulefile))
+ $input_errors[] = gettext("{$currentruleset} seems to be missing!!! Please verify rules files have been downloaded, then go to the Categories tab and save the rule set again.");
+ else
+ $rules_map = suricata_load_rules_map($rulefile);
+}
+
+/* Load up our enablesid and disablesid arrays with 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']);
+
+if ($_GET['act'] == "toggle" && $_GET['ids'] && !empty($rules_map)) {
+
+ // Get the GID tag embedded in the clicked rule icon.
+ $gid = $_GET['gid'];
+
+ // Get the SID tag embedded in the clicked rule icon.
+ $sid= $_GET['ids'];
+
+ // See if the target SID is in our list of modified SIDs,
+ // and toggle it back to default if present; otherwise,
+ // add it to the appropriate modified SID list.
+ if (isset($enablesid[$gid][$sid]))
+ unset($enablesid[$gid][$sid]);
+ elseif (isset($disablesid[$gid][$sid]))
+ unset($disablesid[$gid][$sid]);
+ else {
+ if ($rules_map[$gid][$sid]['disabled'] == 1)
+ $enablesid[$gid][$sid] = "enablesid";
+ else
+ $disablesid[$gid][$sid] = "disablesid";
+ }
+
+ // Write the updated enablesid and disablesid values to the config file.
+ $tmp = "";
+ foreach (array_keys($enablesid) as $k1) {
+ foreach (array_keys($enablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_on'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_on']);
+
+ $tmp = "";
+ foreach (array_keys($disablesid) as $k1) {
+ foreach (array_keys($disablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_off'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_off']);
+
+ /* Update the config.xml file. */
+ write_config();
+
+ $_GET['openruleset'] = $currentruleset;
+ $anchor = "rule_{$gid}_{$sid}";
+}
+
+if ($_GET['act'] == "disable_all" && !empty($rules_map)) {
+
+ // Mark all rules in the currently selected category "disabled".
+ foreach (array_keys($rules_map) as $k1) {
+ foreach (array_keys($rules_map[$k1]) as $k2) {
+ if (isset($enablesid[$k1][$k2]))
+ unset($enablesid[$k1][$k2]);
+ $disablesid[$k1][$k2] = "disablesid";
+ }
+ }
+
+ // Write the updated enablesid and disablesid values to the config file.
+ $tmp = "";
+ foreach (array_keys($enablesid) as $k1) {
+ foreach (array_keys($enablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_on'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_on']);
+
+ $tmp = "";
+ foreach (array_keys($disablesid) as $k1) {
+ foreach (array_keys($disablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_off'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_off']);
+
+ write_config();
+
+ $_GET['openruleset'] = $currentruleset;
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+
+if ($_GET['act'] == "enable_all" && !empty($rules_map)) {
+
+ // Mark all rules in the currently selected category "enabled".
+ foreach (array_keys($rules_map) as $k1) {
+ foreach (array_keys($rules_map[$k1]) as $k2) {
+ if (isset($disablesid[$k1][$k2]))
+ unset($disablesid[$k1][$k2]);
+ $enablesid[$k1][$k2] = "enablesid";
+ }
+ }
+ // Write the updated enablesid and disablesid values to the config file.
+ $tmp = "";
+ foreach (array_keys($enablesid) as $k1) {
+ foreach (array_keys($enablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_on'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_on']);
+
+ $tmp = "";
+ foreach (array_keys($disablesid) as $k1) {
+ foreach (array_keys($disablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_off'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_off']);
+
+ write_config();
+
+ $_GET['openruleset'] = $currentruleset;
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+
+if ($_GET['act'] == "resetcategory" && !empty($rules_map)) {
+
+ // Reset any modified SIDs in the current rule category to their defaults.
+ foreach (array_keys($rules_map) as $k1) {
+ foreach (array_keys($rules_map[$k1]) as $k2) {
+ if (isset($enablesid[$k1][$k2]))
+ unset($enablesid[$k1][$k2]);
+ if (isset($disablesid[$k1][$k2]))
+ unset($disablesid[$k1][$k2]);
+ }
+ }
+
+ // Write the updated enablesid and disablesid values to the config file.
+ $tmp = "";
+ foreach (array_keys($enablesid) as $k1) {
+ foreach (array_keys($enablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_on'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_on']);
+
+ $tmp = "";
+ foreach (array_keys($disablesid) as $k1) {
+ foreach (array_keys($disablesid[$k1]) as $k2)
+ $tmp .= "{$k1}:{$k2}||";
+ }
+ $tmp = rtrim($tmp, "||");
+
+ if (!empty($tmp))
+ $a_rule[$id]['rule_sid_off'] = $tmp;
+ else
+ unset($a_rule[$id]['rule_sid_off']);
+
+ write_config();
+
+ $_GET['openruleset'] = $currentruleset;
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+
+if ($_GET['act'] == "resetall" && !empty($rules_map)) {
+
+ // Remove all modified SIDs from config.xml and save the changes.
+ unset($a_rule[$id]['rule_sid_on']);
+ unset($a_rule[$id]['rule_sid_off']);
+
+ /* Update the config.xml file. */
+ write_config();
+
+ $_GET['openruleset'] = $currentruleset;
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+
+if ($_POST['clear']) {
+ unset($a_rule[$id]['customrules']);
+ write_config();
+ $rebuild_rules = true;
+ suricata_generate_yaml($a_rule[$id]);
+ $rebuild_rules = false;
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+
+if ($_POST['customrules']) {
+ $a_rule[$id]['customrules'] = base64_encode($_POST['customrules']);
+ write_config();
+ $rebuild_rules = true;
+ suricata_generate_yaml($a_rule[$id]);
+ $rebuild_rules = false;
+ $output = "";
+ $retcode = "";
+// exec("/usr/local/bin/snort -T -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/snort.conf 2>&1", $output, $retcode);
+// if (intval($retcode) != 0) {
+// $error = "";
+// $start = count($output);
+// $end = $start - 4;
+// for($i = $start; $i > $end; $i--)
+// $error .= $output[$i];
+// $input_errors[] = "Custom rules have errors:\n {$error}";
+// }
+// else {
+// header("Location: /snort/snort_rules.php?id={$id}&openruleset={$currentruleset}");
+// exit;
+// }
+}
+
+else if ($_POST['apply']) {
+
+ /* Save new configuration */
+ write_config();
+
+ /*************************************************/
+ /* Update the suricata.yaml file and rebuild the */
+ /* rules for this interface. */
+ /*************************************************/
+ $rebuild_rules = true;
+ suricata_generate_yaml($a_rule[$id]);
+ $rebuild_rules = false;
+
+ /* Signal Suricata to "live reload" the rules */
+ suricata_reload_config($a_rule[$id]);
+
+ /* Return to this same page */
+ header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}");
+ exit;
+}
+else if ($_POST['cancel']) {
+
+ /* Return to this same page */
+ header("Location: /suricata/suricata_rules.php?id={$id}");
+ exit;
+}
+
+require_once("guiconfig.inc");
+include_once("head.inc");
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Rules: {$currentruleset}");
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php
+include("fbegin.inc");
+if ($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+
+/* Display message */
+if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+}
+
+if ($savemsg) {
+ print_info_box($savemsg);
+}
+
+?>
+
+<form action="/suricata/suricata_rules.php" method="post" name="iform" id="iform">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td>
+ <?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ echo '</td></tr>';
+ echo '<tr><td class="tabnavtbl">';
+ $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface ");;
+ $tab_array = array();
+ $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"), true, "/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}");
+ display_top_tabs($tab_array);
+ ?>
+ </td></tr>
+ <tr><td><div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="listtopic"><?php echo gettext("Available Rule Categories"); ?></td>
+ </tr>
+
+ <tr>
+ <td class="vncell" height="30px"><strong><?php echo gettext("Category:"); ?></strong>&nbsp;&nbsp;<select id="selectbox" name="selectbox" class="formselect" onChange="go()">
+ <option value='?id=<?=$id;?>&openruleset=custom.rules'>custom.rules</option>
+ <?php
+ $files = explode("||", $pconfig['rulesets']);
+ if ($a_rule[$id]['ips_policy_enable'] == 'on')
+ $files[] = "IPS Policy - " . ucfirst($a_rule[$id]['ips_policy']);
+ if ($a_rule[$id]['autoflowbitrules'] == 'on')
+ $files[] = "Auto-Flowbit Rules";
+ natcasesort($files);
+ foreach ($files as $value) {
+ if ($snortdownload != 'on' && substr($value, 0, mb_strlen(VRT_FILE_PREFIX)) == VRT_FILE_PREFIX)
+ continue;
+ if ($emergingdownload != 'on' && substr($value, 0, mb_strlen(ET_OPEN_FILE_PREFIX)) == ET_OPEN_FILE_PREFIX)
+ continue;
+ if ($etpro != 'on' && substr($value, 0, mb_strlen(ET_PRO_FILE_PREFIX)) == ET_PRO_FILE_PREFIX)
+ continue;
+ if (empty($value))
+ continue;
+ echo "<option value='?id={$id}&openruleset={$value}' ";
+ if ($value == $currentruleset)
+ echo "selected";
+ echo ">{$value}</option>\n";
+ }
+ ?>
+ </select>&nbsp;&nbsp;&nbsp;<?php echo gettext("Select the rule category to view"); ?>
+ </td>
+ </tr>
+
+ <?php if ($currentruleset == 'custom.rules'): ?>
+ <tr>
+ <td class="listtopic"><?php echo gettext("Defined Custom Rules"); ?></td>
+ </tr>
+ <tr>
+ <td valign="top" class="vtable">
+ <input type='hidden' name='openruleset' value='custom.rules'>
+ <input type='hidden' name='id' value='<?=$id;?>'>
+ <textarea wrap="soft" cols="90" rows="40" name="customrules"><?=$pconfig['customrules'];?></textarea>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input name="Submit" type="submit" class="formbtn" id="submit" value="<?php echo gettext(" Save "); ?>" title=" <?php echo gettext("Save custom rules"); ?>"/>&nbsp;&nbsp;
+ <input name="cancel" type="submit" class="formbtn" id="cancel" value="<?php echo gettext("Cancel"); ?>" title="<?php echo gettext("Cancel changes and return to last page"); ?>"/>&nbsp;&nbsp;
+ <input name="clear" type="submit" class="formbtn" id="clear" value="<?php echo gettext("Clear"); ?>" onclick="return confirm('<?php echo gettext("This will erase all custom rules for the interface. Are you sure?"); ?>')" title="<?php echo gettext("Deletes all custom rules"); ?>"/>
+ </td>
+ </tr>
+ <?php else: ?>
+ <tr>
+ <td class="listtopic"><?php echo gettext("Rule Signature ID (SID) Enable/Disable Overrides"); ?></td>
+ </tr>
+ <tr>
+ <td class="vncell">
+ <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0">
+ <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"); ?>"/>
+ <input type='hidden' name='id' value='<?=$id;?>'/>
+ <input type='hidden' name='openruleset' value='<?=$currentruleset;?>'/><br/><br/>
+ <span class="vexpl"><span class="red"><strong><?php echo gettext("Note: ") . "</strong></span>" .
+ gettext("Suricata must be restarted to activate any SID enable/disable changes made on this tab."); ?></span></td>
+ <td class="vexpl" valign="middle"><?php echo "<a href='?id={$id}&openruleset={$currentruleset}&act=resetcategory'>
+ <img src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"15\" height=\"15\"
+ onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"'
+ onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_x_mo.gif\"' border='0'
+ title='" . gettext("Click to remove enable/disable changes for rules in the selected category only") . "'></a>"?>
+ &nbsp;&nbsp;<?php echo gettext("Remove Enable/Disable changes in the current Category"); ?></td>
+ </tr>
+ <tr>
+ <td class="vexpl" valign="middle"><?php echo "<a href='?id={$id}&openruleset={$currentruleset}&act=resetall'>
+ <img src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"15\" height=\"15\"
+ onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"'
+ onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_x_mo.gif\"' border='0'
+ title='" . gettext("Click to remove all enable/disable changes for rules in all categories") . "'></a>"?>
+ &nbsp;&nbsp;<?php echo gettext("Remove all Enable/Disable changes in all Categories"); ?></td>
+ </tr>
+ <tr>
+ <td class="vexpl" valign="middle"><?php echo "<a href='?id={$id}&openruleset={$currentruleset}&act=disable_all'>
+ <img src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"15\" height=\"15\"
+ onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"'
+ onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_x_mo.gif\"' border='0'
+ title='" . gettext("Click to disable all rules in the selected category") . "'></a>"?>
+ &nbsp;&nbsp;<?php echo gettext("Disable all rules in the current Category"); ?></td>
+ </tr>
+ <tr>
+ <td class="vexpl" valign="middle"><?php echo "<a href='?id={$id}&openruleset={$currentruleset}&act=enable_all'>
+ <img src=\"../themes/{$g['theme']}/images/icons/icon_plus.gif\" width=\"15\" height=\"15\"
+ onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_plus.gif\"'
+ onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_plus_mo.gif\"' border='0'
+ title='" . gettext("Click to enable all rules in the selected category") . "'></a>"?>
+ &nbsp;&nbsp;<?php echo gettext("Enable all rules in the current Category"); ?></td>
+ </tr>
+
+ <tr>
+ <td class="vexpl" valign="middle"><a href="javascript: void(0)"
+ onclick="wopen('suricata_rules_edit.php?id=<?=$id;?>&openruleset=<?=$currentruleset;?>','FileViewer',800,600)">
+ <img src="../themes/<?= $g['theme']; ?>/images/icons/icon_service_restart.gif" width="15" height="15" <?php
+ echo "onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_services_restart_mo.gif\"'
+ onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_service_restart.gif\"' ";?>
+ title="<?php echo gettext("Click to view full text of all the category rules"); ?>" width="17" height="17" border="0"></a>
+ &nbsp;&nbsp;<?php echo gettext("View full file contents for the current Category"); ?></td>
+ </tr>
+
+ <?php if ($currentruleset == 'Auto-Flowbit Rules'): ?>
+ <tr>
+ <td colspan="3">&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="3" class="vexpl" align="center"><?php echo "<span class=\"red\"><b>" . gettext("WARNING: ") . "</b></span>" .
+ gettext("You should not disable flowbit rules! Add Suppress List entries for them instead by ") .
+ "<a href='suricata_rules_flowbits.php?id={$id}' title=\"" . gettext("Add Suppress List entry for Flowbit Rule") . "\">" .
+ gettext("clicking here") . ".</a>";?></td>
+ </tr>
+ <?php endif;?>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="listtopic"><?php echo gettext("Selected Category's Rules"); ?></td>
+ </tr>
+ <tr>
+ <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="6%" align="center" axis="number">
+ <col width="8%" align="center" axis="number">
+ <col width="54" align="center" axis="string">
+ <col width="52" align="center" axis="string">
+ <col width="12%" align="center" axis="string">
+ <col width="9%" align="center" axis="string">
+ <col width="12%" align="center" axis="string">
+ <col width="9%" align="center" axis="string">
+ <col axis="string">
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="list">&nbsp;</th>
+ <th class="listhdrr"><?php echo gettext("GID"); ?></th>
+ <th class="listhdrr"><?php echo gettext("SID"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Action"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Proto"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Source"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Port"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Destination"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Port"); ?></th>
+ <th class="listhdrr"><?php echo gettext("Message"); ?></th>
+ </tr>
+ </thead>
+ <tbody>
+
+ <?php
+ $counter = $enable_cnt = $disable_cnt = 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])) {
+ $textss = "<span class=\"gray\">";
+ $textse = "</span>";
+ $iconb = "icon_reject_d.gif";
+ $disable_cnt++;
+ $title = gettext("Disabled by user. Click to toggle to default state");
+ }
+ elseif (($v['disabled'] == 1) && (!isset($enablesid[$gid][$sid]))) {
+ $textss = "<span class=\"gray\">";
+ $textse = "</span>";
+ $iconb = "icon_block_d.gif";
+ $disable_cnt++;
+ $title = gettext("Disabled by default. Click to toggle to enabled state");
+ }
+ elseif (isset($enablesid[$gid][$sid])) {
+ $textss = $textse = "";
+ $iconb = "icon_reject.gif";
+ $enable_cnt++;
+ $title = gettext("Enabled by user. Click to toggle to default state");
+ }
+ else {
+ $textss = $textse = "";
+ $iconb = "icon_block.gif";
+ $enable_cnt++;
+ $title = gettext("Enabled by default. Click to toggle to disabled state");
+ }
+
+ // Pick off the first section of the rule (prior to the start of the MSG field),
+ // and then use a REGX split to isolate the remaining fields into an array.
+ $tmp = substr($v['rule'], 0, strpos($v['rule'], "("));
+ $tmp = trim(preg_replace('/^\s*#+\s*/', '', $tmp));
+ $rule_content = preg_split('/[\s]+/', $tmp);
+
+ // Create custom <span> tags for the fields we truncate so we can
+ // have a "title" attribute for tooltips to show the full string.
+ $srcspan = add_title_attribute($textss, $rule_content[2]);
+ $srcprtspan = add_title_attribute($textss, $rule_content[3]);
+ $dstspan = add_title_attribute($textss, $rule_content[5]);
+ $dstprtspan = add_title_attribute($textss, $rule_content[6]);
+ $protocol = $rule_content[1]; //protocol field
+ $source = truncate($rule_content[2], 14); //source field
+ $source_port = truncate($rule_content[3], 10); //source port field
+ $destination = truncate($rule_content[5], 14); //destination field
+ $destination_port = truncate($rule_content[6], 10); //destination port field
+ $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\">{$textss}
+ <a href='?id={$id}&openruleset={$currentruleset}&act=toggle&ids={$sid}'>
+ <img src=\"../themes/{$g['theme']}/images/icons/{$iconb}\"
+ width=\"11\" height=\"11\" border=\"0\"
+ title='{$title}' id=\"rule_{$gid}_{$sid}\"></a>{$textse}
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$textss}{$gid}{$textse}
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ <a href=\"javascript: void(0)\"
+ onclick=\"wopen('suricata_rules_edit.php?id={$id}&openruleset={$currentruleset}&ids={$sid}&gid={$gid}','FileViewer',800,600)\"
+ title='{$sid_tooltip}'>{$textss}{$sid}{$textse}</a>
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$textss}{$v['action']}{$textse}
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$textss}{$protocol}{$textse}
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$srcspan}{$source}</span>
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$srcprtspan}{$source_port}</span>
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$dstspan}{$destination}</span>
+ </td>
+ <td class=\"listlr\" align=\"center\" style=\"font-size: 10px;\">
+ {$dstprtspan}{$destination_port}</span>
+ </td>
+ <td class=\"listbg\" style=\"word-wrap:break-word; whitespace:pre-line; font-size: 10px; font-color: white;\">
+ {$textss}{$message}{$textse}
+ </td>
+ </tr>";
+ $counter++;
+ }
+ }
+ unset($rulem, $v); ?>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width="100%" border="0" cellspacing="0" cellpadding="1">
+ <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}") . "&nbsp;&nbsp;&nbsp;&nbsp;" .
+ gettext("Enabled: {$enable_cnt}") . "&nbsp;&nbsp;&nbsp;&nbsp;" .
+ gettext("Disabled: {$disable_cnt}"); ?></td>
+ </tr>
+ <tr>
+ <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_block.gif"
+ width="11" height="11"></td>
+ <td><?php echo gettext("Rule default is Enabled"); ?></td>
+ </tr>
+ <tr>
+ <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_block_d.gif"
+ width="11" height="11"></td>
+ <td nowrap><?php echo gettext("Rule default is Disabled"); ?></td>
+ </tr>
+ <tr>
+ <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_reject.gif"
+ width="11" height="11"></td>
+ <td nowrap><?php echo gettext("Rule changed to Enabled by user"); ?></td>
+ </tr>
+ <tr>
+ <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_reject_d.gif"
+ width="11" height="11"></td>
+ <td nowrap><?php echo gettext("Rule changed to Disabled by user"); ?></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <?php endif;?>
+ </table>
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+
+<script language="javascript" type="text/javascript">
+function go()
+{
+ var box = document.iform.selectbox;
+ destination = box.options[box.selectedIndex].value;
+ if (destination)
+ location.href = destination;
+}
+
+function wopen(url, name, w, h)
+{
+// Fudge factors for window decoration space.
+// In my tests these work well on all platforms & browsers.
+ w += 32;
+ h += 96;
+ var win = window.open(url,
+ name,
+ 'width=' + w + ', height=' + h + ', ' +
+ 'location=no, menubar=no, ' +
+ 'status=no, toolbar=no, scrollbars=yes, resizable=yes');
+ win.resizeTo(w, h);
+ win.focus();
+}
+
+<?php if (!empty($anchor)): ?>
+ // Scroll the last enabled/disabled SID into view
+ window.location.hash = "<?=$anchor; ?>";
+ window.scrollBy(0,-60);
+
+<?php endif;?>
+
+</script>
+</body>
+</html>
diff --git a/config/suricata/suricata_rules_edit.php b/config/suricata/suricata_rules_edit.php
new file mode 100644
index 00000000..0dc4c57b
--- /dev/null
+++ b/config/suricata/suricata_rules_edit.php
@@ -0,0 +1,154 @@
+<?php
+/*
+ * suricata_rules_edit.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+$flowbit_rules_file = FLOWBITS_FILENAME;
+$suricatadir = SURICATADIR;
+
+if (!is_array($config['installedpackages']['suricata']['rule'])) {
+ $config['installedpackages']['suricata']['rule'] = array();
+}
+$a_rule = &$config['installedpackages']['suricata']['rule'];
+
+$id = $_GET['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+if (isset($id) && $a_rule[$id]) {
+ $pconfig['enable'] = $a_rule[$id]['enable'];
+ $pconfig['interface'] = $a_rule[$id]['interface'];
+ $pconfig['rulesets'] = $a_rule[$id]['rulesets'];
+}
+
+/* convert fake interfaces to real */
+$if_real = suricata_get_real_interface($pconfig['interface']);
+$suricata_uuid = $a_rule[$id]['uuid'];
+$suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}";
+$file = $_GET['openruleset'];
+$contents = '';
+$wrap_flag = "off";
+
+// Correct displayed file title if necessary
+if ($file == "Auto-Flowbit Rules")
+ $displayfile = FLOWBITS_FILENAME;
+else
+ $displayfile = $file;
+
+// Read the contents of the argument passed to us.
+// It may be an IPS policy string, an individual SID,
+// a standard rules file, or a complete file name.
+// Test for the special case of an IPS Policy file.
+if (substr($file, 0, 10) == "IPS Policy") {
+ $rules_map = suricata_load_vrt_policy($a_rule[$id]['ips_policy']);
+ if (isset($_GET['ids'])) {
+ $contents = $rules_map[$_GET['gid']][trim($_GET['ids'])]['rule'];
+ $wrap_flag = "soft";
+ }
+ else {
+ $contents = "# Suricata IPS Policy - " . ucfirst($a_rule[$id]['ips_policy']) . "\n\n";
+ foreach (array_keys($rules_map) as $k1) {
+ foreach (array_keys($rules_map[$k1]) as $k2) {
+ $contents .= "# Category: " . $rules_map[$k1][$k2]['category'] . " SID: {$k2}\n";
+ $contents .= $rules_map[$k1][$k2]['rule'] . "\n";
+ }
+ }
+ }
+ unset($rules_map);
+}
+// Is it a SID to load the rule text from?
+elseif (isset($_GET['ids'])) {
+ // If flowbit rule, point to interface-specific file
+ if ($file == "Auto-Flowbit Rules")
+ $rules_map = suricata_load_rules_map("{$suricatacfgdir}rules/" . FLOWBITS_FILENAME);
+ else
+ $rules_map = suricata_load_rules_map("{$suricatadir}rules/{$file}");
+ $contents = $rules_map[$_GET['gid']][trim($_GET['ids'])]['rule'];
+ $wrap_flag = "soft";
+}
+
+// Is it our special flowbit rules file?
+elseif ($file == "Auto-Flowbit Rules")
+ $contents = file_get_contents("{$suricatacfgdir}rules/{$flowbit_rules_file}");
+// Is it a rules file in the ../rules/ directory?
+elseif (file_exists("{$suricatadir}rules/{$file}"))
+ $contents = file_get_contents("{$suricatadir}rules/{$file}");
+// Is it a fully qualified path and file?
+elseif (file_exists($file))
+ if (substr(realpath($file), 0, strlen(SURICATALOGDIR)) != SURICATALOGDIR)
+ $contents = gettext("\n\nERROR -- File: {$file} can not be viewed!");
+ else
+ $contents = file_get_contents($file);
+// It is not something we can display, so exit.
+else
+ $input_errors[] = gettext("Unable to open file: {$displayfile}");
+
+$pgtitle = array(gettext("Suricata"), gettext("File Viewer"));
+?>
+
+<?php include("head.inc");?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+<?php if ($savemsg) print_info_box($savemsg); ?>
+<?php // include("fbegin.inc");?>
+
+<form action="suricata_rules_edit.php" method="post">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+ <td class="tabcont">
+ <table width="100%" cellpadding="0" cellspacing="6" bgcolor="#eeeeee">
+ <tr>
+ <td class="pgtitle" colspan="2">Suricata: Rules Viewer</td>
+ </tr>
+ <tr>
+ <td width="20%">
+ <input type="button" class="formbtn" value="Return" onclick="window.close()">
+ </td>
+ <td align="right">
+ <b><?php echo gettext("Rules File: ") . '</b>&nbsp;' . $displayfile; ?>&nbsp;&nbsp;&nbsp;&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="label" colspan="2">
+ <div style="background: #eeeeee; width:100%; height:100%;" id="textareaitem"><!-- NOTE: The opening *and* the closing textarea tag must be on the same line. -->
+ <textarea style="width:100%; height:100%;" wrap="<?=$wrap_flag?>" rows="33" cols="80" name="code2"><?=$contents;?></textarea>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+</form>
+<?php // include("fend.inc");?>
+</body>
+</html>
diff --git a/config/suricata/suricata_rules_flowbits.php b/config/suricata/suricata_rules_flowbits.php
new file mode 100644
index 00000000..ca424344
--- /dev/null
+++ b/config/suricata/suricata_rules_flowbits.php
@@ -0,0 +1,306 @@
+<?php
+/*
+ * suricata_rules_flowbits.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+$suricatadir = SURICATADIR;
+$flowbit_rules_file = FLOWBITS_FILENAME;
+$rules_map = array();
+$supplist = array();
+
+if (!is_array($config['installedpackages']['suricata']['rule'])) {
+ $config['installedpackages']['suricata']['rule'] = array();
+}
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+// Set who called us so we can return to the correct page with
+// the RETURN button. We will just trust this User-Agent supplied
+// string for now.
+session_start();
+if(!isset($_SESSION['org_referer']))
+ $_SESSION['org_referer'] = $_SERVER['HTTP_REFERER'];
+$referrer = $_SESSION['org_referer'];
+
+if ($_POST['cancel']) {
+ session_start();
+ unset($_SESSION['org_referer']);
+ session_write_close();
+ header("Location: {$referrer}");
+ exit;
+}
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ session_start();
+ unset($_SESSION['org_referer']);
+ session_write_close();
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+$if_real = suricata_get_real_interface($a_nat[$id]['interface']);
+$suricata_uuid = $a_nat[$id]['uuid'];
+
+/* We should normally never get to this page if Auto-Flowbits are disabled, but just in case... */
+if ($a_nat[$id]['autoflowbitrules'] == '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) {
+ $rules_map = suricata_load_rules_map("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}");
+ }
+ else
+ $savemsg = gettext("There are no flowbit-required rules necessary for the current enforcing rule set.");
+}
+else
+ $input_errors[] = gettext("Auto-Flowbit rule generation is disabled for this interface!");
+
+if ($_GET['act'] == "addsuppress" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) {
+ $descr = suricata_get_msg($rules_map[$_GET['gen_id']][$_GET['sidid']]['rule']);
+ if (empty($descr))
+ $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n";
+ else
+ $suppress = "# {$descr}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n";
+ if (!is_array($config['installedpackages']['suricata']['suppress']))
+ $config['installedpackages']['suricata']['suppress'] = array();
+ if (!is_array($config['installedpackages']['suricata']['suppress']['item']))
+ $config['installedpackages']['suricata']['suppress']['item'] = array();
+ $a_suppress = &$config['installedpackages']['suricata']['suppress']['item'];
+ $found_list = false;
+
+ if (empty($a_nat[$id]['suppresslistname']) || $a_nat[$id]['suppresslistname'] == 'default') {
+ $s_list = array();
+ $s_list['uuid'] = uniqid();
+ $s_list['name'] = $a_nat[$id]['interface'] . "suppress" . "_" . $s_list['uuid'];
+ $s_list['descr'] = "Auto-generated list for Alert suppression";
+ $s_list['suppresspassthru'] = base64_encode($suppress);
+ $a_suppress[] = $s_list;
+ $a_nat[$id]['suppresslistname'] = $s_list['name'];
+ $found_list = true;
+ } else {
+ /* If we get here, a Suppress List is defined for the interface so see if we can find it */
+ foreach ($a_suppress as $a_id => $alist) {
+ if ($alist['name'] == $a_nat[$id]['suppresslistname']) {
+ $found_list = true;
+ if (!empty($alist['suppresspassthru'])) {
+ $tmplist = base64_decode($alist['suppresspassthru']);
+ $tmplist .= "\n{$suppress}";
+ $alist['suppresspassthru'] = base64_encode($tmplist);
+ $a_suppress[$a_id] = $alist;
+ }
+ else {
+ $alist['suppresspassthru'] = base64_encode($suppress);
+ $a_suppress[$a_id] = $alist;
+ }
+ }
+ }
+ }
+ if ($found_list) {
+ write_config();
+ $rebuild_rules = false;
+ sync_suricata_package_config();
+ suricata_reload_config($a_nat[$id]);
+ $savemsg = gettext("An entry to suppress the Alert for 'gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}' has been added to Suppress List '{$a_nat[$id]['suppresslistname']}'.");
+ }
+ else {
+ /* We did not find the defined list, so notify the user with an error */
+ $input_errors[] = gettext("Suppress List '{$a_nat[$id]['suppresslistname']}' is defined for this interface, but it could not be found!");
+ }
+}
+
+function truncate($string, $length) {
+
+ /********************************
+ * This function truncates the *
+ * passed string to the length *
+ * specified adding ellipsis if *
+ * truncation was necessary. *
+ ********************************/
+ if (strlen($string) > $length)
+ $string = substr($string, 0, ($length - 3)) . "...";
+ return $string;
+}
+
+/* Load up an array with the current Suppression List GID,SID values */
+$supplist = suricata_load_suppress_sigs($a_nat[$id]);
+
+$if_friendly = suricata_get_friendly_interface($a_nat[$id]['interface']);
+$pgtitle = gettext("Suricata: Interface {$if_friendly} - Flowbit Rules");
+include_once("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC" >
+
+<?php
+include("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+if ($input_errors) print_input_errors($input_errors);
+if ($savemsg)
+ print_info_box($savemsg);
+?>
+<form action="suricata_rules_flowbits.php" method="post" name="iform" id="iform">
+<div id="boxarea">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+<td class="tabcont">
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+ <tr>
+ <td valign="middle" class="listtopic"><?php echo gettext("Auto-Generated Flowbit-Required Rules"); ?></td>
+ </tr>
+ <tr>
+ <td width="78%" class="vncell">
+ <?php echo gettext("The rules listed below are required to be included in the rules set ") .
+ gettext("because they set flowbits that are checked and relied upon by rules in the enforcing rules set. ") .
+ gettext("If these dependent flowbits are not set, then some of your chosen rules may not fire. ") .
+ gettext("Enabling all the rules that set these dependent flowbits ensures your chosen rules fire as intended. ") .
+ gettext("Most flowbits rules contain the \"noalert\" keyword to prevent an alert from firing ") .
+ gettext("when the flowbit is detected. For those flowbit rules that do not contain the \"noalert\" option, click the ") .
+ gettext("icon displayed beside the Signature ID (SID) to add the alert to the Suppression List if desired."); ?></td>
+ </tr>
+ <tr>
+ <td valign="middle" class="listtopic"><?php echo gettext("Flowbit-Required Rules for {$if_friendly}"); ?></td>
+ </tr>
+ <tr>
+ <td width="78%" class="vncell">
+ <table width="100%" border="0" cellspacing="2" cellpadding="0">
+ <tr>
+ <td width="17px"><img src="../themes/<?=$g['theme']?>/images/icons/icon_plus.gif" width='12' height='12' border='0'/></td>
+ <td><span class="vexpl"><?php echo gettext("Alert is Not Suppressed"); ?></span></td>
+ <td rowspan="3" align="right"><input id="cancel" name="cancel" type="submit" class="formbtn" <?php
+ echo "value=\"" . gettext("Return") . "\" title=\"" . gettext("Return to previous page") . "\""; ?>/>
+ <input name="id" type="hidden" value="<?=$id;?>" /></td>
+ </tr>
+ <tr>
+ <td width="17px"><img src="../themes/<?=$g['theme']?>/images/icons/icon_plus_d.gif" width='12' height='12' border='0'/></td>
+ <td><span class="vexpl"><?php echo gettext("Alert has been Suppressed"); ?></span></td>
+ </tr>
+ <tr>
+ <td width="17px"> </td>
+ <td colspan="2" class="vexpl"><?php echo "<span class=\"red\"><strong>" .
+ gettext("Note: ") . "</strong></span>". gettext("the icon is only ") .
+ gettext("displayed for flowbit rules without the \"noalert\" option."); ?></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table id="myTable" width="100%" class="sortable" border="1" cellpadding="0" cellspacing="0">
+ <colgroup>
+ <col width="11%" axis="number">
+ <col width="10%" axis="string">
+ <col width="14%" axis="string">
+ <col width="14%" axis="string">
+ <col width="20%" axis="string">
+ <col axis="string">
+ </colgroup>
+ <thead>
+ <tr>
+ <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>
+ <th class="listhdrr" axis="string"><?php echo gettext("Destination"); ?></th>
+ <th class="listhdrr" axis="string"><?php echo gettext("Flowbits"); ?></th>
+ <th class="listhdrr" axis="string"><?php echo gettext("Message"); ?></th>
+ </tr>
+ <thead>
+ <tbody>
+ <?php
+ $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']);
+
+ // Pick off the first section of the rule (prior to the start of the MSG field),
+ // and then use a REGX split to isolate the remaining fields into an array.
+ $tmp = substr($v['rule'], 0, strpos($v['rule'], "("));
+ $tmp = trim(preg_replace('/^\s*#+\s*/', '', $tmp));
+ $rule_content = preg_split('/[\s]+/', $tmp);
+
+ $protocol = $rule_content[1]; //protocol
+ $source = truncate($rule_content[2], 14); //source
+ $destination = truncate($rule_content[5], 14); //destination
+ $message = suricata_get_msg($v['rule']);
+ $flowbits = implode("; ", suricata_get_flowbits($v['rule']));
+ if (strstr($flowbits, "noalert"))
+ $supplink = "";
+ else {
+ if (!isset($supplist[$gid][$sid])) {
+ $supplink = "<a href=\"?id={$id}&act=addsuppress&sidid={$sid}&gen_id={$gid}\">";
+ $supplink .= "<img src=\"../themes/{$g['theme']}/images/icons/icon_plus.gif\" ";
+ $supplink .= "width='12' height='12' border='0' title='";
+ $supplink .= gettext("Click to add to Suppress List") . "'/></a>";
+ }
+ else {
+ $supplink = "<img src=\"../themes/{$g['theme']}/images/icons/icon_plus_d.gif\" ";
+ $supplink .= "width='12' height='12' border='0' title='";
+ $supplink .= gettext("Alert has been suppressed") . "'/>";
+ }
+ }
+
+ // Use "echo" to write the table HTML row-by-row.
+ echo "<tr>" .
+ "<td class=\"listr\">{$sid}&nbsp;{$supplink}</td>" .
+ "<td class=\"listr\">{$protocol}</td>" .
+ "<td class=\"listr\"><span title=\"{$rule_content[2]}\">{$source}</span></td>" .
+ "<td class=\"listr\"><span title=\"{$rule_content[5]}\">{$destination}</span></td>" .
+ "<td class=\"listr\" style=\"word-wrap:break-word; word-break:normal;\">{$flowbits}</td>" .
+ "<td class=\"listr\" style=\"word-wrap:break-word; word-break:normal;\">{$message}</td>" .
+ "</tr>";
+ $count++;
+ }
+ }
+ unset($rulem, $v);
+ ?>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <?php if ($count > 20): ?>
+ <tr>
+ <td align="center" valign="middle">
+ <input id="cancel" name="cancel" type="submit" class="formbtn" <?php
+ echo "value=\"" . gettext("Return") . "\" title=\"" . gettext("Return to previous page") . "\""; ?>/>
+ <input name="id" type="hidden" value="<?=$id;?>" />
+ </td>
+ </tr>
+ <?php endif; ?>
+</table>
+</td>
+</tr>
+</table>
+</div>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_rulesets.php b/config/suricata/suricata_rulesets.php
new file mode 100644
index 00000000..a1609d6c
--- /dev/null
+++ b/config/suricata/suricata_rulesets.php
@@ -0,0 +1,596 @@
+<?php
+/*
+ * suricata_rulesets.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+global $g, $rebuild_rules;
+
+$suricatadir = SURICATADIR;
+$flowbit_rules_file = FLOWBITS_FILENAME;
+
+if (!is_array($config['installedpackages']['suricata']['rule'])) {
+ $config['installedpackages']['suricata']['rule'] = array();
+}
+$a_nat = &$config['installedpackages']['suricata']['rule'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+if (is_null($id)) {
+ header("Location: /suricata/suricata_interfaces.php");
+ exit;
+}
+
+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['ips_policy_enable'] = $a_nat[$id]['ips_policy_enable'];
+ $pconfig['ips_policy'] = $a_nat[$id]['ips_policy'];
+}
+
+$if_real = get_real_interface($pconfig['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';
+$etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules'] == 'on' ? 'on' : 'off';
+$snortcommunitydownload = $config['installedpackages']['suricata']['config'][0]['snortcommunityrules'] == 'on' ? 'on' : 'off';
+
+$no_emerging_files = false;
+$no_snort_files = false;
+
+/* Test rule categories currently downloaded to $SURICATADIR/rules and set appropriate flags */
+if ($emergingdownload == 'on') {
+ $test = glob("{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "*.rules");
+ $et_type = "ET Open";
+}
+elseif ($etpro == 'on') {
+ $test = glob("{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "*.rules");
+ $et_type = "ET Pro";
+}
+else
+ $et_type = "Emerging Threats";
+if (empty($test))
+ $no_emerging_files = true;
+$test = glob("{$suricatadir}rules/" . VRT_FILE_PREFIX . "*.rules");
+if (empty($test))
+ $no_snort_files = true;
+if (!file_exists("{$suricatadir}rules/" . GPL_FILE_PREFIX . "community.rules"))
+ $no_community_files = true;
+
+if (($snortdownload != 'on') || ($a_nat[$id]['ips_policy_enable'] != 'on'))
+ $policy_select_disable = "disabled";
+
+if ($a_nat[$id]['autoflowbitrules'] == '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") . "\"";
+ }
+ else
+ $btn_view_flowb_rules = " disabled";
+}
+else
+ $btn_view_flowb_rules = " disabled";
+
+// If a Snort VRT policy is enabled and selected, remove all Snort VRT
+// rules from the configured rule sets to allow automatic selection.
+if ($a_nat[$id]['ips_policy_enable'] == 'on') {
+ if (isset($a_nat[$id]['ips_policy'])) {
+ $disable_vrt_rules = "disabled";
+ $enabled_sets = explode("||", $a_nat[$id]['rulesets']);
+
+ foreach ($enabled_sets as $k => $v) {
+ if (substr($v, 0, 6) == "suricata_")
+ unset($enabled_sets[$k]);
+ }
+ $a_nat[$id]['rulesets'] = implode("||", $enabled_sets);
+ }
+}
+else
+ $disable_vrt_rules = "";
+
+/* alert file */
+if ($_POST["Submit"]) {
+
+ if ($_POST['ips_policy_enable'] == "on") {
+ $a_nat[$id]['ips_policy_enable'] = 'on';
+ $a_nat[$id]['ips_policy'] = $_POST['ips_policy'];
+ }
+ else {
+ $a_nat[$id]['ips_policy_enable'] = 'off';
+ unset($a_nat[$id]['ips_policy']);
+ }
+
+ $enabled_items = "";
+ if (is_array($_POST['toenable']))
+ $enabled_items = implode("||", $_POST['toenable']);
+ else
+ $enabled_items = $_POST['toenable'];
+
+ $a_nat[$id]['rulesets'] = $enabled_items;
+
+ if ($_POST['autoflowbits'] == "on")
+ $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}");
+ }
+
+ write_config();
+
+ /*************************************************/
+ /* Update the suricata.yaml file and rebuild the */
+ /* rules for this interface. */
+ /*************************************************/
+ $rebuild_rules = true;
+ suricata_generate_yaml($a_nat[$id]);
+ $rebuild_rules = false;
+
+ header("Location: /suricata/suricata_rulesets.php?id=$id");
+ exit;
+}
+
+if ($_POST['unselectall']) {
+ $a_nat[$id]['rulesets'] = "";
+
+ if ($_POST['ips_policy_enable'] == "on") {
+ $a_nat[$id]['ips_policy_enable'] = 'on';
+ $a_nat[$id]['ips_policy'] = $_POST['ips_policy'];
+ }
+ else {
+ $a_nat[$id]['ips_policy_enable'] = 'off';
+ unset($a_nat[$id]['ips_policy']);
+ }
+
+ write_config();
+ sync_suricata_package_config();
+
+ header("Location: /suricata/suricata_rulesets.php?id=$id");
+ exit;
+}
+
+if ($_POST['selectall']) {
+ $rulesets = array();
+
+ if ($_POST['ips_policy_enable'] == "on") {
+ $a_nat[$id]['ips_policy_enable'] = 'on';
+ $a_nat[$id]['ips_policy'] = $_POST['ips_policy'];
+ }
+ else {
+ $a_nat[$id]['ips_policy_enable'] = 'off';
+ unset($a_nat[$id]['ips_policy']);
+ }
+
+ if ($emergingdownload == 'on') {
+ $files = glob("{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "*.rules");
+ foreach ($files as $file)
+ $rulesets[] = basename($file);
+ }
+ elseif ($etpro == 'on') {
+ $files = glob("{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "*.rules");
+ foreach ($files as $file)
+ $rulesets[] = basename($file);
+ }
+
+ if ($snortcommunitydownload == 'on') {
+ $files = glob("{$suricatadir}rules/" . GPL_FILE_PREFIX . "community.rules");
+ foreach ($files as $file)
+ $rulesets[] = 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') {
+ $files = glob("{$suricatadir}rules/" . VRT_FILE_PREFIX . "*.rules");
+ foreach ($files as $file)
+ $rulesets[] = basename($file);
+ }
+
+ $a_nat[$id]['rulesets'] = implode("||", $rulesets);
+
+ write_config();
+ sync_suricata_package_config();
+
+ header("Location: /suricata/suricata_rulesets.php?id=$id");
+ exit;
+}
+
+$enabled_rulesets_array = explode("||", $a_nat[$id]['rulesets']);
+
+$if_friendly = convert_friendly_interface_to_friendly_descr($pconfig['interface']);
+$pgtitle = gettext("Suricata IDS: Interface {$if_friendly} - Categories");
+include_once("head.inc");
+?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?php
+include("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+
+/* Display message */
+if ($input_errors) {
+ print_input_errors($input_errors); // TODO: add checks
+}
+
+if ($savemsg) {
+ print_info_box($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">
+<tr><td>
+<?php
+ $tab_array = array();
+ $tab_array[] = array(gettext("Suricata 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("Alerts"), false, "/suricata/suricata_alerts.php?instance={$id}");
+ $tab_array[] = array(gettext("Suppress"), false, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+ echo '</td></tr>';
+ echo '<tr><td class="tabnavtbl">';
+ $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface ");
+ $tab_array = array();
+ $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}");
+ $tab_array[] = array($menu_iface . gettext("Categories"), true, "/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}");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr>
+ <td>
+ <div id="mainarea">
+ <table id="maintable" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+<?php
+ $isrulesfolderempty = glob("{$suricatadir}rules/*.rules");
+ $iscfgdirempty = array();
+ if (file_exists("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/custom.rules"))
+ $iscfgdirempty = (array)("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/custom.rules");
+ if (empty($isrulesfolderempty)):
+?>
+ <tr>
+ <td class="vexpl"><br/>
+ <?php printf(gettext("# The rules directory is empty: %s%srules%s"), '<strong>',$suricatadir,'</strong>'); ?> <br/><br/>
+ <?php echo gettext("Please go to the ") . '<a href="suricata_download_updates.php"><strong>' . gettext("Updates") .
+ '</strong></a>' . gettext(" tab to download the rules configured on the ") .
+ '<a href="suricata_interfaces_global.php"><strong>' . gettext("Global") .
+ '</strong></a>' . gettext(" tab."); ?>
+ </td>
+ </tr>
+<?php else:
+ $colspan = 4;
+ if ($emergingdownload != 'on')
+ $colspan -= 2;
+ if ($snortdownload != 'on')
+ $colspan -= 2;
+
+?>
+ <tr>
+ <td>
+ <table width="100%" border="0"
+ cellpadding="0" cellspacing="0">
+ <tr>
+ <td colspan="4" class="listtopic"><?php echo gettext("Automatic flowbit resolution"); ?><br/></td>
+ </tr>
+ <tr>
+ <td colspan="4" valign="center" class="listn">
+ <table width="100%" border="0" cellpadding="2" cellspacing="0">
+ <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"; ?>/>
+ &nbsp;&nbsp;<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>
+ <tr>
+ <td width="15%" class="vncell">&nbsp;</td>
+ <td width="85%" class="vtable">
+ <?php echo gettext("Suricata will examine the enabled rules in your chosen " .
+ "rule categories for checked flowbits. Any rules that set these dependent flowbits will " .
+ "be automatically enabled and added to the list of files in the interface rules directory."); ?><br/></td>
+ </tr>
+ <tr>
+ <td width="15%" class="listn"><?php echo gettext("Auto Flowbit Rules"); ?></td>
+ <td width="85%"><input type="button" class="formbtns" value="View" onclick="parent.location='suricata_rules_flowbits.php?id=<?=$id;?>'" <?php echo $btn_view_flowb_rules; ?>/>
+ &nbsp;&nbsp;<span class="vexpl"><?php echo gettext("Click to view auto-enabled rules required to satisfy flowbit dependencies"); ?></span></td>
+ </tr>
+ <tr>
+ <td width="15%">&nbsp;</td>
+ <td width="85%">
+ <?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>
+ </table>
+ </td>
+ </tr>
+
+ <?php if ($snortdownload == 'on'): ?>
+ <tr>
+ <td colspan="4" class="listtopic"><?php echo gettext("Snort IPS Policy selection"); ?><br/></td>
+ </tr>
+ <tr>
+ <td colspan="4" valign="center" class="listn">
+ <table width="100%" border="0" cellpadding="2" cellspacing="0">
+ <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"; ?>
+ <?php if ($snortdownload != "on") echo "disabled" ?> onClick="enable_change()"/>&nbsp;&nbsp;<span class="vexpl">
+ <?php echo gettext("If checked, Suricata will use rules from one of three pre-defined Snort IPS policies."); ?></span></td>
+ </tr>
+ <tr>
+ <td width="15%" class="vncell" id="ips_col1">&nbsp;</td>
+ <td width="85%" class="vtable" id="ips_col2">
+ <?php echo "<span class=\"red\"><strong>" . gettext("Note: ") . "</strong></span>" . gettext("You must be using the Snort VRT rules to use this option."); ?>
+ <?php echo gettext("Selecting this option disables manual selection of Snort VRT categories in the list below, " .
+ "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">
+ <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>
+ <option value="balanced" <?php if ($pconfig['ips_policy'] == "balanced") echo "selected"; ?>><?php echo gettext("Balanced"); ?></option>
+ <option value="security" <?php if ($pconfig['ips_policy'] == "security") echo "selected"; ?>><?php echo gettext("Security"); ?></option>
+ </select>
+ &nbsp;&nbsp;<span class="vexpl"><?php echo gettext("Snort IPS policies are: Connectivity, Balanced or Security."); ?></span></td>
+ </tr>
+ <tr id="ips_row2">
+ <td width="15%">&nbsp;</td>
+ <td width="85%">
+ <?php echo gettext("Connectivity blocks most major threats with few or no false positives. " .
+ "Balanced is a good starter policy. It is speedy, has good base coverage level, and covers " .
+ "most threats of the day. It includes all rules in Connectivity." .
+ "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>
+ </table>
+ </td>
+ </tr>
+ <?php endif; ?>
+ <tr>
+ <td colspan="4" class="listtopic"><?php echo gettext("Select the rulesets Suricata will load at startup"); ?><br/></td>
+ </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="Submit" id="Submit" 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>
+ </tr>
+ </table>
+ </tr>
+ <?php if ($no_community_files)
+ $msg_community = "NOTE: Snort Community Rules have not been downloaded. Perform a Rules Update to enable them.";
+ else
+ $msg_community = "Snort GPLv2 Community Rules (VRT certified)";
+ $community_rules_file = GPL_FILE_PREFIX . "community.rules";
+ ?>
+ <?php if ($snortcommunitydownload == 'on'): ?>
+ <tr id="frheader">
+ <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)): ?>
+ <tr>
+ <td width="5" class="listr" align="center" valign="top">
+ <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">
+ <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>
+ <?php endif; ?>
+ <?php endif; ?>
+
+ <?php if ($no_emerging_files && ($emergingdownload == 'on' || $etpro == 'on'))
+ $msg_emerging = "have not been downloaded.";
+ else
+ $msg_emerging = "are not enabled.";
+ if ($no_snort_files && $snortdownload == 'on')
+ $msg_snort = "have not been downloaded.";
+ else
+ $msg_snort = "are not enabled.";
+ ?>
+ <tr id="frheader">
+ <?php if ($emergingdownload == 'on' && !$no_emerging_files): ?>
+ <td width="5%" class="listhdrr" 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="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>
+ <?php endif; ?>
+ <?php if ($snortdownload == 'on' && !$no_snort_files): ?>
+ <td width="5%" class="listhdrr" 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>
+ <?php endif; ?>
+ </tr>
+ <?php
+ $emergingrules = array();
+ $snortrules = array();
+ if (empty($isrulesfolderempty))
+ $dh = opendir("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/");
+ else
+ $dh = opendir("{$suricatadir}rules/");
+ while (false !== ($filename = readdir($dh))) {
+ $filename = basename($filename);
+ if (substr($filename, -5) != "rules")
+ continue;
+ if (strstr($filename, ET_OPEN_FILE_PREFIX) && $emergingdownload == 'on')
+ $emergingrules[] = $filename;
+ else if (strstr($filename, ET_PRO_FILE_PREFIX) && $etpro == 'on')
+ $emergingrules[] = $filename;
+ else if (strstr($filename, VRT_FILE_PREFIX) && $snortdownload == 'on') {
+ $snortrules[] = $filename;
+ }
+ }
+ sort($emergingrules);
+ sort($snortrules);
+ $i = count($emergingrules);
+ if ($i < count($snortrules))
+ $i = count($snortrules);
+
+ for ($j = 0; $j < $i; $j++) {
+ echo "<tr>\n";
+ if (!empty($emergingrules[$j])) {
+ $file = $emergingrules[$j];
+ echo "<td width='5%' class='listr' align=\"center\" valign=\"top\">";
+ if(is_array($enabled_rulesets_array)) {
+ if(in_array($file, $enabled_rulesets_array))
+ $CHECKED = " checked=\"checked\"";
+ else
+ $CHECKED = "";
+ } else
+ $CHECKED = "";
+ echo " \n<input type='checkbox' name='toenable[]' value='$file' {$CHECKED} />\n";
+ echo "</td>\n";
+ echo "<td class='listr' width='45%' >\n";
+ if (empty($CHECKED))
+ echo $file;
+ else
+ echo "<a href='suricata_rules.php?id={$id}&openruleset=" . urlencode($file) . "'>{$file}</a>\n";
+ echo "</td>\n";
+ } else
+ echo "<td class='listbggrey' width='30%' colspan='2'><br/></td>\n";
+
+ if (!empty($snortrules[$j])) {
+ $file = $snortrules[$j];
+ echo "<td class='listr' width='5%' align=\"center\" valign=\"top\">";
+ if(is_array($enabled_rulesets_array)) {
+ if (!empty($disable_vrt_rules))
+ $CHECKED = $disable_vrt_rules;
+ elseif(in_array($file, $enabled_rulesets_array))
+ $CHECKED = " checked=\"checked\"";
+ else
+ $CHECKED = "";
+ } else
+ $CHECKED = "";
+ 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")
+ echo $file;
+ else
+ echo "<a href='suricata_rules.php?id={$id}&openruleset=" . urlencode($file) . "'>{$file}</a>\n";
+ echo "</td>\n";
+ } else
+ echo "<td class='listbggrey' width='50%' colspan='2'><br/></td>\n";
+ echo "</tr>\n";
+ }
+ ?>
+ </table>
+ </td>
+</tr>
+<tr>
+<td colspan="4" class="vexpl">&nbsp;<br/></td>
+</tr>
+ <tr>
+ <td colspan="4" align="center" valign="middle">
+ <input value="Save" type="submit" name="Submit" id="Submit" class="formbtn" title=" <?php echo gettext("Click to Save changes and rebuild rules"); ?>"/></td>
+ </tr>
+<?php endif; ?>
+</table>
+</div>
+</td>
+</tr>
+</table>
+</form>
+<?php
+include("fend.inc");
+?>
+
+<script language="javascript" type="text/javascript">
+
+function wopen(url, name, w, h)
+{
+// Fudge factors for window decoration space.
+// In my tests these work well on all platforms & browsers.
+w += 32;
+h += 96;
+ var win = window.open(url,
+ name,
+ 'width=' + w + ', height=' + h + ', ' +
+ 'location=no, menubar=no, ' +
+ 'status=no, toolbar=no, scrollbars=yes, resizable=yes');
+ win.resizeTo(w, h);
+ win.focus();
+}
+
+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) == "suricata_")
+ document.iform.elements[i].disabled = !(endis);
+ }
+ }
+}
+
+// Set initial state of dynamic HTML form controls
+enable_change();
+
+</script>
+
+</body>
+</html>
diff --git a/config/suricata/suricata_select_alias.php b/config/suricata/suricata_select_alias.php
new file mode 100644
index 00000000..f1fd4b93
--- /dev/null
+++ b/config/suricata/suricata_select_alias.php
@@ -0,0 +1,226 @@
+<?php
+/* $Id$ */
+/*
+ suricata_select_alias.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("guiconfig.inc");
+require_once("functions.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+// Need to keep track of who called us so we can return to the correct page
+// when the SAVE button is clicked. On initial entry, a GET variable is
+// passed with the referrer's URL encoded within. That value is saved and
+// used when SAVE or CANCEL is clicked to return to the referring page.
+//
+
+// Retrieve the QUERY STRING of the original referrer so we can return it.
+// On the initial pass, we will save it in a hidden POST field so we won't
+// overwrite it on subsequent POST-BACKs to this page.
+if (!isset($_POST['org_querystr']))
+ $querystr = $_SERVER['QUERY_STRING'];
+
+// Retrieve any passed QUERY STRING or POST variables
+$type = $_GET['type'];
+$varname = $_GET['varname'];
+$multi_ip = $_GET['multi_ip'];
+$referrer = urldecode($_GET['returl']);
+if (isset($_POST['type']))
+ $type = $_POST['type'];
+if (isset($_POST['varname']))
+ $varname = $_POST['varname'];
+if (isset($_POST['multi_ip']))
+ $multi_ip = $_POST['multi_ip'];
+if (isset($_POST['returl']))
+ $referrer = urldecode($_POST['returl']);
+if (isset($_POST['org_querystr']))
+ $querystr = $_POST['org_querystr'];
+
+// 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}");
+ exit;
+}
+
+// Used to track if any selectable Aliases are found
+$selectablealias = false;
+
+// Initialize required array variables as necessary
+if (!is_array($config['aliases']['alias']))
+ $config['aliases']['alias'] = array();
+$a_aliases = $config['aliases']['alias'];
+
+// Create an array consisting of the Alias types the
+// caller wants to select from.
+$a_types = array();
+$a_types = explode('|', strtolower($type));
+
+// Create a proper title based on the Alias types
+$title = "a";
+switch (count($a_types)) {
+ case 1:
+ $title .= " " . ucfirst($a_types[0]);
+ break;
+
+ case 2:
+ $title .= " " . ucfirst($a_types[0]) . " or " . ucfirst($a_types[1]);
+ break;
+
+ case 3:
+ $title .= " " . ucfirst($a_types[0]) . ", " . ucfirst($a_types[1]) . " or " . ucfirst($a_types[2]);
+
+ default:
+ $title = "n";
+}
+
+if ($_POST['cancel']) {
+ header("Location: {$referrer}?{$querystr}");
+ exit;
+}
+
+if ($_POST['save']) {
+ if(empty($_POST['alias']))
+ $input_errors[] = gettext("No alias is selected. Please select an alias before saving.");
+
+ // if no errors, write new entry to conf
+ if (!$input_errors) {
+ $selection = $_POST['alias'];
+ header("Location: {$referrer}?{$querystr}&varvalue={$selection}");
+ exit;
+ }
+}
+
+$pgtitle = gettext("Suricata: Select {$title} Alias");
+include("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php include("fbegin.inc"); ?>
+<form action="suricata_select_alias.php" method="post">
+<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;?>">
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<div id="boxarea">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+ <td class="tabcont"><strong><?=gettext("Select an Alias to use from the list below.");?></strong><br/>
+ </td>
+</tr>
+<tr>
+ <td class="tabcont">
+ <table id="sortabletable1" style="table-layout: fixed;" class="sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <colgroup>
+ <col width="5%" align="center">
+ <col width="25%" align="left" axis="string">
+ <col width="35%" align="left" axis="string">
+ <col width="35%" align="left" axis="string">
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="listhdrr"></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>
+ </tr>
+ </thead>
+ <tbody>
+ <?php $i = 0; foreach ($a_aliases as $alias): ?>
+ <?php if (!in_array($alias['type'], $a_types))
+ continue;
+ elseif (($alias['type'] == "network" || $alias['type'] == "host") &&
+ trim(filter_expand_alias($alias['name'])) == "") {
+ $textss = "<span class=\"gray\">";
+ $textse = "</span>";
+ $disable = true;
+ $tooltip = gettext("Aliases representing a FQDN host cannot be used in Suricata configurations.");
+ }
+ else {
+ $textss = "";
+ $textse = "";
+ $disable = "";
+ $selectablealias = true;
+ $tooltip = gettext("Selected entry will be imported. Click to toggle selection.");
+ }
+ ?>
+ <?php if ($disable): ?>
+ <tr title="<?=$tooltip;?>">
+ <td class="listlr" align="center"><img src="../themes/<?=$g['theme'];?>/images/icons/icon_block_d.gif" width="11" height"11" border="0"/>
+ <?php else: ?>
+ <tr>
+ <td class="listlr" align="center"><input type="radio" name="alias" value="<?=htmlspecialchars($alias['name']);?>" title="<?=$tooltip;?>"/></td>
+ <?php endif; ?>
+ <td class="listr" align="left"><?=$textss . htmlspecialchars($alias['name']) . $textse;?></td>
+ <td class="listr" align="left">
+ <?php
+ $tmpaddr = explode(" ", $alias['address']);
+ $addresses = implode(", ", array_slice($tmpaddr, 0, 10));
+ echo "{$textss}{$addresses}{$textse}";
+ if(count($tmpaddr) > 10) {
+ echo "...";
+ }
+ ?>
+ </td>
+ <td class="listbg" align="left">
+ <?=$textss . htmlspecialchars($alias['descr']) . $textse;?>&nbsp;
+ </td>
+ </tr>
+ <?php $i++; endforeach; ?>
+ </table>
+ </td>
+</tr>
+<?php if (!$selectablealias): ?>
+<tr>
+ <td class="tabcont" align="center"><b><?php echo gettext("There are currently no defined Aliases eligible for selection.");?></b></td>
+</tr>
+<tr>
+ <td class="tabcont" align="center">
+ <input type="Submit" name="cancel" value="Cancel" id="cancel" class="formbtn" title="<?=gettext("Cancel import operation and return");?>"/>
+ </td>
+</tr>
+<?php else: ?>
+<tr>
+ <td class="tabcont" align="center">
+ <input type="Submit" name="save" value="Save" id="save" class="formbtn" title="<?=gettext("Import selected item and return");?>"/>&nbsp;&nbsp;&nbsp;
+ <input type="Submit" name="cancel" value="Cancel" id="cancel" class="formbtn" title="<?=gettext("Cancel import operation and return");?>"/>
+ </td>
+</tr>
+<?php endif; ?>
+<tr>
+ <td class="tabcont">
+ <span class="vexpl"><span class="red"><strong><?=gettext("Note:"); ?><br></strong></span><?=gettext("Fully-Qualified Domain Name (FQDN) host Aliases cannot be used as Suricata configuration parameters. Aliases resolving to a single FQDN value are disabled in the list above. In the case of nested Aliases where one or more of the nested values is a FQDN host, the FQDN host will not be included in the {$title} configuration.");?></span>
+ </td>
+</tr>
+</table>
+</div>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_suppress.php b/config/suricata/suricata_suppress.php
new file mode 100644
index 00000000..58839dce
--- /dev/null
+++ b/config/suricata/suricata_suppress.php
@@ -0,0 +1,172 @@
+<?php
+/*
+ suricata_suppress.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+if (!is_array($config['installedpackages']['suricata']['rule']))
+ $config['installedpackages']['suricata']['rule'] = array();
+if (!is_array($config['installedpackages']['suricata']['suppress']))
+ $config['installedpackages']['suricata']['suppress'] = array();
+if (!is_array($config['installedpackages']['suricata']['suppress']['item']))
+ $config['installedpackages']['suricata']['suppress']['item'] = array();
+$a_suppress = &$config['installedpackages']['suricata']['suppress']['item'];
+$id_gen = count($config['installedpackages']['suricata']['suppress']['item']);
+
+function suricata_suppresslist_used($supplist) {
+
+ /****************************************************************/
+ /* This function tests if the passed Suppress List is currently */
+ /* assigned to an interface. It returns TRUE if the list is */
+ /* in use. */
+ /* */
+ /* Returns: TRUE if list is in use, else FALSE */
+ /****************************************************************/
+
+ global $config;
+
+ $suricataconf = $config['installedpackages']['suricata']['rule'];
+ if (empty($suricataconf))
+ return false;
+ foreach ($suricataconf as $value) {
+ if ($value['suppresslistname'] == $supplist)
+ return true;
+ }
+ return false;
+}
+
+if ($_GET['act'] == "del") {
+ if ($a_suppress[$_GET['id']]) {
+ // make sure list is not being referenced by any Suricata-configured interface
+ if (suricata_suppresslist_used($a_suppress[$_GET['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();
+ header("Location: /suricata/suricata_suppress.php");
+ exit;
+ }
+ }
+}
+
+$pgtitle = gettext("Suricata: Suppression Lists");
+include_once("head.inc");
+
+?>
+
+<body link="#000000" vlink="#000000" alink="#000000">
+
+<?php
+include_once("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+if ($input_errors) {
+ print_input_errors($input_errors);
+}
+
+?>
+
+<form action="/suricata/suricata_suppress.php" method="post"><?php if ($savemsg) 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("Global Settings"), false, "/suricata/suricata_global.php");
+ $tab_array[] = array(gettext("Update Rules"), false, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$instanceid}");
+ $tab_array[] = array(gettext("Suppress"), true, "/suricata/suricata_suppress.php");
+ $tab_array[] = array(gettext("Logs Browser"), false, "/suricata/suricata_logs_browser.php");
+ display_top_tabs($tab_array);
+?>
+</td>
+</tr>
+<tr><td><div id="mainarea">
+<table id="maintable" class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+ <td width="30%" class="listhdrr"><?php echo gettext("File Name"); ?></td>
+ <td width="60%" class="listhdr"><?php echo gettext("Description"); ?></td>
+ <td width="10%" class="list"></td>
+</tr>
+<?php $i = 0; foreach ($a_suppress as $list): ?>
+<tr>
+ <td class="listlr"
+ ondblclick="document.location='suricata_suppress_edit.php?id=<?=$i;?>';">
+ <?=htmlspecialchars($list['name']);?></td>
+ <td class="listbg"
+ ondblclick="document.location='suricata_suppress_edit.php?id=<?=$i;?>';">
+ <font color="#FFFFFF"> <?=htmlspecialchars($list['descr']);?>&nbsp;</font>
+ </td>
+
+ <td valign="middle" nowrap class="list">
+ <table border="0" cellspacing="0" cellpadding="1">
+ <tr>
+ <td valign="middle"><a
+ href="suricata_suppress_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 Suppress List"); ?>"></a></td>
+ <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>
+ </tr>
+ </table>
+ </td>
+</tr>
+<?php $i++; endforeach; ?>
+<tr>
+ <td class="list" colspan="2"></td>
+ <td class="list">
+ <table border="0" cellspacing="0" cellpadding="1">
+ <tr>
+ <td valign="middle" width="17">&nbsp;</td>
+ <td valign="middle"><a
+ href="suricata_suppress_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 a new list"); ?>"></a></td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+</div>
+</td></tr>
+<tr>
+ <td colspan="3" width="100%"><br/><span class="vexpl"><span class="red"><strong><?php echo gettext("Note:"); ?></strong></span>
+ <p><?php echo gettext("Here you can create event filtering and " .
+ "suppression for your Suricata package rules."); ?><br/><br/>
+ <?php echo gettext("Please note that you must restart a running Interface so that changes can " .
+ "take effect."); ?></p></span></td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/suricata/suricata_suppress_edit.php b/config/suricata/suricata_suppress_edit.php
new file mode 100644
index 00000000..c2c23f10
--- /dev/null
+++ b/config/suricata/suricata_suppress_edit.php
@@ -0,0 +1,213 @@
+<?php
+/*
+ * suricata_suppress_edit.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("guiconfig.inc");
+require_once("/usr/local/pkg/suricata/suricata.inc");
+
+
+if (!is_array($config['installedpackages']['suricata']))
+ $config['installedpackages']['suricata'] = array();
+$suricataglob = $config['installedpackages']['suricata'];
+
+if (!is_array($config['installedpackages']['suricata']['suppress']))
+ $config['installedpackages']['suricata']['suppress'] = array();
+if (!is_array($config['installedpackages']['suricata']['suppress']['item']))
+ $config['installedpackages']['suricata']['suppress']['item'] = array();
+$a_suppress = &$config['installedpackages']['suricata']['suppress']['item'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+ $id = $_POST['id'];
+
+/* returns true if $name is a valid name for a whitelist file name or ip */
+function is_validwhitelistname($name) {
+ if (!is_string($name))
+ return false;
+
+ if (!preg_match("/[^a-zA-Z0-9\_\.\/]/", $name))
+ return true;
+
+ return false;
+}
+
+if (isset($id) && $a_suppress[$id]) {
+
+ /* old settings */
+ $pconfig['name'] = $a_suppress[$id]['name'];
+ $pconfig['uuid'] = $a_suppress[$id]['uuid'];
+ $pconfig['descr'] = $a_suppress[$id]['descr'];
+ if (!empty($a_suppress[$id]['suppresspassthru'])) {
+ $pconfig['suppresspassthru'] = base64_decode($a_suppress[$id]['suppresspassthru']);
+ $pconfig['suppresspassthru'] = str_replace("&#8203;", "", $pconfig['suppresspassthru']);
+ }
+ if (empty($a_suppress[$id]['uuid']))
+ $pconfig['uuid'] = uniqid();
+}
+
+if ($_POST['submit']) {
+ unset($input_errors);
+ $pconfig = $_POST;
+
+ $reqdfields = explode(" ", "name");
+ $reqdfieldsn = array("Name");
+ do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+
+ if(strtolower($_POST['name']) == "defaultwhitelist")
+ $input_errors[] = "Whitelist file names may not be named defaultwhitelist.";
+
+ if (is_validwhitelistname($_POST['name']) == false)
+ $input_errors[] = "Whitelist 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_suppress as $s_list) {
+ if (isset($id) && ($a_suppress[$id]) && ($a_suppress[$id] === $s_list))
+ continue;
+
+ if ($s_list['name'] == $_POST['name']) {
+ $input_errors[] = "A whitelist file name with this name already exists.";
+ break;
+ }
+ }
+
+
+ if (!$input_errors) {
+ $s_list = array();
+ $s_list['name'] = $_POST['name'];
+ $s_list['uuid'] = uniqid();
+ $s_list['descr'] = mb_convert_encoding($_POST['descr'],"HTML-ENTITIES","auto");
+ if ($_POST['suppresspassthru']) {
+ $s_list['suppresspassthru'] = str_replace("&#8203;", "", $s_list['suppresspassthru']);
+ $s_list['suppresspassthru'] = base64_encode($_POST['suppresspassthru']);
+ }
+
+ if (isset($id) && $a_suppress[$id])
+ $a_suppress[$id] = $s_list;
+ else
+ $a_suppress[] = $s_list;
+
+ write_config();
+ sync_suricata_package_config();
+
+ header("Location: /suricata/suricata_suppress.php");
+ exit;
+ }
+}
+
+$pgtitle = gettext("Suricata: Suppression List Edit - {$a_suppress[$id]['name']}");
+include_once("head.inc");
+
+?>
+
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+
+<?php
+include("fbegin.inc");
+if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';}
+
+if ($input_errors) print_input_errors($input_errors);
+if ($savemsg)
+ print_info_box($savemsg);
+
+?>
+<form action="/suricata/suricata_suppress_edit.php" name="iform" id="iform" method="post">
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<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("Update Rules"), false, "/suricata/suricata_download_updates.php");
+ $tab_array[] = array(gettext("Alerts"), false, "/suricata/suricata_alerts.php?instance={$instanceid}");
+ $tab_array[] = array(gettext("Suppress"), true, "/suricata/suricata_suppress.php");
+ display_top_tabs($tab_array);
+?>
+</td></tr>
+<tr><td><div id="mainarea">
+<table id="maintable" class="tabcont" width="100%" border="0" cellpadding="6" cellspacing="0">
+<tr>
+ <td colspan="2" class="listtopic">Add the name and description of the file.</td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncellreq"><?php echo gettext("Name"); ?></td>
+ <td width="78%" class="vtable"><input name="name" type="text" id="name"
+ class="formfld unknown" size="40" value="<?=htmlspecialchars($pconfig['name']);?>" /> <br />
+ <span class="vexpl"> <?php echo gettext("The list name may only consist of the " .
+ "characters \"a-z, A-Z, 0-9 and _\"."); ?>&nbsp;&nbsp;<span class="red"><?php echo gettext("Note:"); ?> </span>
+ <?php echo gettext("No Spaces or dashes."); ?> </span></td>
+</tr>
+<tr>
+ <td width="22%" valign="top" class="vncell"><?php echo gettext("Description"); ?></td>
+ <td width="78%" class="vtable"><input name="descr" type="text"
+ class="formfld unknown" id="descr" size="40" value="<?=$pconfig['descr'];?>" /> <br />
+ <span class="vexpl"> <?php echo gettext("You may enter a description here for your " .
+ "reference (not parsed)."); ?> </span></td>
+</tr>
+<tr>
+ <td colspan="2" align="center" height="30px">
+ <font size="2"><span class="red"><strong><?php echo gettext("NOTE:"); ?></strong></span></font>
+ <font color='#000000'>&nbsp;<?php echo gettext("The threshold keyword " .
+ "is deprecated as of version 2.8.5. Use the event_filter keyword " .
+ "instead."); ?></font>
+ </td>
+</tr>
+<tr>
+ <td colspan="2" valign="top" class="listtopic"><?php echo gettext("Apply suppression or " .
+ "filters to rules. Valid keywords are 'suppress', 'event_filter' and 'rate_filter'."); ?></td>
+</tr>
+<tr>
+<td colspan="2" valign="top" class="vncell"><b><?php echo gettext("Example 1;"); ?></b>
+ suppress gen_id 1, sig_id 1852, track by_src, ip 10.1.1.54<br/>
+ <b><?php echo gettext("Example 2;"); ?></b> event_filter gen_id 1, sig_id 1851, type limit,
+ track by_src, count 1, seconds 60<br/>
+ <b><?php echo gettext("Example 3;"); ?></b> rate_filter gen_id 135, sig_id 1, track by_src,
+ count 100, seconds 1, new_action log, timeout 10</td>
+</tr>
+<tr>
+ <td colspan="2" class="vtable"><textarea wrap="off" style="width:100%; height:100%;"
+ name="suppresspassthru" cols="90" rows="26" id="suppresspassthru" class="formpre"><?=htmlspecialchars($pconfig['suppresspassthru']);?></textarea>
+ </td>
+</tr>
+<tr>
+ <td colspan="2"><input id="submit" name="submit" type="submit"
+ class="formbtn" value="Save" />&nbsp;&nbsp;<input id="cancelbutton"
+ name="cancelbutton" type="button" class="formbtn" value="Cancel"
+ onclick="history.back();"/> <?php if (isset($id) && $a_suppress[$id]): ?>
+ <input name="id" type="hidden" value="<?=$id;?>"/> <?php endif; ?>
+ </td>
+</tr>
+</table>
+</div>
+</td></tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
+<script type="text/javascript">
+Rounded("div#redbox","all","#FFF","#E0E0E0","smooth");
+</script>
+</body>
+</html>
diff --git a/config/suricata/suricata_uninstall.php b/config/suricata/suricata_uninstall.php
new file mode 100644
index 00000000..071a89a4
--- /dev/null
+++ b/config/suricata/suricata_uninstall.php
@@ -0,0 +1,90 @@
+<?php
+/*
+ suricata_uninstall.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("/usr/local/pkg/suricata/suricata.inc");
+
+global $config, $g;
+
+$suricatadir = SURICATADIR;
+$suricatalogdir = SURICATALOGDIR;
+$rcdir = RCFILEPREFIX;
+$suricata_rules_upd_log = RULES_UPD_LOGFILE;
+
+log_error(gettext("[Suricata] Suricata package uninstall in progress..."));
+
+/* Make sure all active Suricata processes are terminated */
+/* Log a message only if a running process is detected */
+if (is_service_running("suricata"))
+ log_error(gettext("[Suricata] Suricata STOP for all interfaces..."));
+killbyname("suricata");
+sleep(1);
+
+// Delete any leftover suricata PID files in /var/run
+array_map('@unlink', glob("/var/run/suricata_*.pid"));
+
+/* Make sure all active Barnyard2 processes are terminated */
+/* Log a message only if a running process is detected */
+if (is_service_running("barnyard2"))
+ log_error(gettext("[Suricata] Barnyard2 STOP for all interfaces..."));
+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);
+
+/* 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);
+
+/* 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}");
+}
+
+/* Remove the Suricata GUI app directories */
+@unlink("/usr/local/pkg/suricata");
+@unlink("/usr/local/www/suricata");
+
+/* 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(SURICATALOGDIR);
+ 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
new file mode 100644
index 00000000..e62c48eb
--- /dev/null
+++ b/config/suricata/suricata_yaml_template.inc
@@ -0,0 +1,302 @@
+<?php
+
+// This is the template used to generate the suricata.yaml
+// configuration file for the interface. The contents of
+// this file are written to the suricata.yaml file for
+// the interface. Key parameters are provided by the
+// included string variables.
+
+ $suricata_conf_text = <<<EOD
+%YAML 1.1
+---
+
+max-pending-packets: {$max_pend_pkts}
+
+# Runmode the engine should use.
+runmode: autofp
+
+# Specifies the kind of flow load balancer used by the flow pinned autofp mode.
+autofp-scheduler: active-packets
+
+# Daemon working directory
+daemon-directory: {$suricatacfgdir}
+
+default-packet-size: 1514
+
+# The default logging directory.
+default-log-dir: {$suricatalogdir}suricata_{$if_real}{$suricata_uuid}
+
+# Configure the type of alert (and other) logging.
+outputs:
+
+ # a line based alerts log similar to Snort's fast.log
+ - fast:
+ enabled: yes
+ filename: alerts.log
+ append: yes
+ filetype: regular
+
+ # alert output for use with Barnyard2
+ - unified2-alert:
+ enabled: {$barnyard2_enabled}
+ filename: unified2.alert
+ limit: 32mb
+ # Sensor ID field of unified2 alerts.
+ sensor-id: 0
+
+ - http-log:
+ 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"
+ filetype: regular
+
+ - pcap-log:
+ enabled: {$pcap_log_enabled}
+ filename: log.pcap
+ limit: {$pcap_log_limit_size}mb
+ max-files: {$pcap_log_max_files}
+ mode: normal
+
+ - tls-log:
+ enabled: {$tls_log_enabled}
+ filename: tls.log
+ extended: {$tls_log_extended}
+ certs-log-dir: certs
+
+ - stats:
+ enabled: {$stats_log_enabled}
+ filename: stats.log
+ interval: {$stats_upd_interval}
+ append: {$stats_log_append}
+
+ - syslog:
+ enabled: {$alert_syslog}
+ identity: suricata
+ facility: auth
+ level: Info
+
+ - drop:
+ enabled: no
+ filename: drop.log
+ append: yes
+ filetype: regular
+
+ - file-store:
+ enabled: {$file_store_enabled}
+ log-dir: files
+ force-magic: no
+ force-md5: no
+ waldo: file.waldo
+
+ - file-log:
+ enabled: {$json_log_enabled}
+ filename: files-json.log
+ append: {$json_log_append}
+ filetype: regular
+ force-magic: {$json_log_magic}
+ force-md5: {$json_log_md5}
+
+# Magic file. The extension .mgc is added to the value here.
+magic-file: {$suricatacfgdir}/magic
+
+# Specify a threshold config file
+threshold-file: {$suricatacfgdir}/threshold.config
+
+detect-engine:
+ - profile: {$detect_eng_profile}
+ - sgh-mpm-context: {$sgh_mpm_ctx}
+ - inspection-recursion-limit: {$inspection_recursion_limit}
+ - rule-reload: true
+ - delayed-detect: yes
+
+# Suricata is multi-threaded. Here the threading can be influenced.
+threading:
+ set-cpu-affinity: no
+ detect-thread-ratio: 1.5
+
+mpm-algo: ac
+
+pattern-matcher:
+ - b2gc:
+ search-algo: B2gSearchBNDMq
+ hash-size: low
+ bf-size: medium
+ - b2gm:
+ search-algo: B2gSearchBNDMq
+ hash-size: low
+ bf-size: medium
+ - b2g:
+ search-algo: B2gSearchBNDMq
+ hash-size: low
+ bf-size: medium
+ - b3g:
+ search-algo: B3gSearchBNDMq
+ hash-size: low
+ bf-size: medium
+ - wumanber:
+ hash-size: low
+ bf-size: medium
+
+# Defrag settings:
+defrag:
+ memcap: {$frag_memcap}
+ hash-size: {$frag_hash_size}
+ trackers: {$ip_max_trackers}
+ max-frags: {$ip_max_frags}
+ prealloc: yes
+ timeout: {$ip_frag_timeout}
+
+# Flow settings:
+flow:
+ memcap: {$flow_memcap}
+ hash-size: {$flow_hash_size}
+ prealloc: {$flow_prealloc}
+ emergency-recovery: {$flow_emerg_recovery}
+ prune-flows: {$flow_prune}
+
+# Specific timeouts for flows.
+flow-timeouts:
+ default:
+ new: 30
+ established: 300
+ closed: 0
+ emergency-new: 10
+ emergency-established: 100
+ emergency-closed: 0
+ tcp:
+ new: {$flow_tcp_new_timeout}
+ established: {$flow_tcp_established_timeout}
+ closed: {$flow_tcp_closed_timeout}
+ emergency-new: {$flow_tcp_emerg_new_timeout}
+ emergency-established: {$flow_tcp_emerg_established_timeout}
+ emergency-closed: {$flow_tcp_emerg_closed_timeout}
+ udp:
+ new: {$flow_udp_new_timeout}
+ established: {$flow_udp_established_timeout}
+ emergency-new: {$flow_udp_emerg_new_timeout}
+ emergency-established: {$flow_udp_emerg_established_timeout}
+ icmp:
+ new: {$flow_icmp_new_timeout}
+ established: {$flow_icmp_established_timeout}
+ emergency-new: {$flow_icmp_emerg_new_timeout}
+ emergency-established: {$flow_icmp_emerg_established_timeout}
+
+stream:
+ memcap: {$stream_memcap}
+ checksum-validation: no
+ inline: auto
+ max-sessions: {$stream_max_sessions}
+ prealloc-sessions: {$stream_prealloc_sessions}
+ midstream: {$stream_enable_midstream}
+ async-oneside: {$stream_enable_async}
+
+reassembly:
+ memcap: {$reassembly_memcap}
+ depth: {$reassembly_depth}
+ toserver-chunk-size: {$reassembly_to_server_chunk}
+ toclient-chunk-size: {$reassembly_to_client_chunk}
+
+# Host table is used by tagging and per host thresholding subsystems.
+host:
+ hash-size: 4096
+ prealloc: 1000
+ memcap: 16777216
+
+# Host specific policies for defragmentation and TCP stream reassembly.
+host-os-policy:
+ {$host_os_policy}
+
+# Logging configuration. This is not about logging IDS alerts, but
+# IDS output about what its doing, errors, etc.
+logging:
+
+ # This value is overriden by the SC_LOG_LEVEL env var.
+ default-log-level: info
+ default-log-format: "%t - <%d> -- "
+
+ # Define your logging outputs.
+ outputs:
+ - console:
+ enabled: yes
+ - file:
+ enabled: yes
+ filename: {$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/suricata.log
+ - syslog:
+ enabled: {$suricata_use_syslog}
+ facility: auth
+ format: "[%i] <%d> -- "
+
+pcap:
+ - interface: {$if_real}
+ checksum-checks: auto
+
+# For FreeBSD ipfw(8) divert(4) support.
+# ipfw add 100 divert 8000 ip from any to any
+#
+# The 8000 above should be the same number you passed on the command
+# line, i.e. -d 8000
+#
+#ipfw:
+
+default-rule-path: {$suricatacfgdir}/rules
+rule-files:
+ - {$rules_files}
+
+classification-file: {$suricatacfgdir}/classification.config
+reference-config-file: {$suricatacfgdir}/reference.config
+
+# Holds variables that would be used by the engine.
+vars:
+
+ # Holds the address group vars that would be passed in a Signature.
+ address-groups:
+ HOME_NET: "[{$home_net}]"
+ EXTERNAL_NET: "{$external_net}"
+ {$addr_vars}
+
+ # Holds the port group vars that would be passed in a Signature.
+ port-groups:
+ {$port_vars}
+
+# Set the order of alerts bassed 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
+
+# Limit for the maximum number of asn1 frames to decode (default 256)
+asn1-max-frames: {$asn1_max_frames}
+
+engine-analysis:
+ rules-fast-pattern: yes
+ rules: yes
+
+#recursion and match limits for PCRE where supported
+pcre:
+ match-limit: 3500
+ match-limit-recursion: 1500
+
+###########################################################################
+# Configure libhtp.
+libhtp:
+ default-config:
+ {$http_hosts_default_policy}
+
+ {$http_hosts_policy}
+
+coredump:
+ max-dump: unlimited
+
+EOD;
+
+?>