r26133 - in /branches/upstream/libiptables-chainmgr-perl/current: Changes VERSION lib/IPTables/ChainMgr.pm

thialme-guest at users.alioth.debian.org thialme-guest at users.alioth.debian.org
Sat Oct 18 09:22:44 UTC 2008


Author: thialme-guest
Date: Sat Oct 18 09:22:32 2008
New Revision: 26133

URL: http://svn.debian.org/wsvn/pkg-perl/?sc=1&rev=26133
Log:
[svn-upgrade] Integrating new upstream version, libiptables-chainmgr-perl (0.8)

Modified:
    branches/upstream/libiptables-chainmgr-perl/current/Changes
    branches/upstream/libiptables-chainmgr-perl/current/VERSION
    branches/upstream/libiptables-chainmgr-perl/current/lib/IPTables/ChainMgr.pm

Modified: branches/upstream/libiptables-chainmgr-perl/current/Changes
URL: http://svn.debian.org/wsvn/pkg-perl/branches/upstream/libiptables-chainmgr-perl/current/Changes?rev=26133&op=diff
==============================================================================
--- branches/upstream/libiptables-chainmgr-perl/current/Changes (original)
+++ branches/upstream/libiptables-chainmgr-perl/current/Changes Sat Oct 18 09:22:32 2008
@@ -1,8 +1,24 @@
 Revision history for Perl extension IPTables::ChainMgr.
 
+0.8 Fri Oct 17 11:35:15 2008
+    - Added the ability to control iptables execution model.  The default is to
+      use waitpid(), but other options are to use system() or popen().
+    - Added the ability to introduce a configurable time delay between each
+      iptables command.
+    - Added the ability to use a function reference for the SIGCHLD signal
+      handler.
+    - Added the ability to configure the number of seconds used as the alarm
+      timeout for iptables command execution in the waitpid() execution model.
+    - Passed IPTables::ChainMgr option for execution model, configurable alarm
+      timeouts, the SIGCHLD signal handler reference, and the configurable
+      number of seconds for additional sleeps between iptables commands to the
+      IPTables::Parse module.
+    - Bugfix for SIGALRM handling to be more consistent with an example from
+      the perlipc man page.
+
 0.7 Sat May 17 10:49:15 2008
-	- Added perldoc documentation for 0.7 release.
+    - Added perldoc documentation for 0.7 release.
 
 0.01  Tue Feb 22 01:18:14 2005
-	- original version; created by h2xs 1.23 with options
-		-A -X -b 5.6.0 -n IPTables::ChainMgr
+    - original version; created by h2xs 1.23 with options
+        -A -X -b 5.6.0 -n IPTables::ChainMgr

Modified: branches/upstream/libiptables-chainmgr-perl/current/VERSION
URL: http://svn.debian.org/wsvn/pkg-perl/branches/upstream/libiptables-chainmgr-perl/current/VERSION?rev=26133&op=diff
==============================================================================
--- branches/upstream/libiptables-chainmgr-perl/current/VERSION (original)
+++ branches/upstream/libiptables-chainmgr-perl/current/VERSION Sat Oct 18 09:22:32 2008
@@ -1,1 +1,1 @@
-0.7
+0.8

Modified: branches/upstream/libiptables-chainmgr-perl/current/lib/IPTables/ChainMgr.pm
URL: http://svn.debian.org/wsvn/pkg-perl/branches/upstream/libiptables-chainmgr-perl/current/lib/IPTables/ChainMgr.pm?rev=26133&op=diff
==============================================================================
--- branches/upstream/libiptables-chainmgr-perl/current/lib/IPTables/ChainMgr.pm (original)
+++ branches/upstream/libiptables-chainmgr-perl/current/lib/IPTables/ChainMgr.pm Sat Oct 18 09:22:32 2008
@@ -10,7 +10,7 @@
 #
 # Author: Michael Rash (mbr at cipherdyne.org)
 #
-# Version: 0.7
+# Version: 0.8
 #
 ##############################################################################
 #
