State tracking chain_rules() 'extended' attributes bug fix IPTables-Parse-0.9
authorMichael Rash <mbr@cipherdyne.org>
Mon, 27 Feb 2012 01:53:11 +0000 (20:53 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Mon, 27 Feb 2012 01:53:11 +0000 (20:53 -0500)
Applied slightly modified patch from SSIMON to properly pick up usage of
state tracking in rule extended information as shown in this bug:
https://rt.cpan.org/Ticket/Display.html?id=67372#txn-925687
Rule 'extended' hash now includes the 'state' or 'ctstate' key
depending on which iptables state tracking module is being used (if
any).

Changes
README
VERSION
lib/IPTables/Parse.pm
t/basic_tests.pl

diff --git a/Changes b/Changes
index 7b6daf0..46505b7 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,13 @@
 Revision history for Perl extension IPTables::Parse.
 
+0.9 Sun Feb 26 21:01:45 2012
+    - Applied slightly modified patch from SSIMON to properly pick up usage of
+      state tracking in rule extended information as shown in this bug:
+            https://rt.cpan.org/Ticket/Display.html?id=67372#txn-925687
+      Rule 'extended' hash now includes the 'state' or 'ctstate' key
+      depending on which iptables state tracking module is being used (if
+      any).
+
 0.8 Sun Feb 26 14:03:24 2012
     - Major update to support ip6tables policies.
     - Added test suite script t/basic_tests.pl to exercise major functions for
diff --git a/README b/README
index 89c25d5..40f00ed 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-IPTables-Parse version 0.8
+IPTables-Parse version 0.9
 ===========================
 
 The README is used to introduce the module and provide instructions on
diff --git a/VERSION b/VERSION
index aec258d..b63ba69 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.8
+0.9
index 3494cf4..d24340b 100644 (file)
@@ -7,7 +7,7 @@
 #
 # Author: Michael Rash (mbr@cipherdyne.org)
 #
-# Version: 0.8
+# Version: 0.9
 #
 ##################################################################
 #
@@ -21,7 +21,7 @@ use strict;
 use warnings;
 use vars qw($VERSION);
 
-$VERSION = '0.8';
+$VERSION = '0.9';
 
 sub new() {
     my $class = shift;
@@ -96,7 +96,7 @@ sub chain_rules() {
     my $found_chain  = 0;
     my @ipt_lines = ();
 
-    ### only used for IPv4 and NAT
+    ### only used for IPv4 + NAT
     my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|;
 
     ### array of hash refs
@@ -160,6 +160,7 @@ sub chain_rules() {
             'to_port'  => '',
             'extended' => '',
             'state'    => '',
+            'ctstate'  => '',
             'raw'      => $line
         );
 
@@ -219,37 +220,11 @@ sub chain_rules() {
                             $rule{'to_ip'}   = $1;
                             $rule{'to_port'} = $2;
                         }
-
-                        for my $state_hr (@global_accept_state) {
-                            next unless $state_hr->{'src'} eq '0.0.0.0/0';
-                            next unless $state_hr->{'dst'} eq '0.0.0.0/0';
-                            next unless $state_hr->{'proto'} eq 'all' or
-                                $state_hr->{'proto'} = $rule{'proto'};
-                            next unless $state_hr->{'intf_in'} eq '*' or
-                                $state_hr->{'intf_in'} eq $rule{'intf_in'};
-                            next unless $state_hr->{'intf_out'} eq '*' or
-                                $state_hr->{'intf_out'} eq $rule{'intf_out'};
-                            ### if we make it here, then the state rule
-                            ### applies to this rule
-                            $rule{'state'} = $state_hr->{'state'};
-                        }
                     }
-                    if ($rule{'target'} eq 'ACCEPT'
-                            and $rule{'extended'} =~ m|^state\s+(\S+)|) {
-                        my $state_str = $1;
-                        if ($state_str =~ /ESTABLISHED/
-                                or $state_str =~ /RELATED/) {
-
-                            push @global_accept_state, {
-                                'state'    => $state_str,
-                                'src'      => $rule{'src'},
-                                'dst'      => $rule{'dst'},
-                                'intf_in'  => $rule{'intf_in'},
-                                'intf_out' => $rule{'intf_out'},
-                                'proto'    => $rule{'protocol'}
-                            };
-                            my %state_hash = ();
-                        }
+                    if ($rule{'extended'} =~ /\bctstate\s+(\S+)/) {
+                        $rule{'ctstate'} = $1;
+                    } elsif ($rule{'extended'} =~ /\bstate\s+(\S+)/) {
+                        $rule{'state'} = $1;
                     }
                 }
             }
@@ -309,6 +284,12 @@ sub chain_rules() {
                         $rule{'to_ip'}   = $1;
                         $rule{'to_port'} = $2;
                     }
+
+                    if ($rule{'extended'} =~ /\bctstate\s+(\S+)/) {
+                        $rule{'ctstate'} = $1;
+                    } elsif ($rule{'extended'} =~ /\bstate\s+(\S+)/) {
+                        $rule{'state'} = $1;
+                    }
                 }
             }
         }
index aa330a4..e63aa62 100755 (executable)
@@ -166,19 +166,40 @@ sub chain_rules_tests() {
 
             my $rules_ar = $ipt_obj->chain_rules($table, $chain);
 
-            ### compare raw rules list with parsed chain_rules()
-            ### output - basic number check
             $executed++;
 
-            if (($#$out_ar - 2) == $#$rules_ar) {
+            my $matched_state = 1;
+            for (my $i=2; $i<=$#$out_ar; $i++) {
+                if ($out_ar->[$i] =~ /\sctstate/) {
+                    unless (defined $rules_ar->[$i-2]->{'ctstate'}
+                            and $rules_ar->[$i-2]->{'ctstate'}) {
+                        $matched_state = 0;
+                        last;
+                    }
+                } elsif ($out_ar->[$i] =~ /\sstate/) {
+                    unless (defined $rules_ar->[$i-2]->{'state'}
+                            and $rules_ar->[$i-2]->{'state'}) {
+                        $matched_state = 0;
+                        last;
+                    }
+                }
+            }
+
+            ### compare raw rules list with parsed chain_rules()
+            ### output - basic number check
+            if (($#$out_ar - 2) == $#$rules_ar and $matched_state) {
                 &logr("pass ($executed)\n");
                 $passed++;
             } else {
                 &logr("fail ($executed)\n");
-                if (($#$out_ar - 2) > $#$rules_ar) {
-                    &logr("    chain_rules() missed rules.\n");
-                } elsif (($#$out_ar - 2) < $#$rules_ar) {
-                    &logr("    chain_rules() added inappropriate rules.\n");
+                if ($matched_state) {
+                    &logr("    chain_rules() missed extended state info.\n");
+                } else {
+                    if (($#$out_ar - 2) > $#$rules_ar) {
+                        &logr("    chain_rules() missed rules.\n");
+                    } elsif (($#$out_ar - 2) < $#$rules_ar) {
+                        &logr("    chain_rules() added inappropriate rules.\n");
+                    }
                 }
                 $failed++;
             }