Added set_chain_policy() function, minor iptables binary name fix
authorMichael Rash <mbr@cipherdyne.org>
Sat, 3 Mar 2012 03:26:02 +0000 (22:26 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Sat, 3 Mar 2012 03:26:02 +0000 (22:26 -0500)
- Added set_chain_policy() function to allow built-in chain policies to be
  set to the specified target.  iptables/ip6tables does not allow the
  target to be set for non built-in chains.  Behind the scenes this
  function runs the command "iptables -t <table> -P <chain> <target>".
- Minor update to print the iptables binary name in 'croak' error
  conditions.  The binary name is either 'iptables' or 'ip6tables'.
- Minor perldoc updates to render links better (two spaces at the beginning
  of lines).

Changes
README
lib/IPTables/ChainMgr.pm
t/basic_tests.pl

diff --git a/Changes b/Changes
index 2d6af8e..a6f54d0 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,15 @@
 Revision history for Perl extension IPTables::ChainMgr.
 
+1.2 Fri Mar 02 21:09:57 2012
+    - Added set_chain_policy() function to allow built-in chain policies to be
+      set to the specified target.  iptables/ip6tables does not allow the
+      target to be set for non built-in chains.  Behind the scenes this
+      function runs the command "iptables -t <table> -P <chain> <target>".
+    - Minor update to print the iptables binary name in 'croak' error
+      conditions.  The binary name is either 'iptables' or 'ip6tables'.
+    - Minor perldoc updates to render links better (two spaces at the beginning
+      of lines).
+
 1.1 Tue Feb 28 21:15:11 2012
     - Added META.{yml,json} files similarly to fixing this bug filed against
       IPTables::Parse:
diff --git a/README b/README
index 919e0c4..0238933 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-IPTables-ChainMgr version 0.9.9
+IPTables-ChainMgr version 1.1
 ==============================
 
 The README is used to introduce the module and provide instructions on
index a823555..07cb6c9 100644 (file)
@@ -43,14 +43,14 @@ sub new() {
         _ipt_exec_sleep => $args{'ipt_exec_sleep'} || 0,
         _sigchld_handler => $args{'sigchld_handler'} || \&REAPER,
     };
-    croak "[*] $self->{'_iptables'} incorrect iptables path.\n"
+    $self->{'_ipt_bin_name'} = 'iptables';
+    $self->{'_ipt_bin_name'} = $1 if $self->{'_iptables'} =~ m|.*/(\S+)|;
+
+    croak "[*] $self->{'_iptables'} incorrect $self->{'_ipt_bin_name'} path.\n"
         unless -e $self->{'_iptables'};
     croak "[*] $self->{'_iptables'} not executable.\n"
         unless -x $self->{'_iptables'};
 
-    $self->{'_ipt_bin_name'} = 'iptables';
-    $self->{'_ipt_bin_name'} = $1 if $self->{'_iptables'} =~ m|.*/(\S+)|;
-
     bless $self, $class;
 }
 
@@ -132,14 +132,26 @@ sub delete_chain() {
     return $self->run_ipt_cmd("$iptables -t $table -X $del_chain");
 }
 
