Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion lib/Rex/Commands/Iptables.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 ) = @_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this might not be consistent with the other command's convention to support -6 as first parameter to signal usage of IPv6.

Also how about these as target usage examples:

  • chain_exists 'foo'; # $table defaulting to 'filter'
  • chain_exists 'foo', table => 'filter';
  • chain_exists -6, 'foo'; # IPv6

my $iptables = _get_executable( \@params );
my @lines = run "$iptables-save";

return _chain_exists( $table, $chain, @lines );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be simpler and faster to check for the return code of iptables [--table $table] --list $chain > /dev/null command. If the chain exists it will be true, but otherwise false.

Perhaps even the built-in iptables() sub can be used for that too (but it probably needs to be wrapped in a try-catch block as it die()s in case of non-OK return codes).

}

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.
Expand Down