diff options
Diffstat (limited to 'config/suricata')
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> <?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.'); ?> <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>'); ?> + <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); ?> + <?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(":", ":​", $alert_ip_src); + /* Add Reverse DNS lookup icons */ + $alert_ip_src .= "<br/><a onclick=\"javascript:getURL('/diag_dns.php?host={$fields[9]}&dialog_output=true', outputrule);\">"; + $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_log_d.gif' width='11' height='11' border='0' "; + $alert_ip_src .= "title='" . gettext("Resolve host via reverse DNS lookup (quick pop-up)") . "' style=\"cursor: pointer;\"></a> "; + $alert_ip_src .= "<a href='/diag_dns.php?host={$fields[9]}&instance={$instanceid}'>"; + $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; + $alert_ip_src .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && + !isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { + $alert_ip_src .= " <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 .= " <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 .= " "; + $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(":", ":​", $alert_ip_dst); + /* Add Reverse DNS lookup icons */ + $alert_ip_dst .= "<br/><a onclick=\"javascript:getURL('/diag_dns.php?host={$fields[11]}&dialog_output=true', outputrule);\">"; + $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_log_d.gif' width='11' height='11' border='0' "; + $alert_ip_dst .= "title='" . gettext("Resolve host via reverse DNS lookup (quick pop-up)") . "' style=\"cursor: pointer;\"></a> "; + $alert_ip_dst .= "<a href='/diag_dns.php?host={$fields[11]}&instance={$instanceid}'>"; + $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; + $alert_ip_dst .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && + !isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[1]])) { + $alert_ip_dst .= " <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 .= " <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 .= " "; + $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} {$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']);?>"> + <?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"> </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;?>"> + <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"> </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']);?>"/> + <?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']);?>"/> + <?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']);?>"/> + <?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']);?>"/> + <?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']);?>"/> + <?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"); ?> <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"); ?> + <?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']);?>"/> + <?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']);?>"/> + <?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"); ?> <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"); ?> + <?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> + <?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> + <?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"> </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"> </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"> </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;?> ---></b></td> + <td class="vexpl"><? echo $emergingt_net_sig_chk_local; ?></td> + </tr> + <tr> + <td align="right" class="vexpl"><b>SNORT VRT RULES ---></b></td> + <td class="vexpl"><? echo $snort_org_sig_chk_local; ?></td> + </tr> + <td align="right" class="vexpl"><b>SNORT GPLv2 COMMUNITY RULES ---></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"> + <?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"); ?>"/> + + <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> <?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> + <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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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']);?>"> + <?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"> </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;?>"> + <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"> </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> </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> </td> + <td class="vexpl"><?php echo "<span class='red'><strong>" . gettext("Note:") . "</strong></span>" . " " . + gettext("The ETPro rules contain all of the ETOpen rules, so the ETOpen rules are not required and are disabled when the ETPro rules are selected."); ?></td> + </tr> + </table> + <table id="etpro_code_tbl" width="100%" border="0" cellpadding="2" cellspacing="0"> + <tr> + <td colspan="2"> </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> </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"> </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"> <?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"> + <?php echo gettext("Enter the rule update start time in 24-hour format (HH:MM). ") . "<strong>" . + gettext("Default") . " </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; ?> 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>";?> + <input name="suricataloglimitsize" type="text" class="formfld unknown" id="suricataloglimitsize" size="10" value="<?=htmlspecialchars($pconfig['suricataloglimitsize']);?>"> + <?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> + <?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"; ?> + > <?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"; ?> + > <?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"; ?> + > <?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"> </td> + <td width="78%" class="vexpl"><span class="red"><strong><?php echo gettext("Note:");?></strong> + </span><?php echo gettext("Changing any settings on this page will affect all Suricata-configured interfaces.");?></td> +</tr> + </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;?> + </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");?>"/> + <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"> </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) ? " <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']);?> </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">   <?php echo gettext("WARNING: Marked interface currently has no rules defined for Suricata"); ?></span> + <?php else: ?> + <?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"> </td> + </tr> + <tr> + <td> </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"> + </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%"> + </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> </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> + <span class="vexpl"><?php echo gettext("Choose which interface this Suricata instance applies to."); ?><br/> + <span class="red"><?php echo gettext("Hint:"); ?></span> <?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']); ?>"/> + <?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']); ?>"/> + <?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']); ?>"/> + <?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> + <?php echo gettext("Select which IP extracted from the packet you wish to block."); ?><br/> + <span class="red"><?php echo gettext("Hint:") . "</span> " . gettext("Choosing BOTH is suggested, and it is the default value."); ?></span><br/></td> + </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']); ?>"/> + <?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> + <?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> + <?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> + <?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']); ?>"/> + <?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> + <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> <?php echo gettext("Default Home " . + "Net adds only local networks, WAN IPs, Gateways, VPNs and VIPs."); ?><br/> + <span class="red"><?php echo gettext("Hint:"); ?></span> <?php echo gettext("Create an Alias to hold a list of " . + "friendly IPs that the firewall cannot see or to customize the default Home Net."); ?><br/> + </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> + <?php echo gettext("Choose the External Net you want this interface " . + "to use."); ?> <br/><br/> + <span class="red"><?php echo gettext("Note:"); ?></span> <?php echo gettext("Default " . + "External Net is networks that are not Home Net."); ?><br/> + <span class="red"><?php echo gettext("Hint:"); ?></span> <?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> + <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> <?php echo gettext("This option will only be used when block offenders is on."); ?><br/> + <span class="red"><?php echo gettext("Hint:"); ?></span> <?php echo gettext("Default " . + "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> + <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/> <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"> </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";?>> + <?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"> + <?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> + <?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> <?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']);?>"> + <?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']);?>"> + <?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"> </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"); ?>"> + + <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> ' . $_GET['wlist']; ?> + </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> <?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> <?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";?>> + <?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"> + <?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'.");?> + + <?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> + <?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> <?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"> </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"); ?>"> + + <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> <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> <?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"); ?>"/> + <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"); ?>"/> + <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>"?> + <?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>"?> + <?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>"?> + <?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>"?> + <?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> + <?php echo gettext("View full file contents for the current Category"); ?></td> + </tr> + + <?php if ($currentruleset == 'Auto-Flowbit Rules'): ?> + <tr> + <td colspan="3"> </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"> </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}") . " " . + gettext("Enabled: {$enable_cnt}") . " " . + 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> ' . $displayfile; ?> + </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} {$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"; ?>/> + <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"> </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; ?>/> + <span class="vexpl"><?php echo gettext("Click to view auto-enabled rules required to satisfy flowbit dependencies"); ?></span></td> + </tr> + <tr> + <td width="15%"> </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()"/> <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"> </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> + <span class="vexpl"><?php echo gettext("Snort IPS policies are: Connectivity, Balanced or Security."); ?></span></td> + </tr> + <tr id="ips_row2"> + <td width="15%"> </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"> <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;?> + </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");?>"/> + <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']);?> </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"> </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("​", "", $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("​", "", $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 _\"."); ?> <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'> <?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" /> <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; + +?> |