From 61d5c6d6da144fbc12daec5496def0fcf604ce4b Mon Sep 17 00:00:00 2001
From: Tom Eastep <teastep@shorewall.net>
Date: Sat, 26 Nov 2011 09:36:02 -0800
Subject: [PATCH] Implement Shorewall::Chains::clone_rule()

Signed-off-by: Tom Eastep <teastep@shorewall.net>
---
 Shorewall/Perl/Shorewall/Chains.pm    | 15 +++++++++++++++
 Shorewall/Perl/Shorewall/Providers.pm | 18 +++---------------
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm
index f7976e986..e08c6e4ea 100644
--- a/Shorewall/Perl/Shorewall/Chains.pm
+++ b/Shorewall/Perl/Shorewall/Chains.pm
@@ -41,6 +41,7 @@ our @EXPORT = qw(
 		    add_ijump
 		    insert_rule
 		    insert_irule
+		    clone_rule
 		    insert_ijump
 		    rule_target
 		    clear_rule_target
@@ -1281,6 +1282,20 @@ sub insert_irule( $$$$;@ ) {
 }
 
 #
+# Clone an existing rule. Only the rule hash itself is cloned; reference values are shared between the new rule
+# reference and the old.
+#
+sub clone_rule( $ ) {
+    my $oldruleref = $_[0];
+    my $newruleref = {};
+
+    while ( my ( $key, $value ) = each %$oldruleref ) {
+	$newruleref->{$key} = $value;
+    }
+
+    $newruleref;
+}
+
 # Do final work to 'delete' a chain. We leave it in the chain table but clear
 # the 'referenced', 'rules', 'references' and 'blacklist' members.
 #
diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm
index 77688522a..ccb4bfc02 100644
--- a/Shorewall/Perl/Shorewall/Providers.pm
+++ b/Shorewall/Perl/Shorewall/Providers.pm
@@ -1406,29 +1406,17 @@ sub handle_stickiness( $ ) {
 
 		for my $chainref ( $stickyref, $setstickyref ) {
 		    if ( $chainref->{name} eq 'sticky' ) {
-			$rule1 = {};
-
-			while ( my ( $key, $value ) = each %$_ ) {
-			    $rule1->{$key} = $value;
-			}
+			$rule1 = clone_rule( $_ );
 
 			set_rule_target( $rule1, 'MARK',   "--set-mark $mark" );
 			set_rule_option( $rule1, 'recent', "--name $list --update --seconds 300" );
 
-			$rule2 = {};
-
-			while ( my ( $key, $value ) = each %$_ ) {
-			    $rule2->{$key} = $value;
-			}
+			$rule2 = clone_rule( $_ );
 
 			clear_rule_target( $rule2 );
 			set_rule_option( $rule2, 'mark', "--mark 0/$mask -m recent --name $list --remove" );
 		    } else {
-			$rule1 = {};
-
-			while ( my ( $key, $value ) = each %$_ ) {
-			    $rule1->{$key} = $value;
-			}
+			$rule1 = clone_rule( $_ );
 
 			clear_rule_target( $rule1 );
 			set_rule_option( $rule1, 'mark', "--mark $mark\/$mask -m recent --name $list --set" );