--- loncom/init.d/loncontrol 2009/04/22 14:58:59 1.35 +++ loncom/init.d/loncontrol 2009/06/07 23:20:38 1.36 @@ -1,6 +1,6 @@ #!/usr/bin/perl # -# $Id: loncontrol,v 1.35 2009/04/22 14:58:59 raeburn Exp $ +# $Id: loncontrol,v 1.36 2009/06/07 23:20:38 raeburn Exp $ # # The LearningOnline Network with CAPA # @@ -50,6 +50,7 @@ use strict; use lib '/home/httpd/lib/perl/'; use LONCAPA::Configuration; +use Apache::lonnet; my $command=$ARGV[0]; $command=~s/[^a-z]//g; @@ -67,7 +68,9 @@ $ENV{'BASH_ENV'}=""; } } my $suse_config = "/etc/sysconfig/SuSEfirewall2"; - if (!-e $suse_config) { + if (-e $suse_config) { + $fw_chain = 'input_ext'; + } else { if (!-e '/etc/sysconfig/iptables') { print("Unable to find iptables file containing static definitions\n"); } @@ -81,35 +84,49 @@ sub firewall_open_port { return 'inactive firewall' if (! &firewall_is_active); return 'port number unknown' if !$lond_port; my @opened; - my $suse_config = "/etc/sysconfig/SuSEfirewall2"; - if (-e $suse_config) { - if (open(my $fh,"<$suse_config")) { - while(<$fh>) { - chomp(); - if (/^FW_SERVICES_EXT_TCP="([^"]+)"\s*$/) { - my $portstr = $1; - my @suseports = split(/\s+/,$portstr); - foreach my $port ($lond_port) { - if (grep/^\Q$port\E$/,@suseports) { - push(@opened,$port); - } + if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) { + return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n"; + } + # iptables is running with expected chain + # + # For lond port, restrict the servers allowed to attempt to communicate + # to include only source IPs in the LON-CAPA cluster. + foreach my $port ($lond_port) { + print "Opening firewall access on port $port.\n"; + my $result; + if ($port eq $lond_port) { + my (@port_error,@command_error,@lond_port_open); + my %iphost = &Apache::lonnet::get_iphost(); + if (keys(%iphost) > 0) { + &firewall_close_anywhere($port); + foreach my $ip (keys(%iphost)) { + 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); } } } - } - } else { - if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) { - return 'chain error'; - } - # iptables is running with our chain - # - # We could restrict the servers allowed to attempt to communicate - # here, but the logistics of updating the /home/httpd/lonTabs/host.tab - # file are likely to be a problem - foreach my $port ($lond_port) { - print "Opening firewall access on port $port.\n"; - my $result; - my $firewall_command = + if (@lond_port_open) { + push(@opened,$port); + print "Port $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"; + } + 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"; + } + } else { + my $firewall_command = "$iptables -I $fw_chain -p tcp -d 0/0 --dport $port -j ACCEPT"; system($firewall_command); my $return_status = $?>>8; @@ -135,14 +152,23 @@ sub firewall_open_port { sub firewall_is_port_open { my ($port) = @_; - # returns 1 if the firewall port is open, 0 if not. + # 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 (`$iptables -L -n 2>/dev/null | grep "tcp dpt:$port"`) { - return 1; + if ($port eq $lond_port) { + my %iphost = &Apache::lonnet::get_iphost(); + foreach my $ip (keys(%iphost)) { + my $count = `$iptables -L -n 2>/dev/null | grep "tcp dpt:$port" | wc -l`; + return $count; + } } else { - return 0; + if (`$iptables -L -n 2>/dev/null | grep "tcp dpt:$port"`) { + return 1; + } else { + return 0; + } } } @@ -157,23 +183,67 @@ sub firewall_is_active { sub firewall_close_port { return 'inactive firewall' if (! &firewall_is_active); return 'port number unknown' if !$lond_port; - my $suse_config = "/etc/sysconfig/SuSEfirewall2"; - return if (-e $suse_config); + if (! `$iptables -L -n 2>/dev/null | grep $fw_chain | wc -l`) { + return 'Expected chain "'.$fw_chain.'" missing from iptables'."\n"; + } foreach my $port ($lond_port) { print "Closing firewall access on port $port\n"; - 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"; + if ($port eq $lond_port) { + my (@port_error,@command_error,@lond_port_close); + my %iphost = &Apache::lonnet::get_iphost(); + my %toclose; + if (keys(%iphost) > 0) { + open(PIPE, "$iptables -n -L $fw_chain |"); + while () { + chomp(); + next unless (/dpt:\Q$port\E\s*$/); + if (/^ACCEPT\s+tcp\s+\-{2}\s+([\S]+)\s+/) { + $toclose{$1} = $port; + } + } + close(PIPE); + } + foreach my $ip (keys(%iphost)) { + next unless (exists($toclose{$ip})); + 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 $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"; + } + &firewall_close_anywhere($port); } else { - print "Port closed.\n"; + 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; @@ -190,6 +260,29 @@ sub get_lond_port { return $lond_port; } +sub firewall_close_anywhere { + my ($port) = @_; + open(PIPE, "$iptables --line-numbers -n -L $fw_chain |"); + while () { + 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); +} + } # End firewall variable scope sub stop_daemon {