[LON-CAPA-cvs] cvs: loncom /configuration Firewall.pm
raeburn
raeburn@source.lon-capa.org
Thu, 25 Mar 2010 01:47:45 -0000
This is a MIME encoded message
--raeburn1269481665
Content-Type: text/plain
raeburn Thu Mar 25 01:47:45 2010 EDT
Modified files:
/loncom/configuration Firewall.pm
Log:
- get_fw_chain() renamed get_fw_chains()
- return array of chains in use
- Reference to this array of chains is second arg for:
&firewall_close_port() and &firewall_open_port()
- Replace backticks with opened pipe to extract information about chains.
- Streamline code in firewall_is_port_open() to eliminate loop for each
iptables line.
- When using &firewall_open_port() check if entry already exists for specific IP for LON-CAPA port before calling system command to add one.
--raeburn1269481665
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20100325014745.txt"
Index: loncom/configuration/Firewall.pm
diff -u loncom/configuration/Firewall.pm:1.5 loncom/configuration/Firewall.pm:1.6
--- loncom/configuration/Firewall.pm:1.5 Fri Jul 17 00:15:49 2009
+++ loncom/configuration/Firewall.pm Thu Mar 25 01:47:45 2010
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Firewall configuration to allow internal LON-CAPA communication between servers
#
-# $Id: Firewall.pm,v 1.5 2009/07/17 00:15:49 raeburn Exp $
+# $Id: Firewall.pm,v 1.6 2010/03/25 01:47:45 raeburn Exp $
#
# The LearningOnline Network with CAPA
#
@@ -36,23 +36,21 @@
use lib '/home/httpd/perl/lib';
use LONCAPA::Configuration;
-# Firewall code is based on the code in FC2 /etc/init.d/ntpd
-
sub firewall_open_port {
- my ($iptables,$fw_chain,$lond_port,$iphost,$ports) = @_;
+ my ($iptables,$fw_chains,$lond_port,$iphost,$ports) = @_;
return 'inactive firewall' if (!&firewall_is_active());
return 'port number unknown' if !$lond_port;
- my @opened;
- if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) {
- return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n";
+ return 'invalid firewall chain' unless (ref($fw_chains) eq 'ARRAY');
+ my (@opened,@chains,@badchains,@okchains);
+ foreach my $chain (@{$fw_chains}) {
+ if ($chain =~ /^([\w\-]+)$/) {
+ push(@okchains,$1);
+ } else {
+ push(@badchains,$chain);
+ }
}
- #
- # iptables is running with expected chain
- #
- if ($fw_chain =~ /^([\w\-]+)$/) {
- $fw_chain = $1;
- } else {
- return 'Chain name has unexpected format'."\n";
+ if (!@okchains) {
+ return 'None of the chain names has the expected format'."\n";
}
if (ref($ports) ne 'ARRAY') {
return 'List of ports to open needed.';
@@ -70,10 +68,15 @@
if ($port eq $lond_port) {
# For lond port, restrict the servers allowed to attempt to communicate
# to include only source IPs in the LON-CAPA cluster.
- my (@port_error,@command_error,@lond_port_open);
+ my (@port_error,%command_error,@lond_port_open,
+ @lond_port_curropen);
if (ref($iphost) eq 'HASH') {
- if (keys(%{$iphost}) > 0) {
- &firewall_close_anywhere($iptables,$fw_chain,$port);
+ if (keys(%{$iphost}) > 0) {
+ my %curropen;
+ foreach my $fw_chain (@okchains) {
+ &firewall_close_anywhere($iptables,$fw_chain,$port);
+ my $current = &firewall_is_port_open($iptables,$fw_chain,$port,$lond_port,$iphost,\%curropen);
+ }
foreach my $key (keys(%{$iphost})) {
my $ip = '';
if ($key =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) {
@@ -85,46 +88,82 @@
} else {
next;
}
- my $firewall_command =
- "$iptables -I $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
- system($firewall_command);
- my $return_status = $?>>8;
- if ($return_status == 1) {
- push (@port_error,$ip);
- } elsif ($return_status == 2) {
- push(@command_error,$ip);
- } elsif ($return_status == 0) {
- push(@lond_port_open,$ip);
+ if ($curropen{$ip}) {
+ push(@lond_port_curropen,$ip);
+ } else {
+ foreach my $fw_chain (@okchains) {
+ my $firewall_command =
+ "$iptables -I $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
+ system($firewall_command);
+ my $return_status = $?>>8;
+ if ($return_status == 1) {
+ unless(grep(/^\Q$ip\E$/,@port_error)) {
+ push (@port_error,$ip);
+ }
+ } elsif ($return_status == 2) {
+ push(@{$command_error{$fw_chain}},$ip);
+ } elsif ($return_status == 0) {
+ push(@lond_port_open,$ip);
+ last;
+ }
+ }
}
}
}
}
+ if (@lond_port_curropen) {
+ unless (grep(/^\Q$port\E$/,@opened)) {
+ push(@opened,$port);
+ }
+ print "Port already open for ".scalar(@lond_port_curropen)." IP addresses\n";
+ }
if (@lond_port_open) {
- push(@opened,$port);
- print "Port $port opened for ".scalar(@lond_port_open)." IP addresses\n";
+ unless (grep(/^\Q$port\E$/,@opened)) {
+ push(@opened,$port);
+ }
+ print "Port opened for ".scalar(@lond_port_open)." IP addresses\n";
}
if (@port_error) {
- print "Error opening port $port for following IP addresses: ".join(', ',@port_error)."\n";
+ print "Error opening port for following IP addresses: ".join(', ',@port_error)."\n";
}
- if (@command_error) {
- print "Bad command error opening port for following IP addresses: ".
- join(', ',@command_error)."\n".
- 'Command was: "'."$iptables -I $fw_chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
+ if (keys(%command_error) > 0) {
+ foreach my $chain (sort(keys(%command_error))) {
+ if (ref($command_error{$chain}) eq 'ARRAY') {
+ if (@{$command_error{$chain}}) {
+ print "Bad command error opening port for following IP addresses: ".
+ join(', ',@{$command_error{$chain}})."\n".
+ 'Command was: "'."$iptables -I $chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
+ }
+ }
+ }
}
} else {
- my $firewall_command =
- "$iptables -I $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
- system($firewall_command);
- my $return_status = $?>>8;
- if ($return_status == 1) {
- # Error
- print "Error opening port.\n";
- } elsif ($return_status == 2) {
- # Bad command
- print "Bad command error opening port. Command was\n".
- " ".$firewall_command."\n";
- } elsif ($return_status == 0) {
- push(@opened,$port);
+ my (@port_errors,%command_errors);
+ foreach my $fw_chain (@okchains) {
+ my $firewall_command =
+ "$iptables -I $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
+ system($firewall_command);
+ my $return_status = $?>>8;
+ if ($return_status == 1) {
+ push(@port_errors,$fw_chain);
+ } elsif ($return_status == 2) {
+ $command_errors{$fw_chain} = $firewall_command;
+ } elsif ($return_status == 0) {
+ push(@opened,$port);
+ last;
+ }
+ }
+ unless (grep(/^\Q$port\E$/,@opened)) {
+ if (@port_errors) {
+ print "Error opening port for chains: ".
+ join(', ',@port_errors).".\n";
+ }
+ if (keys(%command_errors)) {
+ foreach my $fw_chain (sort(keys(%command_errors))) {
+ print "Bad command error opening port for chain: $fw_chain. Command was\n".
+ " ".$command_errors{$fw_chain}."\n";
+ }
+ }
}
}
}
@@ -137,33 +176,37 @@
}
sub firewall_is_port_open {
- my ($iptables,$fw_chain,$port,$lond_port,$iphost) = @_;
+ my ($iptables,$fw_chain,$port,$lond_port,$iphost,$curropen) = @_;
# for lond port returns number of source IPs for which firewall port is open
# for other ports returns 1 if the firewall port is open, 0 if not.
#
# check if firewall is active or installed
return if (! &firewall_is_active());
- if ($port eq $lond_port) {
- my $count ++;
- if (ref($iphost) eq 'HASH') {
- if (keys(%{$iphost}) > 0) {
- foreach my $ip (keys(%{$iphost})) {
- open(PIPE,"$iptables -L $fw_chain -n 2>/dev/null");
- while(<PIPE>) {
- $count++ if (/^ACCEPT\s+tcp\s+\-{2}\s+\Q$ip\E\s+/);
+ my $count = 0;
+ if (open(PIPE,"$iptables -L $fw_chain -n 2>/dev/null |")) {
+ while(<PIPE>) {
+ if ($port eq $lond_port) {
+ if (ref($iphost) eq 'HASH') {
+ if (/^ACCEPT\s+tcp\s+\-{2}\s+([\S]+)\s+/) {
+ my $ip = $1;
+ if ($iphost->{$ip}) {
+ $count ++;
+ if (ref($curropen) eq 'HASH') {
+ $curropen->{$ip} ++;
+ }
+ }
}
- close(PIPE);
+ }
+ } else {
+ if (/tcp dpt\:\Q$port\E/) {
+ $count ++;
+ last;
}
}
}
- return $count;
- } else {
- if (`$iptables -L -n 2>/dev/null | grep "tcp dpt:$port"`) {
- return 1;
- } else {
- return 0;
- }
+ close(PIPE);
}
+ return $count;
}
sub firewall_is_active {
@@ -175,20 +218,24 @@
}
sub firewall_close_port {
- my ($iptables,$fw_chain,$lond_port,$ports) = @_;
+ my ($iptables,$fw_chains,$lond_port,$ports) = @_;
return 'inactive firewall' if (!&firewall_is_active());
return 'port number unknown' if !$lond_port;
- if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) {
- return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n";
+ return 'invalid firewall chain' unless (ref($fw_chains) eq 'ARRAY');
+ my (@opened,@chains,@badchains,@okchains);
+ foreach my $chain (@{$fw_chains}) {
+ if ($chain =~ /^([\w\-]+)$/) {
+ push(@okchains,$1);
+ } else {
+ push(@badchains,$chain);
+ }
+ }
+ if (!@okchains) {
+ return 'None of the chain names has the expected format'."\n";
}
if (ref($ports) ne 'ARRAY') {
return 'List of ports to close needed.';
}
- if ($fw_chain =~ /^([\w\-]+)$/) {
- $fw_chain = $1;
- } else {
- return 'Chain name has unexpected format'."\n";
- }
foreach my $portnum (@{$ports}) {
my $port = '';
if ($portnum =~ /^(\d+)$/) {
@@ -199,58 +246,75 @@
}
print "Closing firewall access on port $port\n";
if (($port ne '') && ($port eq $lond_port)) {
- my (@port_error,@command_error,@lond_port_close);
- my %to_close;
- open(PIPE, "$iptables -n -L $fw_chain |");
- while (<PIPE>) {
- chomp();
- next unless (/dpt:\Q$port\E\s*$/);
- if (/^ACCEPT\s+tcp\s+\-{2}\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+/) {
- $to_close{$1} = $port;
+ foreach my $fw_chain (@okchains) {
+ my (@port_error,@command_error,@lond_port_close);
+ my %to_close;
+ if (open(PIPE, "$iptables -n -L $fw_chain |")) {
+ while (<PIPE>) {
+ chomp();
+ next unless (/dpt:\Q$port\E\s*$/);
+ if (/^ACCEPT\s+tcp\s+\-{2}\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+/) {
+ $to_close{$1} = $port;
+ }
+ }
+ close(PIPE);
+ }
+ if (keys(%to_close) > 0) {
+ foreach my $ip (keys(%to_close)) {
+ my $firewall_command =
+ "$iptables -D $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
+ system($firewall_command);
+ my $return_status = $?>>8;
+ if ($return_status == 1) {
+ push (@port_error,$ip);
+ } elsif ($return_status == 2) {
+ push(@command_error,$ip);
+ } elsif ($return_status == 0) {
+ push(@lond_port_close,$ip);
+ }
+ }
+ }
+ if (@lond_port_close) {
+ print "Port closed for ".scalar(@lond_port_close)." IP addresses\n";
+ }
+ if (@port_error) {
+ print "Error closing port for following IP addresses: ".join(', ',@port_error)."\n";
+ }
+ if (@command_error) {
+ print "Bad command error opening port for following IP addresses: ".
+ join(', ',@command_error)."\n".
+ 'Command was: "'."$iptables -D $fw_chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
}
}
- close(PIPE);
- if (keys(%to_close) > 0) {
- foreach my $ip (keys(%to_close)) {
+ } else {
+ foreach my $fw_chain (@okchains) {
+ my (@port_error,@command_error,@lond_port_close);
+ my $to_close;
+ if (open(PIPE, "$iptables -n -L $fw_chain |")) {
+ while (<PIPE>) {
+ chomp();
+ next unless (/dpt:\Q$port\E\s*$/);
+ $to_close = 1;
+ }
+ close(PIPE);
+ }
+ if ($to_close) {
my $firewall_command =
- "$iptables -D $fw_chain -p tcp -s $ip -d 0/0 --dport $port -j ACCEPT";
+ "$iptables -D $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
system($firewall_command);
my $return_status = $?>>8;
if ($return_status == 1) {
- push (@port_error,$ip);
+ # Error
+ print "Error closing port for chain: $fw_chain.\n";
} elsif ($return_status == 2) {
- push(@command_error,$ip);
- } elsif ($return_status == 0) {
- push(@lond_port_close,$ip);
+ # Bad command
+ print "Bad command error closing port. Command was\n".
+ " ".$firewall_command."\n";
+ } else {
+ print "Port closed for chain $fw_chain.\n";
}
}
}
- if (@lond_port_close) {
- print "Port $port closed for ".scalar(@lond_port_close)." IP addresses\n";
- }
- if (@port_error) {
- print "Error closing port $port for following IP addresses: ".join(', ',@port_error)."\n";
- }
- if (@command_error) {
- print "Bad command error opening port for following IP addresses: ".
- join(', ',@command_error)."\n".
- 'Command was: "'."$iptables -D $fw_chain -p tcp -s ".'$ip'." -d 0/0 --dport $port -j ACCEPT".'", where $ip is IP address'."\n";
- }
- } else {
- my $firewall_command =
- "$iptables -D $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT";
- system($firewall_command);
- my $return_status = $?>>8;
- if ($return_status == 1) {
- # Error
- print "Error closing port.\n";
- } elsif ($return_status == 2) {
- # Bad command
- print "Bad command error closing port. Command was\n".
- " ".$firewall_command."\n";
- } else {
- print "Port closed.\n";
- }
}
}
return;
@@ -258,25 +322,26 @@
sub firewall_close_anywhere {
my ($iptables,$fw_chain,$port) = @_;
- open(PIPE, "$iptables --line-numbers -n -L $fw_chain |");
- while (<PIPE>) {
- next unless (/dpt:\Q$port\E/);
- chomp();
- if (/^(\d+)\s+ACCEPT\s+tcp\s+\-{2}\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0/) {
- my $firewall_command = "$iptables -D $fw_chain $1";
- system($firewall_command);
- my $return_status = $?>>8;
- if ($return_status == 1) {
- print 'Error closing port '.$port.' for source "anywhere"'."\n";
- } elsif ($return_status == 2) {
- print 'Bad command error closing port '.$port.' for source "anywhere". Command was'."\n".
- ' '.$firewall_command."\n";
- } else {
- print 'Port '.$port.' closed for source "anywhere"'."\n";
+ if (open(PIPE, "$iptables --line-numbers -n -L $fw_chain |")) {
+ while (<PIPE>) {
+ next unless (/dpt:\Q$port\E/);
+ chomp();
+ if (/^(\d+)\s+ACCEPT\s+tcp\s+\-{2}\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0/) {
+ my $firewall_command = "$iptables -D $fw_chain $1";
+ system($firewall_command);
+ my $return_status = $?>>8;
+ if ($return_status == 1) {
+ print 'Error closing port '.$port.' for source "anywhere"'."\n";
+ } elsif ($return_status == 2) {
+ print 'Bad command error closing port '.$port.' for source "anywhere". Command was'."\n".
+ ' '.$firewall_command."\n";
+ } else {
+ print 'Port '.$port.' closed for source "anywhere"'."\n";
+ }
}
}
+ close(PIPE);
}
- close(PIPE);
}
sub get_lond_port {
@@ -293,28 +358,41 @@
return $lond_port;
}
-sub get_fw_chain {
+sub get_fw_chains {
my ($iptables) = @_;
- my $fw_chain = 'RH-Firewall-1-INPUT';
+ my @fw_chains;
my $suse_config = "/etc/sysconfig/SuSEfirewall2";
if (-e $suse_config) {
- $fw_chain = 'input_ext';
+ push(@fw_chains,'input_ext');
} else {
if (!-e '/etc/sysconfig/iptables') {
if (!-e '/var/lib/iptables') {
print("Unable to find iptables file containing static definitions\n");
}
+ push(@fw_chains,'RH-Firewall-1-INPUT');
}
if ($iptables eq '') {
$iptables = &get_pathto_iptables();
}
- my $count = `$iptables -L -n 2>/dev/null |grep $fw_chain |wc -l`;
- chomp($count);
- if (!$count) {
- $fw_chain ='INPUT';
+ my %counts;
+ my @posschains = ('RH-Firewall-1-INPUT','INPUT');
+ if (open(PIPE,"$iptables -L -n |")) {
+ while(<PIPE>) {
+ foreach my $chain (@posschains) {
+ if (/(\Q$chain\E)/) {
+ $counts{$1} ++;
+ }
+ }
+ }
+ close(PIPE);
+ }
+ foreach my $fw_chain (@posschains) {
+ if ($counts{$fw_chain}) {
+ push(@fw_chains,$fw_chain);
+ }
}
}
- return $fw_chain;
+ return @fw_chains;
}
sub get_pathto_iptables {
@@ -362,19 +440,19 @@
=over 4
-=item LONCAPA::Firewall::firewall_open_port( $iptables,$fw_chain,$lond_port,$iphost,$port );
+=item LONCAPA::Firewall::firewall_open_port( $iptables,$fw_chains,$lond_port,$iphost,$port );
=back
=over 4
-=item LONCAPA::Firewall::firewall_close_port( $iptables,$fw_chain,$lond_port,$ports );
+=item LONCAPA::Firewall::firewall_close_port( $iptables,$fw_chains,$lond_port,$ports );
=back
=over 4
-=item LONCAPA::Firewall::firewall_is_port_open( $iptables,$fw_chain,$port,$lond_port,$iphost );
+=item LONCAPA::Firewall::firewall_is_port_open( $iptables,$fw_chain,$port,$lond_port,$iphost,$curropen );
=back
@@ -398,7 +476,7 @@
=over 4
-=item LONCAPA::Firewall::get_fw_chain();
+=item LONCAPA::Firewall::get_fw_chains();
=back
--raeburn1269481665--