[LON-CAPA-cvs] cvs: loncom /init.d loncontrol

raeburn raeburn@source.lon-capa.org
Sun, 07 Jun 2009 23:20:38 -0000


This is a MIME encoded message

--raeburn1244416838
Content-Type: text/plain

raeburn		Sun Jun  7 23:20:38 2009 EDT

  Modified files:              
    /loncom/init.d	loncontrol 
  Log:
  - open/close firewall for port 5663 for SuSE as well as Fedora/RHEL/CentOS/Scientific Linux.
  - restrict inbound traffic on port 5663 to IP addresses identified for hosts in LON-CAPA cluster to which server belongs.
  - loncontrol start and loncontrol stop will eliminate firewall rule which allows inbound traffic on port 5663 from anywhere.
  - reports number of IP addresses for which lond port was opened or closed
  - more verbose message when expected chain is missing from current iptables listing.  
  
  
--raeburn1244416838
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20090607232038.txt"

Index: loncom/init.d/loncontrol
diff -u loncom/init.d/loncontrol:1.35 loncom/init.d/loncontrol:1.36
--- loncom/init.d/loncontrol:1.35	Wed Apr 22 14:58:59 2009
+++ loncom/init.d/loncontrol	Sun Jun  7 23:20:38 2009
@@ -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 @@
 	}
     }
     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 @@
     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_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_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 (<PIPE>) {
+                    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 @@
     return $lond_port;
 }
 
+sub firewall_close_anywhere {
+    my ($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";
+            }
+        }
+    }
+    close(PIPE);
+}
+
 } # End firewall variable scope
 
 sub stop_daemon {

--raeburn1244416838--