Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 582 lines (514 sloc) 18.116 kb
#!/usr/bin/perl -w
#
#######################################################################
#
# File: install.pl
#
# Purpose: This is the installation script for fwsnort.
#
# Copyright (C) 2003-2011 Michael Rash (mbr@cipherdyne.org)
#
# License (GNU Public License):
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# TODO:
# - Write the uninstall() routine. :)
#
#######################################################################
#
# $Id$
#
use Cwd;
use IO::Socket;
use File::Copy;
use File::Path;
use Getopt::Long;
use strict;
#========================= config ========================
my $fwsnort_conf_file = 'fwsnort.conf';
my $sbin_dir = '/usr/sbin';
my $update_website = 'www.emergingthreats.net';
### system binaries
my $perlCmd = '/usr/bin/perl';
my $makeCmd = '/usr/bin/make';
my $wgetCmd = '/usr/bin/wget';
my $gzipCmd = '/bin/gzip';
my $tarCmd = '/bin/tar';
#======================= end config ======================
my %config = ();
### map perl modules to versions
my %required_perl_modules = (
'Net::IPv4Addr' => {
'force-install' => 0,
'mod-dir' => 'Net-IPv4Addr'
},
'IPTables::Parse' => {
'force-install' => 1,
'mod-dir' => 'IPTables-Parse'
}
);
### rules update link
my $rules_url = 'http://rules.emergingthreats.net/open/snort-2.9.0/emerging-all.rules';
### establish some defaults
my $uninstall = 0;
my $skip_module_install = 0;
my $cmdline_force_install = 0;
my $force_mod_re = '';
my $exclude_mod_re = '';
my $deps_dir = 'deps';
my $help = 0;
my $locale = 'C'; ### default LC_ALL env variable
my $no_locale = 0;
my $src_dir = getcwd() or die "[*] Could not get current working directory.";
my %cmds = (
'perl' => $perlCmd,
'make' => $makeCmd,
'gzip' => $gzipCmd,
'wget' => $wgetCmd,
'tar' => $tarCmd
);
### make Getopts case sensitive
Getopt::Long::Configure('no_ignore_case');
&usage(1) unless (GetOptions(
'force-mod-install' => \$cmdline_force_install, ### force install of all modules
'Force-mod-regex=s' => \$force_mod_re, ### force specific mod install with regex
'Exclude-mod-regex=s' => \$exclude_mod_re, ### exclude a particular perl module
'Skip-mod-install' => \$skip_module_install,
'rules-url=s' => \$rules_url,
'uninstall' => \$uninstall, ### uninstall fwsnort
'LC_ALL=s' => \$locale,
'no-LC_ALL' => \$no_locale,
'help' => \$help
));
&usage(0) if $help;
### set LC_ALL env variable
$ENV{'LC_ALL'} = $locale unless $no_locale;
&import_config();
$force_mod_re = qr|$force_mod_re| if $force_mod_re;
$exclude_mod_re = qr|$exclude_mod_re| if $exclude_mod_re;
### see if the deps/ directory exists, and if not then we are installing
### from the -nodeps sources so don't install any perl modules
$skip_module_install = 1 unless -d $deps_dir;
### make sure the system binaries are where we think they are.
&check_commands();
### check to make sure we are running as root
$< == 0 && $> == 0 or die "You need to be root (or equivalent UID 0",
" account) to install/uninstall fwsnort!\n";
if ($uninstall) {
&uninstall();
} else {
&install()
}
exit 0;
#===================== end main ===================
sub install() {
die "[*] You must run install.pl from the fwsnort " .
"sources directory." unless -e 'fwsnort' and -e 'fwsnort.conf';
unless (-d $config{'CONF_DIR'}) {
print "[+] mkdir $config{'CONF_DIR'}\n";
mkdir $config{'CONF_DIR'}, 0500;
}
unless (-d $config{'RULES_DIR'}) {
print "[+] mkdir $config{'RULES_DIR'}\n";
mkdir $config{'RULES_DIR'}, 0500;
}
### install perl modules
unless ($skip_module_install) {
for my $module (keys %required_perl_modules) {
&install_perl_module($module);
}
}
chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
my $local_rules_dir = 'deps/snort_rules';
if (-d 'deps' and -d $local_rules_dir
and &query_get_emerging_threats_sigs()) {
chdir $local_rules_dir or die "[*] Could not chdir $local_rules_dir";
if (-e 'emerging-all.rules') {
move 'emerging-all.rules', 'emerging-all.rules.tmp'
or die "[*] Could not move emerging-all.rules -> ",
"emerging-all.rules.tmp";
}
system "$cmds{'wget'} $rules_url";
if (-e 'emerging-all.rules') { ### successful download
unlink 'emerging-all.rules.tmp';
} else {
print "[-] Could not download emerging-all.rules file.\n";
if (-e 'emerging-all.rules.tmp') {
### move the original back
move 'emerging-all.rules', 'emerging-all.rules.tmp'
or die "[*] Could not move emerging-all.rules -> ",
"emerging-all.rules.tmp";
}
}
chdir '../..';
}
if (-d 'deps' and -d $local_rules_dir) {
opendir D, $local_rules_dir or die "[*] Could not open ",
"the $local_rules_dir directory: $!";
my @rfiles = readdir D;
closedir D;
print "[+] Copying all rules files to $config{'RULES_DIR'}\n";
for my $rfile (@rfiles) {
next unless $rfile =~ /\.rules$/;
print "[+] Installing $rfile\n";
copy "$local_rules_dir/${rfile}", "$config{'RULES_DIR'}/${rfile}"
or die "[*] Could not copy $local_rules_dir/${rfile} ",
"-> $config{'RULES_DIR'}/${rfile}";
}
}
print "\n";
### install the fwsnort.8 man page
&install_manpage();
my $preserve_rv = 0;
if (-e "$config{'CONF_DIR'}/fwsnort.conf") {
$preserve_rv = &query_preserve_config();
}
if ($preserve_rv) {
&preserve_config();
} else {
print "[+] Copying fwsnort.conf -> $config{'CONF_DIR'}/fwsnort.conf\n";
copy 'fwsnort.conf', "$config{'CONF_DIR'}/fwsnort.conf";
chmod 0600, "$config{'CONF_DIR'}/fwsnort.conf";
}
print "[+] Copying fwsnort -> ${sbin_dir}/fwsnort\n";
copy 'fwsnort', "${sbin_dir}/fwsnort";
chmod 0500, "${sbin_dir}/fwsnort";
print "\n========================================================\n",
"\n[+] fwsnort will generate an iptables script located at:\n",
" /etc/fwsnort/fwsnort.sh when executed.\n",
"\n[+] fwsnort has been successfully installed!\n\n";
return;
}
sub install_perl_module() {
my $mod_name = shift;
chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
chdir $deps_dir or die "[*] Could not chdir($deps_dir): $!";
die '[*] Missing force-install key in required_perl_modules hash.'
unless defined $required_perl_modules{$mod_name}{'force-install'};
die '[*] Missing mod-dir key in required_perl_modules hash.'
unless defined $required_perl_modules{$mod_name}{'mod-dir'};
if ($exclude_mod_re and $exclude_mod_re =~ /$mod_name/) {
print "[+] Excluding installation of $mod_name module.\n";
return;
}
my $version = '(NA)';
my $mod_dir = $required_perl_modules{$mod_name}{'mod-dir'};
if (-e "$mod_dir/VERSION") {
open F, "< $mod_dir/VERSION" or
die "[*] Could not open $mod_dir/VERSION: $!";
$version = <F>;
close F;
chomp $version;
} else {
print "[-] Warning: VERSION file does not exist in $mod_dir\n";
}
my $install_module = 0;
if ($required_perl_modules{$mod_name}{'force-install'}
or $cmdline_force_install) {
### install regardless of whether the module may already be
### installed
$install_module = 1;
} elsif ($force_mod_re and $force_mod_re =~ /$mod_name/) {
print "[+] Forcing installation of $mod_name module.\n";
$install_module = 1;
} else {
if (has_perl_module($mod_name)) {
print "[+] Module $mod_name is already installed in the ",
"system perl tree, skipping.\n";
} else {
### install the module in the /usr/lib/fwsnort directory because
### it is not already installed.
$install_module = 1;
}
}
if ($install_module) {
unless (-d $config{'LIBS_DIR'}) {
print "[+] Creating $config{'LIBS_DIR'}\n";
mkdir $config{'LIBS_DIR'}, 0755
or die "[*] Could not mkdir $config{'LIBS_DIR'}: $!";
}
print "[+] Installing the $mod_name $version perl " .
"module in $config{'LIBS_DIR'}/\n";
my $mod_dir = $required_perl_modules{$mod_name}{'mod-dir'};
chdir $mod_dir or die "[*] Could not chdir to ",
"$mod_dir: $!";
unless (-e 'Makefile.PL') {
die "[*] Your $mod_name source directory appears to be incomplete!\n",
" Download the latest sources from ",
"http://www.cipherdyne.org/\n";
}
system "$cmds{'make'} clean" if -e 'Makefile';
system "$cmds{'perl'} Makefile.PL " .
"PREFIX=$config{'LIBS_DIR'} LIB=$config{'LIBS_DIR'}";
system $cmds{'make'};
# system "$cmds{'make'} test";
system "$cmds{'make'} install";
print "\n\n";
}
chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
return;
}
sub has_perl_module() {
my $module = shift;
# 5.8.0 has a bug with require Foo::Bar alone in an eval, so an
# extra statement is a workaround.
my $file = "$module.pm";
$file =~ s{::}{/}g;
eval { require $file };
return $@ ? 0 : 1;
}
sub uninstall() {
### FIXME
return;
}
sub install_manpage() {
my $manpage = 'fwsnort.8';
### remove old man page
unlink "/usr/local/man/man8/${manpage}" if
(-e "/usr/local/man/man8/${manpage}");
### default location to put the fwsnort man page, but check with
### /etc/man.config
my $mpath = '/usr/share/man/man8';
if (-e '/etc/man.config') {
### prefer to install $manpage in /usr/local/man/man8 if
### this directory is configured in /etc/man.config
open M, '< /etc/man.config' or
die "[*] Could not open /etc/man.config: $!";
my @lines = <M>;
close M;
### prefer the path "/usr/share/man"
my $found = 0;
for my $line (@lines) {
chomp $line;
if ($line =~ m|^MANPATH\s+/usr/share/man|) {
$found = 1;
last;
}
}
### try to find "/usr/local/man" if we didn't find /usr/share/man
unless ($found) {
for my $line (@lines) {
chomp $line;
if ($line =~ m|^MANPATH\s+/usr/local/man|) {
$mpath = '/usr/local/man/man8';
$found = 1;
last;
}
}
}
### if we still have not found one of the above man paths,
### just select the first one out of /etc/man.config
unless ($found) {
for my $line (@lines) {
chomp $line;
if ($line =~ m|^MANPATH\s+(\S+)|) {
$mpath = $1;
last;
}
}
}
}
mkdir $mpath, 0755 unless -d $mpath;
my $mfile = "${mpath}/${manpage}";
print "[+] Installing $manpage man page as $mfile\n";
copy $manpage, $mfile or die "[*] Could not copy $manpage to " .
"$mfile: $!";
chmod 0644, $mfile;
print "[+] Compressing manpage $mfile\n";
### remove the old one so gzip doesn't prompt us
unlink "${mfile}.gz" if -e "${mfile}.gz";
system "$gzipCmd $mfile";
return;
}
sub query_get_emerging_threats_sigs() {
my $ans = '';
print "[+] Would you like to download the latest Snort rules from \n",
" http://$update_website/?\n";
while ($ans ne 'y' && $ans ne 'n') {
print " ([y]/n)? ";
$ans = <STDIN>;
return 1 if $ans eq "\n";
chomp $ans;
}
if ($ans eq 'y') {
return 1;
}
return 0;
}
sub import_config() {
open C, "< $fwsnort_conf_file"
or die "[*] Could not open $fwsnort_conf_file: $!";
while (<C>) {
next if /^\s*#/;
if (/^\s*(\S+)\s+(.*?)\;/) {
my $varname = $1;
my $val = $2;
if ($val =~ m|/.+| and $varname =~ /^\s*(\S+)Cmd$/) {
### found a command
$cmds{$1} = $val;
} else {
$config{$varname} = $val;
}
}
}
close C;
### resolve internal vars within variable values
&expand_vars();
&required_vars();
return;
}
sub expand_vars() {
my $has_sub_var = 1;
my $resolve_ctr = 0;
while ($has_sub_var) {
$resolve_ctr++;
$has_sub_var = 0;
if ($resolve_ctr >= 20) {
die "[*] Exceeded maximum variable resolution counter.";
}
for my $hr (\%config, \%cmds) {
for my $var (keys %$hr) {
my $val = $hr->{$var};
if ($val =~ m|\$(\w+)|) {
my $sub_var = $1;
die "[*] sub-ver $sub_var not allowed within same ",
"variable $var" if $sub_var eq $var;
if (defined $config{$sub_var}) {
$val =~ s|\$$sub_var|$config{$sub_var}|;
$hr->{$var} = $val;
} else {
die "[*] sub-var \"$sub_var\" not defined in ",
"config for var: $var."
}
$has_sub_var = 1;
}
}
}
}
return;
}
sub required_vars() {
my @required_vars = qw(
CONF_DIR RULES_DIR ARCHIVE_DIR QUEUE_RULES_DIR LOG_DIR LIBS_DIR
CONF_FILE FWSNORT_SCRIPT LOG_FILE
);
for my $var (@required_vars) {
die "[*] Variable $var not defined in $fwsnort_conf_file. Exiting.\n"
unless defined $config{$var};
}
return;
}
sub check_commands() {
my @path = qw(
/bin
/usr/bin
/usr/local/bin
);
CMD: for my $cmd (keys %cmds) {
unless (-x $cmds{$cmd}) {
my $found = 0;
PATH: for my $dir (@path) {
if (-x "${dir}/${cmd}") {
$cmds{$cmd} = "${dir}/${cmd}";
$found = 1;
last PATH;
}
}
unless ($found) {
die "[*] Could not find $cmd, edit the ",
"config section of install.pl";
}
}
}
return;
}
sub query_preserve_config() {
my $ans = '';
while ($ans ne 'y' && $ans ne 'n') {
print "[+] Would you like to preserve the config from the\n",
' existing fwsnort installation ([y]/n)? ';
$ans = <STDIN>;
return 1 if $ans eq "\n";
chomp $ans;
}
if ($ans eq 'y') {
return 1;
}
return 0;
}
sub preserve_config() {
my $file = 'fwsnort.conf';
open C, "< $file" or die "[*] Could not open $file: $!";
my @new_lines = <C>;
close C;
open CO, "< $config{'CONF_DIR'}/$file" or die "[*] Could not open ",
"$config{'CONF_DIR'}/$file: $!";
my @orig_lines = <CO>;
close CO;
print "[+] Preserving existing config: $config{'CONF_DIR'}/$file\n";
### write to a tmp file and then move.
my $printed_intf_warning = 0;
open CONF, "> $config{'CONF_DIR'}/${file}.new" or die "[*] Could not open ",
"$config{'CONF_DIR'}/${file}.new: $!";
for my $new_line (@new_lines) {
if ($new_line =~ /^\s*#/) {
print CONF $new_line;
} elsif ($new_line =~ /^\s*(\S+)/) {
my $var = $1;
my $found = 0;
for my $orig_line (@orig_lines) {
if ($orig_line =~ /^\s*\S+INTF\s/) {
### interfaces are no longer used!
unless ($printed_intf_warning) {
print " NOTE: Interfaces are no longer used as of the ",
"0.8.0 release;\n removing $var\n";
$printed_intf_warning = 1;
}
}
if ($orig_line =~ /^\s*$var\s/
and $orig_line !~ /INTF/) {
print CONF $orig_line;
$found = 1;
last;
}
}
unless ($found) {
print CONF $new_line;
}
} else {
print CONF $new_line;
}
}
close CONF;
move "$config{'CONF_DIR'}/${file}.new", "$config{'CONF_DIR'}/$file";
return;
}
sub usage() {
my $exit = shift;
print <<_HELP_;
install.pl: [options]
-f, --force-mod-install - Install all perl modules regardless
of whether they already installed on
the system.
-F, --Force-mod-regex <regex> - Install perl module that matches a
specific regular expression.
-E, --Exclude-mod-regex <re> - Exclude a perl module that matches this
regular expression.
-S, --Skip-mod-install - Skip installation of modules.
-r, --rules-url <url> - Specify the URL to use for updating the
Emerging Threats rule set - the default is:
$rules_url
-u, --uninstall - uninstall fwsnort
-h, --help - print help and exit
_HELP_
exit $exit;
}
Jump to Line
Something went wrong with that request. Please try again.