@@ -28,18 +28,22 @@
 use warnings;
 use vars qw($VERSION);
 
-$VERSION = '0.5';
+$VERSION = '0.8';
 
 sub new() {
     my $class = shift;
     my %args  = @_;
 
     my $self = {
-        _iptables => $args{'iptables'} || '/sbin/iptables',
-        _iptout   => $args{'iptout'}   || '/tmp/ipt.out',
-        _ipterr   => $args{'ipterr'}   || '/tmp/ipt.err',
-        _debug    => $args{'debug'}    || 0,
-        _verbose  => $args{'verbose'}  || 0,
+        _iptables  => $args{'iptables'}  || '/sbin/iptables',
+        _iptout    => $args{'iptout'}    || '/tmp/ipt.out',
+        _ipterr    => $args{'ipterr'}    || '/tmp/ipt.err',
+        _ipt_alarm => $args{'ipt_alarm'} || 30,
+        _debug     => $args{'debug'}     || 0,
+        _verbose   => $args{'verbose'}   || 0,
+        _ipt_exec_style => $args{'ipt_exec_style'} || 'waitpid',
+        _ipt_exec_sleep => $args{'ipt_exec_sleep'} || 0,
+        _sigchld_handler => $args{'sigchld_handler'} || \&REAPER,
     };
     croak "[*] $self->{'_iptables'} incorrect iptables path.\n"
         unless -e $self->{'_iptables'};
@@ -123,21 +127,21 @@
     return $self->run_ipt_cmd("$iptables -t $table -X $del_chain");
 }
 