+sub set_chain_policy() {
+    my $self = shift;
+    my $table = shift || croak '[*] Must specify a table, e.g. "filter".';
+    my $chain = shift || croak '[*] Must specify a chain.';
+    my $target  = shift || croak qq|[-] Must specify an | .
+        qq|$self->{'_ipt_bin_name'} target, e.g. "DROP"|;
+    my $iptables = $self->{'_iptables'};
+
+    ### set the chain policy: note that $chain must be a built-in chain
+    return $self->run_ipt_cmd("$iptables -t $table -P $chain $target");
+}
+
 sub append_ip_rule() {
     my $self = shift;
     my $src = shift || croak '[-] Must specify a src address/network.';
     my $dst = shift || croak '[-] Must specify a dst address/network.';
     my $table   = shift || croak '[-] Must specify a table, e.g. "filter".';
     my $chain   = shift || croak '[-] Must specify a chain.';
-    my $target  = shift ||
-        croak '[-] Must specify a iptables target, e.g. "DROP"';
+    my $target  = shift || croak qq|[-] Must specify an | .
+        qq|$self->{'_ipt_bin_name'} target, e.g. "DROP"|;
 
     ### optionally add port numbers and protocols, etc.
     my $extended_href = shift || {};
@@ -229,7 +241,8 @@ sub add_ip_rule() {
     my $table   = shift || croak '[-] Must specify a table, e.g. "filter".';
     my $chain   = shift || croak '[-] Must specify a chain.';
     my $target  = shift ||
-        croak '[-] Must specify a iptables target, e.g. "DROP"';
+        croak qq|[-] Must specify an $self->{'_ipt_bin_name'} | .
+            qq|target, e.g. "DROP"|;
     ### optionally add port numbers and protocols, etc.
     my $extended_href = shift || {};
     my $iptables = $self->{'_iptables'};
@@ -330,8 +343,8 @@ sub delete_ip_rule() {
     my $dst = shift || croak '[-] Must specify a dst address/network.';
     my $table  = shift || croak '[-] Must specify a table, e.g. "filter".';
     my $chain  = shift || croak '[-] Must specify a chain.';
-    my $target = shift ||
-        croak '[-] Must specify a iptables target, e.g. "DROP"';
+    my $target = shift || croak qq|[-] Must specify an | .
+        qq|$self->{'_ipt_bin_name'} target, e.g. "DROP"|;
     ### optionally add port numbers and protocols, etc.
     my $extended_href = shift || {};
     my $iptables = $self->{'_iptables'};
@@ -375,10 +388,10 @@ sub find_ip_rule() {
     my $verbose = $self->{'_verbose'};
     my $src   = shift || croak '[*] Must specify source address.';
     my $dst   = shift || croak '[*] Must specify destination address.';
-    my $table = shift || croak '[*] Must specify iptables table.';
-    my $chain = shift || croak '[*] Must specify iptables chain.';
-    my $target = shift ||
-        croak '[*] Must specify iptables target (this may be a chain).';
+    my $table = shift || croak qq|[*] Must specify $self->{'_ipt_bin_name'} table.|;
+    my $chain = shift || croak qq|[*] Must specify $self->{'_ipt_bin_name'} chain.|;
+    my $target = shift || croak qq|[*] Must specify | .
+        qq|$self->{'_ipt_bin_name'} target (this may be a chain).|;
 
     ### optionally add port numbers and protocols, etc.
     my $extended_href = shift || {};
@@ -582,7 +595,8 @@ sub REAPER {
 
 sub run_ipt_cmd() {
     my $self  = shift;
-    my $cmd = shift || croak '[*] Must specify an iptables command to run.';
+    my $cmd = shift || croak qq|[*] Must specify an | .
+        qq|$self->{'_ipt_bin_name'} command to run.|;
     my $iptables  = $self->{'_iptables'};
     my $iptout    = $self->{'_iptout'};
     my $ipterr    = $self->{'_ipterr'};
@@ -594,7 +608,7 @@ sub run_ipt_cmd() {
     my $sigchld_handler = $self->{'_sigchld_handler'};
 
 
-    croak "[*] $cmd does not look like an iptables command."
+    croak "[*] $cmd does not look like an $self->{'_ipt_bin_name'} command."
         unless $cmd =~ m|^\s*iptables| or $cmd =~ m|^\S+/iptables|
             or $cmd =~ m|^\s*ip6tables| or $cmd =~ m|^\S+/ip6tables|;
 
@@ -619,7 +633,7 @@ sub run_ipt_cmd() {
         if ($debug or $verbose) {
             print $fh localtime() . " [+] IPTables::ChainMgr: ",
                 "sleeping for $ipt_exec_sleep seconds before ",
-                "executing iptables command.\n";
+                "executing $self->{'_ipt_bin_name'} command.\n";
         }
         sleep $ipt_exec_sleep;
     }
@@ -647,7 +661,8 @@ sub run_ipt_cmd() {
                 ### iptables should never take longer than 30 seconds to execute,
                 ### unless there is some absolutely enormous policy or the kernel
                 ### is exceedingly busy
-                local $SIG{'ALRM'} = sub {die "[*] iptables command timeout.\n"};
+                local $SIG{'ALRM'} = sub {die "[*] $self->{'_ipt_bin_name'} " .
+                    "command timeout.\n"};
                 alarm $ipt_alarm;
                 waitpid($ipt_pid, 0);
                 alarm 0;
@@ -656,7 +671,7 @@ sub run_ipt_cmd() {
                 kill 9, $ipt_pid unless kill 15, $ipt_pid;
             }
         } else {
-            croak "[*] Could not fork iptables: $!"
+            croak "[*] Could not fork $self->{'_ipt_bin_name'}: $!"
                 unless defined $ipt_pid;
 
             ### exec the iptables command and preserve stdout and stderr
@@ -678,7 +693,8 @@ sub run_ipt_cmd() {
     }
 
     if ($debug or $verbose) {
-        print $fh localtime() . "     iptables command stdout:\n";
+        print $fh localtime() . "     $self->{'_ipt_bin_name'} " .
+            "command stdout:\n";
         for my $line (@stdout) {
             if ($line =~ /\n$/) {
                 print $fh $line;
@@ -686,7 +702,8 @@ sub run_ipt_cmd() {
                 print $fh $line, "\n";
             }
         }
-        print $fh localtime() . "     iptables command stderr:\n";
+        print $fh localtime() . "     $self->{'_ipt_bin_name'} " .
+            "command stderr:\n";
         for my $line (@stderr) {
             if ($line =~ /\n$/) {
                 print $fh $line;
@@ -718,7 +735,7 @@ IPTables::ChainMgr - Perl extension for manipulating iptables and ip6tables poli
       'iptout'   => '/tmp/iptables.out',
       'ipterr'   => '/tmp/iptables.err',
       'debug'    => 0,
-      'verbose'  => 0
+      'verbose'  => 0,
 
       ### advanced options
       'ipt_alarm' => 5,  ### max seconds to wait for iptables execution.
@@ -748,6 +765,9 @@ IPTables::ChainMgr - Perl extension for manipulating iptables and ip6tables poli
       $ipt_obj->delete_chain('filter', 'INPUT', 'CUSTOM');
   }
 
+  # set the policy on the FORWARD table to DROP
+  $ipt_obj->set_chain_policy('filter', 'FORWARD', 'DROP');
+
   # create new iptables chain in the 'filter' table
   $ipt_obj->create_chain('filter', 'CUSTOM');
 
@@ -827,7 +847,7 @@ IPTables::ChainMgr - Perl extension for manipulating iptables and ip6tables poli
 The C<IPTables::ChainMgr> package provides an interface to manipulate iptables
 and ip6tables policies on Linux systems through the direct execution of
 iptables/ip6tables commands.  Although making a perl extension of libiptc
-provided by the iptables project is possible (and has been done by the
+provided by the Netfilter project is possible (and has been done by the
 IPTables::libiptc module available from CPAN), it is also easy enough to just
 execute iptables/ip6tables commands directly in order to both parse and change
 the configuration of the policy.  Further, this simplifies installation since
@@ -880,9 +900,19 @@ values are returned:
 
   ($rv, $out_ar, $errs_ar) = $ipt_obj->flush_chain('filter', 'CUSTOM');
 
-The flush_chain() function in the example above executes the iptables command
+The flush_chain() function in the example above executes the command
 "/sbin/iptables -t filter -F CUSTOM" or "/sbin/ip6tables -t filter -F CUSTOM".
 
+=item set_chain_policy($table, $chain, $target)
+
+This function sets the policy of a built-in chain (iptables/ip6tables does not allow
+this for non built-in chains) to the specified target:
+
+  ($rv, $out_ar, $errs_ar) = $ipt_obj->set_chain_policy('filter', 'FORWARD', 'DROP');
+
+In this example, the following command is executed behind the scenes:
+"/sbin/iptables -t filter -P FORWARD DROP" or "/sbin/ip6tables -t filter -P FORWARD DROP".
+
 =item delete_chain($table, $jump_from_chain, $chain)
 
 This function deletes a chain from the specified table along with any jump
@@ -1006,14 +1036,15 @@ lists:
   The psad mailing list: http://lists.sourceforge.net/lists/listinfo/psad-discuss
   The fwsnort mailing list: http://lists.sourceforge.net/lists/listinfo/fwsnort-discuss
 
-The latest version of the IPTables::ChainMgr extension can be found at:
+The latest version of the IPTables::ChainMgr extension can be found on CPAN and
+also here:
 
-http://www.cipherdyne.org/modules/
+  http://www.cipherdyne.org/modules/
 
 Source control is provided by git:
 
-http://www.cipherdyne.org/git/IPTables-ChainMgr.git
-http://www.cipherdyne.org/cgi-bin/gitweb.cgi?p=IPTables-ChainMgr.git;a=summary
+  http://www.cipherdyne.org/git/IPTables-ChainMgr.git
+  http://www.cipherdyne.org/cgi-bin/gitweb.cgi?p=IPTables-ChainMgr.git;a=summary
 
 =head1 CREDITS
 
index aa1f32c..2307f51 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/perl -w
 
 use lib (qw|../lib ../../IPTables-Parse/lib ../../IPTables-Parse.git/lib|);
+use Data::Dumper;
 use strict;
 
 eval {
@@ -135,6 +136,7 @@ sub test_cycle() {
     &add_jump_rule_test($ipt_obj, $test_table, $test_chain);
     &find_jump_rule_test($ipt_obj, $test_table, $test_chain);
     &flush_chain_test($ipt_obj, $test_table, $test_chain);
+    &set_chain_policy_test($ipt_obj, $test_table, $test_chain);
     &delete_chain_test($ipt_obj, $test_table, $test_jump_from_chain, $test_chain);
 
     return;
@@ -167,6 +169,29 @@ sub flush_chain_test() {
     return;
 }
 
+sub set_chain_policy_test() {
+    my ($ipt_obj, $test_table, $test_chain) = @_;
+
+    for my $target (qw/DROP ACCEPT/) {
+        &dots_print("cannot set chain policy: $test_table $test_chain $target");
+
+        my ($rv, $out_ar, $err_ar) = $ipt_obj->set_chain_policy($test_table,
+            $test_chain, $target);
+
+        if ($rv) {  ### bad, cannot set policy for a non built-in chain
+            $rv = 0;
+        } else {
+            $rv = 1;
+        }
+
+        &pass_fail($rv, "   Was able to set $test_table $test_chain chain " .
+            "policy to $target, should only be able to do this for built-in chains.");
+    }
+
+    return;
+}
+
+
 sub add_jump_rule_test() {
     my ($ipt_obj, $test_table, $test_chain) = @_;