aboutsummaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/snort-dev/snort.inc14
-rw-r--r--config/snort/bin/oinkmaster_contrib/oinkmaster.pl2754
-rw-r--r--config/snort/pfsense_rules/local.rules7
-rw-r--r--config/snort/pfsense_rules/pfsense_rules.tar.gz.md52
-rw-r--r--config/snort/pfsense_rules/rules/pfsense-voip.rules11
-rwxr-xr-xconfig/snort/snort.inc425
-rw-r--r--config/snort/snort.xml142
-rw-r--r--config/snort/snort_advanced.xml12
-rw-r--r--config/snort/snort_check_for_rule_updates.php657
-rw-r--r--config/snort/snort_download_rules.php345
-rw-r--r--config/snort/snort_dynamic_ip_reload.php5
-rw-r--r--config/snort/snort_rules.php63
12 files changed, 4152 insertions, 285 deletions
diff --git a/config/snort-dev/snort.inc b/config/snort-dev/snort.inc
index 3b13ba14..ebcab85c 100644
--- a/config/snort-dev/snort.inc
+++ b/config/snort-dev/snort.inc
@@ -88,8 +88,6 @@ function sync_package_snort()
exec("/bin/cp /usr/local/etc/snort/threshold.conf-sample /usr/local/etc/snort/threshold.conf");
exec("/bin/cp /usr/local/etc/snort/unicode.map-sample /usr/local/etc/snort/unicode.map");
exec("/bin/rm -f /usr/local/etc/rc.d/snort");
- exec("/bin/rm /tmp/snort_download_halt.pid");
- exec("/bin/rm /tmp/snort.sh.pid");
$first = 0;
$snortInterfaces = array(); /* -gtm */
@@ -147,34 +145,32 @@ function sync_package_snort()
/* TODO; get snort to start under nologin shell */
foreach($snortInterfaces as $snortIf)
{
- $start .= "sleep 8\n";
+ $start .= "sleep 4\n";
$start .= "snort -c /usr/local/etc/snort/snort.conf -l /var/log/snort -D -i {$snortIf} -q\n";
/* define snortbarnyardlog_chk */
$snortbarnyardlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog'];
if ($snortbarnyardlog_info_chk == on)
$start .= "\nsleep 4;barnyard2 -c /usr/local/etc/barnyard2.conf -d /var/log/snort -f snort.u2 -w /usr/local/etc/snort/barnyard2.waldo -D -q\n";
}
- $check_if_snort_runs = "\nif [ \"`pgrep -x snort`\" != \"\" ] ; then\n\tlogger -p daemon.info -i -t SnortStartup \"Snort already running...\"\n/usr/local/bin/php -f /usr/local/pkg/pf/snort_dynamic_ip_reload.php\n\texit 1\nfi\n\n";
+ $check_if_snort_runs = "\n\tif [ \"`ls -A /usr/local/etc/snort/rules`\" ] ; then\n\techo \"rules exist\"\n\telse\n\techo \"rules DONT exist\"\n\texit 2\n\tfi \n\n\tif [ \"`pgrep -x snort`\" = \"\" ] ; then\n\t/bin/rm /tmp/snort.sh.pid\n\tfi \n\n\tif [ \"`pgrep -x snort`\" != \"\" ] ; then\n\tlogger -p daemon.info -i -t SnortStartup \"Snort already running...\"\n\t/usr/local/bin/php -f /usr/local/pkg/pf/snort_dynamic_ip_reload.php\n\texit 1\n\tfi\n\n";
$if_snort_pid = "\nif ls /tmp/snort.sh.pid > /dev/null\nthen\n echo \"snort.sh is running\"\n exit 0\nelse\n echo \"snort.sh is not running\"\nfi\n";
$echo_snort_sh_pid = "\necho \"snort.sh run\" > /tmp/snort.sh.pid\n";
$echo_snort_sh_startup_log = "\necho \"snort.sh run\" >> /tmp/snort.sh_startup.log\n";
$del_old_pids = "\nrm -f /var/run/snort_*\n";
$sample_before = "BEFORE_MEM=`top | grep Wired | awk '{print \$12}'`\n";
- $sample_after = "AFTER_MEM=`top | grep Wired | awk '{print \$12}'`\n";
+ $sample_after = "\n\tAFTER_MEM=`top | grep Wired | awk '{print \$12}'`\n";
if ($snort_performance == "ac-bnfa")
$sleep_before_final = "\necho \"Sleeping before final memory sampling...\"\nWAITSECURE=60\n";
else
$sleep_before_final = "\necho \"Sleeping before final memory sampling...\"\nWAITSECURE=300\n";
$sleep_before_final .= "while [ \"\$MYSNORTLOG\" = \"\" -a \$WAITSECURE -gt 0 ] ; do\n\tsleep 2\n\tMYSNORTLOG=`/usr/sbin/clog /var/log/system.log | grep snort | tail | grep 'Snort initialization completed successfully'`\n\tWAITSECURE=`expr \$WAITSECURE - 1`\ndone\n";
$total_used_after = "TOTAL_USAGE=`top | grep snort | grep -v grep | awk '{ print \$6 }'`\n";
- $echo_usage = "\nif [ \$WAITSECURE -eq 0 -a \"\$MYSNORTLOG\" = \"\" ] ; then\n\techo \"Snort has not finished starting, please check log for possible errors.\"\n";
- $echo_usage .= "else\n\t" . $sample_after . "\t" . $total_used_after . "\techo \"Ram free BEFORE starting Snort: \$BEFORE_MEM -- Ram free AFTER starting Snort: \$AFTER_MEM -- Mode " . $snort_performance . " -- Snort memory usage: \$TOTAL_USAGE\" | logger -p daemon.info -i -t SnortStartup\nfi\n";
- $rm_snort_sh_pid = "\nrm /tmp/snort.sh.pid\n";
+ $echo_usage .= $sample_after . "\t" . $total_used_after . "\techo \"Ram free BEFORE starting Snort: \$BEFORE_MEM -- Ram free AFTER starting Snort: \$AFTER_MEM -- Mode " . $snort_performance . " -- Snort memory usage: \$TOTAL_USAGE\" | logger -p daemon.info -i -t SnortStartup\n\n";
/* write out rc.d start/stop file */
write_rcfile(array(
"file" => "snort.sh",
- "start" => "{$check_if_snort_runs}{$if_snort_pid}{$echo_snort_sh_pid}{$echo_snort_sh_startup_log}{$del_old_pids}{$sample_before}{$start}{$sleep_before_final}{$echo_usage}{$rm_snort_sh_pid}",
+ "start" => "{$check_if_snort_runs}{$if_snort_pid}{$echo_snort_sh_pid}{$echo_snort_sh_startup_log}{$del_old_pids}{$sample_before}{$start}{$sleep_before_final}{$echo_usage}",
"stop" => "/usr/bin/killall snort; killall barnyard2"
)
);
diff --git a/config/snort/bin/oinkmaster_contrib/oinkmaster.pl b/config/snort/bin/oinkmaster_contrib/oinkmaster.pl
new file mode 100644
index 00000000..f9c4d215
--- /dev/null
+++ b/config/snort/bin/oinkmaster_contrib/oinkmaster.pl
@@ -0,0 +1,2754 @@
+#!/usr/bin/perl -w
+
+# $Id: oinkmaster.pl,v 1.406 2006/02/10 13:02:44 andreas_o Exp $ #
+
+# Copyright (c) 2001-2006 Andreas Östling <andreaso@it.su.se>
+# 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.
+#
+# 3. Neither the name of the author nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+# CONTRIBUTORS "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 COPYRIGHT OWNER OR
+# CONTRIBUTORS 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.
+
+
+use 5.006001;
+
+use strict;
+use File::Basename;
+use File::Copy;
+use File::Path;
+use File::Spec;
+use Getopt::Long;
+use File::Temp qw(tempdir);
+
+sub show_usage();
+sub parse_cmdline($);
+sub read_config($ $);
+sub sanity_check();
+sub download_file($ $);
+sub unpack_rules_archive($ $ $);
+sub join_tmp_rules_dirs($ $ @);
+sub process_rules($ $ $ $ $ $);
+sub process_rule($ $ $ $ $ $ $ $);
+sub setup_rules_hash($ $);
+sub get_first_only($ $ $);
+sub print_changes($ $);
+sub print_changetype($ $ $ $);
+sub print_summary_change($ $);
+sub make_backup($ $);
+sub get_changes($ $ $);
+sub update_rules($ @);
+sub copy_rules($ $);
+sub is_in_path($);
+sub get_next_entry($ $ $ $ $ $);
+sub get_new_vars($ $ $ $);
+sub add_new_vars($ $);
+sub write_new_vars($ $);
+sub msdos_to_cygwin_path($);
+sub parse_mod_expr($ $ $ $);
+sub untaint_path($);
+sub approve_changes();
+sub parse_singleline_rule($ $ $);
+sub join_multilines($);
+sub minimize_diff($ $);
+sub catch_sigint();
+sub clean_exit($);
+
+
+my $VERSION = 'Oinkmaster v2.0, Copyright (C) 2001-2006 '.
+ 'Andreas Östling <andreaso@it.su.se>';
+my $OUTFILE = 'snortrules.tar.gz';
+my $RULES_DIR = 'rules';
+
+my $PRINT_NEW = 1;
+my $PRINT_OLD = 2;
+my $PRINT_BOTH = 3;
+
+my %config = (
+ careful => 0,
+ check_removed => 0,
+ config_test_mode => 0,
+ enable_all => 0,
+ interactive => 0,
+ make_backup => 0,
+ minimize_diff => 0,
+ min_files => 1,
+ min_rules => 1,
+ quiet => 0,
+ summary_output => 0,
+ super_quiet => 0,
+ update_vars => 0,
+ use_external_bins => 1,
+ verbose => 0,
+ use_path_checks => 1,
+ rule_actions => "alert|drop|log|pass|reject|sdrop|activate|dynamic",
+ tmp_basedir => $ENV{TMP} || $ENV{TMPDIR} || $ENV{TEMPDIR} || '/tmp',
+);
+
+
+# Regexp to match the start of a multi-line rule.
+# %ACTIONS% will be replaced with content of $config{actions} later.
+# sid and msg will then be looked for in parse_singleline_rule().
+my $MULTILINE_RULE_REGEXP = '^\s*#*\s*(?:%ACTIONS%)'.
+ '\s.*\\\\\s*\n$'; # ';
+
+# Regexp to match a single-line rule.
+# sid and msg will then be looked for in parse_singleline_rule().
+my $SINGLELINE_RULE_REGEXP = '^\s*#*\s*(?:%ACTIONS%)'.
+ '\s.+;\s*\)\s*$'; # ';
+
+# Match var line where var name goes into $1.
+my $VAR_REGEXP = '^\s*var\s+(\S+)\s+(\S+)';
+
+# Allowed characters in misc paths/filenames, including the ones in the tarball.
+my $OK_PATH_CHARS = 'a-zA-Z\d\ _\(\)\[\]\.\-+:\\\/~@,=';
+
+# Default locations for configuration file.
+my @DEFAULT_CONFIG_FILES = qw(
+ /etc/oinkmaster.conf
+ /usr/local/etc/oinkmaster.conf
+);
+
+my @DEFAULT_DIST_VAR_FILES = qw(
+ snort.conf
+);
+
+my (%loaded, $tmpdir);
+
+
+
+#### MAIN ####
+
+# No buffering.
+select(STDERR);
+$| = 1;
+select(STDOUT);
+$| = 1;
+
+
+my $start_date = scalar(localtime);
+
+# Assume the required Perl modules are available if we're on Windows.
+$config{use_external_bins} = 0 if ($^O eq "MSWin32");
+
+# Parse command line arguments and add at least %config{output_dir}.
+parse_cmdline(\%config);
+
+# If no config was specified on command line, look for one in default locations.
+if ($#{$config{config_files}} == -1) {
+ foreach my $config (@DEFAULT_CONFIG_FILES) {
+ if (-e "$config") {
+ push(@{${config{config_files}}}, $config);
+ last;
+ }
+ }
+}
+
+# If no dist var file was specified on command line, set to default file(s).
+if ($#{$config{dist_var_files}} == -1) {
+ foreach my $var_file (@DEFAULT_DIST_VAR_FILES) {
+ push(@{${config{dist_var_files}}}, $var_file);
+ }
+}
+
+# If config is still not defined, we can't continue.
+if ($#{$config{config_files}} == -1) {
+ clean_exit("configuration file not found in default locations\n".
+ "(@DEFAULT_CONFIG_FILES)\n".
+ "Put it there or use the \"-C <file>\" argument.");
+}
+
+read_config($_, \%config) for @{$config{config_files}};
+
+# Now substitute "%ACTIONS%" with $config{rule_actions}, which may have
+# been modified after reading the config file.
+$SINGLELINE_RULE_REGEXP =~ s/%ACTIONS%/$config{rule_actions}/;
+$MULTILINE_RULE_REGEXP =~ s/%ACTIONS%/$config{rule_actions}/;
+
+# If we're told not to use external binaries, load the Perl modules now.
+unless ($config{use_external_bins}) {
+ print STDERR "Loading Perl modules.\n" if ($config{verbose});
+
+ eval {
+ require IO::Zlib;
+ require Archive::Tar;
+ require LWP::UserAgent;
+ };
+
+ clean_exit("failed to load required Perl modules:\n\n$@\n".
+ "Install them or set use_external_bins to 1 ".
+ "if you want to use external binaries instead.")
+ if ($@);
+}
+
+
+# Do some basic sanity checking and exit if something fails.
+# A new PATH will be set.
+sanity_check();
+
+$SIG{INT} = \&catch_sigint;
+
+# Create temporary dir.
+$tmpdir = tempdir("oinkmaster.XXXXXXXXXX", DIR => File::Spec->rel2abs($config{tmp_basedir}))
+ or clean_exit("could not create temporary directory in $config{tmp_basedir}: $!");
+
+# If we're in config test mode and have come this far, we're done.
+if ($config{config_test_mode}) {
+ print "No fatal errors in configuration.\n";
+ clean_exit("");
+}
+
+umask($config{umask}) if exists($config{umask});
+
+# Download and unpack all the rules archives into separate tmp dirs.
+my @url_tmpdirs;
+foreach my $url (@{$config{url}}) {
+ my $url_tmpdir = tempdir("url.XXXXXXXXXX", DIR => $tmpdir)
+ or clean_exit("could not create temporary directory in $tmpdir: $!");
+ push(@url_tmpdirs, "$url_tmpdir/$RULES_DIR");
+ if ($url =~ /^dir:\/\/(.+)/) {
+ mkdir("$url_tmpdir/$RULES_DIR")
+ or clean_exit("Could not create $url_tmpdir/$RULES_DIR");
+ copy_rules($1, "$url_tmpdir/$RULES_DIR");
+ } else {
+ download_file($url, "$url_tmpdir/$OUTFILE");
+ unpack_rules_archive("$url", "$url_tmpdir/$OUTFILE", $RULES_DIR);
+ }
+}
+
+# Copy all rules files from the tmp dirs into $RULES_DIR in the tmp directory.
+# File matching 'skipfile' a directive will not be copied.
+# Filenames (with full path) will be stored as %new_files{filename}.
+# Will exit in case of duplicate filenames.
+my $num_files = join_tmp_rules_dirs("$tmpdir/$RULES_DIR", \my %new_files, @url_tmpdirs);
+
+# Make sure we have at least the minimum number of files.
+clean_exit("not enough rules files in downloaded rules archive(s).\n".
+ "Number of rules files is $num_files but minimum is set to $config{min_files}.")
+ if ($num_files < $config{min_files});
+
+# This is to read in possible 'localsid' rules.
+my %rh_tmp = setup_rules_hash(\%new_files, $config{output_dir});
+
+# Disable/modify/clean downloaded rules.
+my $num_rules = process_rules(\@{$config{sid_modify_list}},
+ \%{$config{sid_disable_list}},
+ \%{$config{sid_enable_list}},
+ \%{$config{sid_local_list}},
+ \%rh_tmp,
+ \%new_files);
+
+# Make sure we have at least the minimum number of rules.
+clean_exit("not enough rules in downloaded archive(s).\n".
+ "Number of rules is $num_rules but minimum is set to $config{min_rules}.")
+ if ($num_rules < $config{min_rules});
+
+# Setup a hash containing the content of all processed rules files.
+my %rh = setup_rules_hash(\%new_files, $config{output_dir});
+
+# Compare the new rules to the old ones.
+my %changes = get_changes(\%rh, \%new_files, $RULES_DIR);
+
+# Check for variables that exist in dist snort.conf(s) but not in local snort.conf.
+get_new_vars(\%changes, \@{$config{dist_var_files}}, $config{varfile}, \@url_tmpdirs)
+ if ($config{update_vars});
+
+
+# Find out if something had changed.
+my $something_changed = 0;
+
+$something_changed = 1
+ if (keys(%{$changes{modified_files}}) ||
+ keys(%{$changes{added_files}}) ||
+ keys(%{$changes{removed_files}}) ||
+ $#{$changes{new_vars}} > -1);
+
+
+# Update files listed in %changes{modified_files} (copy the new files
+# from the temporary directory into our output directory) and add new
+# variables to the local snort.conf if requested, unless we're running in
+# careful mode. Create backup first if running with -b.
+my $printed = 0;
+if ($something_changed) {
+ if ($config{careful}) {
+ print STDERR "Skipping backup since we are running in careful mode.\n"
+ if ($config{make_backup} && (!$config{quiet}));
+ } else {
+ if ($config{interactive}) {
+ print_changes(\%changes, \%rh);
+ $printed = 1;
+ }
+
+ if (!$config{interactive} || ($config{interactive} && approve_changes)) {
+ make_backup($config{output_dir}, $config{backup_dir})
+ if ($config{make_backup});
+
+ add_new_vars(\%changes, $config{varfile})
+ if ($config{update_vars});
+
+ update_rules($config{output_dir}, keys(%{$changes{modified_files}}));
+ }
+ }
+} else {
+ print STDERR "No files modified - no need to backup old files, skipping.\n"
+ if ($config{make_backup} && !$config{quiet});
+}
+
+print "\nOinkmaster is running in careful mode - not updating anything.\n"
+ if ($something_changed && $config{careful});
+
+print_changes(\%changes, \%rh)
+ if (!$printed && ($something_changed || !$config{quiet}));
+
+
+# Everything worked. Do a clean exit without any error message.
+clean_exit("");
+
+
+# END OF MAIN #
+
+
+
+# Show usage information and exit.
+sub show_usage()
+{
+ my $progname = basename($0);
+
+ print STDERR << "RTFM";
+
+$VERSION
+
+Usage: $progname -o <outdir> [options]
+
+<outdir> is where to put the new files.
+This should be the directory where you store your Snort rules.
+
+Options:
+-b <dir> Backup your old rules into <dir> before overwriting them
+-c Careful mode (dry run) - check for changes but do not update anything
+-C <file> Use this configuration file instead of the default
+ May be specified multiple times to load multiple files
+-e Enable all rules that are disabled by default
+-h Show this usage information
+-i Interactive mode - you will be asked to approve the changes (if any)
+-m Minimize diff when printing result by removing common parts in rules
+-q Quiet mode - no output unless changes were found
+-Q Super-quiet mode - like -q but even more quiet
+-r Check for rules files that exist in the output directory
+ but not in the downloaded rules archive
+-s Leave out details in rules results, just print SID, msg and filename
+-S <file> Look for new variables in this file in the downloaded archive instead
+ of the default (@DEFAULT_DIST_VAR_FILES). Used in conjunction with -U.
+ May be specified multiple times to search multiple files.
+-T Config test - just check configuration file(s) for errors/warnings
+-u <url> Download from this URL instead of URL(s) in the configuration file
+ (http|https|ftp|file|scp:// ... .tar.gz|.gz, or dir://<dir>)
+ May be specified multiple times to grab multiple rules archives
+-U <file> Merge new variables from downloaded snort.conf(s) into <file>
+-v Verbose mode (debug)
+-V Show version and exit
+
+RTFM
+ exit;
+}
+
+
+
+# Parse the command line arguments and exit if we don't like them.
+sub parse_cmdline($)
+{
+ my $cfg_ref = shift;
+
+ Getopt::Long::Configure("bundling");
+
+ my $cmdline_ok = GetOptions(
+ "b=s" => \$$cfg_ref{backup_dir},
+ "c" => \$$cfg_ref{careful},
+ "C=s" => \@{$$cfg_ref{config_files}},
+ "e" => \$$cfg_ref{enable_all},
+ "h" => \&show_usage,
+ "i" => \$$cfg_ref{interactive},
+ "m" => \$$cfg_ref{minimize_diff},
+ "o=s" => \$$cfg_ref{output_dir},
+ "q" => \$$cfg_ref{quiet},
+ "Q" => \$$cfg_ref{super_quiet},
+ "r" => \$$cfg_ref{check_removed},
+ "s" => \$$cfg_ref{summary_output},
+ "S=s" => \@{$$cfg_ref{dist_var_files}},
+ "T" => \$$cfg_ref{config_test_mode},
+ "u=s" => \@{$$cfg_ref{url}},
+ "U=s" => \$$cfg_ref{varfile},
+ "v" => \$$cfg_ref{verbose},
+ "V" => sub {
+ print "$VERSION\n";
+ exit(0);
+ }
+ );
+
+
+ show_usage unless ($cmdline_ok && $#ARGV == -1);
+
+ $$cfg_ref{quiet} = 1 if ($$cfg_ref{super_quiet});
+ $$cfg_ref{update_vars} = 1 if ($$cfg_ref{varfile});
+
+ if ($$cfg_ref{backup_dir}) {
+ $$cfg_ref{backup_dir} = File::Spec->canonpath($$cfg_ref{backup_dir});
+ $$cfg_ref{make_backup} = 1;
+ }
+
+ # Cannot specify dist var files without specifying var target file.
+ if (@{$$cfg_ref{dist_var_files}} && !$$cfg_ref{update_vars}) {
+ clean_exit("You can not specify distribution variable file(s) without ".
+ "also specifying local file to merge into");
+ }
+
+ # -o <dir> is the only required option in normal usage.
+ if ($$cfg_ref{output_dir}) {
+ $$cfg_ref{output_dir} = File::Spec->canonpath($$cfg_ref{output_dir});
+ } else {
+ warn("Error: no output directory specified.\n");
+ show_usage();
+ }
+
+ # Mark that url was set on command line (so we don't override it later).
+ $$cfg_ref{cmdline_url} = 1 if ($#{$config{url}} > -1);
+}
+
+
+
+# Read in stuff from the configuration file.
+sub read_config($ $)
+{
+ my $config_file = shift;
+ my $cfg_ref = shift;
+ my $linenum = 0;
+ my $multi;
+ my %templates;
+
+ $config_file = File::Spec->canonpath(File::Spec->rel2abs($config_file));
+
+ clean_exit("configuration file \"$config_file\" does not exist.\n")
+ unless (-e "$config_file");
+
+ clean_exit("\"$config_file\" is not a file.\n")
+ unless (-f "$config_file");
+
+ print STDERR "Loading $config_file\n"
+ unless ($config{quiet});
+
+ # Avoid loading the same file multiple times to avoid infinite recursion etc.
+ if ($^O eq "MSWin32") {
+ clean_exit("attempt to load \"$config_file\" twice.")
+ if ($loaded{$config_file}++);
+ } else {
+ my ($dev, $ino) = (stat($config_file))[0,1]
+ or clean_exit("unable to stat $config_file: $!");
+ clean_exit("attempt to load \"$config_file\" twice.")
+ if ($loaded{$dev, $ino}++);
+ }
+
+ open(CONF, "<", "$config_file")
+ or clean_exit("could not open configuration file \"$config_file\": $!");
+ my @conf = <CONF>;
+ close(CONF);
+
+ LINE:while ($_ = shift(@conf)) {
+ $linenum++;
+
+ unless ($multi) {
+ s/^\s*//;
+ s/^#.*//;
+ }
+
+ # Multi-line start/continuation.
+ if (/\\\s*\n$/) {
+ s/\\\s*\n$//;
+ s/^\s*#.*//;
+
+ # Be strict about removing #comments in modifysid/define_template statements, as
+ # they may contain other '#' chars.
+ if (defined($multi) && ($multi =~ /^modifysid/i || $multi =~ /^define_template/i)) {
+ s/#.*// if (/^\s*\d+[,\s\d]+#/);
+ } else {
+ s/\s*\#.*// unless (/^modifysid/i || /^define_template/i);
+ }
+
+ $multi .= $_;
+ next LINE;
+ }
+
+ # Last line of multi-line directive.
+ if (defined($multi)) {
+ $multi .= $_;
+ $_ = $multi;
+ undef($multi);
+ }
+
+ # Remove traling whitespaces (*after* a possible multi-line is rebuilt).
+ s/\s*$//;
+
+ # Remove comments unless it's a modifysid/define_template line
+ # (the "#" may be part of the modifysid expression).
+ s/\s*\#.*// unless (/^modifysid/i || /^define_template/i);
+
+ # Skip blank lines.
+ next unless (/\S/);
+
+ # Use a template and make $_ a "modifysid" line.
+ if (/^use_template\s+(\S+)\s+(\S+[^"]*)\s*(".*")*(?:#.*)*/i) {
+ my ($template_name, $sid, $args) = ($1, $2, $3);
+
+ if (exists($templates{$template_name})) {
+ my $template = $templates{$template_name}; # so we don't substitute %ARGx% globally
+
+ # Evaluate each "%ARGx%" in the template to the corresponding value.
+ if (defined($args)) {
+ my @args = split(/"\s+"/, $args);
+ foreach my $i (1 .. @args) {
+ $args[$i - 1] =~ s/^"//;
+ $args[$i - 1] =~ s/"$//;
+ $template =~ s/%ARG$i%/$args[$i - 1]/g;
+ }
+ }
+
+ # There should be no %ARGx% stuff left now.
+ if ($template =~ /%ARG\d%/) {
+ warn("WARNING: too few arguments for template \"$template_name\"\n");
+ $_ = "error"; # so it will be reported as an invalid line later
+ }
+
+ unless ($_ eq "error") {
+ $_ = "modifysid $sid $template\n";
+ print STDERR "Template \"$template_name\" expanded to: $_"
+ if ($config{verbose});
+ }
+
+ } else {
+ warn("WARNING: template \"$template_name\" has not been defined\n");
+ }
+ }
+
+ # new template definition.
+ if (/^define_template\s+(\S+)\s+(".+"\s+\|\s+".*")\s*(?:#.*)*$/i) {
+ my ($template_name, $template) = ($1, $2);
+
+ if (exists($templates{$template_name})) {
+ warn("WARNING: line $linenum in $config_file: ".
+ "template \"$template_name\" already defined, keeping old\n");
+ } else {
+ $templates{$template_name} = $template;
+ }
+
+ # modifysid <SIDORFILE[,SIDORFILE, ...]> "substthis" | "withthis"
+ } elsif (/^modifysids*\s+(\S+.*)\s+"(.+)"\s+\|\s+"(.*)"\s*(?:#.*)*$/i) {
+ my ($sid_list, $subst, $repl) = ($1, $2, $3);
+ warn("WARNING: line $linenum in $config_file is invalid, ignoring\n")
+ unless(parse_mod_expr(\@{$$cfg_ref{sid_modify_list}},
+ $sid_list, $subst, $repl));
+
+ # disablesid <SID[,SID, ...]>
+ } elsif (/^disablesids*\s+(\d.*)/i) {
+ my $sid_list = $1;
+ foreach my $sid (split(/\s*,\s*/, $sid_list)) {
+ if ($sid =~ /^\d+$/) {
+ $$cfg_ref{sid_disable_list}{$sid}++;
+ } else {
+ warn("WARNING: line $linenum in $config_file: ".
+ "\"$sid\" is not a valid SID, ignoring\n");
+ }
+ }
+
+ # localsid <SID[,SID, ...]>
+ } elsif (/^localsids*\s+(\d.*)/i) {
+ my $sid_list = $1;
+ foreach my $sid (split(/\s*,\s*/, $sid_list)) {
+ if ($sid =~ /^\d+$/) {
+ $$cfg_ref{sid_local_list}{$sid}++;
+ } else {
+ warn("WARNING: line $linenum in $config_file: ".
+ "\"$sid\" is not a valid SID, ignoring\n");
+ }
+ }
+
+ # enablesid <SID[,SID, ...]>
+ } elsif (/^enablesids*\s+(\d.*)/i) {
+ my $sid_list = $1;
+ foreach my $sid (split(/\s*,\s*/, $sid_list)) {
+ if ($sid =~ /^\d+$/) {
+ $$cfg_ref{sid_enable_list}{$sid}++;
+ } else {
+ warn("WARNING: line $linenum in $config_file: ".
+ "\"$sid\" is not a valid SID, ignoring\n");
+ }
+ }
+
+ # skipfile <file[,file, ...]>
+ } elsif (/^skipfiles*\s+(.*)/i) {
+ my $args = $1;
+ foreach my $file (split(/\s*,\s*/, $args)) {
+ if ($file =~ /^\S+$/) {
+ $config{verbose} && print STDERR "Adding file to ignore list: $file.\n";
+ $$cfg_ref{file_ignore_list}{$file}++;
+ } else {
+ warn("WARNING: line $linenum in $config_file is invalid, ignoring\n");
+ }
+ }
+
+ } elsif (/^url\s*=\s*(.*)/i) {
+ push(@{$$cfg_ref{url}}, $1)
+ unless ($$cfg_ref{cmdline_url});
+
+ } elsif (/^path\s*=\s*(.+)/i) {
+ $$cfg_ref{path} = $1;
+
+ } elsif (/^update_files\s*=\s*(.+)/i) {
+ $$cfg_ref{update_files} = $1;
+
+ } elsif (/^rule_actions\s*=\s*(.+)/i) {
+ $$cfg_ref{rule_actions} = $1;
+
+ } elsif (/^umask\s*=\s*([0-7]{4})$/i) {
+ $$cfg_ref{umask} = oct($1);
+
+ } elsif (/^min_files\s*=\s*(\d+)/i) {
+ $$cfg_ref{min_files} = $1;
+
+ } elsif (/^min_rules\s*=\s*(\d+)/i) {
+ $$cfg_ref{min_rules} = $1;
+
+ } elsif (/^tmpdir\s*=\s*(.+)/i) {
+ $$cfg_ref{tmp_basedir} = $1;
+
+ } elsif (/^use_external_bins\s*=\s*([01])/i) {
+ $$cfg_ref{use_external_bins} = $1;
+
+ } elsif (/^scp_key\s*=\s*(.+)/i) {
+ $$cfg_ref{scp_key} = $1;
+
+ } elsif (/^use_path_checks\s*=\s*([01])/i) {
+ $$cfg_ref{use_path_checks} = $1;
+
+ } elsif (/^user_agent\s*=\s*(.+)/i) {
+ $$cfg_ref{user_agent} = $1;
+
+ } elsif (/^include\s+(\S+.*)/i) {
+ my $include = $1;
+ read_config($include, $cfg_ref);
+ } else {
+ warn("WARNING: line $linenum in $config_file is invalid, ignoring\n");
+ }
+ }
+}
+
+
+
+# Make a few basic tests to make sure things look ok.
+# Will also set a new PATH as defined in the config file.
+sub sanity_check()
+{
+ my @req_params = qw(path update_files); # required parameters in conf
+ my @req_binaries = qw(gzip tar); # required binaries (unless we use modules)
+
+ # Can't use both quiet mode and verbose mode.
+ clean_exit("quiet mode and verbose mode at the same time doesn't make sense.")
+ if ($config{quiet} && $config{verbose});
+
+ # Can't use multiple output modes.
+ clean_exit("can't use multiple output modes at the same time.")
+ if ($config{minimize_diff} && $config{summary_output});
+
+ # Make sure all required variables are defined in the config file.
+ foreach my $param (@req_params) {
+ clean_exit("the required parameter \"$param\" is not defined in the configuration file.")
+ unless (exists($config{$param}));
+ }
+
+ # We now know a path was defined in the config, so set it.
+ # If we're under cygwin and path was specified as msdos style, convert
+ # it to cygwin style to avoid problems.
+ if ($^O eq "cygwin" && $config{path} =~ /^[a-zA-Z]:[\/\\]/) {
+ $ENV{PATH} = "";
+ foreach my $path (split(/;/, $config{path})) {
+ $ENV{PATH} .= "$path:" if (msdos_to_cygwin_path(\$path));
+ }
+ chop($ENV{PATH});
+ } else {
+ $ENV{PATH} = $config{path};
+ }
+
+ # Reset environment variables that may cause trouble.
+ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+
+ # Make sure $config{update_files} is a valid regexp.
+ eval {
+ "foo" =~ /$config{update_files}/;
+ };
+
+ clean_exit("update_files (\"$config{update_files}\") is not a valid regexp: $@")
+ if ($@);
+
+ # Make sure $config{rule_actions} is a valid regexp.
+ eval {
+ "foo" =~ /$config{rule_actions}/;
+ };
+
+ clean_exit("rule_actions (\"$config{rule_actions}\") is not a valid regexp: $@")
+ if ($@);
+
+ # If a variable file (probably local snort.conf) has been specified,
+ # it must exist. It must also be writable unless we're in careful mode.
+ if ($config{update_vars}) {
+ $config{varfile} = untaint_path($config{varfile});
+
+ clean_exit("variable file \"$config{varfile}\" does not exist.")
+ unless (-e "$config{varfile}");
+
+ clean_exit("variable file \"$config{varfile}\" is not a file.")
+ unless (-f "$config{varfile}");
+
+ clean_exit("variable file \"$config{varfile}\" is not writable by you.")
+ if (!$config{careful} && !-w "$config{varfile}");
+
+ # Make sure dist var files don't contain [back]slashes
+ # (probably means user confused it with local var file).
+ my %dist_var_files;
+ foreach my $dist_var_file (@{${config{dist_var_files}}}) {
+ clean_exit("variable file \"$dist_var_file\" specified multiple times")
+ if (exists($dist_var_files{$dist_var_file}));
+ $dist_var_files{$dist_var_file} = 1;
+ clean_exit("variable file \"$dist_var_file\" contains slashes or backslashes ".
+ "but it must be specified as a filename (without path) ".
+ "that exists in the downloaded rules, e.g. \"snort.conf\"")
+ if ($dist_var_file =~ /\// || $dist_var_file =~ /\\/);
+ }
+ }
+
+ # Make sure all required binaries can be found, unless
+ # we're used to use Perl modules instead.
+ # Wget is only required if url is http[s] or ftp.
+ if ($config{use_external_bins}) {
+ foreach my $binary (@req_binaries) {
+ clean_exit("$binary not found in PATH ($ENV{PATH}).")
+ unless (is_in_path($binary));
+ }
+ }
+
+ # Make sure $url is defined (either by -u <url> or url=... in the conf).
+ clean_exit("URL not specified. Specify at least one \"url=<url>\" in the \n".
+ "Oinkmaster configuration file or use the \"-u <url>\" argument")
+ if ($#{$config{url}} == -1);
+
+ # Make sure all urls look ok, and untaint them.
+ my @urls = @{$config{url}};
+ $#{$config{url}} = -1;
+ foreach my $url (@urls) {
+ clean_exit("incorrect URL: \"$url\"")
+ unless ($url =~ /^((?:https*|ftp|file|scp):\/\/.+\.(?:tar\.gz|tgz))$/
+ || $url =~ /^(dir:\/\/.+)/);
+ my $ok_url = $1;
+
+ if ($ok_url =~ /^dir:\/\/(.+)/) {
+ my $dir = untaint_path($1);
+ clean_exit("\"$dir\" does not exist or is not a directory")
+ unless (-d $dir);
+
+ # Simple check if the output dir is specified as url (probably a mistake).
+ if (File::Spec->canonpath(File::Spec->rel2abs($dir))
+ eq File::Spec->canonpath(File::Spec->rel2abs($config{output_dir}))) {
+ clean_exit("Download directory can not be same as output directory");
+ }
+ }
+ push(@{$config{url}}, $ok_url);
+ }
+
+ # Wget must be found if url is http[s]:// or ftp://.
+ if ($config{use_external_bins}) {
+ clean_exit("wget not found in PATH ($ENV{PATH}).")
+ if ($config{'url'} =~ /^(https*|ftp):/ && !is_in_path("wget"));
+ }
+
+ # scp must be found if scp://...
+ clean_exit("scp not found in PATH ($ENV{PATH}).")
+ if ($config{'url'} =~ /^scp:/ && !is_in_path("scp"));
+
+ # ssh key must exist if specified and url is scp://...
+ clean_exit("ssh key \"$config{scp_key}\" does not exist.")
+ if ($config{'url'} =~ /^scp:/ && exists($config{scp_key})
+ && !-e $config{scp_key});
+
+ # Untaint output directory string.
+ $config{output_dir} = untaint_path($config{output_dir});
+
+ # Make sure the output directory exists and is readable.
+ clean_exit("the output directory \"$config{output_dir}\" doesn't exist ".
+ "or isn't readable by you.")
+ if (!-d "$config{output_dir}" || !-x "$config{output_dir}");
+
+ # Make sure the output directory is writable unless running in careful mode.
+ clean_exit("the output directory \"$config{output_dir}\" isn't writable by you.")
+ if (!$config{careful} && !-w "$config{output_dir}");
+
+ # Make sure we have read permission on all rules files in the output dir,
+ # and also write permission unless we're in careful mode.
+ # This is to avoid bailing out in the middle of an execution if a copy
+ # fails because of permission problem.
+ opendir(OUTDIR, "$config{output_dir}")
+ or clean_exit("could not open directory $config{output_dir}: $!");
+
+ while ($_ = readdir(OUTDIR)) {
+ next if (/^\.\.?$/ || exists($config{file_ignore_list}{$_}));
+
+ if (/$config{update_files}/) {
+ unless (-r "$config{output_dir}/$_") {
+ closedir(OUTDIR);
+ clean_exit("no read permission on \"$config{output_dir}/$_\"\n".
+ "Read permission is required on all rules files ".
+ "inside the output directory.\n")
+ }
+
+ if (!$config{careful} && !-w "$config{output_dir}/$_") {
+ closedir(OUTDIR);
+ clean_exit("no write permission on \"$config{output_dir}/$_\"\n".
+ "Write permission is required on all rules files ".
+ "inside the output directory.\n")
+ }
+ }
+ }
+
+ closedir(OUTDIR);
+
+ # Make sure the backup directory exists and is writable if running with -b.
+ if ($config{make_backup}) {
+ $config{backup_dir} = untaint_path($config{backup_dir});
+ clean_exit("the backup directory \"$config{backup_dir}\" doesn't exist or ".
+ "isn't writable by you.")
+ if (!-d "$config{backup_dir}" || !-w "$config{backup_dir}");
+ }
+
+ # Convert tmp_basedir to cygwin style if running cygwin and msdos style was specified.
+ if ($^O eq "cygwin" && $config{tmp_basedir} =~ /^[a-zA-Z]:[\/\\]/) {
+ msdos_to_cygwin_path(\$config{tmp_basedir})
+ or clean_exit("could not convert temporary dir to cygwin style");
+ }
+
+ # Make sure temporary directory exists.
+ clean_exit("the temporary directory \"$config{tmp_basedir}\" does not ".
+ "exist or isn't writable by you.")
+ if (!-d "$config{tmp_basedir}" || !-w "$config{tmp_basedir}");
+
+ # Also untaint it.
+ $config{tmp_basedir} = untaint_path($config{tmp_basedir});
+
+ # Make sure stdin and stdout are ttys if we're running in interactive mode.
+ clean_exit("you can not run in interactive mode when STDIN/STDOUT is not a TTY.")
+ if ($config{interactive} && !(-t STDIN && -t STDOUT));
+}
+
+
+
+# Download the rules archive.
+sub download_file($ $)
+{
+ my $url = shift;
+ my $localfile = shift;
+ my $log = "$tmpdir/wget.log";
+ my $ret;
+
+ # If there seems to be a password in the url, replace it with "*password*"
+ # and use new string when printing the url to screen.
+ my $obfuscated_url = $url;
+ $obfuscated_url = "$1:*password*\@$2"
+ if ($obfuscated_url =~ /^(\S+:\/\/.+?):.+?@(.+)/);
+
+ # Ofbuscate oinkcode as well.
+ $obfuscated_url = "$1*oinkcode*$2"
+ if ($obfuscated_url =~ /^(\S+:\/\/.+\.cgi\/)[0-9a-z]{32,64}(\/.+)/i);
+
+ my @user_agent_opt;
+ @user_agent_opt = ("-U", $config{user_agent}) if (exists($config{user_agent}));
+
+ # Use wget if URL starts with "http[s]" or "ftp" and we use external binaries.
+ if ($config{use_external_bins} && $url =~ /^(?:https*|ftp)/) {
+ print STDERR "Downloading file from $obfuscated_url... "
+ unless ($config{quiet});
+
+ if ($config{verbose}) {
+ print STDERR "\n";
+ my @wget_cmd = ("wget", "-v", "-O", $localfile, $url, @user_agent_opt);
+ clean_exit("could not download from $obfuscated_url")
+ if (system(@wget_cmd));
+
+ } else {
+ my @wget_cmd = ("wget", "-v", "-o", $log, "-O", $localfile, $url, @user_agent_opt);
+ if (system(@wget_cmd)) {
+ my $log_output;
+ open(LOG, "<", "$log")
+ or clean_exit("could not open $log for reading: $!");
+ # Sanitize oinkcode in wget's log (password is automatically sanitized).
+ while (<LOG>) {
+ $_ = "$1*oinkcode*$2"
+ if (/(\S+:\/\/.+\.cgi\/)[0-9a-z]{32,64}(\/.+)/i);
+ $log_output .= $_;
+ }
+ close(LOG);
+ clean_exit("could not download from $obfuscated_url. ".
+ "Output from wget follows:\n\n $log_output");
+ }
+ print STDERR "done.\n" unless ($config{quiet});
+ }
+
+ # Use LWP if URL starts with "http[s]" or "ftp" and use_external_bins=0.
+ } elsif (!$config{use_external_bins} && $url =~ /^(?:https*|ftp)/) {
+ print STDERR "Downloading file from $obfuscated_url... "
+ unless ($config{quiet});
+
+ my %lwp_opt;
+ $lwp_opt{agent} = $config{user_agent} if (exists($config{user_agent}));
+
+ my $ua = LWP::UserAgent->new(%lwp_opt);
+ $ua->env_proxy;
+ my $request = HTTP::Request->new(GET => $url);
+ my $response = $ua->request($request, $localfile);
+
+ clean_exit("could not download from $obfuscated_url: " . $response->status_line)
+ unless $response->is_success;
+
+ print "done.\n" unless ($config{quiet});
+
+ # Grab file from local filesystem if file://...
+ } elsif ($url =~ /^file/) {
+ $url =~ s/^file:\/\///;
+
+ clean_exit("the file $url does not exist.")
+ unless (-e "$url");
+
+ clean_exit("the file $url is empty.")
+ unless (-s "$url");
+
+ print STDERR "Copying file from $url... "
+ unless ($config{quiet});
+
+ copy("$url", "$localfile")
+ or clean_exit("unable to copy $url to $localfile: $!");
+
+ print STDERR "done.\n"
+ unless ($config{quiet});
+
+ # Grab file using scp if scp://...
+ } elsif ($url =~ /^scp/) {
+ $url =~ s/^scp:\/\///;
+
+ my @cmd;
+ push(@cmd, "scp");
+ push(@cmd, "-i", "$config{scp_key}") if (exists($config{scp_key}));
+ push(@cmd, "-q") if ($config{quiet});
+ push(@cmd, "-v") if ($config{verbose});
+ push(@cmd, "$url", "$localfile");
+
+ print STDERR "Copying file from $url using scp:\n"
+ unless ($config{quiet});
+
+ clean_exit("scp returned error when trying to copy $url")
+ if (system(@cmd));
+
+ # Unknown download method.
+ } else {
+ clean_exit("unknown or unsupported download method\n");
+ }
+
+ # Make sure the downloaded file actually exists.
+ clean_exit("failed to download $url: ".
+ "local target file $localfile doesn't exist after download.")
+ unless (-e "$localfile");
+
+ # Also make sure it's at least non-empty.
+ clean_exit("failed to download $url: local target file $localfile is empty ".
+ "after download (perhaps you're out of diskspace or file in url is empty?)")
+ unless (-s "$localfile");
+}
+
+
+
+# Copy all rules files from the tmp dirs (one for each url)
+# into a single directory inside the tmp dir, except for files
+# matching a 'skipfile' directive'.
+# Will exit in case of colliding filenames.
+sub join_tmp_rules_dirs($ $ @)
+{
+ my $rules_dir = shift;
+ my $new_files_ref = shift;
+ my @url_tmpdirs = @_;
+
+ my %rules_files;
+
+ clean_exit("failed to create directory \"$rules_dir\": $!")
+ unless (mkdir($rules_dir));
+
+ foreach my $url_tmpdir (@url_tmpdirs) {
+ opendir(URL_TMPDIR, "$url_tmpdir")
+ or clean_exit("could not open directory \"$url_tmpdir\": $!");
+
+ while ($_ = readdir(URL_TMPDIR)) {
+ next if (/^\.\.?$/ || exists($config{file_ignore_list}{$_}) || !/$config{update_files}/);
+
+ if (exists($rules_files{$_})) {
+ closedir(URL_TMPDIR);
+ clean_exit("a file called \"$_\" exists in multiple rules archives")
+ }
+
+ # Make sure it's a regular file.
+ unless (-f "$url_tmpdir/$_" && !-l "$url_tmpdir/$_") {
+ closedir(URL_TMPDIR);
+ clean_exit("downloaded \"$_\" is not a regular file.")
+ }
+
+ $rules_files{$_} = 1;
+ $$new_files_ref{"$rules_dir/$_"} = 1;
+
+ my $src_file = untaint_path("$url_tmpdir/$_");
+ unless (copy("$src_file", "$rules_dir")) {
+ closedir(URL_TMPDIR);
+ clean_exit("could not copy \"$src_file\" to \"$rules_dir\": $!");
+ }
+ }
+
+ closedir(URL_TMPDIR);
+ }
+
+ return (keys(%$new_files_ref));
+}
+
+
+
+# Make a few basic sanity checks on the rules archive and then
+# uncompress/untar it if everything looked ok.
+sub unpack_rules_archive($ $ $)
+{
+ my $url = shift; # only used when printing warnings/errors
+ my $archive = shift;
+ my $rules_dir = shift;
+
+ my ($tar, @tar_content);
+
+ my $old_dir = untaint_path(File::Spec->rel2abs(File::Spec->curdir()));
+
+ my $dir = dirname($archive);
+ chdir("$dir") or clean_exit("$url: could not change directory to \"$dir\": $!");
+
+ if ($config{use_external_bins}) {
+
+ # Run integrity check on the gzip file.
+ clean_exit("$url: integrity check on gzip file failed (file transfer failed or ".
+ "file in URL not in gzip format?).")
+ if (system("gzip", "-t", "$archive"));
+
+ # Decompress it.
+ system("gzip", "-d", "$archive")
+ and clean_exit("$url: unable to uncompress $archive.");
+
+ # Suffix has now changed from .tar.gz|.tgz to .tar.
+ $archive =~ s/\.gz$//;
+
+ # Make sure the .tar file now exists.
+ # (Gzip may not return an error if it was not a gzipped file...)
+ clean_exit("$url: failed to unpack gzip file (file transfer failed or ".
+ "file in URL not in tar'ed gzip format?).")
+ unless (-e "$archive");
+
+ my $stdout_file = "$tmpdir/tar_content.out";
+
+ open(OLDOUT, ">&STDOUT") or clean_exit("could not dup STDOUT: $!");
+ open(STDOUT, ">$stdout_file") or clean_exit("could not redirect STDOUT: $!");
+
+ my $ret = system("tar", "tf", "$archive");
+
+ close(STDOUT);
+ open(STDOUT, ">&OLDOUT") or clean_exit("could not dup STDOUT: $!");
+ close(OLDOUT);
+
+ clean_exit("$url: could not list files in tar archive (is it broken?)")
+ if ($ret);
+
+ open(TAR, "$stdout_file") or clean_exit("failed to open $stdout_file: $!");
+ @tar_content = <TAR>;
+ close(TAR);
+
+ # use_external_bins=0
+ } else {
+ $tar = Archive::Tar->new($archive, 1);
+ clean_exit("$url: failed to read $archive (file transfer failed or ".
+ "file in URL not in tar'ed gzip format?).")
+ unless (defined($tar));
+ @tar_content = $tar->list_files();
+ }
+
+ # Make sure we could grab some content from the tarball.
+ clean_exit("$url: could not list files in tar archive (is it broken?)")
+ if ($#tar_content < 0);
+
+ # For each filename in the archive, do some basic sanity checks.
+ foreach my $filename (@tar_content) {
+ chomp($filename);
+
+ # We don't want absolute filename.
+ clean_exit("$url: rules archive contains absolute filename. ".
+ "Offending file/line:\n$filename")
+ if ($filename =~ /^\//);
+
+ # We don't want to have any weird characters anywhere in the filename.
+ clean_exit("$url: illegal character in filename in tar archive. Allowed are ".
+ "$OK_PATH_CHARS\nOffending file/line:\n$filename")
+ if ($config{use_path_checks} && $filename =~ /[^$OK_PATH_CHARS]/);
+
+ # We don't want to unpack any "../../" junk (check is useless now though).
+ clean_exit("$url: filename in tar archive contains \"..\".\n".
+ "Offending file/line:\n$filename")
+ if ($filename =~ /\.\./);
+ }
+
+ # Looks good. Now we can untar it.
+ print STDERR "Archive successfully downloaded, unpacking... "
+ unless ($config{quiet});
+
+ if ($config{use_external_bins}) {
+ clean_exit("failed to untar $archive.")
+ if system("tar", "xf", "$archive");
+ } else {
+ mkdir("$rules_dir") or clean_exit("could not create \"$rules_dir\" directory: $!\n");
+ foreach my $file ($tar->list_files) {
+ next unless ($file =~ /^$rules_dir\/[^\/]+$/); # only ^rules/<file>$
+
+ my $content = $tar->get_content($file);
+
+ # Symlinks in the archive will make get_content return undef.
+ clean_exit("could not get content from file \"$file\" in downloaded archive, ".
+ "make sure it is a regular file\n")
+ unless (defined($content));
+
+ open(RULEFILE, ">", "$file")
+ or clean_exit("could not open \"$file\" for writing: $!\n");
+ print RULEFILE $content;
+ close(RULEFILE);
+ }
+ }
+
+ # Make sure that non-empty rules directory existed in archive.
+ # We permit empty rules directory if min_files is set to 0 though.
+ clean_exit("$url: no \"$rules_dir\" directory found in tar file.")
+ unless (-d "$dir/$rules_dir");
+
+ my $num_files = 0;
+ opendir(RULESDIR, "$dir/$rules_dir")
+ or clean_exit("could not open directory \"$dir/$rules_dir\": $!");
+
+ while ($_ = readdir(RULESDIR)) {
+ next if (/^\.\.?$/);
+ $num_files++;
+ }
+
+ closedir(RULESDIR);
+
+ clean_exit("$url: directory \"$rules_dir\" in unpacked archive is empty")
+ if ($num_files == 0 && $config{min_files} != 0);
+
+ chdir($old_dir)
+ or clean_exit("could not change directory back to $old_dir: $!");
+
+ print STDERR "done.\n"
+ unless ($config{quiet});
+}
+
+
+
+# Open all rules files in the temporary directory and disable/modify all
+# rules/lines as requested in oinkmaster.conf, and then write back to the
+# same files. Also clean unwanted whitespaces and duplicate sids from them.
+sub process_rules($ $ $ $ $ $)
+{
+ my $modify_sid_ref = shift;
+ my $disable_sid_ref = shift;
+ my $enable_sid_ref = shift;
+ my $local_sid_ref = shift;
+ my $rh_tmp_ref = shift;
+ my $newfiles_ref = shift;
+ my %sids;
+
+ my %stats = (
+ disabled => 0,
+ enabled => 0,
+ modified => 0,
+ total => 0,
+ );
+
+ warn("WARNING: all rules that are disabled by default will be enabled\n")
+ if ($config{enable_all} && !$config{quiet});
+
+ print STDERR "Processing downloaded rules... "
+ unless ($config{quiet});
+
+ print STDERR "\n"
+ if ($config{verbose});
+
+ # Phase #1 - process all active rules and store in temporary hash.
+ # In case of dups, we use the one with the highest rev.
+ foreach my $file (sort(keys(%$newfiles_ref))) {
+
+ open(INFILE, "<", "$file")
+ or clean_exit("could not open $file for reading: $!");
+ my @infile = <INFILE>;
+ close(INFILE);
+
+ my ($single, $multi, $nonrule, $msg, $sid);
+
+ RULELOOP:while (get_next_entry(\@infile, \$single, \$multi, \$nonrule, \$msg, \$sid)) {
+
+ # We don't care about non-rules in this phase.
+ next RULELOOP if (defined($nonrule));
+
+ # Even if it was a single-line rule, we want a copy in $multi.
+ $multi = $single unless (defined($multi));
+
+ my %rule = (
+ single => $single,
+ multi => $multi,
+ );
+
+ # modify/disable/enable this rule as requested unless there is a matching
+ # localsid statement. Possible verbose messages and warnings will be printed.
+ unless (exists($$local_sid_ref{$sid})) {
+ process_rule($modify_sid_ref, $disable_sid_ref, $enable_sid_ref,
+ \%rule, $sid, \%stats, 1, basename($file));
+ }
+
+ $stats{total}++;
+
+ $single = $rule{single};
+ $multi = $rule{multi};
+
+ # Only care about active rules in this phase (the rule may have been
+ # disabled by a disablesid or a modifysid statement above, so we can't
+ # do this check earlier).
+ next RULELOOP if ($multi =~ /^#/);
+
+ # Is it a dup? If so, see if this seems to be more recent (higher rev).
+ if (exists($sids{$sid})) {
+ warn("\nWARNING: duplicate SID in downloaded archive, SID=$sid, ".
+ "only keeping rule with highest 'rev'\n")
+ unless($config{super_quiet});
+
+ my ($old_rev) = ($sids{$sid}{single} =~ /\brev\s*:\s*(\d+)\s*;/);
+ my ($new_rev) = ($single =~ /\brev\s*:\s*(\d+)\s*;/);
+
+ # This is so rules with a rev gets higher prio than
+ # rules without any rev.
+ $old_rev = -1 unless (defined($old_rev));
+ $new_rev = -1 unless (defined($new_rev));
+
+ # If this rev is higher than the one in the last stored rule with
+ # this sid, replace rule with this one. This is also done if the
+ # revs are equal because we assume the rule appearing last in the
+ # rules file is the more recent rule.
+ if ($new_rev >= $old_rev) {
+ $sids{$sid}{single} = $single;
+ $sids{$sid}{multi} = $multi;
+ }
+
+ # No dup.
+ } else {
+ $sids{$sid}{single} = $single;
+ $sids{$sid}{multi} = $multi;
+ }
+ }
+ }
+
+ # Phase #2 - read all rules files again, but when writing active rules
+ # back to the files, use the one stored in the sid hash (which is free of dups).
+ foreach my $file (sort(keys(%$newfiles_ref))) {
+
+ open(INFILE, "<", "$file")
+ or clean_exit("could not open $file for reading: $!");
+ my @infile = <INFILE>;
+ close(INFILE);
+
+ # Write back to the same file.
+ open(OUTFILE, ">", "$file")
+ or clean_exit("could not open $file for writing: $!");
+
+ my ($single, $multi, $nonrule, $msg, $sid);
+
+ RULELOOP:while (get_next_entry(\@infile, \$single, \$multi, \$nonrule, \$msg, \$sid)) {
+ if (defined($nonrule)) {
+ print OUTFILE "$nonrule";
+ next RULELOOP;
+ }
+
+ # Even if it was a single-line rule, we want a copy in $multi.
+ $multi = $single unless (defined($multi));
+
+ # If this rule is marked as localized and has not yet been written,
+ # write the old version to the new rules file.
+ if (exists($$local_sid_ref{$sid}) && !exists($sids{$sid}{printed})) {
+
+ # Just ignore the rule in the downloaded file if it doesn't
+ # exist in the same local file.
+ unless(exists($$rh_tmp_ref{old}{rules}{basename($file)}{$sid})) {
+ warn("WARNING: SID $sid is marked as local and exists in ".
+ "downloaded " . basename($file) . " but the SID does not ".
+ "exist in the local file, ignoring rule\n")
+ if ($config{verbose});
+
+ next RULELOOP;
+ }
+
+ print OUTFILE $$rh_tmp_ref{old}{rules}{basename($file)}{$sid};
+ $sids{$sid}{printed} = 1;
+
+ warn("SID $sid is marked as local, keeping your version from ".
+ basename($file) . ".\n".
+ "Your version: $$rh_tmp_ref{old}{rules}{basename($file)}{$sid}".
+ "Downloaded version: $multi\n")
+ if ($config{verbose});
+
+ next RULELOOP;
+ }
+
+ my %rule = (
+ single => $single,
+ multi => $multi,
+ );
+
+ # modify/disable/enable this rule. Possible verbose messages and warnings
+ # will not be printed (again) as this was done in the first phase.
+ # We send the stats to a dummy var as this was collected on the
+ # first phase as well.
+ process_rule($modify_sid_ref, $disable_sid_ref, $enable_sid_ref,
+ \%rule, $sid, \my %unused_stats, 0, basename($file));
+
+ $single = $rule{single};
+ $multi = $rule{multi};
+
+ # Disabled rules are printed right back to the file, unless
+ # there also is an active rule with the same sid. Als o make
+ # sure we only print the sid once, even though it's disabled.
+ if ($multi =~ /^#/ && !exists($sids{$sid}) && !exists($sids{$sid}{printed})) {
+ print OUTFILE $multi;
+ $sids{$sid}{printed} = 1;
+ next RULELOOP;
+ }
+
+ # If this sid has not yet been printed and this is the place where
+ # the sid with the highest rev was, print the rule to the file.
+ # (There can be multiple totally different rules with the same sid
+ # and we don't want to put the wrong rule in the wrong place.
+ if (!exists($sids{$sid}{printed}) && $single eq $sids{$sid}{single}) {
+ print OUTFILE $multi;
+ $sids{$sid}{printed} = 1;
+ }
+ }
+
+ close(OUTFILE);
+ }
+
+ print STDERR "disabled $stats{disabled}, enabled $stats{enabled}, ".
+ "modified $stats{modified}, total=$stats{total}\n"
+ unless ($config{quiet});
+
+ # Print warnings on attempt at enablesid/disablesid/localsid on non-existent
+ # rule if we're in verbose mode.
+ if ($config{verbose}) {
+ foreach my $sid (keys(%$enable_sid_ref)) {
+ warn("WARNING: attempt to use \"enablesid\" on non-existent SID $sid\n")
+ unless (exists($sids{$sid}));
+ }
+
+ foreach my $sid (keys(%$disable_sid_ref)) {
+ warn("WARNING: attempt to use \"disablesid\" on non-existent SID $sid\n")
+ unless (exists($sids{$sid}));
+ }
+
+ foreach my $sid (keys(%$local_sid_ref)) {
+ warn("WARNING: attempt to use \"localsid\" on non-existent SID $sid\n")
+ unless (exists($sids{$sid}));
+ }
+ }
+
+ # Print warnings on attempt at modifysid'ing non-existent stuff, unless quiet mode.
+ unless ($config{quiet}) {
+ my %new_files;
+ foreach my $file (sort(keys(%$newfiles_ref))) {
+ $new_files{basename($file)} = 1;
+ }
+
+ my %mod_tmp;
+ foreach my $mod_expr (@$modify_sid_ref) {
+ my ($type, $arg) = ($mod_expr->[2], $mod_expr->[3]);
+ $mod_tmp{$type}{$arg} = 1;
+ }
+
+ foreach my $sid (keys(%{$mod_tmp{sid}})) {
+ warn("WARNING: attempt to use \"modifysid\" on non-existent SID $sid\n")
+ unless (exists($sids{$sid}));
+ }
+
+ foreach my $file (keys(%{$mod_tmp{file}})) {
+ warn("WARNING: attempt to use \"modifysid\" on non-existent file $file\n")
+ unless(exists($new_files{$file}));
+ }
+ }
+
+ # Return total number of valid rules.
+ return ($stats{total});
+}
+
+
+
+# Process (modify/enable/disable) a rule as requested.
+sub process_rule($ $ $ $ $ $ $ $)
+{
+ my $modify_sid_ref = shift;
+ my $disable_sid_ref = shift;
+ my $enable_sid_ref = shift;
+ my $rule_ref = shift;
+ my $sid = shift;
+ my $stats_ref = shift;
+ my $print_messages = shift;
+ my $filename = shift;
+
+ # Just for easier access.
+ my $single = $$rule_ref{single};
+ my $multi = $$rule_ref{multi};
+
+ # Some rules may be commented out by default.
+ # Enable them if -e is specified (both single-line and multi-line,
+ # version, because we don't know which version one we're going to
+ # use below.
+ # Enable them if -e is specified.
+ if ($multi =~ /^#/ && $config{enable_all}) {
+ $multi =~ s/^#*//;
+ $multi =~ s/\n#*/\n/g;
+ $single =~ s/^#*//;
+ $$stats_ref{enabled}++;
+ }
+
+ # Modify rule if requested. For disablesid/enablesid we work
+ # on the multi-line version of the rule (if exists). For
+ # modifysid that's no good since we don't know where in the
+ # rule the trailing backslashes and newlines are going to be
+ # and we don't want them to affect the regexp.
+ MOD_EXP:foreach my $mod_expr (@$modify_sid_ref) {
+ my ($subst, $repl, $type, $arg) =
+ ($mod_expr->[0], $mod_expr->[1], $mod_expr->[2], $mod_expr->[3]);
+
+ my $print_modify_warnings = 0;
+ $print_modify_warnings = 1 if (!$config{super_quiet} && $print_messages && $type eq "sid");
+
+ if ($type eq "wildcard" || ($type eq "sid" && $sid eq $arg) ||
+ ($type eq "file" && $filename eq $arg)) {
+
+ if ($single =~ /$subst/si) {
+ print STDERR "Modifying rule, SID=$sid, filename=$filename, ".
+ "match type=$type, subst=$subst, ".
+ "repl=$repl\nBefore: $single"
+ if ($print_messages && $config{verbose});
+
+
+ # If user specified a backreference but the regexp did not set $1 - don't modify rule.
+ if (!defined($1) && ($repl =~ /[^\\]\$\d+/ || $repl =~ /[^\\]\$\{\d+\}/
+ || $repl =~ /^qq\/\$\d+/ || $repl =~ /^qq\/\$\{\d+\}/)) {
+ warn("WARNING: SID $sid matches modifysid expression \"$subst\" but ".
+ "backreference variable \$1 is undefined after match, ".
+ "keeping original rule\n")
+ if ($print_modify_warnings);
+ next MOD_EXP;
+ }
+
+ # Do the substitution on the single-line version and put it
+ # back in $multi.
+ $single =~ s/$subst/$repl/eei;
+ $multi = $single;
+
+ print STDERR "After: $single\n"
+ if ($print_messages && $config{verbose});
+
+ $$stats_ref{modified}++;
+ } else {
+ if ($print_modify_warnings) {
+ warn("WARNING: SID $sid does not match modifysid ".
+ "expression \"$subst\", keeping original rule\n");
+ }
+ }
+ }
+ }
+
+ # Disable rule if requested and it's not already disabled.
+ if (exists($$disable_sid_ref{$sid}) && $multi !~ /^\s*#/) {
+ $multi = "#$multi";
+ $multi =~ s/\n([^#].+)/\n#$1/g;
+ $$stats_ref{disabled}++;
+ }
+
+ # Enable rule if requested and it's not already enabled.
+ if (exists($$enable_sid_ref{$sid}) && $multi =~ /^\s*#/) {
+ $multi =~ s/^#+//;
+ $multi =~ s/\n#+(.+)/\n$1/g;
+ $$stats_ref{enabled}++;
+ }
+
+ $$rule_ref{single} = $single;
+ $$rule_ref{multi} = $multi;
+}
+
+
+
+# Setup rules hash.
+# Format for rules will be: rh{old|new}{rules{filename}{sid} = single-line rule
+# Format for non-rules will be: rh{old|new}{other}{filename} = array of lines
+# List of added files will be stored as rh{added_files}{filename}
+sub setup_rules_hash($ $)
+{
+ my $new_files_ref = shift;
+ my $output_dir = shift;
+
+ my (%rh, %old_sids);
+
+ print STDERR "Setting up rules structures... "
+ unless ($config{quiet});
+
+ foreach my $file (sort(keys(%$new_files_ref))) {
+ warn("\nWARNING: downloaded rules file $file is empty\n")
+ if (!-s "$file" && $config{verbose});
+
+ open(NEWFILE, "<", "$file")
+ or clean_exit("could not open $file for reading: $!");
+ my @newfile = <NEWFILE>;
+ close(NEWFILE);
+
+ # From now on we don't care about the path, so remove it.
+ $file = basename($file);
+
+ my ($single, $multi, $nonrule, $msg, $sid);
+
+ while (get_next_entry(\@newfile, \$single, \$multi, \$nonrule, \$msg, \$sid)) {
+ if (defined($single)) {
+ $rh{new}{rules}{"$file"}{"$sid"} = $single;
+ } else {
+ push(@{$rh{new}{other}{"$file"}}, $nonrule);
+ }
+ }
+
+ # Also read in old (aka local) file if it exists.
+ # We do a sid dup check in these files.
+ if (-f "$output_dir/$file") {
+ open(OLDFILE, "<", "$output_dir/$file")
+ or clean_exit("could not open $output_dir/$file for reading: $!");
+ my @oldfile = <OLDFILE>;
+ close(OLDFILE);
+
+ while (get_next_entry(\@oldfile, \$single, \$multi, \$nonrule, undef, \$sid)) {
+ if (defined($single)) {
+ warn("\nWARNING: duplicate SID in your local rules, SID ".
+ "$sid exists multiple times, you may need to fix this manually!\n")
+ if (exists($old_sids{$sid}));
+
+ $rh{old}{rules}{"$file"}{"$sid"} = $single;
+ $old_sids{$sid}++;
+ } else {
+ push(@{$rh{old}{other}{"$file"}}, $nonrule);
+ }
+ }
+ } else {
+ $rh{added_files}{"$file"}++;
+ }
+ }
+
+ print STDERR "done.\n"
+ unless ($config{quiet});
+
+ return (%rh);
+}
+
+
+
+# Return lines that exist only in first array but not in second one.
+sub get_first_only($ $ $)
+{
+ my $first_only_ref = shift;
+ my $first_arr_ref = shift;
+ my $second_arr_ref = shift;
+ my %arr_hash;
+
+ @arr_hash{@$second_arr_ref} = ();
+
+ foreach my $line (@$first_arr_ref) {
+
+ # Skip blank lines and CVS Id tags.
+ next unless ($line =~ /\S/);
+ next if ($line =~ /^\s*#+\s*\$I\S:.+Exp\s*\$/);
+
+ push(@$first_only_ref, $line)
+ unless(exists($arr_hash{$line}));
+ }
+}
+
+
+
+# Backup files in output dir matching $config{update_files} into the backup dir.
+sub make_backup($ $)
+{
+ my $src_dir = shift; # dir with the rules to be backed up
+ my $dest_dir = shift; # where to put the backup tarball
+
+ my ($sec, $min, $hour, $mday, $mon, $year) = (localtime)[0 .. 5];
+
+ my $date = sprintf("%4d%02d%02d-%02d%02d%02d",
+ $year + 1900, $mon + 1, $mday, $hour, $min, $sec);
+
+ my $backup_tarball = "rules-backup-$date.tar";
+ my $backup_tmp_dir = File::Spec->catdir("$tmpdir", "rules-backup-$date");
+ my $dest_file = File::Spec->catfile("$dest_dir", "$backup_tarball.gz");
+
+ print STDERR "Creating backup of old rules..."
+ unless ($config{quiet});
+
+ mkdir("$backup_tmp_dir", 0700)
+ or clean_exit("could not create temporary backup directory $backup_tmp_dir: $!");
+
+ # Copy all rules files from the rules dir to the temporary backup dir.
+ opendir(OLDRULES, "$src_dir")
+ or clean_exit("could not open directory $src_dir: $!");
+
+ while ($_ = readdir(OLDRULES)) {
+ next if (/^\.\.?$/);
+ if (/$config{update_files}/) {
+ my $src_file = untaint_path("$src_dir/$_");
+ copy("$src_file", "$backup_tmp_dir/")
+ or warn("WARNING: could not copy $src_file to $backup_tmp_dir/: $!");
+ }
+ }
+
+ closedir(OLDRULES);
+
+ # Also backup the -U <file> (as "variable-file.conf") if specified.
+ if ($config{update_vars}) {
+ copy("$config{varfile}", "$backup_tmp_dir/variable-file.conf")
+ or warn("WARNING: could not copy $config{varfile} to $backup_tmp_dir: $!")
+ }
+
+ my $old_dir = untaint_path(File::Spec->rel2abs(File::Spec->curdir()));
+
+ # Change directory to $tmpdir (so we'll be right below the directory where
+ # we have our rules to be backed up).
+ chdir("$tmpdir") or clean_exit("could not change directory to $tmpdir: $!");
+
+ if ($config{use_external_bins}) {
+ clean_exit("tar command returned error when archiving backup files.\n")
+ if (system("tar","cf","$backup_tarball","rules-backup-$date"));
+
+ clean_exit("gzip command returned error when compressing backup file.\n")
+ if (system("gzip","$backup_tarball"));
+
+ $backup_tarball .= ".gz";
+
+ } else {
+ my $tar = Archive::Tar->new;
+ opendir(RULES, "rules-backup-$date")
+ or clean_exit("unable to open directory \"rules-backup-$date\": $!");
+
+ while ($_ = readdir(RULES)) {
+ next if (/^\.\.?$/);
+ $tar->add_files("rules-backup-$date/$_");
+ }
+
+ closedir(RULES);
+
+ $backup_tarball .= ".gz";
+
+ # Write tarball. Print stupid error message if it fails as
+ # we can't use $tar->error or Tar::error on all platforms.
+ $tar->write("$backup_tarball", 1);
+
+ clean_exit("could not create backup archive: tarball empty after creation\n")
+ unless (-s "$backup_tarball");
+ }
+
+ # Change back to old directory (so it will work with -b <directory> as either
+ # an absolute or a relative path.
+ chdir("$old_dir")
+ or clean_exit("could not change directory back to $old_dir: $!");
+
+ copy("$tmpdir/$backup_tarball", "$dest_file")
+ or clean_exit("unable to copy $tmpdir/$backup_tarball to $dest_file/: $!\n");
+
+ print STDERR " saved as $dest_file.\n"
+ unless ($config{quiet});
+}
+
+
+
+# Print the results.
+sub print_changes($ $)
+{
+ my $ch_ref = shift;
+ my $rh_ref = shift;
+
+ my ($sec, $min, $hour, $mday, $mon, $year) = (localtime)[0 .. 5];
+
+ my $date = sprintf("%4d%02d%02d %02d:%02d:%02d",
+ $year + 1900, $mon + 1, $mday, $hour, $min, $sec);
+
+ print "\n[***] Results from Oinkmaster started $date [***]\n";
+
+ # Print new variables.
+ if ($config{update_vars}) {
+ if ($#{$$ch_ref{new_vars}} > -1) {
+ print "\n[*] New variables: [*]\n";
+ foreach my $var (@{$$ch_ref{new_vars}}) {
+ print " $var";
+ }
+ } else {
+ print "\n[*] New variables: [*]\n None.\n"
+ unless ($config{super_quiet});
+ }
+ }
+
+
+ # Print rules modifications.
+ print "\n[*] Rules modifications: [*]\n None.\n"
+ if (!keys(%{$$ch_ref{rules}}) && !$config{super_quiet});
+
+ # Print added rules.
+ if (exists($$ch_ref{rules}{added})) {
+ print "\n[+++] Added rules: [+++]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{added}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_NEW, "Added to",
+ \%{$$ch_ref{rules}{added}}, $rh_ref);
+ }
+ }
+
+ # Print enabled rules.
+ if (exists($$ch_ref{rules}{ena})) {
+ print "\n[+++] Enabled rules: [+++]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{ena}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_NEW, "Enabled in",
+ \%{$$ch_ref{rules}{ena}}, $rh_ref);
+ }
+ }
+
+ # Print enabled + modified rules.
+ if (exists($$ch_ref{rules}{ena_mod})) {
+ print "\n[+++] Enabled and modified rules: [+++]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{ena_mod}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_BOTH, "Enabled and modified in",
+ \%{$$ch_ref{rules}{ena_mod}}, $rh_ref);
+ }
+ }
+
+ # Print modified active rules.
+ if (exists($$ch_ref{rules}{mod_act})) {
+ print "\n[///] Modified active rules: [///]\n";
+
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{mod_act}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_BOTH, "Modified active in",
+ \%{$$ch_ref{rules}{mod_act}}, $rh_ref);
+ }
+ }
+
+ # Print modified inactive rules.
+ if (exists($$ch_ref{rules}{mod_ina})) {
+ print "\n[///] Modified inactive rules: [///]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{mod_ina}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_BOTH, "Modified inactive in",
+ \%{$$ch_ref{rules}{mod_ina}}, $rh_ref);
+ }
+ }
+
+ # Print disabled + modified rules.
+ if (exists($$ch_ref{rules}{dis_mod})) {
+ print "\n[---] Disabled and modified rules: [---]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{dis_mod}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_BOTH, "Disabled and modified in",
+ \%{$$ch_ref{rules}{dis_mod}}, $rh_ref);
+ }
+ }
+
+ # Print disabled rules.
+ if (exists($$ch_ref{rules}{dis})) {
+ print "\n[---] Disabled rules: [---]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{dis}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_NEW, "Disabled in",
+ \%{$$ch_ref{rules}{dis}}, $rh_ref);
+ }
+ }
+
+ # Print removed rules.
+ if (exists($$ch_ref{rules}{removed})) {
+ print "\n[---] Removed rules: [---]\n";
+ if ($config{summary_output}) {
+ print_summary_change(\%{$$ch_ref{rules}{removed}}, $rh_ref);
+ } else {
+ print_changetype($PRINT_OLD, "Removed from",
+ \%{$$ch_ref{rules}{removed}}, $rh_ref);
+ }
+ }
+
+
+ # Print non-rule modifications.
+ print "\n[*] Non-rule line modifications: [*]\n None.\n"
+ if (!keys(%{$$ch_ref{other}}) && !$config{super_quiet});
+
+ # Print added non-rule lines.
+ if (exists($$ch_ref{other}{added})) {
+ print "\n[+++] Added non-rule lines: [+++]\n";
+ foreach my $file (sort({uc($a) cmp uc($b)} keys(%{$$ch_ref{other}{added}}))) {
+ my $num = $#{$$ch_ref{other}{added}{$file}} + 1;
+ print "\n -> Added to $file ($num):\n";
+ foreach my $line (@{$$ch_ref{other}{added}{$file}}) {
+ print " $line";
+ }
+ }
+ }
+
+ # Print removed non-rule lines.
+ if (keys(%{$$ch_ref{other}{removed}}) > 0) {
+ print "\n[---] Removed non-rule lines: [---]\n";
+ foreach my $file (sort({uc($a) cmp uc($b)} keys(%{$$ch_ref{other}{removed}}))) {
+ my $num = $#{$$ch_ref{other}{removed}{$file}} + 1;
+ print "\n -> Removed from $file ($num):\n";
+ foreach my $other (@{$$ch_ref{other}{removed}{$file}}) {
+ print " $other";
+ }
+ }
+ }
+
+
+ # Print list of added files.
+ if (keys(%{$$ch_ref{added_files}})) {
+ print "\n[+] Added files (consider updating your snort.conf to include them if needed): [+]\n\n";
+ foreach my $added_file (sort({uc($a) cmp uc($b)} keys(%{$$ch_ref{added_files}}))) {
+ print " -> $added_file\n";
+ }
+ } else {
+ print "\n[*] Added files: [*]\n None.\n"
+ unless ($config{super_quiet} || $config{summary_output});
+ }
+
+ # Print list of possibly removed files if requested.
+ if ($config{check_removed}) {
+ if (keys(%{$$ch_ref{removed_files}})) {
+ print "\n[-] Files possibly removed from the archive ".
+ "(consider removing them from your snort.conf if needed): [-]\n\n";
+ foreach my $removed_file (sort({uc($a) cmp uc($b)} keys(%{$$ch_ref{removed_files}}))) {
+ print " -> $removed_file\n";
+ }
+ } else {
+ print "\n[*] Files possibly removed from the archive: [*]\n None.\n"
+ unless ($config{super_quiet} || $config{summary_output});
+ }
+ }
+
+ print "\n";
+}
+
+
+
+# Helper for print_changes().
+sub print_changetype($ $ $ $)
+{
+ my $type = shift; # $PRINT_OLD|$PRINT_NEW|$PRINT_BOTH
+ my $string = shift; # string to print before filename
+ my $ch_ref = shift; # reference to an entry in the rules changes hash
+ my $rh_ref = shift; # reference to rules hash
+
+ foreach my $file (sort({uc($a) cmp uc($b)} keys(%$ch_ref))) {
+ my $num = keys(%{$$ch_ref{$file}});
+ print "\n -> $string $file ($num):\n";
+ foreach my $sid (keys(%{$$ch_ref{$file}})) {
+ if ($type == $PRINT_OLD) {
+ print " $$rh_ref{old}{rules}{$file}{$sid}"
+ } elsif ($type == $PRINT_NEW) {
+ print " $$rh_ref{new}{rules}{$file}{$sid}"
+ } elsif ($type == $PRINT_BOTH) {
+
+ my $old = $$rh_ref{old}{rules}{$file}{$sid};
+ my $new = $$rh_ref{new}{rules}{$file}{$sid};
+
+ if ($config{minimize_diff}) {
+ my ($old, $new) = minimize_diff($old, $new);
+ print "\n old SID $sid: $old";
+ print " new SID $sid: $new";
+ } else {
+ print "\n old: $old";
+ print " new: $new";
+ }
+ }
+ }
+ }
+}
+
+
+
+# Print changes in bmc style, i.e. only sid and msg, no full details.
+sub print_summary_change($ $)
+{
+ my $ch_ref = shift; # reference to an entry in the rules changes hash
+ my $rh_ref = shift; # reference to rules hash
+
+ my (@sids, %sidmap);
+
+ print "\n";
+
+ # First get all the sids (may be spread across multiple files.
+ foreach my $file (keys(%$ch_ref)) {
+ foreach my $sid (keys(%{$$ch_ref{$file}})) {
+ push(@sids, $sid);
+ if (exists($$rh_ref{new}{rules}{$file}{$sid})) {
+ $sidmap{$sid}{rule} = $$rh_ref{new}{rules}{$file}{$sid};
+ } else {
+ $sidmap{$sid}{rule} = $$rh_ref{old}{rules}{$file}{$sid};
+ }
+ $sidmap{$sid}{file} = $file;
+ }
+ }
+
+ # Print rules, sorted by sid.
+ foreach my $sid (sort {$a <=> $b} (@sids)) {
+ my @rule = $sidmap{$sid}{rule};
+ my $file = $sidmap{$sid}{file};
+ get_next_entry(\@rule, undef, undef, undef, \(my $msg), undef);
+ printf("%8d - %s (%s)\n", $sid, $msg, $file);
+ }
+
+ print "\n";
+}
+
+
+
+# Compare the new rules to the old ones.
+sub get_changes($ $ $)
+{
+ my $rh_ref = shift;
+ my $new_files_ref = shift;
+ my $rules_dir = shift;
+ my %changes;
+
+ print STDERR "Comparing new files to the old ones... "
+ unless ($config{quiet});
+
+ # We have the list of added files (without full path) in $rh_ref{added_files}
+ # but we'd rather want to have it in $changes{added_files} now.
+ $changes{added_files} = $$rh_ref{added_files};
+
+ # New files are also regarded as modified since we want to update
+ # (i.e. add) those as well. Here we want them with full path.
+ foreach my $file (keys(%{$changes{added_files}})) {
+ $changes{modified_files}{"$tmpdir/$rules_dir/$file"}++;
+ }
+
+ # Add list of possibly removed files if requested.
+ if ($config{check_removed}) {
+ opendir(OLDRULES, "$config{output_dir}")
+ or clean_exit("could not open directory $config{output_dir}: $!");
+
+ while ($_ = readdir(OLDRULES)) {
+ next if (/^\.\.?$/);
+ $changes{removed_files}{"$_"} = 1
+ if (/$config{update_files}/ &&
+ !exists($config{file_ignore_list}{$_}) &&
+ !-e "$tmpdir/$rules_dir/$_");
+ }
+
+ closedir(OLDRULES);
+ }
+
+ # For each new rules file...
+ FILELOOP:foreach my $file_w_path (sort(keys(%$new_files_ref))) {
+ my $file = basename($file_w_path);
+
+ # Skip comparison if it's an added file.
+ next FILELOOP if (exists($$rh_ref{added_files}{$file}));
+
+ # For each sid in the new file...
+ foreach my $sid (keys(%{$$rh_ref{new}{rules}{$file}})) {
+ my $new_rule = $$rh_ref{new}{rules}{$file}{$sid};
+
+ # Sid also exists in the old file?
+ if (exists($$rh_ref{old}{rules}{$file}{$sid})) {
+ my $old_rule = $$rh_ref{old}{rules}{$file}{$sid};
+
+ # Are they identical?
+ unless ($new_rule eq $old_rule) {
+ $changes{modified_files}{$file_w_path}++;
+
+ # Find out in which way the rules are different.
+ if ("#$old_rule" eq $new_rule) {
+ $changes{rules}{dis}{$file}{$sid}++;
+ } elsif ($old_rule eq "#$new_rule") {
+ $changes{rules}{ena}{$file}{$sid}++;
+ } elsif ($old_rule =~ /^\s*#/ && $new_rule !~ /^\s*#/) {
+ $changes{rules}{ena_mod}{$file}{$sid}++;
+ } elsif ($old_rule !~ /^\s*#/ && $new_rule =~ /^\s*#/) {
+ $changes{rules}{dis_mod}{$file}{$sid}++;
+ } elsif ($old_rule =~ /^\s*#/ && $new_rule =~ /^\s*#/) {
+ $changes{rules}{mod_ina}{$file}{$sid}++;
+ } else {
+ $changes{rules}{mod_act}{$file}{$sid}++;
+ }
+
+ }
+ } else { # sid not found in old file, i.e. it's added
+ $changes{modified_files}{$file_w_path}++;
+ $changes{rules}{added}{$file}{$sid}++;
+ }
+ } # foreach sid
+
+ # Check for removed rules, i.e. sids that exist in the old file but
+ # not in the new one.
+ foreach my $sid (keys(%{$$rh_ref{old}{rules}{$file}})) {
+ unless (exists($$rh_ref{new}{rules}{$file}{$sid})) {
+ $changes{modified_files}{$file_w_path}++;
+ $changes{rules}{removed}{$file}{$sid}++;
+ }
+ }
+
+ # Check for added non-rule lines.
+ get_first_only(\my @added,
+ \@{$$rh_ref{new}{other}{$file}},
+ \@{$$rh_ref{old}{other}{$file}});
+
+ if (scalar(@added)) {
+ @{$changes{other}{added}{$file}} = @added;
+ $changes{modified_files}{$file_w_path}++;
+ }
+
+ # Check for removed non-rule lines.
+ get_first_only(\my @removed,
+ \@{$$rh_ref{old}{other}{$file}},
+ \@{$$rh_ref{new}{other}{$file}});
+
+ if (scalar(@removed)) {
+ @{$changes{other}{removed}{$file}} = @removed;
+ $changes{modified_files}{$file_w_path}++;
+ }
+
+ } # foreach new file
+
+ print STDERR "done.\n" unless ($config{quiet});
+
+ return (%changes);
+}
+
+
+
+# Simply copy the modified rules files to the output directory.
+sub update_rules($ @)
+{
+ my $dst_dir = shift;
+ my @modified_files = @_;
+
+ print STDERR "Updating local rules files... "
+ if (!$config{quiet} || $config{interactive});
+
+ foreach my $file_w_path (@modified_files) {
+ copy("$file_w_path", "$dst_dir")
+ or clean_exit("could not copy $file_w_path to $dst_dir: $!");
+ }
+
+ print STDERR "done.\n"
+ if (!$config{quiet} || $config{interactive});
+}
+
+
+# Simply copy rules files from one dir to another.
+# Links are not allowed.
+sub copy_rules($ $)
+{
+ my $src_dir = shift;
+ my $dst_dir = shift;
+
+ print STDERR "Copying rules from $src_dir... "
+ if (!$config{quiet} || $config{interactive});
+
+ opendir(SRC_DIR, $src_dir)
+ or clean_exit("could not open directory $src_dir: $!");
+
+ my $num_files = 0;
+ while ($_ = readdir(SRC_DIR)) {
+ next if (/^\.\.?$/ || exists($config{file_ignore_list}{$_})
+ || !/$config{update_files}/);
+
+ my $src_file = untaint_path("$src_dir/$_");
+
+ # Make sure it's a regular file.
+ unless (-f "$src_file" && !-l "$src_file") {
+ closedir(SRC_DIR);
+ clean_exit("\"$src_file\" is not a regular file.")
+ }
+
+ unless (copy($src_file, $dst_dir)) {
+ closedir(SRC_DIR);
+ clean_exit("could not copy \"$src_file\" to \"$dst_dir\"/: $!");
+ }
+ $num_files++;
+ }
+
+ closedir(SRC_DIR);
+
+ print STDERR "$num_files files copied.\n"
+ if (!$config{quiet} || $config{interactive});
+}
+
+
+
+# Return true if file is in PATH and is executable.
+sub is_in_path($)
+{
+ my $file = shift;
+
+ foreach my $dir (File::Spec->path()) {
+ if ((-f "$dir/$file" && -x "$dir/$file")
+ || (-f "$dir/$file.exe" && -x "$dir/$file.exe")) {
+ print STDERR "Found $file binary in $dir\n"
+ if ($config{verbose});
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+
+# get_next_entry() will parse the array referenced in the first arg
+# and return the next entry. The array should contain a rules file,
+# and the returned entry will be removed from the array.
+# An entry is one of:
+# - single-line rule (put in 2nd ref)
+# - multi-line rule (put in 3rd ref)
+# - non-rule line (put in 4th ref)
+# If the entry is a multi-line rule, its single-line version is also
+# returned (put in the 2nd ref).
+# If it's a rule, the msg string will be put in 4th ref and sid in 5th.
+sub get_next_entry($ $ $ $ $ $)
+{
+ my $arr_ref = shift;
+ my $single_ref = shift;
+ my $multi_ref = shift;
+ my $nonrule_ref = shift;
+ my $msg_ref = shift;
+ my $sid_ref = shift;
+
+ undef($$single_ref);
+ undef($$multi_ref);
+ undef($$nonrule_ref);
+ undef($$msg_ref);
+ undef($$sid_ref);
+
+ my $line = shift(@$arr_ref) || return(0);
+ my $disabled = 0;
+ my $broken = 0;
+
+ chomp($line);
+ $line .= "\n";
+
+ # Possible beginning of multi-line rule?
+ if ($line =~ /$MULTILINE_RULE_REGEXP/oi) {
+ $$single_ref = $line;
+ $$multi_ref = $line;
+
+ $disabled = 1 if ($line =~ /^\s*#/);
+
+ # Keep on reading as long as line ends with "\".
+ while (!$broken && $line =~ /\\\s*\n$/) {
+
+ # Remove trailing "\" and newline for single-line version.
+ $$single_ref =~ s/\\\s*\n//;
+
+ # If there are no more lines, this can not be a valid multi-line rule.
+ if (!($line = shift(@$arr_ref))) {
+
+ warn("\nWARNING: got EOF while parsing multi-line rule: $$multi_ref\n")
+ if ($config{verbose});
+
+ @_ = split(/\n/, $$multi_ref);
+
+ undef($$multi_ref);
+ undef($$single_ref);
+
+ # First line of broken multi-line rule will be returned as a non-rule line.
+ $$nonrule_ref = shift(@_) . "\n";
+ $$nonrule_ref =~ s/\s*\n$/\n/; # remove trailing whitespaces
+
+ # The rest is put back to the array again.
+ foreach $_ (reverse((@_))) {
+ unshift(@$arr_ref, "$_\n");
+ }
+
+ return (1); # return non-rule
+ }
+
+ # Multi-line continuation.
+ $$multi_ref .= $line;
+
+ # If there are non-comment lines in the middle of a disabled rule,
+ # mark the rule as broken to return as non-rule lines.
+ if ($line !~ /^\s*#/ && $disabled) {
+ $broken = 1;
+ } elsif ($line =~ /^\s*#/ && !$disabled) {
+ # comment line (with trailing slash) in the middle of an active rule - ignore it
+ } else {
+ $line =~ s/^\s*#*\s*//; # remove leading # in single-line version
+ $$single_ref .= $line;
+ }
+
+ } # while line ends with "\"
+
+ # Single-line version should now be a valid rule.
+ # If not, it wasn't a valid multi-line rule after all.
+ if (!$broken && parse_singleline_rule($$single_ref, $msg_ref, $sid_ref)) {
+
+ $$single_ref =~ s/^\s*//; # remove leading whitespaces
+ $$single_ref =~ s/^#+\s*/#/; # remove whitespaces next to leading #
+ $$single_ref =~ s/\s*\n$/\n/; # remove trailing whitespaces
+
+ $$multi_ref =~ s/^\s*//;
+ $$multi_ref =~ s/\s*\n$/\n/;
+ $$multi_ref =~ s/^#+\s*/#/;
+
+ return (1); # return multi
+
+ # Invalid multi-line rule.
+ } else {
+ warn("\nWARNING: invalid multi-line rule: $$single_ref\n")
+ if ($config{verbose} && $$multi_ref !~ /^\s*#/);
+
+ @_ = split(/\n/, $$multi_ref);
+
+ undef($$multi_ref);
+ undef($$single_ref);
+
+ # First line of broken multi-line rule will be returned as a non-rule line.
+ $$nonrule_ref = shift(@_) . "\n";
+ $$nonrule_ref =~ s/\s*\n$/\n/; # remove trailing whitespaces
+
+ # The rest is put back to the array again.
+ foreach $_ (reverse((@_))) {
+ unshift(@$arr_ref, "$_\n");
+ }
+
+ return (1); # return non-rule
+ }
+
+ # Check if it's a regular single-line rule.
+ } elsif (parse_singleline_rule($line, $msg_ref, $sid_ref)) {
+ $$single_ref = $line;
+ $$single_ref =~ s/^\s*//;
+ $$single_ref =~ s/^#+\s*/#/;
+ $$single_ref =~ s/\s*\n$/\n/;
+
+ return (1); # return single
+
+ # Non-rule line.
+ } else {
+
+ # Do extra check and warn if it *might* be a rule anyway,
+ # but that we just couldn't parse for some reason.
+ warn("\nWARNING: line may be a rule but it could not be parsed ".
+ "(missing sid?): $line\n")
+ if ($config{verbose} && $line =~ /^\s*alert .+msg\s*:\s*".+"\s*;/);
+
+ $$nonrule_ref = $line;
+ $$nonrule_ref =~ s/\s*\n$/\n/;
+
+ return (1); # return non-rule
+ }
+}
+
+
+
+# Look for variables that exist in dist var files but not in local var file.
+sub get_new_vars($ $ $ $)
+{
+ my $ch_ref = shift;
+ my $dist_var_files_ref = shift;
+ my $local_var_file = shift;
+ my $url_tmpdirs_ref = shift;
+
+ my %new_vars;
+ my (%old_vars, %dist_var_files, %found_dist_var_files);
+ my $confs_found = 0;
+
+
+ # Warn in case we can't find a specified dist file.
+ foreach my $dir (@$url_tmpdirs_ref) {
+ foreach my $dist_var_file (@$dist_var_files_ref) {
+ if (-e "$dir/$dist_var_file") {
+ $found_dist_var_files{$dist_var_file} = 1;
+ $confs_found++;
+ }
+ }
+ }
+
+ foreach my $dist_var_file (@$dist_var_files_ref) {
+ unless (exists($found_dist_var_files{$dist_var_file})) {
+ warn("WARNING: did not find variable file \"$dist_var_file\" in ".
+ "downloaded archive(s)\n")
+ unless($config{quiet});
+ }
+ }
+
+ unless ($confs_found) {
+ unless ($config{quiet}) {
+ warn("WARNING: no variable files found in downloaded archive(s), ".
+ "aborting check for new variables\n");
+ return;
+ }
+ }
+
+ # Read in variable names from old (target) var file.
+ open(LOCAL_VAR_FILE, "<", "$local_var_file")
+ or clean_exit("could not open $local_var_file for reading: $!");
+
+ my @local_var_conf = <LOCAL_VAR_FILE>;
+
+ foreach $_ (join_multilines(\@local_var_conf)) {
+ $old_vars{lc($1)}++ if (/$VAR_REGEXP/i);
+ }
+
+ close(LOCAL_VAR_FILE);
+
+ # Read in variables from new file(s).
+ foreach my $dir (@$url_tmpdirs_ref) {
+ foreach my $dist_var_file (@$dist_var_files_ref) {
+ my $conf = "$dir/$dist_var_file";
+ if (-e "$conf") {
+ my $num_new = 0;
+ print STDERR "Checking downloaded $dist_var_file for new variables... "
+ unless ($config{quiet});
+
+ open(DIST_CONF, "<", "$conf")
+ or clean_exit("could not open $conf for reading: $!");
+ my @dist_var_conf = <DIST_CONF>;
+ close(DIST_CONF);
+
+ foreach $_ (join_multilines(\@dist_var_conf)) {
+ if (/$VAR_REGEXP/i && !exists($old_vars{lc($1)})) {
+ my ($varname, $varval) = (lc($1), $2);
+ if (exists($new_vars{$varname})) {
+ warn("\nWARNING: new variable \"$varname\" is defined multiple ".
+ "times in downloaded files\n");
+ }
+ s/^\s*//;
+ push(@{$$ch_ref{new_vars}}, "$_\n");
+ $new_vars{$varname} = $varval;
+ $num_new++;
+ }
+ }
+
+ close(DIST_CONF);
+ print STDERR "$num_new new found.\n"
+ unless ($config{quiet});
+ }
+ }
+ }
+}
+
+
+
+# Add new variables to local snort.conf.
+sub add_new_vars($ $)
+{
+ my $ch_ref = shift;
+ my $varfile = shift;
+ my $tmp_varfile = "$tmpdir/tmp_varfile.conf";
+ my $new_content;
+
+ return unless ($#{$changes{new_vars}} > -1);
+
+ print STDERR "Adding new variables to $varfile... "
+ unless ($config{quiet});
+
+ open(OLD_LOCAL_CONF, "<", "$varfile")
+ or clean_exit("could not open $varfile for reading: $!");
+ my @old_content = <OLD_LOCAL_CONF>;
+ close(OLD_LOCAL_CONF);
+
+ open(NEW_LOCAL_CONF, ">", "$tmp_varfile")
+ or clean_exit("could not open $tmp_varfile for writing: $!");
+
+ my @old_vars = grep(/$VAR_REGEXP/i, @old_content);
+
+
+ # If any vars exist in old file, put new vars right after them.
+ if ($#old_vars > -1) {
+ while ($_ = shift(@old_content)) {
+ print NEW_LOCAL_CONF $_;
+ last if ($_ eq $old_vars[$#old_vars]);
+ }
+ }
+
+ print NEW_LOCAL_CONF @{$changes{new_vars}};
+ print NEW_LOCAL_CONF @old_content;
+
+ close(NEW_LOCAL_CONF);
+
+ clean_exit("could not copy $tmp_varfile to $varfile: $!")
+ unless (copy("$tmp_varfile", "$varfile"));
+
+ print STDERR "done.\n"
+ unless ($config{quiet});
+}
+
+
+
+# Convert msdos style path to cygwin style, e.g.
+# c:\foo => /cygdrive/c/foo
+sub msdos_to_cygwin_path($)
+{
+ my $path_ref = shift;
+
+ if ($$path_ref =~ /^([a-zA-Z]):[\/\\](.*)/) {
+ my ($drive, $dir) = ($1, $2);
+ $dir =~ s/\\/\//g;
+ $$path_ref = "/cygdrive/$drive/$dir";
+ return (1);
+ }
+
+ return (0);
+}
+
+
+
+# Parse and process a modifysid expression.
+# Return 1 if valid, or otherwise 0.
+sub parse_mod_expr($ $ $ $)
+{
+ my $mod_list_ref = shift; # where to store valid entries
+ my $sid_arg_list = shift; # comma-separated list of SIDs/files or wildcard
+ my $subst = shift; # regexp to look for
+ my $repl = shift; # regexp to replace it with
+
+ my @tmp_mod_list;
+
+ $sid_arg_list =~ s/\s+$//;
+
+ foreach my $sid_arg (split(/\s*,\s*/, $sid_arg_list)) {
+ my $type = "";
+
+ $type = "sid" if ($sid_arg =~ /^\d+$/);
+ $type = "file" if ($sid_arg =~ /^\S+.*\.\S+$/);
+ $type = "wildcard" if ($sid_arg eq "*");
+
+ return (0) unless ($type);
+
+ # Sanity check to make sure user escaped at least all the "$" in $subst.
+ if ($subst =~ /[^\\]\$./ || $subst =~ /^\$/) {
+ warn("WARNING: unescaped \$ in expression \"$subst\", all special ".
+ "characters must be escaped\n");
+ return (0);
+ }
+
+ # Only allow backreference variables. The check should at least catch some user typos.
+ if (($repl =~ /[^\\]\$(\D.)/ && $1 !~ /{\d/) || $repl =~ /[^\\]\$$/
+ || ($repl =~ /^\$(\D.)/ && $1 !~ /{\d/)) {
+ warn("WARNING: illegal replacement expression \"$repl\": unescaped \$ ".
+ "that isn't a backreference\n");
+ return (0);
+ }
+
+ # Don't permit unescaped @.
+ if ($repl =~ /[^\\]\@/ || $repl =~ /^\@/) {
+ warn("WARNING: illegal replacement expression \"$repl\": unescaped \@\n");
+ return (0);
+ }
+
+ # Make sure the regexp is valid.
+ my $repl_qq = "qq/$repl/";
+ my $dummy = "foo";
+
+ eval {
+ $dummy =~ s/$subst/$repl_qq/ee;
+ };
+
+ # We should probably check for warnings as well as errors...
+ if ($@) {
+ warn("Invalid regexp: $@");
+ return (0);
+ }
+
+ push(@tmp_mod_list, [$subst, $repl_qq, $type, $sid_arg]);
+ }
+
+ # If we come this far, all sids and the regexp were parsed successfully, so
+ # append them to real mod list array.
+ foreach my $mod_entry (@tmp_mod_list) {
+ push(@$mod_list_ref, $mod_entry);
+ }
+
+ return (1);
+}
+
+
+
+# Untaint a path. Die if it contains illegal chars.
+sub untaint_path($)
+{
+ my $path = shift;
+ my $orig_path = $path;
+
+ return $path unless ($config{use_path_checks});
+
+ (($path) = $path =~ /^([$OK_PATH_CHARS]+)$/)
+ or clean_exit("illegal character in path/filename ".
+ "\"$orig_path\", allowed are $OK_PATH_CHARS\n".
+ "Fix this or set use_path_checks=0 in oinkmaster.conf ".
+ "to disable this check completely if it is too strict.\n");
+
+ return ($path);
+}
+
+
+
+# Ask user to approve changes. Return 1 for yes, 0 for no.
+sub approve_changes()
+{
+ my $answer = "";
+
+ while ($answer !~ /^[yn]/i) {
+ print "Do you approve these changes? [Yn] ";
+ $answer = <STDIN>;
+ $answer = "y" unless ($answer =~ /\S/);
+ }
+
+ return ($answer =~ /^y/i);
+}
+
+
+
+# Remove common leading and trailing stuff from two rules.
+sub minimize_diff($ $)
+{
+ my $old_rule = shift;
+ my $new_rule = shift;
+
+ my $original_old = $old_rule;
+ my $original_new = $new_rule;
+
+ # Additional chars to print next to the diffing part.
+ my $additional_chars = 20;
+
+ # Remove the rev keyword from the rules, as it often
+ # makes the whole diff minimizing useless.
+ $old_rule =~ s/\s*\b(rev\s*:\s*\d+\s*;)\s*//;
+ my $old_rev = $1;
+
+ $new_rule =~ s/\s*\b(rev\s*:\s*\d+\s*;)\s*//;
+ my $new_rev = $1;
+
+ # If rev was the only thing that changed, we want to restore the rev
+ # before continuing so we don't remove common stuff from rules that
+ # are identical.
+ if ($old_rule eq $new_rule) {
+ $old_rule = $original_old;
+ $new_rule = $original_new;
+ }
+
+ # Temporarily remove possible leading # so it works nicely
+ # with modified rules that are also being either enabled or disabled.
+ my $old_is_disabled = 0;
+ my $new_is_disabled = 0;
+
+ $old_is_disabled = 1 if ($old_rule =~ s/^#//);
+ $new_is_disabled = 1 if ($new_rule =~ s/^#//);
+
+ # Go forward char by char until they aren't equeal.
+ # $i will bet set to the index where they diff.
+ my @old = split(//, $old_rule);
+ my @new = split(//, $new_rule);
+
+ my $i = 0;
+ while ($i <= $#old && $i <= $#new && $old[$i] eq $new[$i]) {
+ $i++;
+ }
+
+ # Now same thing but backwards.
+ # $j will bet set to the index where they diff.
+ @old = reverse(split(//, $old_rule));
+ @new = reverse(split(//, $new_rule));
+
+ my $j = 0;
+ while ($j <= $#old && $j <= $#new && $old[$j] eq $new[$j]) {
+ $j++;
+ }
+
+ # Print some additional chars on either side, if there is room for it.
+ $i -= $additional_chars;
+ $i = 0 if ($i < 0);
+
+ $j = -$j + $additional_chars;
+ $j = 0 if ($j > -1);
+
+ my ($old, $new);
+
+ # Print entire rules (i.e. they can not be shortened).
+ if (!$i && !$j) {
+ $old = $old_rule;
+ $new = $new_rule;
+
+ # Leading and trailing stuff can be removed.
+ } elsif ($i && $j) {
+ $old = "..." . substr($old_rule, $i, $j) . "...";
+ $new = "..." . substr($new_rule, $i, $j) . "...";
+
+ # Trailing stuff can be removed.
+ } elsif (!$i && $j) {
+ $old = substr($old_rule, $i, $j) . "...";
+ $new = substr($new_rule, $i, $j) . "...";
+
+ # Leading stuff can be removed.
+ } elsif ($i && !$j) {
+ $old = "..." . substr($old_rule, $i);
+ $new = "..." . substr($new_rule, $i);
+ }
+
+ chomp($old, $new);
+ $old .= "\n";
+ $new .= "\n";
+
+ # Restore possible leading # now.
+ $old = "#$old" if ($old_is_disabled);
+ $new = "#$new" if ($new_is_disabled);
+
+ return ($old, $new);
+}
+
+
+
+# Check a string and return 1 if it's a valid single-line snort rule.
+# Msg string is put in second arg, sid in third (those are the only
+# required keywords, besides the leading rule actions).
+sub parse_singleline_rule($ $ $)
+{
+ my $line = shift;
+ my $msg_ref = shift;
+ my $sid_ref = shift;
+
+ undef($$msg_ref);
+ undef($$sid_ref);
+
+ if ($line =~ /$SINGLELINE_RULE_REGEXP/oi) {
+
+ if ($line =~ /\bmsg\s*:\s*"(.+?)"\s*;/i) {
+ $$msg_ref = $1;
+ } else {
+ return (0);
+ }
+
+ if ($line =~ /\bsid\s*:\s*(\d+)\s*;/i) {
+ $$sid_ref = $1;
+ } else {
+ return (0);
+ }
+
+ return (1);
+ }
+
+ return (0);
+}
+
+
+
+# Merge multiline directives in an array by simply removing traling backslashes.
+sub join_multilines($)
+{
+ my $multiline_conf_ref = shift;
+ my $joined_conf = "";
+
+ foreach $_ (@$multiline_conf_ref) {
+ s/\\\s*\n$//;
+ $joined_conf .= $_;
+ }
+
+ return (split/\n/, $joined_conf);
+}
+
+
+
+# Catch SIGINT.
+sub catch_sigint()
+{
+ $SIG{INT} = 'IGNORE';
+ print STDERR "\nInterrupted, cleaning up.\n";
+ sleep(1);
+ clean_exit("interrupted by signal");
+}
+
+
+
+# Remove temporary directory and exit.
+# If a non-empty string is given as argument, it will be regarded
+# as an error message and we will use die() with the message instead
+# of just exit(0).
+sub clean_exit($)
+{
+ my $err_msg = shift;
+
+ $SIG{INT} = 'DEFAULT';
+
+ if (defined($tmpdir) && -d "$tmpdir") {
+ chdir(File::Spec->rootdir());
+ rmtree("$tmpdir", 0, 1);
+ undef($tmpdir);
+ }
+
+ if (!defined($err_msg) || $err_msg eq "") {
+ exit(0);
+ } else {
+ chomp($err_msg);
+ die("\n$0: Error: $err_msg\n\nOink, oink. Exiting...\n");
+ }
+}
+
+
+
+#### EOF ####
diff --git a/config/snort/pfsense_rules/local.rules b/config/snort/pfsense_rules/local.rules
new file mode 100644
index 00000000..a9072733
--- /dev/null
+++ b/config/snort/pfsense_rules/local.rules
@@ -0,0 +1,7 @@
+# ----------------
+# LOCAL RULES
+# ----------------
+# This file intentionally does not come with signatures. Put your local
+# additions here. Pfsense first install rule. Rule edit tabe fails with out this file.
+#
+# \ No newline at end of file
diff --git a/config/snort/pfsense_rules/pfsense_rules.tar.gz.md5 b/config/snort/pfsense_rules/pfsense_rules.tar.gz.md5
index 97a55e1d..0aede4a0 100644
--- a/config/snort/pfsense_rules/pfsense_rules.tar.gz.md5
+++ b/config/snort/pfsense_rules/pfsense_rules.tar.gz.md5
@@ -1 +1 @@
-101 \ No newline at end of file
+102 \ No newline at end of file
diff --git a/config/snort/pfsense_rules/rules/pfsense-voip.rules b/config/snort/pfsense_rules/rules/pfsense-voip.rules
index 3142c0b6..12f2fdf2 100644
--- a/config/snort/pfsense_rules/rules/pfsense-voip.rules
+++ b/config/snort/pfsense_rules/rules/pfsense-voip.rules
@@ -1,11 +1,10 @@
-alert ip any any -> $HOME_NET $SIP_PROXY_PORTS (msg:"OPTIONS SIP scan"; content:"OPTIONS"; depth:7; threshold: type both , track by_src, count 30, seconds 3; sid:5000004; rev:1;)
+alert ip any any -> $HOME_NET $SIP_PROXY_PORTS (msg:"OPTIONS SIP scan"; content:"OPTIONS"; depth:7; threshold: type both , track by_src, count 30, seconds 3; sid:5000001; rev:1;)
# Excessive number of SIP 4xx Responses Does not work
-#### alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"Excessive number of SIP 4xx Responses - possible user or password guessing attack"; pcre:"/^SIP\/2.0 4\d{2}"; threshold: type both, track by_src, count 100, seconds 60; sid:5000008; rev:1;)
-alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"Ghost call attack"; content:"SIP/2.0 180"; depth:11; threshold: type both, track by_src, count 100, seconds 60; sid:5000009; rev:1;)
-
+#### alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"Excessive number of SIP 4xx Responses - possible user or password guessing attack"; pcre:"/^SIP\/2.0 4\d{2}"; threshold: type both, track by_src, count 100, seconds 60; sid:5000002; rev:1;)
+alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"Ghost call attack"; content:"SIP/2.0 180"; depth:11; threshold: type both, track by_src, count 100, seconds 60; sid:5000003; rev:1;)
# Rule for alerting of INVITE flood attack:
-alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"INVITE message flooding"; content:"INVITE"; depth:6; threshold: type both , track by_src, count 100, seconds 60; sid:5000002; rev:1;)
+alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"INVITE message flooding"; content:"INVITE"; depth:6; threshold: type both , track by_src, count 100, seconds 60; sid:5000004; rev:1;)
# Rule for alerting of REGISTER flood attack:
alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"REGISTER message flooding"; content:"REGISTER"; depth:8; threshold: type both , track by_src, count 100, seconds 60; sid:5000005; rev:1;)
# Threshold rule for unauthorized responses:
-alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"INVITE message flooding"; content:"SIP/2.0 401 Unauthorized"; depth:24; threshold: type both, track by_src, count 100, seconds 60; sid:5000008; rev:1;)
+alert ip any any -> $SIP_PROXY_IP $SIP_PROXY_PORTS (msg:"INVITE message flooding"; content:"SIP/2.0 401 Unauthorized"; depth:24; threshold: type both, track by_src, count 100, seconds 60; sid:5000006; rev:1;)
diff --git a/config/snort/snort.inc b/config/snort/snort.inc
index 884f0883..ebcab85c 100755
--- a/config/snort/snort.inc
+++ b/config/snort/snort.inc
@@ -53,7 +53,6 @@ function sync_package_snort_reinstall()
/* start snort service */
start_service("snort");
}
-
function sync_package_snort()
{
global $config, $g;
@@ -89,7 +88,7 @@ function sync_package_snort()
exec("/bin/cp /usr/local/etc/snort/threshold.conf-sample /usr/local/etc/snort/threshold.conf");
exec("/bin/cp /usr/local/etc/snort/unicode.map-sample /usr/local/etc/snort/unicode.map");
exec("/bin/rm -f /usr/local/etc/rc.d/snort");
-
+
$first = 0;
$snortInterfaces = array(); /* -gtm */
@@ -137,8 +136,8 @@ function sync_package_snort()
if($bpfmaxinsns)
mwexec_bg("sysctl net.bpf.maxinsns={$bpfmaxinsns}");
- /* always stop snort2c before starting snort -gtm */
- $start .= "/usr/bin/killall snort2c\n";
+ /* always stop barnyard2 before starting snort -gtm */
+ $start .= "/usr/bin/killall barnyard2\n";
/* start a snort process for each interface -gtm */
/* Note the sleep delay. Seems to help getting mult interfaces to start -gtm */
@@ -146,36 +145,103 @@ function sync_package_snort()
/* TODO; get snort to start under nologin shell */
foreach($snortInterfaces as $snortIf)
{
- $start .= "sleep 8\n";
+ $start .= "sleep 4\n";
$start .= "snort -c /usr/local/etc/snort/snort.conf -l /var/log/snort -D -i {$snortIf} -q\n";
+ /* define snortbarnyardlog_chk */
+ $snortbarnyardlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog'];
+ if ($snortbarnyardlog_info_chk == on)
+ $start .= "\nsleep 4;barnyard2 -c /usr/local/etc/barnyard2.conf -d /var/log/snort -f snort.u2 -w /usr/local/etc/snort/barnyard2.waldo -D -q\n";
}
-
- /* if block offenders is checked, start snort2c */
- if($_POST['blockoffenders']) {
- $start .= "\nsleep 8\n";
- $start .= "snort2c -w /var/db/whitelist -a /var/log/snort/alert\n";
- }
-
- $sample_before = "\nBEFORE_MEM=`top | grep Free | grep Wired | awk '{print \$10}'`\n";
- $sample_after = "\nAFTER_MEM=`top | grep Free | grep Wired | awk '{print \$10}'`\n";
- $sleep_before_final = "\necho \"Sleeping before final memory sampling...\"\nsleep 17";
- $total_free_after = "\nTOTAL_USAGE=`top | grep snort | grep -v grep | awk '{ print \$6 }'`\n";
- $echo_usage = "\necho \"Ram free BEFORE starting Snort: \${BEFORE_MEM} -- Ram free AFTER starting Snort: \${AFTER_MEM}\" -- Mode {$snort_performance} -- Snort memory usage: \$TOTAL_USAGE | logger -p daemon.info -i -t SnortStartup\n";
-
+ $check_if_snort_runs = "\n\tif [ \"`ls -A /usr/local/etc/snort/rules`\" ] ; then\n\techo \"rules exist\"\n\telse\n\techo \"rules DONT exist\"\n\texit 2\n\tfi \n\n\tif [ \"`pgrep -x snort`\" = \"\" ] ; then\n\t/bin/rm /tmp/snort.sh.pid\n\tfi \n\n\tif [ \"`pgrep -x snort`\" != \"\" ] ; then\n\tlogger -p daemon.info -i -t SnortStartup \"Snort already running...\"\n\t/usr/local/bin/php -f /usr/local/pkg/pf/snort_dynamic_ip_reload.php\n\texit 1\n\tfi\n\n";
+ $if_snort_pid = "\nif ls /tmp/snort.sh.pid > /dev/null\nthen\n echo \"snort.sh is running\"\n exit 0\nelse\n echo \"snort.sh is not running\"\nfi\n";
+ $echo_snort_sh_pid = "\necho \"snort.sh run\" > /tmp/snort.sh.pid\n";
+ $echo_snort_sh_startup_log = "\necho \"snort.sh run\" >> /tmp/snort.sh_startup.log\n";
+ $del_old_pids = "\nrm -f /var/run/snort_*\n";
+ $sample_before = "BEFORE_MEM=`top | grep Wired | awk '{print \$12}'`\n";
+ $sample_after = "\n\tAFTER_MEM=`top | grep Wired | awk '{print \$12}'`\n";
+ if ($snort_performance == "ac-bnfa")
+ $sleep_before_final = "\necho \"Sleeping before final memory sampling...\"\nWAITSECURE=60\n";
+ else
+ $sleep_before_final = "\necho \"Sleeping before final memory sampling...\"\nWAITSECURE=300\n";
+ $sleep_before_final .= "while [ \"\$MYSNORTLOG\" = \"\" -a \$WAITSECURE -gt 0 ] ; do\n\tsleep 2\n\tMYSNORTLOG=`/usr/sbin/clog /var/log/system.log | grep snort | tail | grep 'Snort initialization completed successfully'`\n\tWAITSECURE=`expr \$WAITSECURE - 1`\ndone\n";
+ $total_used_after = "TOTAL_USAGE=`top | grep snort | grep -v grep | awk '{ print \$6 }'`\n";
+ $echo_usage .= $sample_after . "\t" . $total_used_after . "\techo \"Ram free BEFORE starting Snort: \$BEFORE_MEM -- Ram free AFTER starting Snort: \$AFTER_MEM -- Mode " . $snort_performance . " -- Snort memory usage: \$TOTAL_USAGE\" | logger -p daemon.info -i -t SnortStartup\n\n";
+
/* write out rc.d start/stop file */
write_rcfile(array(
"file" => "snort.sh",
- "start" => "{$sample_before}{$start}{$sleep_before_final}{$sample_after}{$echo_usage}",
- "stop" => "/usr/bin/killall snort; killall snort2c"
+ "start" => "{$check_if_snort_runs}{$if_snort_pid}{$echo_snort_sh_pid}{$echo_snort_sh_startup_log}{$del_old_pids}{$sample_before}{$start}{$sleep_before_final}{$echo_usage}",
+ "stop" => "/usr/bin/killall snort; killall barnyard2"
)
);
/* create snort configuration file */
create_snort_conf();
+/* create barnyard2 configuration file */
+$snortbarnyardlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog'];
+if ($snortbarnyardlog_info_chk == on)
+ create_barnyard2_conf();
+
+ /* snort will not start on install untill setting are set */
+if ($config['installedpackages']['snort']['config'][0]['autorulesupdate7'] != "") {
/* start snort service */
conf_mount_ro();
start_service("snort");
+ }
+}
+
+/* open barnyard2.conf for writing */
+function create_barnyard2_conf() {
+ global $bconfig, $bg;
+ /* write out barnyard2_conf */
+ $barnyard2_conf_text = generate_barnyard2_conf();
+// conf_mount_rw();
+ $bconf = fopen("/usr/local/etc/barnyard2.conf", "w");
+ if(!$bconf) {
+ log_error("Could not open /usr/local/etc/barnyard2.conf for writing.");
+ exit;
+ }
+ fwrite($bconf, $barnyard2_conf_text);
+ fclose($bconf);
+// conf_mount_ro();
+}
+/* open barnyard2.conf for writing" */
+function generate_barnyard2_conf() {
+
+ global $config, $g;
+ conf_mount_rw();
+
+/* define snortbarnyardlog */
+$snortbarnyardlog_database_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog_database'];
+
+$barnyard2_conf_text = <<<EOD
+
+ Copyright (C) 2006 Scott Ullrich
+ part of pfSense
+ All rights reserved.
+
+# set the appropriate paths to the file(s) your Snort process is using
+config reference-map: /usr/local/etc/snort/reference.config
+config class-map: /usr/local/etc/snort/classification.config
+config gen-msg-map: /usr/local/etc/snort/gen-msg.map
+config sid-msg-map: /usr/local/etc/snort/sid-msg.map
+
+config hostname: pfsense.local
+config interface: vr0
+
+# Step 2: setup the input plugins
+input unified2
+
+# database: log to a variety of databases
+# output database: log, mysql, user=snort password=snort123 dbname=snort host=192.168.1.22
+
+$snortbarnyardlog_database_info_chk
+
+EOD;
+
+ return $barnyard2_conf_text;
+
}
function create_snort_conf() {
@@ -194,10 +260,9 @@ function create_snort_conf() {
}
function snort_deinstall() {
-// $text_ww = "*/60\t* \t 1\t *\t *\t root\t /usr/bin/nice -n20 /usr/local/pkg/snort_check_for_rule_updates.php";
-// $filenamea = "/etc/crontab";
- /* remove auto rules update helper */
-// remove_text_from_file($filenamea, $text_ww);
+
+ global $config, $g;
+
/* remove custom sysctl */
remove_text_from_file("/etc/sysctl.conf", "sysctl net.bpf.bufsize=20480");
/* decrease bpf buffers back to 4096, from 20480 */
@@ -212,6 +277,69 @@ function snort_deinstall() {
exec("cd /var/db/pkg && pkg_delete `ls | grep libdnet`");
exec("/usr/bin/killall -9 snort");
exec("/usr/bin/killall snort");
+
+ /* Remove snort cron entries Ugly code needs smoothness*/
+
+ function snort_rm_blocked_deinstall_cron($should_install) {
+ global $config, $g;
+
+ $is_installed = false;
+
+ if(!$config['cron']['item'])
+ return;
+
+ $x=0;
+ foreach($config['cron']['item'] as $item) {
+ if (strstr($item['command'], "snort2c")) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+ if($is_installed == true) {
+ if($x > 0) {
+ unset($config['cron']['item'][$x]);
+ write_config();
+ }
+ configure_cron();
+ }
+ }
+
+ function snort_rules_up_deinstall_cron($should_install) {
+ global $config, $g;
+
+ $is_installed = false;
+
+ if(!$config['cron']['item'])
+ return;
+
+ $x=0;
+ foreach($config['cron']['item'] as $item) {
+ if (strstr($item['command'], "snort_check_for_rule_updates.php")) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+ if($is_installed == true) {
+ if($x > 0) {
+ unset($config['cron']['item'][$x]);
+ write_config();
+ }
+ configure_cron();
+ }
+ }
+
+snort_rm_blocked_deinstall_cron("");
+snort_rules_up_deinstall_cron("");
+
+
+ /* Unset snort registers in conf.xml IMPORTANT snort will not start with out this */
+ /* Keep this as a last step */
+ unset($config['installedpackages']['snort']['config'][0]['autorulesupdate7']);
+ unset($config['installedpackages']['snort']['config'][0]['rm_blocked']);
+ write_config();
+
}
function generate_snort_conf() {
@@ -241,15 +369,22 @@ $tcpdumplog_info_chk = $config['installedpackages']['snortadvanced']['config'][0
if ($tcpdumplog_info_chk == on)
$tcpdumplog_type = "output log_tcpdump: snorttcpd.log";
-/* define snortmysqllog */
-$snortmysqllog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortmysqllog'];
+/* define snortbarnyardlog_chk */
+$snortbarnyardlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog'];
+if ($snortbarnyardlog_info_chk == on)
+ $snortbarnyardlog_type = "barnyard2 -c /usr/local/etc/barnyard2.conf -d /var/log/snort -f snort.u2 -w /usr/local/etc/snort/barnyard2.waldo -D";
/* define snortunifiedlog */
$snortunifiedlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortunifiedlog'];
if ($snortunifiedlog_info_chk == on)
$snortunifiedlog_type = "output unified2: filename snort.u2, limit 128";
-/* define servers and ports snortdefservers */
+/* define spoink */
+$spoink_info_chk = $config['installedpackages']['snort']['config'][0]['blockoffenders7'];
+if ($spoink_info_chk == on)
+ $spoink_type = "output alert_pf: /var/db/whitelist,snort2c";
+
+ /* define servers and ports snortdefservers */
/* def DNS_SERVSERS */
$def_dns_servers_info_chk = $config['installedpackages']['snortdefservers']['config'][0]['def_dns_servers'];
@@ -508,6 +643,230 @@ else
else
$snort_performance = "ac-bnfa";
+ /* set the snort block hosts time IMPORTANT snort has trouble installing if snort_rm_blocked_info_ck != "" */
+ $snort_rm_blocked_info_ck = $config['installedpackages']['snort']['config'][0]['rm_blocked'];
+ if ($snort_rm_blocked_info_ck == "never_b")
+ $snort_rm_blocked_false = "";
+ else
+ $snort_rm_blocked_false = "true";
+
+if ($snort_rm_blocked_info_ck != "") {
+function snort_rm_blocked_install_cron($should_install) {
+ global $config, $g;
+
+ if ($g['booting']==true)
+ return;
+
+ $is_installed = false;
+
+ if(!$config['cron']['item'])
+ return;
+
+ $x=0;
+ foreach($config['cron']['item'] as $item) {
+ if (strstr($item['command'], "snort2c")) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+ $snort_rm_blocked_info_ck = $config['installedpackages']['snort']['config'][0]['rm_blocked'];
+ if ($snort_rm_blocked_info_ck == "1h_b") {
+ $snort_rm_blocked_min = "*/5";
+ $snort_rm_blocked_hr = "*";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "3600";
+ }
+ if ($snort_rm_blocked_info_ck == "3h_b") {
+ $snort_rm_blocked_min = "*/15";
+ $snort_rm_blocked_hr = "*";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "10800";
+ }
+ if ($snort_rm_blocked_info_ck == "6h_b") {
+ $snort_rm_blocked_min = "*/30";
+ $snort_rm_blocked_hr = "*";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "21600";
+ }
+ if ($snort_rm_blocked_info_ck == "12h_b") {
+ $snort_rm_blocked_min = "2";
+ $snort_rm_blocked_hr = "*/1";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "43200";
+ }
+ if ($snort_rm_blocked_info_ck == "1d_b") {
+ $snort_rm_blocked_min = "2";
+ $snort_rm_blocked_hr = "*/2";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "86400";
+ }
+ if ($snort_rm_blocked_info_ck == "4d_b") {
+ $snort_rm_blocked_min = "2";
+ $snort_rm_blocked_hr = "*/8";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "345600";
+ }
+ if ($snort_rm_blocked_info_ck == "7d_b") {
+ $snort_rm_blocked_min = "2";
+ $snort_rm_blocked_hr = "*/14";
+ $snort_rm_blocked_mday = "*";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "604800";
+ }
+ if ($snort_rm_blocked_info_ck == "28d_b") {
+ $snort_rm_blocked_min = "2";
+ $snort_rm_blocked_hr = "0";
+ $snort_rm_blocked_mday = "*/2";
+ $snort_rm_blocked_month = "*";
+ $snort_rm_blocked_wday = "*";
+ $snort_rm_blocked_expire = "2419200";
+ }
+ switch($should_install) {
+ case true:
+ if(!$is_installed) {
+ $cron_item = array();
+ $cron_item['minute'] = "$snort_rm_blocked_min";
+ $cron_item['hour'] = "$snort_rm_blocked_hr";
+ $cron_item['mday'] = "$snort_rm_blocked_mday";
+ $cron_item['month'] = "$snort_rm_blocked_month";
+ $cron_item['wday'] = "$snort_rm_blocked_wday";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -t $snort_rm_blocked_expire snort2c";
+ $config['cron']['item'][] = $cron_item;
+ write_config("Installed 15 minute filter reload for Time Based Rules");
+ configure_cron();
+ }
+ break;
+ case false:
+ if($is_installed == true) {
+ if($x > 0) {
+ unset($config['cron']['item'][$x]);
+ write_config();
+ }
+ configure_cron();
+ }
+ break;
+ }
+ }
+ snort_rm_blocked_install_cron("");
+ snort_rm_blocked_install_cron($snort_rm_blocked_false);
+}
+
+ /* set the snort rules update time */
+ $snort_rules_up_info_ck = $config['installedpackages']['snort']['config'][0]['autorulesupdate7'];
+ if ($snort_rules_up_info_ck == "never_up")
+ $snort_rules_up_false = "";
+ else
+ $snort_rules_up_false = "true";
+
+if ($snort_rules_up_info_ck != "") {
+function snort_rules_up_install_cron($should_install) {
+ global $config, $g;
+
+ if ($g['booting']==true)
+ return;
+
+ $is_installed = false;
+
+ if(!$config['cron']['item'])
+ return;
+
+ $x=0;
+ foreach($config['cron']['item'] as $item) {
+ if (strstr($item['command'], "snort_check_for_rule_updates.php")) {
+ $is_installed = true;
+ break;
+ }
+ $x++;
+ }
+ $snort_rules_up_info_ck = $config['installedpackages']['snort']['config'][0]['autorulesupdate7'];
+ if ($snort_rules_up_info_ck == "6h_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "*/6";
+ $snort_rules_up_mday = "*";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ if ($snort_rules_up_info_ck == "12h_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "*/12";
+ $snort_rules_up_mday = "*";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ if ($snort_rules_up_info_ck == "1d_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "0";
+ $snort_rules_up_mday = "*/1";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ if ($snort_rules_up_info_ck == "4d_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "0";
+ $snort_rules_up_mday = "*/4";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ if ($snort_rules_up_info_ck == "7d_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "0";
+ $snort_rules_up_mday = "*/7";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ if ($snort_rules_up_info_ck == "28d_up") {
+ $snort_rules_up_min = "3";
+ $snort_rules_up_hr = "0";
+ $snort_rules_up_mday = "*/28";
+ $snort_rules_up_month = "*";
+ $snort_rules_up_wday = "*";
+ }
+ switch($should_install) {
+ case true:
+ if(!$is_installed) {
+ $cron_item = array();
+ $cron_item['minute'] = "$snort_rules_up_min";
+ $cron_item['hour'] = "$snort_rules_up_hr";
+ $cron_item['mday'] = "$snort_rules_up_mday";
+ $cron_item['month'] = "$snort_rules_up_month";
+ $cron_item['wday'] = "$snort_rules_up_wday";
+ $cron_item['who'] = "root";
+ $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/snort_check_for_rule_updates.php >> /usr/local/etc/snort_bkup/snort_update.log";
+ $config['cron']['item'][] = $cron_item;
+ write_config("Installed 15 minute filter reload for Time Based Rules");
+ configure_cron();
+ }
+ break;
+ case false:
+ if($is_installed == true) {
+ if($x > 0) {
+ unset($config['cron']['item'][$x]);
+ write_config();
+ }
+ configure_cron();
+ }
+ break;
+ }
+ }
+ snort_rules_up_install_cron("");
+ snort_rules_up_install_cron($snort_rules_up_false);
+}
+
/* open snort2c's whitelist for writing */
$whitelist = fopen("/var/db/whitelist", "w");
if(!$whitelist) {
@@ -592,11 +951,11 @@ else
/* should we whitelist vpns? */
$whitelistvpns = $config['installedpackages']['snort']['config'][0]['whitelistvpns'];
- /* grab a list of vpns and whitelist if user desires */
+ /* grab a list of vpns and whitelist if user desires added by nestorfish 954 */
if($whitelistvpns) {
$vpns_list = get_vpns_list();
$whitelist_vpns = split(" ", $vpns_list);
- foreach($whitelist_split as $wl)
+ foreach($whitelist_vpns as $wl)
if(trim($wl))
fwrite($whitelist, trim($wl) . "\n");
}
@@ -772,14 +1131,15 @@ preprocessor frag3_engine: policy first
preprocessor frag3_engine: policy bsd detect_anomalies
preprocessor stream5_global: max_tcp 8192, track_tcp yes, \
-track_udp yes, track_icmp yes
+track_udp yes
+# track_icmp yes
preprocessor stream5_tcp: bind_to any, policy windows
preprocessor stream5_tcp: bind_to any, policy linux
preprocessor stream5_tcp: bind_to any, policy vista
preprocessor stream5_tcp: bind_to any, policy macos
preprocessor stream5_tcp: policy BSD, ports both all, use_static_footprint_sizes
preprocessor stream5_udp
-preprocessor stream5_icmp
+# preprocessor stream5_icmp
##########################
#
@@ -799,7 +1159,7 @@ preprocessor perfmonitor: time 300 file /var/log/snort/snort.stats pktcnt 10000
preprocessor http_inspect: global iis_unicode_map unicode.map 1252
preprocessor http_inspect_server: server default \
- ports { 80 8080 3128 } \
+ ports { 80 8080 } \
no_alerts \
non_strict \
non_rfc_char { 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 } \
@@ -964,6 +1324,7 @@ $alertsystemlog_type
$tcpdumplog_type
$snortmysqllog_info_chk
$snortunifiedlog_type
+$spoink_type
#################
#
diff --git a/config/snort/snort.xml b/config/snort/snort.xml
index f8e35c28..2370be0e 100644
--- a/config/snort/snort.xml
+++ b/config/snort/snort.xml
@@ -46,8 +46,8 @@
<requirements>Describe your package requirements here</requirements>
<faq>Currently there are no FAQ items provided.</faq>
<name>Snort</name>
- <version>2.8.4.1</version>
- <title>Services: Snort 2.8.4.1 pkg v. 1.5</title>
+ <version>2.8.4.1_1</version>
+ <title>Services: Snort 2.8.4.1_2 pkg v. 1.6</title>
<include_file>/usr/local/pkg/snort.inc</include_file>
<menu>
<name>Snort</name>
@@ -59,6 +59,7 @@
<name>snort</name>
<rcfile>snort.sh</rcfile>
<executable>snort</executable>
+ <description>Snort is the most widely deployed IDS/IPS technology worldwide..</description>
</service>
<tabs>
<tab>
@@ -106,82 +107,87 @@
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort.inc</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort.inc</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/bin/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/bin/snort2c</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/bin/barnyard2</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/bin/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/bin/oinkmaster_contrib/create-sidmap.pl</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/bin/oinkmaster_contrib/create-sidmap.pl</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/bin/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/bin/mons2c</item>
- </additional_files_needed>
+ <item>http://www.pfsense.com/packages/config/snort-dev/bin/oinkmaster_contrib/oinkmaster.pl</item>
+ </additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_download_rules.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_download_rules.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_rules.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_rules.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_rules_edit.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_rules_edit.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_rulesets.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_rulesets.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_whitelist.xml</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_whitelist.xml</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_blocked.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_blocked.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_check_for_rule_updates.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_check_for_rule_updates.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_alerts.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_alerts.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/pkg/pf/</prefix>
+ <chmod>077</chmod>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_dynamic_ip_reload.php</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_dynamic_ip_reload.php</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_advanced.xml</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_advanced.xml</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_define_servers.xml</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_define_servers.xml</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/snort_threshold.xml</item>
</additional_files_needed>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
<chmod>077</chmod>
- <item>http://www.pfsense.com/packages/config/snort/snort_threshold.xml</item>
+ <item>http://www.pfsense.com/packages/config/snort-dev/pfsense_rules/local.rules</item>
</additional_files_needed>
<fields>
<field>
@@ -194,7 +200,7 @@
<multiple>true</multiple>
</field>
<field>
- <fielddescr>Performance</fielddescr>
+ <fielddescr>Memory Performance</fielddescr>
<fieldname>performance</fieldname>
<description>Lowmem and ac-bnfa are recommended for low end systems, Ac: high memory, best performance, ac-std: moderate memory,high performance, acs: small memory, moderateperformance, ac-banded: small memory,moderate performance, ac-sparsebands: small memory, high performance.</description>
<type>select</type>
@@ -246,16 +252,92 @@
</field>
<field>
<fielddescr>Block offenders</fielddescr>
- <fieldname>blockoffenders</fieldname>
+ <fieldname>blockoffenders7</fieldname>
<description>Checking this option will automatically block hosts that generate a snort alert.</description>
<type>checkbox</type>
<size>60</size>
</field>
<field>
+ <fielddescr>Remove blocked hosts every</fielddescr>
+ <fieldname>rm_blocked</fieldname>
+ <description>Please select the amount of time hosts are blocked</description>
+ <type>select</type>
+ <options>
+ <option>
+ <name>never</name>
+ <value>never_b</value>
+ </option>
+ <option>
+ <name>1 hour</name>
+ <value>1h_b</value>
+ </option>
+ <option>
+ <name>3 hours</name>
+ <value>3h_b</value>
+ </option>
+ <option>
+ <name>6 hours</name>
+ <value>6h_b</value>
+ </option>
+ <option>
+ <name>12 hours</name>
+ <value>12h_b</value>
+ </option>
+ <option>
+ <name>1 day</name>
+ <value>1d_b</value>
+ </option>
+ <option>
+ <name>4 days</name>
+ <value>4d_b</value>
+ </option>
+ <option>
+ <name>7 days</name>
+ <value>7d_b</value>
+ </option>
+ <option>
+ <name>28 days</name>
+ <value>28d_b</value>
+ </option>
+ </options>
+ </field>
+ <field>
+ </field>
+ <field>
<fielddescr>Update rules automatically</fielddescr>
- <fieldname>automaticrulesupdate</fieldname>
- <description>Checking this option will automatically check for and update rules once a week from snort.org.</description>
- <type>checkbox</type>
+ <fieldname>autorulesupdate7</fieldname>
+ <description>Please select the update times for rules.</description>
+ <type>select</type>
+ <options>
+ <option>
+ <name>never</name>
+ <value>never_up</value>
+ </option>
+ <option>
+ <name>6 hours</name>
+ <value>6h_up</value>
+ </option>
+ <option>
+ <name>12 hours</name>
+ <value>12h_up</value>
+ </option>
+ <option>
+ <name>1 day</name>
+ <value>1d_up</value>
+ </option>
+ <option>
+ <name>4 days</name>
+ <value>4d_up</value>
+ </option>
+ <option>
+ <name>7 days</name>
+ <value>7d_up</value>
+ </option>
+ <option>
+ <name>28 days</name>
+ <value>28d_up</value>
+ </option>
+ </options>
</field>
<field>
<fielddescr>Whitelist VPNs automatically</fielddescr>
@@ -276,27 +358,21 @@
<type>checkbox</type>
</field>
<field>
- <fielddescr>Sync Snort configuration to secondary cluster members</fielddescr>
- <fieldname>syncxmlrpc</fieldname>
- <description>Checking this option will automatically sync the snort configuration via XMLRPC to CARP cluster members.</description>
- <type>checkbox</type>
- </field>
- <field>
<fielddescr>Install emergingthreats rules.</fielddescr>
<fieldname>emergingthreats</fieldname>
<description>Emerging Threats is an open source community that produces fastest moving and diverse Snort Rules.</description>
<type>checkbox</type>
</field>
</fields>
- <custom_add_php_command>
- </custom_add_php_command>
<custom_php_resync_config_command>
sync_package_snort();
</custom_php_resync_config_command>
+ <custom_add_php_command>
+ </custom_add_php_command>
<custom_php_install_command>
sync_package_snort_reinstall();
</custom_php_install_command>
<custom_php_deinstall_command>
snort_deinstall();
</custom_php_deinstall_command>
-</packagegui>
+</packagegui> \ No newline at end of file
diff --git a/config/snort/snort_advanced.xml b/config/snort/snort_advanced.xml
index fa7f7d0f..6e81123f 100644
--- a/config/snort/snort_advanced.xml
+++ b/config/snort/snort_advanced.xml
@@ -153,9 +153,15 @@
<description>Snort will log packets to a tcpdump-formatted file. The file then can be analyzed by a wireshark type of application. WARNING: File may become large.</description>
<type>checkbox</type>
</field>
+ <field>
+ <fielddescr>Enable Barnyard2.</fielddescr>
+ <fieldname>snortbarnyardlog</fieldname>
+ <description>This will enable barnyard2 in the snort package. You will also have to set the database credentials.</description>
+ <type>checkbox</type>
+ </field>
<field>
- <fielddescr>Log to a mysql database.</fielddescr>
- <fieldname>snortmysqllog</fieldname>
+ <fielddescr>Barnyard2 Log Mysql Database.</fielddescr>
+ <fieldname>snortbarnyardlog_database</fieldname>
<description>Example: output database: log, mysql, dbname=snort user=snort host=localhost password=xyz</description>
<type>input</type>
<size>101</size>
@@ -164,7 +170,7 @@
<field>
<fielddescr>Log Alerts to a snort unified file.</fielddescr>
<fieldname>snortunifiedlog</fieldname>
- <description>Snort will log Alerts to a file in the UNIFIED format.</description>
+ <description>Snort will log Alerts to a file in the UNIFIED2 format. This is a requirement barnyard2.</description>
<type>checkbox</type>
</field>
</fields>
diff --git a/config/snort/snort_check_for_rule_updates.php b/config/snort/snort_check_for_rule_updates.php
index 90df3bc7..4430c4a2 100644
--- a/config/snort/snort_check_for_rule_updates.php
+++ b/config/snort/snort_check_for_rule_updates.php
@@ -1,9 +1,7 @@
-#!/usr/local/bin/php -f
<?php
-
/* $Id$ */
/*
- snort_check_for_rule_updates.php
+ snort_rulesets.php
Copyright (C) 2006 Scott Ullrich
All rights reserved.
@@ -29,97 +27,606 @@
POSSIBILITY OF SUCH DAMAGE.
*/
-$console_mode = true;
+/* Setup enviroment */
+$tmpfname = "/tmp/snort_rules_up";
+$snortdir = "/usr/local/etc/snort_bkup";
+$snortdir_wan = "/usr/local/etc/snort";
+$snort_filename_md5 = "snortrules-snapshot-2.8.tar.gz.md5";
+$snort_filename = "snortrules-snapshot-2.8.tar.gz";
+$emergingthreats_filename_md5 = "version.txt";
+$emergingthreats_filename = "emerging.rules.tar.gz";
+$pfsense_rules_filename_md5 = "pfsense_rules.tar.gz.md5";
+$pfsense_rules_filename = "pfsense_rules.tar.gz";
+require("/usr/local/pkg/snort.inc");
require_once("config.inc");
-require_once("functions.inc");
-require_once("/usr/local/pkg/snort.inc");
-require_once("service-utils.inc");
-/* check to see if carp settings exist, and get a handle */
-if($config['installedpackages']['carpsettings']) {
- $carp = &$config['installedpackages']['carpsettings']['config'][0];
- $password = $carp['password'];
-}
+?>
-/* if we are not a CARP cluster master, sleep for a random
- * amount of time allowing for other members to download the configuration
- */
-if(!$password) {
- $sleepietime = rand(5,700);
- sleep($sleepietime);
-}
-$last_ruleset_download = $config['installedpackages']['snort']['last_ruleset_download'];
+<?php
+
+$up_date_time = date('l jS \of F Y h:i:s A');
+echo "";
+echo "#########################";
+echo "$up_date_time";
+echo "#########################";
+echo "";
+
+/* Begin main code */
+/* Set user agent to Mozilla */
ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
-$text = file_get_contents("http://www.snort.org/pub-bin/downloads.cgi");
-if (preg_match_all("/.*RELEASED\: (.*)\</", $text, $matches))
- $last_update_date = trim($matches[1][0]);
-$date1ts = strtotime($last_update_date);
-$date2ts = strtotime($last_ruleset_download);
-/* is there a newer ruleset available? */
-if($date1ts > $date2ts or !$last_ruleset_download) {
- log_error("There is a new set of Snort rules posted. Downloading...");
- if(!$oinkid) {
- log_error("Oinkid is not defined. We cannot automatically update the ruleset.");
- echo "Oinkid is not defined. We cannot automatically update the ruleset.";
- exit;
- }
- echo "Downloading snort rule updates...";
- /* setup some variables */
+ini_set("memory_limit","125M");
+
+/* send current buffer */
+ob_flush();
+
+/* define oinkid */
+if($config['installedpackages']['snort'])
+ $oinkid = $config['installedpackages']['snort']['config'][0]['oinkmastercode'];
+
+/* if missing oinkid exit */
+if(!$oinkid) {
+ echo "Please add you oink code\n";
+ exit;
+}
+
+/* premium_subscriber check */
+//unset($config['installedpackages']['snort']['config'][0]['subscriber']);
+//write_config();
+$premium_subscriber_chk = $config['installedpackages']['snort']['config'][0]['subscriber'];
+
+if ($premium_subscriber_chk === on) {
+ $premium_subscriber = "_s";
+}else{
$premium_subscriber = "";
+}
- /* Snort version */
- $snort_version = "2.8";
-
- /* Are we using the premium subscriber subscription? */
- if($config['installedpackages']['snortadvanced']['config'][0]['subscriber']) {
- // http://www.snort.org/pub-bin/downloads.cgi/Download/sub_rules/snortrules-snapshot-CURRENT_s.tar.gz.md5
- $premium_subscriber = "_s";
- $snort_download_prefix = "http://www.snort.org/pub-bin/oinkmaster.cgi";
- } else {
- // http://www.snort.org/pub-bin/downloads.cgi/Download/vrt_os/snortrules-snapshot-CURRENT.tar.gz.md5
- $premium_subscriber = "";
- $snort_download_prefix = "http://www.snort.org/pub-bin/oinkmaster.cgi";
- }
+$premium_url_chk = $config['installedpackages']['snort']['config'][0]['subscriber'];
+if ($premium_url_chk === on) {
+ $premium_url = "sub-rules";
+}else{
+ $premium_url = "reg-rules";
+}
+
+/* send current buffer */
+ob_flush();
+
+/* remove old $tmpfname files */
+if (file_exists("{$tmpfname}")) {
+ exec("/bin/rm -r {$tmpfname}");
+ apc_clear_cache();
+}
+
+/* send current buffer */
+ob_flush();
+
+/* If tmp dir does not exist create it */
+if (file_exists($tmpfname)) {
+ echo "The directory tmp exists...\n";
+} else {
+ mkdir("{$tmpfname}", 700);
+}
+
+/* download md5 sig from snort.org */
+if (file_exists("{$tmpfname}/{$snort_filename_md5}")) {
+ echo "md5 temp file exists...\n";
+} else {
+ echo "Downloading md5 file...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://dl.snort.org/{$premium_url}/snortrules-snapshot-2.8{$premium_subscriber}.tar.gz.md5?oink_code={$oinkid}");
+// $image = @file_get_contents("http://www.mtest.local/pub-bin/oinkmaster.cgi/{$oinkid}/snortrules-snapshot-2.8{$premium_subscriber}.tar.gz.md5");
+ $f = fopen("{$tmpfname}/snortrules-snapshot-2.8.tar.gz.md5", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done. downloading md5\n";
+}
+
+/* download md5 sig from emergingthreats.net */
+$emergingthreats_url_chk = $config['installedpackages']['snort']['config'][0]['emergingthreats'];
+if ($emergingthreats_url_chk == on) {
+ echo "Downloading md5 file...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://www.emergingthreats.net/version.txt");
+// $image = @file_get_contents("http://www.mtest.local/pub-bin/oinkmaster.cgi/{$oinkid}/version.txt");
+ $f = fopen("{$tmpfname}/version.txt", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done. downloading md5\n";
+}
+
+/* download md5 sig from pfsense.org */
+if (file_exists("{$tmpfname}/{$pfsense_rules_filename_md5}")) {
+ echo "md5 temp file exists...\n";
+} else {
+ echo "Downloading pfsense md5 file...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://www.pfsense.com/packages/config/snort/pfsense_rules/pfsense_rules.tar.gz.md5");
+// $image = @file_get_contents("http://www.mtest.local/pub-bin/oinkmaster.cgi/{$oinkid}/pfsense_rules.tar.gz.md5");
+ $f = fopen("{$tmpfname}/pfsense_rules.tar.gz.md5", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done. downloading md5\n";
+}
- /* Set snort rules download filename */
- $snort_filename = "snortrules-snapshot-{$snort_version}{$premium_subscriber}.tar.gz";
- $snort_filename_md5 = "snortrules-snapshot-{$snort_version}{$premium_subscriber}.tar.gz.md5";
+/* Time stamps define */
+$last_md5_download = $config['installedpackages']['snort']['last_md5_download'];
+$last_rules_install = $config['installedpackages']['snort']['last_rules_install'];
- /* multi user system, request new filename and create directory */
- $tmpfname = tempnam("/tmp", "snortRules");
- exec("/bin/rm -rf {$tmpfname};/bin/mkdir -p {$tmpfname}");
+/* If md5 file is empty wait 15min exit */
+if (0 == filesize("{$tmpfname}/snortrules-snapshot-2.8.tar.gz.md5")){
+ echo "Please wait... You may only check for New Rules every 15 minutes...\n";
+ echo "Rules are released every month from snort.org. You may download the Rules at any time.\n";
+ exit(0);
+}
- /* download snort rules */
- exec("fetch -q -o {$tmpfname}/{$snort_filename} $dl");
- verify_downloaded_file($tmpfname . "/{$snort_filename}");
+/* If emergingthreats md5 file is empty wait 15min exit not needed */
- /* download snort rules md5 file */
- $static_output = gettext("Downloading current snort rules md5... ");
- exec("fetch -q -o {$tmpfname}/{$snort_filename_md5} $dl_md5");
- verify_downloaded_file($tmpfname . "/{$snort_filename_md5}");
+/* If pfsense md5 file is empty wait 15min exit */
+if (0 == filesize("{$tmpfname}/$pfsense_rules_filename_md5")){
+ echo "Please wait... You may only check for New Pfsense Rules every 15 minutes...\n";
+ echo "Rules are released to support Pfsense packages.\n";
+ exit(0);
+}
- /* verify downloaded rules signature */
- verify_snort_rules_md5($tmpfname);
+/* Check if were up to date snort.org */
+if (file_exists("{$snortdir}/snortrules-snapshot-2.8.tar.gz.md5")){
+$md5_check_new_parse = file_get_contents("{$tmpfname}/{$snort_filename_md5}");
+$md5_check_new = `/bin/echo "{$md5_check_new_parse}" | /usr/bin/awk '{ print $1 }'`;
+$md5_check_old_parse = file_get_contents("{$snortdir}/{$snort_filename_md5}");
+$md5_check_old = `/bin/echo "{$md5_check_old_parse}" | /usr/bin/awk '{ print $1 }'`;
+/* Write out time of last sucsessful md5 to cache */
+$config['installedpackages']['snort']['last_md5_download'] = date("Y-M-jS-h:i-A");
+write_config();
+if ($md5_check_new == $md5_check_old) {
+ echo "Your rules are up to date...\n";
+ echo "You may start Snort now, check update.\n";
+ $snort_md5_check_ok = on;
+ }
+}
- /* extract rules */
- extract_snort_rules_md5($tmpfname);
+/* Check if were up to date emergingthreats.net */
+$emergingthreats_url_chk = $config['installedpackages']['snort']['config'][0]['emergingthreats'];
+if ($emergingthreats_url_chk == on) {
+if (file_exists("{$snortdir}/version.txt")){
+$emerg_md5_check_new_parse = file_get_contents("{$tmpfname}/version.txt");
+$emerg_md5_check_new = `/bin/echo "{$emerg_md5_check_new_parse}" | /usr/bin/awk '{ print $1 }'`;
+$emerg_md5_check_old_parse = file_get_contents("{$snortdir}/version.txt");
+$emerg_md5_check_old = `/bin/echo "{$emerg_md5_check_old_parse}" | /usr/bin/awk '{ print $1 }'`;
+/* Write out time of last sucsessful md5 to cache */
+$config['installedpackages']['snort']['last_md5_download'] = date("Y-M-jS-h:i-A");
+write_config();
+if ($emerg_md5_check_new == $emerg_md5_check_old) {
+ echo "Your emergingthreats rules are up to date...\n";
+ echo "You may start Snort now, check update.\n";
+ $emerg_md5_check_chk_ok = on;
+ }
+ }
+}
- $config['installedpackages']['snort']['last_ruleset_download'] = date("Y-m-d");
- write_config();
+/* Check if were up to date pfsense.org */
+if (file_exists("{$snortdir}/$pfsense_rules_filename_md5")){
+$pfsense_md5_check_new_parse = file_get_contents("{$tmpfname}/{$snort_filename_md5}");
+$pfsense_md5_check_new = `/bin/echo "{$pfsense_md5_check_new_parse}" | /usr/bin/awk '{ print $1 }'`;
+$pfsense_md5_check_old_parse = file_get_contents("{$snortdir}/{$snort_filename_md5}");
+$pfsense_md5_check_old = `/bin/echo "{$md5_check_old_parse}" | /usr/bin/awk '{ print $1 }'`;
+if ($pfsense_md5_check_new == $pfsense_md5_check_old) {
+ $pfsense_md5_check_ok = on;
+ }
+}
+
+/* Make Clean Snort Directory emergingthreats not checked */
+if ($snort_md5_check_ok == on && $emergingthreats_url_chk != on) {
+ echo "Cleaning the snort Directory...\n";
+ echo "removing...\n";
+ exec("/bin/rm {$snortdir}/rules/emerging*\n");
+ exec("/bin/rm {$snortdir}/version.txt");
+ echo "Done making cleaning emrg direcory.\n";
+}
+/* Check if were up to date exits */
+if ($snort_md5_check_ok == on && $emerg_md5_check_chk_ok == on && $pfsense_md5_check_ok == on) {
+ echo "Your rules are up to date...\n";
+ echo "You may start Snort now...\n";
+ exit(0);
+}
+
+if ($snort_md5_check_ok == on && $pfsense_md5_check_ok == on && $emergingthreats_url_chk != on) {
+ echo "Your rules are up to date...\n";
+ echo "You may start Snort now...\n";
+ exit(0);
+}
+
+/* You are Not Up to date, always stop snort when updating rules for low end machines */;
+echo "You are NOT up to date...\n";
+echo "Stopping Snort service...\n";
+$chk_if_snort_up = exec("pgrep -x snort");
+if ($chk_if_snort_up != "") {
+ exec("/usr/bin/touch /tmp/snort_download_halt.pid");
stop_service("snort");
sleep(2);
- start_service("snort");
+}
+
+/* download snortrules file */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/{$snort_filename}")) {
+ echo "Snortrule tar file exists...\n";
+} else {
+
+ echo "There is a new set of Snort rules posted. Downloading...\n";
+ echo "May take 4 to 10 min...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://dl.snort.org/{$premium_url}/snortrules-snapshot-2.8{$premium_subscriber}.tar.gz?oink_code={$oinkid}");
+// $image = @file_get_contents("http://www.mtest.local/pub-bin/oinkmaster.cgi/{$oinkid}/snortrules-snapshot-2.8{$premium_subscriber}.tar.gz");
+ $f = fopen("{$tmpfname}/snortrules-snapshot-2.8.tar.gz", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done downloading rules file.\n";
+ if (150000 > filesize("{$tmpfname}/$snort_filename")){
+ echo "Error with the snort rules download...\n";
+ echo "Snort rules file downloaded failed...\n";
+ exit(0);
+ }
+ }
+}
+
+/* download emergingthreats rules file */
+if ($emergingthreats_url_chk == on) {
+if ($emerg_md5_check_chk_ok != on) {
+if (file_exists("{$tmpfname}/{$emergingthreats_filename}")) {
+ echo "Emergingthreats tar file exists...\n";
+} else {
+ echo "There is a new set of Emergingthreats rules posted. Downloading...\n";
+ echo "May take 4 to 10 min...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://www.emergingthreats.net/rules/emerging.rules.tar.gz");
+// $image = @file_get_contents("http://www.emergingthreats.net/rules/emerging.rules.tar.gz");
+ $f = fopen("{$tmpfname}/emerging.rules.tar.gz", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done downloading Emergingthreats rules file.\n";
+ }
+ }
+ }
+
+/* download pfsense rules file */
+if ($pfsense_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/{$pfsense_rules_filename}")) {
+ echo "Snortrule tar file exists...\n";
+} else {
+
+ echo "There is a new set of Pfsense rules posted. Downloading...\n";
+ echo "May take 4 to 10 min...\n";
+ ini_set('user_agent','Mozilla/4.0 (compatible; MSIE 6.0)');
+ $image = @file_get_contents("http://www.pfsense.com/packages/config/snort/pfsense_rules/pfsense_rules.tar.gz");
+// $image = @file_get_contents("http://www.mtest.local/pub-bin/oinkmaster.cgi/{$oinkid}/pfsense_rules.tar.gz");
+ $f = fopen("{$tmpfname}/pfsense_rules.tar.gz", 'w');
+ fwrite($f, $image);
+ fclose($f);
+ echo "Done downloading rules file.\n";
+ }
+}
+
+/* Untar snort rules file individually to help people with low system specs */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/{$snort_filename}")) {
+ echo "Extracting rules...\n";
+ echo "May take a while...\n";
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} etc/");
+ exec("`/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/*`");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/bad-traffic.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/chat.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/dos.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/exploit.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/imap.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/misc.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/multimedia.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/netbios.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/nntp.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/p2p.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/smtp.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/sql.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/web-client.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/web-misc.rules/");
+ echo "Done extracting Rules.\n";
+} else {
+ echo "The Download rules file missing...\n";
+ echo "Error rules extracting failed...\n";
+ exit(0);
+ }
+}
+
+/* Untar emergingthreats rules to tmp */
+if ($emergingthreats_url_chk == on) {
+if ($emerg_md5_check_chk_ok != on) {
+if (file_exists("{$tmpfname}/{$emergingthreats_filename}")) {
+ echo "Extracting rules...\n";
+ echo "May take a while...\n";
+ exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$snortdir} rules/");
+ }
+ }
+}
+
+/* Untar Pfsense rules to tmp */
+if ($pfsense_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/{$pfsense_rules_filename}")) {
+ echo "Extracting Pfsense rules...\n";
+ echo "May take a while...\n";
+ exec("/usr/bin/tar xzf {$tmpfname}/{$pfsense_rules_filename} -C {$snortdir} rules/");
+ }
+}
+
+/* Untar snort signatures */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/{$snort_filename}")) {
+$signature_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['signatureinfo'];
+if ($premium_url_chk == on) {
+ echo "Extracting Signatures...\n";
+ echo "May take a while...\n";
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} doc/signatures/");
+ echo "Done extracting Signatures.\n";
+ }
+ }
+}
+
+/* Make Clean Snort Directory */
+//if ($snort_md5_check_ok != on && $emerg_md5_check_chk_ok != on && $pfsense_md5_check_ok != on) {
+//if (file_exists("{$snortdir}/rules")) {
+// echo "Cleaning the snort Directory...\n";
+// echo "removing...\n";
+// exec("/bin/mkdir -p {$snortdir}");
+// exec("/bin/mkdir -p {$snortdir}/rules");
+// exec("/bin/mkdir -p {$snortdir}/signatures");
+// exec("/bin/rm {$snortdir}/*");
+// exec("/bin/rm {$snortdir}/rules/*");
+// exec("/bin/rm {$snortdir_wan}/*");
+// exec("/bin/rm {$snortdir_wan}/rules/*");
+// exec("/bin/rm /usr/local/lib/snort/dynamicrules/*");
+//} else {
+// echo "Making Snort Directory...\n";
+// echo "should be fast...\n";
+// exec("/bin/mkdir {$snortdir}");
+// exec("/bin/mkdir {$snortdir}/rules");
+// exec("/bin/rm {$snortdir_wan}/\*");
+// exec("/bin/rm {$snortdir_wan}/rules/*");
+// exec("/bin/rm /usr/local/lib/snort/dynamicrules/\*");
+// echo "Done making snort direcory.\n";
+// }
+//}
+
+/* Copy so_rules dir to snort lib dir */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$snortdir}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/")) {
+ echo "Copying so_rules...\n";
+ echo "May take a while...\n";
+ sleep(2);
+ exec("`/bin/cp -f {$snortdir}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/* /usr/local/lib/snort/dynamicrules/`");
+ exec("/bin/cp {$snortdir}/so_rules/bad-traffic.rules {$snortdir}/rules/bad-traffic.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/chat.rules {$snortdir}/rules/chat.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/dos.rules {$snortdir}/rules/dos.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/exploit.rules {$snortdir}/rules/exploit.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/imap.rules {$snortdir}/rules/imap.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/misc.rules {$snortdir}/rules/misc.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/multimedia.rules {$snortdir}/rules/multimedia.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/netbios.rules {$snortdir}/rules/netbios.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/nntp.rules {$snortdir}/rules/nntp.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/p2p.rules {$snortdir}/rules/p2p.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/smtp.rules {$snortdir}/rules/smtp.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/sql.rules {$snortdir}/rules/sql.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/web-client.rules {$snortdir}/rules/web-client.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/web-misc.rules {$snortdir}/rules/web-misc.so.rules");
+ exec("/bin/rm -r {$snortdir}/so_rules");
+ echo "Done copying so_rules.\n";
+} else {
+ echo "Directory so_rules does not exist...\n";
+ echo "Error copping so_rules...\n";
+ exit(0);
+ }
+}
+
+/* enable disable setting will carry over with updates */
+/* TODO carry signature changes with the updates */
+if ($snort_md5_check_ok != on || $emerg_md5_check_chk_ok != on || $pfsense_md5_check_ok != on) {
+
+if (!empty($config['installedpackages']['snort']['rule_sid_on'])) {
+$enabled_sid_on = $config['installedpackages']['snort']['rule_sid_on'];
+$enabled_sid_on_array = split('\|\|', $enabled_sid_on);
+foreach($enabled_sid_on_array as $enabled_item_on)
+$selected_sid_on_sections .= "$enabled_item_on\n";
+ }
+
+if (!empty($config['installedpackages']['snort']['rule_sid_off'])) {
+$enabled_sid_off = $config['installedpackages']['snort']['rule_sid_off'];
+$enabled_sid_off_array = split('\|\|', $enabled_sid_off);
+foreach($enabled_sid_off_array as $enabled_item_off)
+$selected_sid_off_sections .= "$enabled_item_off\n";
+ }
+
+$snort_sid_text = <<<EOD
+
+###########################################
+# #
+# this is auto generated on snort updates #
+# #
+###########################################
+
+path = /bin:/usr/bin:/usr/local/bin
+
+update_files = \.rules$|\.config$|\.conf$|\.txt$|\.map$
+
+url = dir:///usr/local/etc/snort_bkup/rules
+
+$selected_sid_on_sections
+
+$selected_sid_off_sections
+
+EOD;
+
+ /* open snort's threshold.conf for writing */
+ $oinkmasterlist = fopen("/usr/local/etc/snort_bkup/oinkmaster.conf", "w");
+
+ fwrite($oinkmasterlist, "$snort_sid_text");
+
+ /* close snort's threshold.conf file */
+ fclose($oinkmasterlist);
+
+}
+
+/* Copy configs to snort dir */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$snortdir}/etc/Makefile.am")) {
+ echo "Copying configs to snort directory...\n";
+ exec("/bin/cp {$snortdir}/etc/* {$snortdir}");
+ exec("/bin/rm -r {$snortdir}/etc");
+} else {
+ echo "The snort configs does not exist...\n";
+ echo "Error copping config...\n";
+ exit(0);
+ }
+}
+
+/* Copy md5 sig to snort dir */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/$snort_filename_md5")) {
+ echo "Copying md5 sig to snort directory...\n";
+ exec("/bin/cp {$tmpfname}/$snort_filename_md5 {$snortdir}/$snort_filename_md5");
+} else {
+ echo "The md5 file does not exist...\n";
+ echo "Error copping config...\n";
+ exit(0);
+ }
+}
+
+/* Copy emergingthreats md5 sig to snort dir */
+if ($emergingthreats_url_chk == on) {
+if ($emerg_md5_check_chk_ok != on) {
+if (file_exists("{$tmpfname}/$emergingthreats_filename_md5")) {
+ echo "Copying md5 sig to snort directory...\n";
+ exec("/bin/cp {$tmpfname}/$emergingthreats_filename_md5 {$snortdir}/$emergingthreats_filename_md5");
+} else {
+ echo "The emergingthreats md5 file does not exist...\n";
+ echo "Error copping config...\n";
+ exit(0);
+ }
+ }
+}
+
+/* Copy Pfsense md5 sig to snort dir */
+if ($pfsense_md5_check_ok != on) {
+if (file_exists("{$tmpfname}/$pfsense_rules_filename_md5")) {
+ echo "Copying Pfsense md5 sig to snort directory...\n";
+ exec("/bin/cp {$tmpfname}/$pfsense_rules_filename_md5 {$snortdir}/$pfsense_rules_filename_md5");
+} else {
+ echo "The Pfsense md5 file does not exist...\n";
+ echo "Error copping config...\n";
+ exit(0);
+ }
+}
+
+/* Copy signatures dir to snort dir */
+if ($snort_md5_check_ok != on) {
+$signature_info_chk = $config['installedpackages']['snort']['config'][0]['signatureinfo'];
+if ($premium_url_chk == on) {
+if (file_exists("{$snortdir}/doc/signatures")) {
+ echo "Copying signatures...\n";
+ echo "May take a while...\n";
+ exec("/bin/mv -f {$snortdir}/doc/signatures {$snortdir}/signatures");
+ exec("/bin/rm -r {$snortdir}/doc/signatures");
+ echo "Done copying signatures.\n";
+} else {
+ echo "Directory signatures exist...\n";
+ echo "Error copping signature...\n";
+ exit(0);
+ }
+ }
+}
+
+/* double make shure clean up emerg rules that dont belong */
+if (file_exists("/usr/local/etc/snort_bkup/rules/emerging-botcc-BLOCK.rules")) {
+ apc_clear_cache();
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-botcc-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-botcc.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-compromised-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-drop-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-dshield-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-rbn-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-tor-BLOCK.rules");
+}
- /* cleanup temporary directory */
- exec("/bin/rm -rf {$tmpfname};");
- echo "Rules are now up to date.\n";
- log_error("Snort rules updated. New version: {$last_update_date}.");
+if (file_exists("/usr/local/lib/snort/dynamicrules/lib_sfdynamic_example_rule.so")) {
+ exec("/bin/rm /usr/local/lib/snort/dynamicrules/lib_sfdynamic_example_rule.so");
+ exec("/bin/rm /usr/local/lib/snort/dynamicrules/lib_sfdynamic_example\*");
+}
+
+echo "Updating Alert Messages...\n";
+echo "Please Wait...\n";
+sleep(2);
+exec("/usr/local/bin/perl /usr/local/bin/create-sidmap.pl /usr/local/etc/snort_bkup/rules > /usr/local/etc/snort_bkup/gen-msg.map");
+
+/* Run oinkmaster to snort_wan and cp configs */
+/* If oinkmaster is not needed cp rules normally */
+/* TODO add per interface settings here */
+if ($snort_md5_check_ok != on || $emerg_md5_check_chk_ok != on || $pfsense_md5_check_ok != on) {
+
+ if (empty($config['installedpackages']['snort']['rule_sid_on']) || empty($config['installedpackages']['snort']['rule_sid_off'])) {
+echo "Your first set of rules are being copied...\n";
+echo "May take a while...\n";
+
+ exec("/bin/cp {$snortdir}/rules/* {$snortdir_wan}/rules/");
+ exec("/bin/cp {$snortdir}/classification.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/gen-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/generators {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/reference.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/snort.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/threshold.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/unicode.map {$snortdir_wan}");
+
+} else {
+ echo "Your enable and disable changes are being applied to your fresh set of rules...\n";
+ echo "May take a while...\n";
+ exec("/bin/cp {$snortdir}/classification.config {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/gen-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/generators {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/reference.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid-msg.map {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/snort.conf {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/threshold.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/unicode.map {$snortdir_wan}");
+
+ /* oinkmaster.pl will convert saved changes for the new updates then we have to change #alert to # alert for the gui */
+ /* might have to add a sleep for 3sec for flash drives or old drives */
+ exec("/usr/local/bin/perl /usr/local/bin/oinkmaster.pl -C /usr/local/etc/snort_bkup/oinkmaster.conf -o /usr/local/etc/snort/rules > /usr/local/etc/snort_bkup/oinkmaster.log");
+ exec("/usr/local/bin/perl -pi -e 's/#alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+ exec("/usr/local/bin/perl -pi -e 's/##alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+ exec("/usr/local/bin/perl -pi -e 's/## alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+
+ }
+}
+
+/* remove old $tmpfname files */
+if (file_exists("{$tmpfname}")) {
+ echo "Cleaning up...\n";
+ exec("/bin/rm -r /tmp/snort_rules_up");
+}
+
+/* php code to flush out cache some people are reportting missing files this might help */
+sleep(5);
+apc_clear_cache();
+exec("/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync");
+
+/* if snort is running hardrestart, if snort is not running do nothing */
+if (file_exists("/tmp/snort_download_halt.pid")) {
+ start_service("snort");
+ echo "The Rules update finished...\n";
+ echo "Snort has restarted with your new set of rules...\n";
+ exec("/bin/rm /tmp/snort_download_halt.pid");
} else {
- echo "Rules are up to date.\n";
- log_error("Snort rules are up to date. Not updating.");
+ echo "The Rules update finished...\n";
+ echo "You may start snort now...\n";
}
-?> \ No newline at end of file
+?>
diff --git a/config/snort/snort_download_rules.php b/config/snort/snort_download_rules.php
index 904f8057..8eca3d34 100644
--- a/config/snort/snort_download_rules.php
+++ b/config/snort/snort_download_rules.php
@@ -29,7 +29,8 @@
/* Setup enviroment */
$tmpfname = "/tmp/snort_rules_up";
-$snortdir = "/usr/local/etc/snort";
+$snortdir = "/usr/local/etc/snort_bkup";
+$snortdir_wan = "/usr/local/etc/snort";
$snort_filename_md5 = "snortrules-snapshot-2.8.tar.gz.md5";
$snort_filename = "snortrules-snapshot-2.8.tar.gz";
$emergingthreats_filename_md5 = "version.txt";
@@ -168,6 +169,11 @@ if (file_exists("{$tmpfname}")) {
apc_clear_cache();
}
+/* Make shure snortdir exits */
+exec("/bin/mkdir -p {$snortdir}");
+exec("/bin/mkdir -p {$snortdir}/rules");
+exec("/bin/mkdir -p {$snortdir}/signatures");
+
/* send current buffer */
ob_flush();
@@ -290,9 +296,6 @@ if ($emerg_md5_check_new == $emerg_md5_check_old) {
update_output_window(gettext("You may start Snort now, check update."));
hide_progress_bar_status();
$emerg_md5_check_chk_ok = on;
- /* Timestamps to html */
-// echo "\n<p align=center><b>You last checked for updates: </b>{$last_md5_download}</p>\n";
-// echo "\n<p align=center><b>You last installed for rules: </b>{$last_rules_install}</p>\n";
}
}
}
@@ -314,6 +317,8 @@ if ($snort_md5_check_ok == on && $emergingthreats_url_chk != on) {
update_output_window(gettext("removing..."));
exec("/bin/rm {$snortdir}/rules/emerging*");
exec("/bin/rm {$snortdir}/version.txt");
+ exec("/bin/rm {$snortdir_wan}/rules/emerging*");
+ exec("/bin/rm {$snortdir_wan}/version.txt");
update_status(gettext("Done making cleaning emrg direcory."));
}
@@ -330,12 +335,15 @@ if ($snort_md5_check_ok == on && $pfsense_md5_check_ok == on && $emergingthreats
exit(0);
}
-/* "You are Not Up to date */;
+/* You are Not Up to date, always stop snort when updating rules for low end machines */;
update_status(gettext("You are NOT up to date..."));
- update_output_window(gettext("Stopping Snort service..."));
-stop_service("snort");
-sleep(2);
-// start_service("snort");
+update_output_window(gettext("Stopping Snort service..."));
+$chk_if_snort_up = exec("pgrep -x snort");
+if ($chk_if_snort_up != "") {
+ exec("/usr/bin/touch /tmp/snort_download_halt.pid");
+ stop_service("snort");
+ sleep(2);
+}
/* download snortrules file */
if ($snort_md5_check_ok != on) {
@@ -421,23 +429,23 @@ if ($snort_md5_check_ok != on) {
if (file_exists("{$tmpfname}/{$snort_filename}")) {
update_status(gettext("Extracting rules..."));
update_output_window(gettext("May take a while..."));
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} etc/");
- exec("`/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/*`");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/bad-traffic.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/chat.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/dos.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/exploit.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/imap.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/misc.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/multimedia.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/netbios.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/nntp.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/p2p.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/smtp.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/sql.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/web-client.rules/");
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} so_rules/web-misc.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} etc/");
+ exec("`/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/*`");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/bad-traffic.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/chat.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/dos.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/exploit.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/imap.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/misc.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/multimedia.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/netbios.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/nntp.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/p2p.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/smtp.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/sql.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/web-client.rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} so_rules/web-misc.rules/");
update_status(gettext("Done extracting Rules."));
} else {
update_status(gettext("The Download rules file missing..."));
@@ -452,7 +460,7 @@ if ($emerg_md5_check_chk_ok != on) {
if (file_exists("{$tmpfname}/{$emergingthreats_filename}")) {
update_status(gettext("Extracting rules..."));
update_output_window(gettext("May take a while..."));
- exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$tmpfname} rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$snortdir} rules/");
}
}
}
@@ -462,7 +470,7 @@ if ($pfsense_md5_check_ok != on) {
if (file_exists("{$tmpfname}/{$pfsense_rules_filename}")) {
update_status(gettext("Extracting Pfsense rules..."));
update_output_window(gettext("May take a while..."));
- exec("/usr/bin/tar xzf {$tmpfname}/{$pfsense_rules_filename} -C {$tmpfname} rules/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$pfsense_rules_filename} -C {$snortdir} rules/");
}
}
@@ -473,43 +481,125 @@ $signature_info_chk = $config['installedpackages']['snortadvanced']['config'][0]
if ($premium_url_chk == on) {
update_status(gettext("Extracting Signatures..."));
update_output_window(gettext("May take a while..."));
- exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} doc/signatures/");
+ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir} doc/signatures/");
update_status(gettext("Done extracting Signatures."));
}
}
}
/* Make Clean Snort Directory */
-if ($snort_md5_check_ok != on && $emerg_md5_check_chk_ok != on && $pfsense_md5_check_ok != on) {
-if (file_exists("{$snortdir}/rules")) {
- update_status(gettext("Cleaning the snort Directory..."));
- update_output_window(gettext("removing..."));
- exec("/bin/rm {$snortdir}/*");
- exec("/bin/rm {$snortdir}/rules/*");
- exec("/bin/rm /usr/local/lib/snort/dynamicrules/*");
+//if ($snort_md5_check_ok != on && $emerg_md5_check_chk_ok != on && $pfsense_md5_check_ok != on) {
+//if (file_exists("{$snortdir}/rules")) {
+// update_status(gettext("Cleaning the snort Directory..."));
+// update_output_window(gettext("removing..."));
+// exec("/bin/mkdir -p {$snortdir}");
+// exec("/bin/mkdir -p {$snortdir}/rules");
+// exec("/bin/mkdir -p {$snortdir}/signatures");
+// exec("/bin/rm {$snortdir}/*");
+// exec("/bin/rm {$snortdir}/rules/*");
+// exec("/bin/rm {$snortdir_wan}/*");
+// exec("/bin/rm {$snortdir_wan}/rules/*");
+
+// exec("/bin/rm /usr/local/lib/snort/dynamicrules/*");
+//} else {
+// update_status(gettext("Making Snort Directory..."));
+// update_output_window(gettext("should be fast..."));
+// exec("/bin/mkdir -p {$snortdir}");
+// exec("/bin/mkdir -p {$snortdir}/rules");
+// exec("/bin/rm {$snortdir_wan}/*");
+// exec("/bin/rm {$snortdir_wan}/rules/*");
+// exec("/bin/rm /usr/local/lib/snort/dynamicrules/\*");
+// update_status(gettext("Done making snort direcory."));
+// }
+//}
+
+/* Copy so_rules dir to snort lib dir */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$snortdir}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/")) {
+ update_status(gettext("Copying so_rules..."));
+ update_output_window(gettext("May take a while..."));
+ exec("`/bin/cp -f {$snortdir}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/* /usr/local/lib/snort/dynamicrules/`");
+ exec("/bin/cp {$snortdir}/so_rules/bad-traffic.rules {$snortdir}/rules/bad-traffic.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/chat.rules {$snortdir}/rules/chat.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/dos.rules {$snortdir}/rules/dos.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/exploit.rules {$snortdir}/rules/exploit.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/imap.rules {$snortdir}/rules/imap.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/misc.rules {$snortdir}/rules/misc.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/multimedia.rules {$snortdir}/rules/multimedia.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/netbios.rules {$snortdir}/rules/netbios.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/nntp.rules {$snortdir}/rules/nntp.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/p2p.rules {$snortdir}/rules/p2p.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/smtp.rules {$snortdir}/rules/smtp.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/sql.rules {$snortdir}/rules/sql.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/web-client.rules {$snortdir}/rules/web-client.so.rules");
+ exec("/bin/cp {$snortdir}/so_rules/web.misc.rules {$snortdir}/rules/web.misc.so.rules");
+ exec("/bin/rm -r {$snortdir}/so_rules");
+ update_status(gettext("Done copying so_rules."));
} else {
- update_status(gettext("Making Snort Directory..."));
- update_output_window(gettext("should be fast..."));
- exec("/bin/mkdir {$snortdir}");
- exec("/bin/mkdir {$snortdir}/rules");
- exec("/bin/rm /usr/local/lib/snort/dynamicrules/*");
- update_status(gettext("Done making snort direcory."));
- }
+ update_status(gettext("Directory so_rules does not exist..."));
+ update_output_window(gettext("Error copping so_rules..."));
+ exit(0);
+ }
}
-/* Copy snort rules and emergingthreats and pfsense dir to snort dir */
+/* enable disable setting will carry over with updates */
+/* TODO carry signature changes with the updates */
if ($snort_md5_check_ok != on || $emerg_md5_check_chk_ok != on || $pfsense_md5_check_ok != on) {
-if (file_exists("{$tmpfname}/rules")) {
- update_status(gettext("Copying rules..."));
- update_output_window(gettext("May take a while..."));
- exec("/bin/cp {$tmpfname}/rules/* {$snortdir}/rules");
- update_status(gettext("Done copping rules."));
- /* Write out time of last sucsessful rule install catch */
- $config['installedpackages']['snort']['last_rules_install'] = date("Y-M-jS-h:i-A");
- write_config();
+
+if (!empty($config['installedpackages']['snort']['rule_sid_on'])) {
+$enabled_sid_on = $config['installedpackages']['snort']['rule_sid_on'];
+$enabled_sid_on_array = split('\|\|', $enabled_sid_on);
+foreach($enabled_sid_on_array as $enabled_item_on)
+$selected_sid_on_sections .= "$enabled_item_on\n";
+ }
+
+if (!empty($config['installedpackages']['snort']['rule_sid_off'])) {
+$enabled_sid_off = $config['installedpackages']['snort']['rule_sid_off'];
+$enabled_sid_off_array = split('\|\|', $enabled_sid_off);
+foreach($enabled_sid_off_array as $enabled_item_off)
+$selected_sid_off_sections .= "$enabled_item_off\n";
+ }
+
+$snort_sid_text = <<<EOD
+
+###########################################
+# #
+# this is auto generated on snort updates #
+# #
+###########################################
+
+path = /bin:/usr/bin:/usr/local/bin
+
+update_files = \.rules$|\.config$|\.conf$|\.txt$|\.map$
+
+url = dir:///usr/local/etc/snort_bkup/rules
+
+$selected_sid_on_sections
+
+$selected_sid_off_sections
+
+EOD;
+
+ /* open snort's threshold.conf for writing */
+ $oinkmasterlist = fopen("/usr/local/etc/snort_bkup/oinkmaster.conf", "w");
+
+ fwrite($oinkmasterlist, "$snort_sid_text");
+
+ /* close snort's threshold.conf file */
+ fclose($oinkmasterlist);
+
+}
+
+/* Copy configs to snort dir */
+if ($snort_md5_check_ok != on) {
+if (file_exists("{$snortdir}/etc/Makefile.am")) {
+ update_status(gettext("Copying configs to snort directory..."));
+ exec("/bin/cp {$snortdir}/etc/* {$snortdir}");
+ exec("/bin/rm -r {$snortdir}/etc");
+
} else {
- update_status(gettext("Directory rules does not exists..."));
- update_output_window(gettext("Error copying rules direcory..."));
+ update_status(gettext("The snort configs does not exist..."));
+ update_output_window(gettext("Error copping config..."));
exit(0);
}
}
@@ -551,27 +641,16 @@ if (file_exists("{$tmpfname}/$pfsense_rules_filename_md5")) {
exit(0);
}
}
-
-/* Copy configs to snort dir */
-if ($snort_md5_check_ok != on) {
-if (file_exists("{$tmpfname}/etc/Makefile.am")) {
- update_status(gettext("Copying configs to snort directory..."));
- exec("/bin/cp {$tmpfname}/etc/* {$snortdir}");
-} else {
- update_status(gettext("The snort configs does not exist..."));
- update_output_window(gettext("Error copping config..."));
- exit(0);
- }
-}
-
+
/* Copy signatures dir to snort dir */
if ($snort_md5_check_ok != on) {
$signature_info_chk = $config['installedpackages']['snort']['config'][0]['signatureinfo'];
if ($premium_url_chk == on) {
-if (file_exists("{$tmpfname}/doc/signatures")) {
+if (file_exists("{$snortdir}/doc/signatures")) {
update_status(gettext("Copying signatures..."));
update_output_window(gettext("May take a while..."));
- exec("/bin/mv -f {$tmpfname}/doc/signatures {$snortdir}/signatures");
+ exec("/bin/mv -f {$snortdir}/doc/signatures {$snortdir}/signatures");
+ exec("/bin/rm -r {$snortdir}/doc/signatures");
update_status(gettext("Done copying signatures."));
} else {
update_status(gettext("Directory signatures exist..."));
@@ -580,65 +659,95 @@ if (file_exists("{$tmpfname}/doc/signatures")) {
}
}
}
-
-/* Copy so_rules dir to snort lib dir */
-if ($snort_md5_check_ok != on) {
-if (file_exists("{$tmpfname}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/")) {
- update_status(gettext("Copying so_rules..."));
- update_output_window(gettext("May take a while..."));
- exec("`/bin/cp -f {$tmpfname}/so_rules/precompiled/FreeBSD-7.0/i386/2.8.4/* /usr/local/lib/snort/dynamicrules/`");
- exec("/bin/cp {$tmpfname}/so_rules/bad-traffic.rules {$snortdir}/rules/bad-traffic.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/chat.rules {$snortdir}/rules/chat.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/dos.rules {$snortdir}/rules/dos.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/exploit.rules {$snortdir}/rules/exploit.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/imap.rules {$snortdir}/rules/imap.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/misc.rules {$snortdir}/rules/misc.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/multimedia.rules {$snortdir}/rules/multimedia.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/netbios.rules {$snortdir}/rules/netbios.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/nntp.rules {$snortdir}/rules/nntp.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/p2p.rules {$snortdir}/rules/p2p.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/smtp.rules {$snortdir}/rules/smtp.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/sql.rules {$snortdir}/rules/sql.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/web-client.rules {$snortdir}/rules/web-client.so.rules");
- exec("/bin/cp {$tmpfname}/so_rules/web.misc.rules {$snortdir}/rules/web.misc.so.rules");
- update_status(gettext("Done copying so_rules."));
-} else {
- update_status(gettext("Directory so_rules does not exist..."));
- update_output_window(gettext("Error copping so_rules..."));
- exit(0);
- }
-}
-/* double make shure clean up emerg rules that dont belong */
-if (file_exists("/usr/local/etc/snort/rules/emerging-botcc-BLOCK.rules")) {
+/* double make shure cleanup emerg rules that dont belong */
+if (file_exists("/usr/local/etc/snort_bkup/rules/emerging-botcc-BLOCK.rules")) {
apc_clear_cache();
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-botcc-BLOCK.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-botcc.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-compromised-BLOCK.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-drop-BLOCK.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-dshield-BLOCK.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-rbn-BLOCK.rules");
- exec("/bin/rm /usr/local/etc/snort/rules/emerging-tor-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-botcc-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-botcc.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-compromised-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-drop-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-dshield-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-rbn-BLOCK.rules");
+ exec("/bin/rm /usr/local/etc/snort_bkup/rules/emerging-tor-BLOCK.rules");
+}
+
+if (file_exists("/usr/local/lib/snort/dynamicrules/lib_sfdynamic_example_rule.so")) {
+ exec("/bin/rm /usr/local/lib/snort/dynamicrules/lib_sfdynamic_example_rule.so");
+ exec("/bin/rm /usr/local/lib/snort/dynamicrules/lib_sfdynamic_example\*");
+}
+
+/* create a msg-map for snort */
+update_status(gettext("Updating Alert Messages..."));
+update_output_window(gettext("Please Wait..."));
+exec("/usr/local/bin/perl /usr/local/bin/create-sidmap.pl /usr/local/etc/snort_bkup/rules > /usr/local/etc/snort_bkup/gen-msg.map");
+
+/* Run oinkmaster to snort_wan and cp configs */
+/* If oinkmaster is not needed cp rules normally */
+/* TODO add per interface settings here */
+if ($snort_md5_check_ok != on || $emerg_md5_check_chk_ok != on || $pfsense_md5_check_ok != on) {
+
+ if (empty($config['installedpackages']['snort']['rule_sid_on']) || empty($config['installedpackages']['snort']['rule_sid_off'])) {
+ update_status(gettext("Your first set of rules are being copied..."));
+ update_output_window(gettext("May take a while..."));
+ exec("/bin/cp {$snortdir}/rules/* {$snortdir_wan}/rules/");
+ exec("/bin/cp {$snortdir}/classification.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/gen-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/generators {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/reference.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/snort.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/threshold.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/unicode.map {$snortdir_wan}");
+
+} else {
+ update_status(gettext("Your enable and disable changes are being applied to your fresh set of rules..."));
+ update_output_window(gettext("May take a while..."));
+
+ exec("/bin/cp {$snortdir}/classification.config {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/gen-msg.map {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/generators {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/reference.config {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/sid-msg.map {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/snort.conf {$snortdir_wan}");
+// exec("/bin/cp {$snortdir}/threshold.conf {$snortdir_wan}");
+ exec("/bin/cp {$snortdir}/unicode.map {$snortdir_wan}");
+
+ /* oinkmaster.pl will convert saved changes for the new updates then we have to change #alert to # alert for the gui */
+ /* might have to add a sleep for 3sec for flash drives or old drives */
+ exec("/usr/local/bin/perl /usr/local/bin/oinkmaster.pl -C /usr/local/etc/snort_bkup/oinkmaster.conf -o /usr/local/etc/snort/rules > /usr/local/etc/snort_bkup/oinkmaster.log");
+ exec("/usr/local/bin/perl -pi -e 's/#alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+ exec("/usr/local/bin/perl -pi -e 's/##alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+ exec("/usr/local/bin/perl -pi -e 's/## alert/# alert/g' /usr/local/etc/snort/rules/*.rules");
+
+
+ }
}
-if (file_exists("/usr/local/lib/snort/dynamicrules//lib_sfdynamic_example_rule.so")) {
- exec("/bin/rm /usr/local/lib/snort/dynamicrules//lib_sfdynamic_example_rule.so");
- exec("/bin/rm /usr/local/lib/snort/dynamicrules//lib_sfdynamic_example*");
+/* remove old $tmpfname files */
+if (file_exists("{$tmpfname}")) {
+ update_status(gettext("Cleaning up..."));
+ exec("/bin/rm -r /tmp/snort_rules_up");
+// apc_clear_cache();
}
/* php code to flush out cache some people are reportting missing files this might help */
-sleep(5);
+sleep(2);
apc_clear_cache();
exec("/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync ;/bin/sync");
-
-update_status(gettext("Updating Alert Messages..."));
-update_output_window(gettext("Please Wait..."));
-exec("/usr/local/bin/create-sidmap.pl /usr/local/etc/snort/rules > /usr/local/etc/snort/gen-msg.map");
-
-/* php code finish */
-update_status(gettext("The Rules update finished..."));
-update_output_window(gettext("You may start snort now..."));
+/* if snort is running hardrestart, if snort is not running do nothing */
+if (file_exists("/tmp/snort_download_halt.pid")) {
+ start_service("snort");
+ update_status(gettext("The Rules update finished..."));
+ update_output_window(gettext("Snort has restarted with your new set of rules..."));
+ exec("/bin/rm /tmp/snort_download_halt.pid");
+} else {
+ update_status(gettext("The Rules update finished..."));
+ update_output_window(gettext("You may start snort now..."));
+}
/* hide progress bar and lets end this party */
hide_progress_bar_status();
diff --git a/config/snort/snort_dynamic_ip_reload.php b/config/snort/snort_dynamic_ip_reload.php
index dbd6d015..7933ba16 100644
--- a/config/snort/snort_dynamic_ip_reload.php
+++ b/config/snort/snort_dynamic_ip_reload.php
@@ -40,7 +40,10 @@ if($config['interfaces']['wan']['ipaddr'] == "pppoe" or
create_snort_conf();
mwexec("/sbin/pfctl -t snort2c -T flush");
exec("killall -HUP snort");
- exec("/usr/bin/killall snort2c; snort2c -w /var/db/whitelist -a /var/log/snort/alert");
+ /* define snortbarnyardlog_chk */
+ $snortbarnyardlog_info_chk = $config['installedpackages']['snortadvanced']['config'][0]['snortbarnyardlog'];
+ if ($snortbarnyardlog_info_chk == on)
+ exec("/usr/bin/killall barnyard2; /usr/local/bin/barnyard2 -c /usr/local/etc/barnyard2.conf -d /var/log/snort -f snort.u2 -w /usr/local/etc/snort/barnyard2.waldo -D -q\n");
}
?> \ No newline at end of file
diff --git a/config/snort/snort_rules.php b/config/snort/snort_rules.php
index 76413727..fa4a5a4a 100644
--- a/config/snort/snort_rules.php
+++ b/config/snort/snort_rules.php
@@ -27,9 +27,10 @@
POSSIBILITY OF SUCH DAMAGE.
*/
require("guiconfig.inc");
+require("config.inc");
if(!is_dir("/usr/local/etc/snort/rules"))
- Header("Location: snort_download_rules.php");
+ header("Location: snort_rules.php", false);
function get_middle($source, $beginning, $ending, $init_pos) {
$beginning_pos = strpos($source, $beginning, $init_pos);
@@ -200,10 +201,10 @@ if ($_POST)
}
if ($_POST['apply']) {
- stop_service("snort");
- sleep(2);
- start_service("snort");
- $savemsg = "The snort rules selections have been saved. Restarting Snort.";
+// stop_service("snort");
+// sleep(2);
+// start_service("snort");
+ $savemsg = "The snort rules selections have been saved. Please restart snort by clicking save on the settings tab.";
$stopMsg = false;
}
@@ -250,6 +251,54 @@ else if ($_GET['act'] == "toggle")
$splitcontents = load_rule_file($file);
$stopMsg = true;
+
+ //write disable/enable sid to config.xml
+ if ($disabled == false) {
+ $string_sid = strstr($tempstring, 'sid:');
+ $sid_pieces = explode(";", $string_sid);
+ $sid_off_cut = $sid_pieces[0];
+ // sid being turned off
+ $sid_off = str_replace("sid:", "", $sid_off_cut);
+ // rule_sid_on registers
+ $sid_on_pieces = $config['installedpackages']['snort']['rule_sid_on'];
+ // if off sid is the same as on sid remove it
+ $sid_on_old = str_replace("||enablesid $sid_off", "", "$sid_on_pieces");
+ // write the replace sid back as empty
+ $config['installedpackages']['snort']['rule_sid_on'] = $sid_on_old;
+ // rule sid off registers
+ $sid_off_pieces = $config['installedpackages']['snort']['rule_sid_off'];
+ // if off sid is the same as off sid remove it
+ $sid_off_old = str_replace("||disablesid $sid_off", "", "$sid_off_pieces");
+ // write the replace sid back as empty
+ $config['installedpackages']['snort']['rule_sid_off'] = $sid_off_old;
+ // add sid off registers to new off sid
+ $config['installedpackages']['snort']['rule_sid_off'] = "||disablesid $sid_off" . $config['installedpackages']['snort']['rule_sid_off'];
+ write_config();
+ }
+ else
+ {
+ $string_sid = strstr($tempstring, 'sid:');
+ $sid_pieces = explode(";", $string_sid);
+ $sid_on_cut = $sid_pieces[0];
+ // sid being turned off
+ $sid_on = str_replace("sid:", "", $sid_on_cut);
+ // rule_sid_off registers
+ $sid_off_pieces = $config['installedpackages']['snort']['rule_sid_off'];
+ // if off sid is the same as on sid remove it
+ $sid_off_old = str_replace("||disablesid $sid_on", "", "$sid_off_pieces");
+ // write the replace sid back as empty
+ $config['installedpackages']['snort']['rule_sid_off'] = $sid_off_old;
+ // rule sid on registers
+ $sid_on_pieces = $config['installedpackages']['snort']['rule_sid_on'];
+ // if on sid is the same as on sid remove it
+ $sid_on_old = str_replace("||enablesid $sid_on", "", "$sid_on_pieces");
+ // write the replace sid back as empty
+ $config['installedpackages']['snort']['rule_sid_on'] = $sid_on_old;
+ // add sid on registers to new on sid
+ $config['installedpackages']['snort']['rule_sid_on'] = "||enablesid $sid_on" . $config['installedpackages']['snort']['rule_sid_on'];
+ write_config();
+ }
+
}
@@ -410,8 +459,8 @@ function go()
$counter2++;
$destination_port = $rule_content[$counter2];//destination port location
- $message = get_middle($tempstring, 'msg:"', '";', 0);
-
+ $message = get_middle($tempstring, 'msg:"', '";', 0);
+
echo "<tr>";
echo "<td class=\"listt\">";
echo $textss;