-sub add_ip_rule() {
+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 $rulenum = shift || croak '[-] Must specify an insert rule number.';
     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"';
+
     ### optionally add port numbers and protocols, etc.
     my $extended_href = shift || {};
     my $iptables = $self->{'_iptables'};
 
     ### normalize src/dst if necessary; this is because iptables
-    ### always reports network address for subnets
+    ### always reports the network address for subnets
     my $normalized_src = $self->normalize_net($src);
     my $normalized_dst = $self->normalize_net($dst);
 
@@ -168,6 +172,93 @@
     my $msg     = '';
     my $idx_err = '';
 
+    if ($extended_href) {
+        $ipt_cmd = "$iptables -t $table -A $chain ";
+        $ipt_cmd .= "-p $extended_href->{'protocol'} "
+            if defined $extended_href->{'protocol'};
+        $ipt_cmd .= "-s $normalized_src ";
+        $ipt_cmd .= "--sport $extended_href->{'s_port'} "
+            if defined $extended_href->{'s_port'};
+        $ipt_cmd .= "-d $normalized_dst ";
+        $ipt_cmd .= "--dport $extended_href->{'d_port'} "
+            if defined $extended_href->{'d_port'};
+        $ipt_cmd .= "-j $target";
+
+        $msg = "Table: $table, chain: $chain, added $normalized_src " .
+            "-> $normalized_dst ";
+        for my $key qw(protocol s_port d_port) {
+            $msg .= "$key $extended_href->{$key} "
+                if defined $extended_href->{$key};
+        }
+
+        ### for NAT
+        if (defined $extended_href->{'to_ip'} and
+                defined $extended_href->{'to_port'}) {
+            $ipt_cmd .= " --to $extended_href->{'to_ip'}:" .
+                "$extended_href->{'to_port'}";
+            $msg .= "$extended_href->{'to_ip'}:$extended_href->{'to_port'}";
+        }
+
+        $msg =~ s/\s*$//;
+    } else {
+        $ipt_cmd = "$iptables -t $table -A $chain " .
+            "-s $normalized_src -d $normalized_dst -j $target";
+        $msg = "Table: $table, chain: $chain, added $normalized_src " .
+            "-> $normalized_dst";
+    }
+    my ($rv, $out_aref, $err_aref) = $self->run_ipt_cmd($ipt_cmd);
+    if ($rv) {
+        push @$out_aref, $msg if $msg;
+    }
+    push @$err_aref, $idx_err if $idx_err;
+    return $rv, $out_aref, $err_aref;
+}
+
+sub add_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 $rulenum = shift || croak '[-] Must specify an insert rule number.';
+    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"';
+    ### optionally add port numbers and protocols, etc.
+    my $extended_href = shift || {};
+    my $iptables = $self->{'_iptables'};
+
+    ### normalize src/dst if necessary; this is because iptables
+    ### always reports the network address for subnets
+    my $normalized_src = $self->normalize_net($src);
+    my $normalized_dst = $self->normalize_net($dst);
+
+    ### first check to see if this rule already exists
+    my ($rule_position, $num_chain_rules)
+            = $self->find_ip_rule($normalized_src, $normalized_dst, $table,
+                $chain, $target, $extended_href);
+
+    if ($rule_position) {
+        my $msg = '';
+        if ($extended_href) {
+            $msg = "Table: $table, chain: $chain, $normalized_src -> " .
+                "$normalized_dst ";
+            for my $key qw(protocol s_port d_port) {
+                $msg .= "$key $extended_href->{$key} "
+                    if defined $extended_href->{$key};
+            }
+            $msg .= 'rule already exists.';
+        } else {
+            $msg = "Table: $table, chain: $chain, $normalized_src -> " .
+                "$normalized_dst rule already exists.";
+        }
+        return 1, [$msg], [];
+    }
+
+    ### we need to add the rule
+    my $ipt_cmd = '';
+    my $msg     = '';
+    my $idx_err = '';
+
     ### check to see if the insertion index ($rulenum) is too big
     $rulenum = 1 if $rulenum <= 0;
     if ($rulenum > $num_chain_rules+1) {
@@ -267,6 +358,8 @@
 
 sub find_ip_rule() {
     my $self = shift;
+    my $debug   = $self->{'_debug'};
+    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.';
@@ -277,8 +370,25 @@
     my $extended_href = shift || {};
     my $iptables = $self->{'_iptables'};
 
-    my $ipt_parse = new IPTables::Parse('iptables' => $iptables)
-        or croak "[*] Could not acquire IPTables::Parse object";
+    my $ipt_parse = new IPTables::Parse(
+        'iptables'  => $self->{'_iptables'},
+        'iptout'    => $self->{'_iptout'},
+        'ipterr'    => $self->{'_ipterr'},
+        'debug'     => $self->{'_debug'},
+        'verbose'   => $self->{'_verbose'},
+        'ipt_alarm' => $self->{'_ipt_alarm'},
+        'ipt_exec_style' => $self->{'_ipt_exec_style'},
+        'ipt_exec_sleep' => $self->{'_ipt_exec_sleep'},
+        'sigchld_handler' => $self->{'_sigchld_handler'},
+    ) or croak "[*] Could not acquire IPTables::Parse object";
+
+    my $fh = *STDERR;
+    $fh = *STDOUT if $verbose;
+
+    if ($debug or $verbose) {
+        print $fh localtime() . " [+] IPTables::Parse::VERSION",
+            "$IPTables::Parse::VERSION\n"
+    }
 
     my $chain_aref = $ipt_parse->chain_rules($table, $chain);
 
@@ -396,54 +506,89 @@
     return;
 }
 
-
 sub run_ipt_cmd() {
     my $self  = shift;
     my $cmd = shift || croak '[*] Must specify an iptables command to run.';
-    my $iptables = $self->{'_iptables'};
-    my $iptout   = $self->{'_iptout'};
-    my $ipterr   = $self->{'_ipterr'};
-    my $debug    = $self->{'_debug'};
-    my $verbose  = $self->{'_verbose'};
+    my $iptables  = $self->{'_iptables'};
+    my $iptout    = $self->{'_iptout'};
+    my $ipterr    = $self->{'_ipterr'};
+    my $debug     = $self->{'_debug'};
+    my $ipt_alarm = $self->{'_ipt_alarm'};
+    my $verbose   = $self->{'_verbose'};
+    my $ipt_exec_style = $self->{'_ipt_exec_style'};
+    my $ipt_exec_sleep = $self->{'_ipt_exec_sleep'};
+    my $sigchld_handler = $self->{'_sigchld_handler'};
+
     croak "[*] $cmd does not look like an iptables command."
         unless $cmd =~ m|^\s*iptables| or $cmd =~ m|^\S+/iptables|;
-
-    my $fh = *STDERR;
-    $fh = *STDOUT if $verbose;
-
-    if ($debug or $verbose) {
-        print $fh localtime() . " [+] IPTables::ChainMgr::run_ipt_cmd() $cmd\n";
-    }
-
-    my $ipt_pid;
-
-    local $SIG{'CHLD'} = \&REAPER;
-    if ($ipt_pid = fork()) {
-        local $SIG{'ALRM'} = sub {die "[*] iptables command timeout.\n"};
-        ### iptables should never take longer than 60 seconds to execute,
-        ### unless there is some absolutely enormous policy or the kernel
-        ### is exceedingly busy
-        alarm 60;
-        eval {
-            waitpid($ipt_pid, 0);
-        };
-        alarm 0;
-        if ($@) {
-            kill 9, $ipt_pid unless kill 15, $ipt_pid;
-        }
-    } else {
-        die "[*] Could not fork iptables: $!"
-            unless defined $ipt_pid;
-
-        ### exec the iptables command and preserve stdout and stderr
-        exec qq{$cmd > $iptout 2> $ipterr};
-    }
 
     my $rv = 1;
     my @stdout = ();
     my @stderr = ();
 
-    if (-e $iptout) {
+    my $fh = *STDERR;
+    $fh = *STDOUT if $verbose;
+
+    if ($debug or $verbose) {
+        print $fh localtime() . " [+] IPTables::ChainMgr::",
+            "run_ipt_cmd(${ipt_exec_style}()) $cmd\n";
+        if ($ipt_exec_sleep > 0) {
+            print $fh localtime() . " [+] IPTables::ChainMgr::",
+                "run_ipt_cmd() sleep seconds: $ipt_exec_sleep\n";
+        }
+    }
+
+    if ($ipt_exec_sleep > 0) {
+
+        if ($debug or $verbose) {
+            print $fh localtime() . " [+] IPTables::ChainMgr: ",
+                "sleeping for $ipt_exec_sleep seconds before ",
+                "executing iptables command.\n";
+        }
+        sleep $ipt_exec_sleep;
+    }
+
+    if ($ipt_exec_style eq 'system') {
+        system qq{$cmd > $iptout 2> $ipterr};
+    } elsif ($ipt_exec_style eq 'popen') {
+        open CMD, "$cmd 2> $ipterr |" or croak "[*] Could not execute $cmd: $!";
+        @stdout = <CMD>;
+        close CMD;
+        open F, "> $iptout" or croak "[*] Could not open $iptout: $!";
+        print F for @stdout;
+        close F;
+    } else {
+        my $ipt_pid;
+
+        if ($debug or $verbose) {
+            print $fh localtime() . " [+] IPTables::ChainMgr: " .
+                "Setting SIGCHLD handler to: " . $sigchld_handler . "\n";
+        }
+
+        local $SIG{'CHLD'} = $sigchld_handler;
+        if ($ipt_pid = fork()) {
+            eval {
+                ### 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"};
+                alarm $ipt_alarm;
+                waitpid($ipt_pid, 0);
+                alarm 0;
+            };
+            if ($@) {
+                kill 9, $ipt_pid unless kill 15, $ipt_pid;
+            }
+        } else {
+            croak "[*] Could not fork iptables: $!"
+                unless defined $ipt_pid;
+
+            ### exec the iptables command and preserve stdout and stderr
+            exec qq{$cmd > $iptout 2> $ipterr};
+        }
+    }
+
+    if (not @stdout and -e $iptout) {
         open F, "< $iptout" or croak "[*] Could not open $iptout";
         @stdout = <F>;
         close F;
@@ -481,7 +626,6 @@
 1;
 
 __END__
-# Below is stub documentation for your module. You'd better edit it!
 
 =head1 NAME
 
@@ -497,6 +641,13 @@
       'ipterr'   => '/tmp/iptables.err',
       'debug'    => 0,
       'verbose'  => 0
+
+      ### advanced options
+      'ipt_alarm' => 5,  ### max seconds to wait for iptables execution.
+      'ipt_exec_style' => 'waitpid',  ### can be 'waitpid',
+                                      ### 'system', or 'popen'.
+      'ipt_exec_sleep' => 1, ### add in time delay between execution of
+                             ### iptables commands (default is 0).
   );
 
   my $ipt_obj = new IPTables::ChainMgr(%opts)
@@ -541,9 +692,16 @@
       '192.168.1.2', 5, 'filter', 'INPUT', 'ACCEPT', {});
 
   # add rule at the 4th rule position to allow all traffic from
-  # 10.1.2.3 to 192.168.1.2 via the CUSTOM chain in the filter table
+  # 10.1.2.3 to 192.168.1.2 over TCP port 80 via the CUSTOM chain
+  # in the filter table
   ($rv, $out_ar, $errs_ar) = $ipt_obj->add_ip_rule('10.1.2.3',
-      '192.168.1.2', 5, 'filter', 'CUSTOM', 'ACCEPT',
+      '192.168.1.2', 4, 'filter', 'CUSTOM', 'ACCEPT',
+      {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80});
+
+  # append rule at the end of the CUSTOM chain in the filter table to
+  # allow all traffic from 10.1.2.3 to 192.168.1.2 via port 80
+  ($rv, $out_ar, $errs_ar) = $ipt_obj->append_ip_rule('10.1.2.3',
+      '192.168.1.2', 'filter', 'CUSTOM', 'ACCEPT',
       {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80});
 
   # run an arbitrary iptables command and collect the output
@@ -555,11 +713,12 @@
 The C<IPTables::ChainMgr> package provide an interface to manipulate iptables
 policies on Linux systems through the direct execution of iptables commands.
 Although making a perl extension of libiptc provided by the iptables project is
-possible (and has been done by the FIXME module), it is easy to just execute
-iptables commands directly in order to both parse and change the configuration of
-the policy.  Further, this simplifies installation since the only external
-requirement is (in the spirit of scripting) to be able to point IPTables::ChainMgr
-at an installed iptables binary instead of having to compile against a library.
+possible (and has been done by the IPTables::libiptc module available from CPAN),
+it is also easy enough to just execute iptables commands directly in order to
+both parse and change the configuration of the policy.  Further, this simplifies
+installation since the only external requirement is (in the spirit of scripting)
+to be able to point IPTables::ChainMgr at an installed iptables binary instead
+of having to compile against a library.
 
 =head1 FUNCTIONS
 
@@ -643,6 +802,12 @@
 
 This function inserts a rule into the running iptables chain and table at the
 specified rule number.  Return values are success or failure along with the
+iptables stdout and stderr.
+
+=item append_ip_rule($src, $dst, $table, $chain, $target, %extended_info)
+
+This function appends a rule at the end of the iptables chain in the specified
+table.  Return values are success or failure along with the
 iptables stdout and stderr.
 
 =item delete_ip_rule($src, $dst, $table, $chain, $target, %extended_info)
@@ -686,8 +851,9 @@
 The IPTables::ChainMgr extension is closely associated with the IPTables::Parse
 extension, and both are heavily used by the psad, fwsnort, and fwknop projects
 to manipulate iptables policies based on various criteria (see the psad(8),
-fwsnort(8), and fwknop(8) man pages).  As always, the iptables(8) provides the
-best information on command line execution and theory behind iptables.
+fwsnort(8), and fwknop(8) man pages).  As always, the iptables(8) man page
+provides the best information on command line execution and theory behind
+iptables.
 
 Although there is no mailing that is devoted specifically to the IPTables::ChainMgr
 extension, questions about the extension will be answered on the following




More information about the Pkg-perl-cvs-commits mailing list