From 19f86a35b1d4fba517e92ee0b031756b9f282222 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Tue, 2 Jan 2018 19:16:42 +0100 Subject: [PATCH 1/3] Check if an iptables chain exists --- lib/Rex/Commands/Iptables.pm | 45 +++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/Rex/Commands/Iptables.pm b/lib/Rex/Commands/Iptables.pm index 1f1887c26..2b86a61cd 100644 --- a/lib/Rex/Commands/Iptables.pm +++ b/lib/Rex/Commands/Iptables.pm @@ -104,7 +104,7 @@ use Rex::Logger; @EXPORT = qw(iptables is_nat_gateway iptables_list iptables_clear open_port close_port redirect_port - default_state_rule); + default_state_rule chain_exists); sub iptables; @@ -485,6 +485,49 @@ sub _iptables_list { return $ret; } +=head2 chain_exists + +Returns true if a chain exists in a table, false otherwise. + +In this example we create a chain unless it already exists. + + task "create_chain", sub { + iptables(t => 'filter', N => 'FOO') + unless chain_exists('filter','FOO'); + }; + + +=cut + +sub chain_exists { + my ( $table, $chain, @params ) = @_; + my $iptables = _get_executable( \@params ); + my @lines = run "$iptables-save"; + + return _chain_exists( $table, $chain, @lines ); +} + +sub _chain_exists { + my ( $table, $chain, @lines ) = @_; + my ($current_table); + for my $line (@lines) { + chomp $line; + + next if ( $line eq "COMMIT" ); + next if ( $line =~ m/^#/ ); + if ( $line =~ m/^:(\w+)/ ) { + return 1 if $current_table eq $table && $chain eq $1; + next; + } + + if ( $line =~ m/^\*([a-z]+)$/ ) { + $current_table = $1; + next; + } + } + return 0; +} + =head2 iptables_clear Remove all iptables rules. From 6973e30cd368bbe50f2d11289b12006e3f7423c6 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Sun, 13 Oct 2019 11:33:58 +0200 Subject: [PATCH 2/3] Test chain exists in iptables --- t/commands/iptables.t | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/t/commands/iptables.t b/t/commands/iptables.t index 690c289ef..488f1ff48 100644 --- a/t/commands/iptables.t +++ b/t/commands/iptables.t @@ -1,7 +1,7 @@ use strict; use warnings; -use Test::More tests => 32; +use Test::More tests => 36; use Rex::Commands::Iptables; @@ -55,3 +55,8 @@ is( $rules->{foo}->[0]->[13], "50", "up to 50" ); is( $rules->{foo}->[0]->[14], "j", "jump to" ); is( $rules->{foo}->[0]->[15], "RETURN", "RETURN" ); +is(Rex::Commands::Iptables::chain_exists('foo'),0); +is(Rex::Commands::Iptables::chain_exists('INPUT'),1); + +is(Rex::Commands::Iptables::chain_exists('foo', table => 'filter'),0); +is(Rex::Commands::Iptables::chain_exists('INPUT', table => 'filter'),1); From 2da9ab97f4ea6cdf564d3a110d6bd244017464b5 Mon Sep 17 00:00:00 2001 From: Francesc Guasch Date: Sun, 13 Oct 2019 11:36:18 +0200 Subject: [PATCH 3/3] Use built-in iptables to check for chain exists --- lib/Rex/Commands/Iptables.pm | 43 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/lib/Rex/Commands/Iptables.pm b/lib/Rex/Commands/Iptables.pm index 2b86a61cd..e372a24e8 100644 --- a/lib/Rex/Commands/Iptables.pm +++ b/lib/Rex/Commands/Iptables.pm @@ -489,43 +489,38 @@ sub _iptables_list { Returns true if a chain exists in a table, false otherwise. + + chain_exists 'foo'; # $table defaulting to 'filter' + chain_exists 'foo', table => 'filter'; + chain_exists -6, 'foo'; # IPv6 + + In this example we create a chain unless it already exists. task "create_chain", sub { - iptables(t => 'filter', N => 'FOO') - unless chain_exists('filter','FOO'); + iptables(t => 'filter', N => 'foo') + unless chain_exists('foo'); }; =cut sub chain_exists { - my ( $table, $chain, @params ) = @_; - my $iptables = _get_executable( \@params ); - my @lines = run "$iptables-save"; + my @params = @_; + my $ipt_version = _get_ip_version( \@params ); + my ( $chain, %args ) = @params; - return _chain_exists( $table, $chain, @lines ); -} + my $table = (delete $args{table} or 'filter'); -sub _chain_exists { - my ( $table, $chain, @lines ) = @_; - my ($current_table); - for my $line (@lines) { - chomp $line; + eval { + iptables($ipt_version, list => $chain); + }; - next if ( $line eq "COMMIT" ); - next if ( $line =~ m/^#/ ); - if ( $line =~ m/^:(\w+)/ ) { - return 1 if $current_table eq $table && $chain eq $1; - next; - } + return 0 if $@ && $@ =~ /No chain/; + die $@ if $@; + + return 1; - if ( $line =~ m/^\*([a-z]+)$/ ) { - $current_table = $1; - next; - } - } - return 0; } =head2 iptables_clear