diff --git a/lib/Rex/Commands/Iptables.pm b/lib/Rex/Commands/Iptables.pm index 1f1887c26..e372a24e8 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,44 @@ sub _iptables_list { return $ret; } +=head2 chain_exists + +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('foo'); + }; + + +=cut + +sub chain_exists { + my @params = @_; + my $ipt_version = _get_ip_version( \@params ); + my ( $chain, %args ) = @params; + + my $table = (delete $args{table} or 'filter'); + + eval { + iptables($ipt_version, list => $chain); + }; + + return 0 if $@ && $@ =~ /No chain/; + die $@ if $@; + + return 1; + +} + =head2 iptables_clear Remove all iptables rules. 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);