### optionally add port numbers and protocols, etc.
my $extended_href = shift || {};
- my $iptables = $self->{'_iptables'};
-
- ### normalize src/dst if necessary; this is because iptables
- ### always reports the network address for subnets
- my $normalized_src = $self->normalize_net($src);
- my $normalized_dst = $self->normalize_net($dst);
-
- ### first check to see if this rule already exists
- my ($rule_position, $num_chain_rules)
- = $self->find_ip_rule($normalized_src, $normalized_dst, $table,
- $chain, $target, $extended_href);
-
- if ($rule_position) {
- my $msg = '';
- if (keys %$extended_href) {
- $msg = "Table: $table, chain: $chain, $normalized_src -> " .
- "$normalized_dst ";
- for my $key (qw(protocol s_port d_port mac_source)) {
- $msg .= "$key $extended_href->{$key} "
- if defined $extended_href->{$key};
- }
- $msg .= 'rule already exists.';
- } else {
- $msg = "Table: $table, chain: $chain, $normalized_src -> " .
- "$normalized_dst rule already exists.";
- }
- return 1, [$msg], [];
- }
-
- ### we need to add the rule
- my $ipt_cmd = '';
- my $msg = '';
- my $idx_err = '';
-
- if (keys %$extended_href) {
- $ipt_cmd = "$iptables -t $table -A $chain ";
- $ipt_cmd .= "-p $extended_href->{'protocol'} "
- if defined $extended_href->{'protocol'};
- $ipt_cmd .= "-s $normalized_src ";
- $ipt_cmd .= "--sport $extended_href->{'s_port'} "
- if defined $extended_href->{'s_port'};
- $ipt_cmd .= "-d $normalized_dst ";
- $ipt_cmd .= "--dport $extended_href->{'d_port'} "
- if defined $extended_href->{'d_port'};
- $ipt_cmd .= "-m mac --mac-source $extended_href->{'mac_source'} "
- if defined $extended_href->{'mac_source'};
- $ipt_cmd .= "-j $target";
-
- $msg = "Table: $table, chain: $chain, added $normalized_src " .
- "-> $normalized_dst ";
- for my $key (qw(protocol s_port d_port mac_source)) {
- $msg .= "$key $extended_href->{$key} "
- if defined $extended_href->{$key};
- }
-
- ### for NAT
- if (defined $extended_href->{'to_ip'} and
- defined $extended_href->{'to_port'}) {
- $ipt_cmd .= " --to $extended_href->{'to_ip'}:" .
- "$extended_href->{'to_port'}";
- $msg .= "$extended_href->{'to_ip'}:$extended_href->{'to_port'}";
- }
- $msg =~ s/\s*$//;
- } else {
- $ipt_cmd = "$iptables -t $table -A $chain " .
- "-s $normalized_src -d $normalized_dst -j $target";
- $msg = "Table: $table, chain: $chain, added $normalized_src " .
- "-> $normalized_dst";
- }
- my ($rv, $out_aref, $err_aref) = $self->run_ipt_cmd($ipt_cmd);
- if ($rv) {
- push @$out_aref, $msg if $msg;
- }
- push @$err_aref, $idx_err if $idx_err;
- return $rv, $out_aref, $err_aref;
+ ### -1 for append
+ return $self->add_ip_rule($src, $dst, -1, $table,
+ $chain, $target, $extended_href);
}
sub add_ip_rule() {
my $self = shift;
my $src = shift || croak '[-] Must specify a src address/network.';
my $dst = shift || croak '[-] Must specify a dst address/network.';
- my $rulenum = shift || croak '[-] Must specify an insert rule number.';
+ (my $rulenum = shift) >= -1 || croak '[-] Must specify an insert rule number, or -1 for append.';
my $table = shift || croak '[-] Must specify a table, e.g. "filter".';
my $chain = shift || croak '[-] Must specify a chain.';
my $target = shift ||
if (keys %$extended_href) {
$msg = "Table: $table, chain: $chain, $normalized_src -> " .
"$normalized_dst ";
- for my $key (qw(protocol s_port d_port mac_source)) {
+ for my $key (qw(protocol s_port d_port mac_source state ctstate)) {
$msg .= "$key $extended_href->{$key} "
if defined $extended_href->{$key};
}
my $msg = '';
my $idx_err = '';
- ### check to see if the insertion index ($rulenum) is too big
- $rulenum = 1 if $rulenum <= 0;
- if ($rulenum > $num_chain_rules+1) {
- $idx_err = "Rule position $rulenum is past end of $chain " .
- "chain ($num_chain_rules rules), compensating."
- if $num_chain_rules > 0;
- $rulenum = $num_chain_rules + 1;
+ if ($rulenum == 0) {
+ $ipt_cmd = "$iptables -t $table -I $chain 1 ";
+ } elsif ($rulenum < 0) {
+ ### switch to append mode
+ $ipt_cmd = "$iptables -t $table -A $chain ";
+ } else {
+ ### check to see if the insertion index ($rulenum) is too big
+ if ($rulenum > $num_chain_rules+1) {
+ $idx_err = "Rule position $rulenum is past end of $chain " .
+ "chain ($num_chain_rules rules), compensating."
+ if $num_chain_rules > 0;
+ $rulenum = $num_chain_rules + 1;
+ }
+ $ipt_cmd = "$iptables -t $table -I $chain $rulenum ";
}
- $rulenum = 1 if $rulenum == 0;
if (keys %$extended_href) {
- $ipt_cmd = "$iptables -t $table -I $chain $rulenum ";
$ipt_cmd .= "-p $extended_href->{'protocol'} "
if defined $extended_href->{'protocol'};
$ipt_cmd .= "-s $normalized_src ";
$msg = "Table: $table, chain: $chain, added $normalized_src " .
"-> $normalized_dst ";
- for my $key (qw(protocol s_port d_port mac_source)) {
+ for my $key (qw(protocol s_port d_port mac_source state ctstate)) {
$msg .= "$key $extended_href->{$key} "
if defined $extended_href->{$key};
}
$msg =~ s/\s*$//;
} else {
- $ipt_cmd = "$iptables -t $table -I $chain $rulenum " .
- "-s $normalized_src -d $normalized_dst -j $target";
+ $ipt_cmd .= "-s $normalized_src -d $normalized_dst -j $target";
$msg = "Table: $table, chain: $chain, added $normalized_src " .
"-> $normalized_dst";
}
my $extended_msg = '';
if (keys %$extended_href) {
- for my $key (qw(protocol s_port d_port mac_source)) {
+ for my $key (qw(protocol s_port d_port mac_source state ctstate)) {
$extended_msg .= "$key: $extended_href->{$key} "
if defined $extended_href->{$key};
}
d_port
to_ip
to_port
+ mac_source
state
ctstate
)) {
$found = 0;
last;
}
+ } elsif ($key eq 'mac_source') {
+ ### make sure case does not matter
+ unless (lc($extended_href->{$key})
+ eq lc($rule_href->{$key})) {
+ $found = 0;
+ last;
+ }
} else {
unless ($extended_href->{$key}
eq $rule_href->{$key}) {
my $ipv6_src = 'fe80::200:f8ff:fe21:67cf';
my $ipv6_dst = '0000:0000:00AA:0000:0000:AA00:0000:0001/64';
+my $mac_source = 'ff:ff:ff:c6:33:58';
+
my $logfile = 'test.log';
my $PRINT_LEN = 68;
my $chain_past_end = 1000;
&chain_does_not_exist_test($ipt_obj, $test_table, $test_chain);
&create_chain_test($ipt_obj, $test_table, $test_chain);
&add_rules_tests($ipt_obj, $test_table, $test_chain);
+ &find_rules_tests($ipt_obj, $test_table, $test_chain);
&flush_chain_test($ipt_obj, $test_table, $test_chain);
&delete_chain_test($ipt_obj, $test_table, $test_jump_from_chain, $test_chain);
}
for my $target (qw/LOG ACCEPT RETURN/) {
- &dots_print("add_ip_rules(): $test_table $test_chain $src_ip -> $dst_ip $target ");
+ &dots_print("add_ip_rule(): $test_table $test_chain $src_ip -> $dst_ip $target ");
my ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
$dst_ip, $chain_past_end, $test_table, $test_chain, $target, {});
&pass_fail($rv, " Could not add $src_ip -> $dst_ip $target rule.");
}
+ for my $target (qw/LOG ACCEPT RETURN/) {
+ &dots_print("append_ip_rule(): $test_table $test_chain $src_ip -> $dst_ip $target ");
+ my ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, -1, $test_table, $test_chain, $target, {});
+
+ &pass_fail($rv, " Could not append $src_ip -> $dst_ip $target rule.");
+ }
+
return;
}
{'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80, 'ctstate' => 'ESTABLISHED,RELATED'});
&pass_fail($rv, " Could not add TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target rule");
+ ### TCP + mac source
+ &dots_print("add_ip_rules(): $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) $target mac_source $mac_source ");
+ ($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
+ $dst_ip, $chain_past_end, $test_table, $test_chain, $target,
+ {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80, 'mac_source' => $mac_source});
+ &pass_fail($rv, " Could not add TCP $src_ip(0) -> $dst_ip(80) $target mac_source $mac_source");
+
### UDP
&dots_print("add_ip_rules(): $test_table $test_chain UDP $src_ip(0) -> $dst_ip(53) $target ");
($rv, $out_ar, $err_ar) = $ipt_obj->add_ip_rule($src_ip,
'd_port' => 80, 'ctstate' => 'ESTABLISHED,RELATED'});
&pass_fail($rule_position, " Could not find TCP $src_ip(0) -> $dst_ip(80) ctstate ESTABLISHED,RELATED $target rule");
+ &dots_print("find rule: $test_table $test_chain TCP $src_ip(0) -> $dst_ip(80) $target mac_source $mac_source ");
+ ($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
+ $dst_ip, $test_table, $test_chain, $target,
+ {'protocol' => 'tcp', 's_port' => 0, 'd_port' => 80,
+ 'mac_source' => $mac_source});
+ &pass_fail($rule_position, " Could not find TCP $src_ip(0) -> $dst_ip(80) $target mac_source $mac_source");
+
&dots_print("find rule: $test_table $test_chain UDP $src_ip(0) -> $dst_ip(53) $target ");
($rule_position, $num_chain_rules) = $ipt_obj->find_ip_rule($src_ip,
$dst_ip, $test_table, $test_chain, $target,