summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorBob Gilligan <gilligan@vyatta.com>2009-01-21 17:27:31 -0800
committerBob Gilligan <gilligan@vyatta.com>2009-01-21 17:27:31 -0800
commitc1b35e85eff4bb00ed7e7098fa1aee54d919608a (patch)
tree55d0f19e36d14f4a6fa4e24d14949fa3ae769d15 /scripts
parentcc811731ba98e6b5f76cfea66960c2c8e2943532 (diff)
downloadvyatta-cfg-firewall-c1b35e85eff4bb00ed7e7098fa1aee54d919608a.tar.gz
vyatta-cfg-firewall-c1b35e85eff4bb00ed7e7098fa1aee54d919608a.zip
Initial support for IPv6.
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/firewall/vyatta-firewall.pl313
1 files changed, 226 insertions, 87 deletions
diff --git a/scripts/firewall/vyatta-firewall.pl b/scripts/firewall/vyatta-firewall.pl
index 0ad6a77..9625c43 100755
--- a/scripts/firewall/vyatta-firewall.pl
+++ b/scripts/firewall/vyatta-firewall.pl
@@ -9,19 +9,37 @@ use Getopt::Long;
# Send output of shell commands to syslog for debugging and so that
# the user is not confused by it. Log at debug level, which is supressed
# by default, so that we don't unnecessarily fill up the syslog file.
-
my $logger = 'logger -t firewall-cfg -p local0.debug --';
+# Enable printing debug output to stdout.
+my $debug_flag = 0;
+
+# Enable sending debug output to syslog.
+my $syslog_flag = 0;
+
my @updateints = ();
GetOptions("setup" => \$setup,
"teardown" => \$teardown,
"update-rules" => \$updaterules,
"update-interfaces=s{4}" => \@updateints,
+ "debug" => \$debug_flag,
+ "syslog" => \$syslog_flag
);
-# mapping from config node to iptables table
-my %table_hash = ( 'name' => 'filter',
- 'modify' => 'mangle', );
+# mapping from config node to iptables/ip6tables table
+my %table_hash = ( 'name' => 'filter',
+ 'ipv6-name' => 'filter',
+ 'modify' => 'mangle',
+ 'ipv6-modify' => 'mangle' );
+
+# mapping from config node to iptables command. Note that this table
+# has the same keys as %table hash, so a loop iterating through the
+# keys of %table_hash can use the same keys to find the value associated
+# with the key in this table.
+my %cmd_hash = ( 'name' => 'iptables',
+ 'ipv6-name' => 'ip6tables',
+ 'modify' => 'iptables',
+ 'ipv6-modify' => 'ip6tables');
sub other_table {
my $this = shift;
@@ -29,12 +47,14 @@ sub other_table {
}
if (defined $setup) {
- setup_iptables();
+ setup_iptables(iptables);
+ setup_iptables(ip6tables);
exit 0;
}
my $update_zero_count = 0;
if (defined $updaterules) {
+ # Iterate through the top-level trees under "firewall"
foreach (keys %table_hash) {
update_rules($_);
}
@@ -45,6 +65,7 @@ if ($#updateints == 3) {
my ($action, $int_name, $direction, $chain) = @updateints;
my $tree = chain_configured(0, $chain, undef);
my $table = $table_hash{$tree};
+ my $iptables_cmd = $cmd_hash{$tree};
if ($action eq "update") {
# make sure chain exists
if (!defined($tree)) {
@@ -55,18 +76,23 @@ if ($#updateints == 3) {
}
# chain must have been set up. no need to set up again.
# user may specify a chain in a different tree. try to delete it
- # from the "other" tree first.
- update_ints('delete', $int_name, $direction, $chain, other_table($table));
+ # from the "other" trees first.
+ foreach $other_tree (keys %table_hash) {
+ if ($other_tree ne $tree) {
+ update_ints('delete', $int_name, $direction, $chain,
+ $table_hash{$other_tree}, $cmd_hash{$other_tree});
+ }
+ }
# do update action.
- update_ints(@updateints, $table);
+ update_ints(@updateints, $table, $iptables_cmd);
} else {
# delete
if (defined($tree)) {
- update_ints(@updateints, $table);
+ update_ints(@updateints, $table, $iptables_cmd);
} else {
- # chain not configured. try both tables.
+ # chain not configured. try all tables.
foreach (keys %table_hash) {
- update_ints(@updateints, $table_hash{$_});
+ update_ints(@updateints, $table_hash{$_}, $cmd_hash{$_});
}
}
}
@@ -77,7 +103,7 @@ if ($#updateints == 3) {
if (defined $teardown) {
foreach (keys %table_hash) {
$update_zero_count += 1;
- teardown_iptables($table_hash{$_});
+ teardown_iptables($table_hash{$_}, $cmd_hash{$_});
}
exit 0;
}
@@ -95,29 +121,73 @@ sub help() {
print "\n";
}
+sub run_cmd($$$) {
+ my ($cmd_to_run, $redirect_flag, $logger_flag) = @_;
+
+ my $cmd_extras;
+
+ if ($debug_flag) {
+ print "DEBUG: Running: $cmd_to_run \n";
+ }
+
+ if ($syslog_flag) {
+ system("$logger DEBUG: Running: $cmd_to_run");
+ }
+
+ if ($redirect_flag) {
+ $cmd_extras = ' 2>&1';
+ }
+
+ if ($logger_flag) {
+ $cmd_extras = "$cmd_extras | $logger";
+ }
+
+ system("$cmd_to_run $cmd_extras");
+}
+
+sub log_msg($) {
+ my $message = shift;
+
+ if ($debug_flag) {
+ print "DEBUG: $message";
+ }
+
+ if ($syslog_flag) {
+ system("$logger DEBUG: $message");
+ }
+}
+
sub update_rules($) {
- my $tree = shift;
- my $table = $table_hash{$tree};
+ my $tree = shift; # name, modify, ipv6-name or ipv6-modify
+ my $table = $table_hash{$tree}; # "filter" or "mangle"
+ my $iptables_cmd = $cmd_hash{$tree}; # "iptables" or "ip6tables"
my $config = new Vyatta::Config;
my $name = undef;
my %nodes = ();
- system ("$logger Executing update_rules.");
+ log_msg "update_rules: $tree $table $iptables_cmd\n";
$config->setLevel("firewall $tree");
%nodes = $config->listNodeStatus();
if ((scalar (keys %nodes)) == 0) {
+
+ log_msg "update_rules: no nodes at this level \n";
+
# no names. teardown the user chains and return.
$update_zero_count += 1;
- teardown_iptables($table);
+ teardown_iptables($table, $iptables_cmd);
return;
}
# by default, nothing needs to be tracked.
my $stateful = 0;
+ # Iterate through ruleset names under "name" or "modify"
for $name (keys %nodes) {
+
+ log_msg "update_rules: status of node $name is $nodes{$name} \n";
+
if ($nodes{$name} eq "static") {
# not changed. check if stateful.
$config->setLevel("firewall $tree $name rule");
@@ -132,6 +202,7 @@ sub update_rules($) {
}
next;
} elsif ($nodes{$name} eq "added") {
+
# create the chain
my $ctree = chain_configured(2, $name, $tree);
if (defined($ctree)) {
@@ -140,17 +211,20 @@ sub update_rules($) {
. "Rule set name \"$name\" already used in \"$ctree\"\n";
exit 1;
}
- setup_chain($table, "$name");
+ setup_chain($table, "$name", $iptables_cmd);
# handle the rules below.
} elsif ($nodes{$name} eq "deleted") {
+
+ log_msg "node $name is $nodes{$name} \n";
+
# delete the chain
- if (chain_referenced($table, $name)) {
+ if (chain_referenced($table, $name, $iptables_cmd)) {
# disallow deleting a chain if it's still referenced
print STDERR 'Firewall config error: '
. "Cannot delete rule set \"$name\" (still in use)\n";
exit 1;
}
- delete_chain($table, "$name");
+ delete_chain($table, "$name", $iptables_cmd);
next;
} elsif ($nodes{$name} eq "changed") {
# handle the rules below.
@@ -166,9 +240,10 @@ sub update_rules($) {
# no rules. flush the user rules.
# note that this clears the counters on the default DROP rule.
# we could delete rule one by one if those are important.
- system("$logger Running: iptables -F $name");
- system("iptables -t $table -F $name 2>&1 | $logger");
- add_default_drop_rule($table, $name);
+# system("$logger Running: $iptables_cmd -F $name");
+# system("$iptables_cmd -t $table -F $name 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t $table -F $name", 1, 1);
+ add_default_drop_rule($table, $name, $iptables_cmd);
next;
}
@@ -199,9 +274,12 @@ sub update_rules($) {
if (!defined) {
last;
}
- system ("$logger Insert iptables $table $name $iptablesrule $_");
- system ("iptables -t $table --insert $name $iptablesrule $_");
- die "iptables error: $! - $_" if ($? >> 8);
+
+ # system ("$logger Insert $iptables_cmd $table $name $iptablesrule $_");
+ # system ("$iptables_cmd -t $table --insert $name $iptablesrule $_");
+ run_cmd("$iptables_cmd -t $table --insert $name $iptablesrule $_",
+ 0, 0);
+ die "$iptables_cmd error: $! - $_" if ($? >> 8);
$iptablesrule++;
}
} elsif ("$rulehash{$rule}" eq "changed") {
@@ -222,18 +300,22 @@ sub update_rules($) {
my $ipt_rules = $oldnode->get_num_ipt_rules();
for (1 .. $ipt_rules) {
- system ("$logger Delete iptables $table $name $iptablesrule");
- system ("iptables -t $table --delete $name $iptablesrule");
- die "iptables error: $! - $rule" if ($? >> 8);
+ # system ("$logger Delete $iptables_cmd $table $name $iptablesrule");
+ # system ("$iptables_cmd -t $table --delete $name $iptablesrule");
+ run_cmd("$iptables_cmd -t $table --delete $name $iptablesrule", 0,
+ 0);
+ die "$iptables_cmd error: $! - $rule" if ($? >> 8);
}
foreach (@rule_strs) {
if (!defined) {
last;
}
- system ("$logger Insert iptables $table $name $iptablesrule $_");
- system ("iptables -t $table --insert $name $iptablesrule $_");
- die "iptables error: $! - $rule_str" if ($? >> 8);
+ # system ("$logger Insert $iptables_cmd $table $name $iptablesrule $_");
+ # system ("$iptables_cmd -t $table --insert $name $iptablesrule $_");
+ run_cmd("$iptables_cmd -t $table --insert $name $iptablesrule $_",
+ 0, 0);
+ die "$iptables_cmd error: $! - $rule_str" if ($? >> 8);
$iptablesrule++;
}
} elsif ("$rulehash{$rule}" eq "deleted") {
@@ -242,17 +324,20 @@ sub update_rules($) {
my $ipt_rules = $node->get_num_ipt_rules();
for (1 .. $ipt_rules) {
- system ("$logger Delete iptables $table $name $iptablesrule");
- system ("iptables -t $table --delete $name $iptablesrule");
- die "iptables error: $! - $rule" if ($? >> 8);
+ # system ("$logger Delete $iptables_cmd $table $name $iptablesrule");
+ # system ("$iptables_cmd -t $table --delete $name $iptablesrule");
+ run_cmd("$iptables_cmd -t $table --delete $name $iptablesrule",
+ 0, 0);
+ die "$iptables_cmd error: $! - $rule" if ($? >> 8);
}
}
}
}
+
if ($stateful) {
- enable_fw_conntrack();
+ enable_fw_conntrack($iptables_cmd);
} else {
- disable_fw_conntrack();
+ disable_fw_conntrack($iptables_cmd);
}
}
@@ -282,11 +367,13 @@ sub chain_configured($$$) {
}
sub update_ints() {
- my ($action, $int_name, $direction, $chain, $table) = @_;
+ my ($action, $int_name, $direction, $chain, $table, $iptables_cmd) = @_;
my $interface = undef;
+ log_msg "update_ints: @_ \n";
+
if (! defined $action || ! defined $int_name || ! defined $direction
- || ! defined $chain || ! defined $table) {
+ || ! defined $chain || ! defined $table || ! defined $iptables_cmd) {
return -1;
}
@@ -321,14 +408,32 @@ sub update_ints() {
};
}
+ # In the update case, we want to see if the new rule will replace one
+ # that is already in the table. In the delete case, we need to find
+ # the rule in the table that we need to delete. Either way, we
+ # start by listing the rules rules already in the table.
my $grep = "egrep ^[0-9] | grep $int_name";
my @lines
- = `iptables -t $table -L $direction -n -v --line-numbers | $grep`;
+ = `$iptables_cmd -t $table -L $direction -n -v --line-numbers | $grep`;
my ($cmd, $num, $oldchain, $in, $out, $ignore)
= (undef, undef, undef, undef, undef, undef);
+
foreach (@lines) {
- ($num, $ignore, $ignore, $oldchain, $ignore, $ignore, $in, $out,
- $ignore, $ignore) = split /\s+/;
+ # Parse the line representing one rule in the table. Note that
+ # there is a slight difference in output format between the "iptables"
+ # and "ip6tables" comands. The "iptables" command displays "--" in
+ # the "opt" column, while the "ip6tables" command leaves that
+ # column blank.
+ if ($iptables_cmd eq "iptables") {
+ ($num, $ignore, $ignore, $oldchain, $ignore, $ignore, $in, $out,
+ $ignore, $ignore) = split /\s+/;
+ } else {
+ ($num, $ignore, $ignore, $oldchain, $ignore, $in, $out,
+ $ignore, $ignore) = split /\s+/;
+
+ }
+
+ # Look for a matching rule...
if (($dir_str eq 'in' && $in eq $int_name)
|| ($dir_str eq 'out' && $out eq $int_name)
|| ($dir_str eq 'local' && $in eq $int_name)) {
@@ -344,6 +449,7 @@ sub update_ints() {
last;
}
}
+
if (!defined($cmd)) {
# no matching rule
if ($action eq 'update') {
@@ -359,37 +465,43 @@ sub update_ints() {
# no match. do nothing.
return 0 if (!defined($cmd));
- system ("$logger Running: iptables -t $table $cmd");
- system("iptables -t $table $cmd");
+ # system ("$logger Running: $iptables_cmd -t $table $cmd");
+ # system("$iptables_cmd -t $table $cmd");
+ run_cmd("$iptables_cmd -t $table $cmd", 0, 0);
exit 1 if ($? >> 8);
# the following delete_chain is probably no longer necessary since we
# now disallow deleting a chain when it's still referenced
if ($action eq 'replace' || $action eq 'delete') {
if (!defined(chain_configured(2, $oldchain, undef))) {
- if (!chain_referenced($table, $oldchain)) {
- delete_chain($table, $oldchain);
+ if (!chain_referenced($table, $oldchain, $iptables_cmd)) {
+ delete_chain($table, $oldchain, $iptables_cmd);
}
}
}
return 0;
}
-sub enable_fw_conntrack {
+sub enable_fw_conntrack($) {
# potentially we can add rules in the FW_CONNTRACK chain to provide
# finer-grained control over which packets are tracked.
- system("$logger Running: iptables -t raw -R FW_CONNTRACK 1 -J ACCEPT");
- system("iptables -t raw -R FW_CONNTRACK 1 -j ACCEPT 2>&1 | $logger");
+ my $iptables_cmd = shift;
+ # system("$logger Running: $iptables_cmd -t raw -R FW_CONNTRACK 1 -J ACCEPT");
+ # system("$iptables_cmd -t raw -R FW_CONNTRACK 1 -j ACCEPT 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -R FW_CONNTRACK 1 -j ACCEPT", 1, 1);
}
-sub disable_fw_conntrack {
- system("$logger Running: iptables -t raw -R FW_CONNTRACK 1 -j RETURN");
- system("iptables -t raw -R FW_CONNTRACK 1 -j RETURN 2>&1 | $logger");
+sub disable_fw_conntrack($) {
+ my $iptables_cmd = shift;
+ # system("$logger Running: $iptables_cmd -t raw -R FW_CONNTRACK 1 -j RETURN");
+ # system("$iptables_cmd -t raw -R FW_CONNTRACK 1 -j RETURN 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -R FW_CONNTRACK 1 -j RETURN", 1, 1);
}
-sub teardown_iptables($) {
- my $table = shift;
- my @chains = `iptables -L -n -t $table`;
+sub teardown_iptables($$) {
+ my ($table, $iptables_cmd) = @_;
+ log_msg "teardown_iptables executing: $iptables_cmd -L -n -t $table\n";
+ my @chains = `$iptables_cmd -L -n -t $table`;
my $chain;
# $chain is going to look like this...
@@ -402,7 +514,7 @@ sub teardown_iptables($) {
if (($chain =~ /references/) && !($chain =~ /VYATTA_\w+_HOOK/)) {
($chain) = split /\(/, $chain;
$chain =~ s/\s//g;
- delete_chain($table, "$chain");
+ delete_chain($table, "$chain", $iptables_cmd);
}
}
}
@@ -410,53 +522,69 @@ sub teardown_iptables($) {
# remove the conntrack setup.
return if ($update_zero_count != scalar(keys %table_hash));
my @lines
- = `iptables -t raw -L PREROUTING -vn --line-numbers | egrep ^[0-9]`;
+ = `$iptables_cmd -t raw -L PREROUTING -vn --line-numbers | egrep ^[0-9]`;
foreach (@lines) {
my ($num, $ignore, $ignore, $chain, $ignore, $ignore, $in, $out,
$ignore, $ignore) = split /\s+/;
if ($chain eq "FW_CONNTRACK") {
- system("iptables -t raw -D PREROUTING $num 2>&1 | $logger");
- system("iptables -t raw -D OUTPUT $num 2>&1 | $logger");
- system("iptables -t raw -F FW_CONNTRACK 2>&1 | $logger");
- system("iptables -t raw -X FW_CONNTRACK 2>&1 | $logger");
+ # system("$iptables_cmd -t raw -D PREROUTING $num 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -D PREROUTING", 1, 1);
+ # system("$iptables_cmd -t raw -D OUTPUT $num 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -D OUTPUT $num", 1, 1);
+ # system("$iptables_cmd -t raw -F FW_CONNTRACK 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -F FW_CONNTRACK", 1, 1);
+ # system("$iptables_cmd -t raw -X FW_CONNTRACK 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -X FW_CONNTRACK", 1, 1);
last;
}
}
}
-sub setup_iptables() {
- foreach (keys %table_hash) {
+sub setup_iptables($) {
+ my $iptables_cmd = shift;
+ foreach $table (filter, mangle) {
$update_zero_count += 1;
- teardown_iptables($table_hash{$_});
+ teardown_iptables($table, $iptables_cmd);
}
+
# by default, nothing is tracked (the last rule in raw/PREROUTING).
- system("iptables -t raw -N FW_CONNTRACK 2>&1 | $logger");
- system("iptables -t raw -A FW_CONNTRACK -j RETURN 2>&1 | $logger");
- system("iptables -t raw -I PREROUTING 1 -j FW_CONNTRACK 2>&1 | $logger");
- system("iptables -t raw -I OUTPUT 1 -j FW_CONNTRACK 2>&1 | $logger");
+ # system("$iptables_cmd -t raw -N FW_CONNTRACK 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -N FW_CONNTRACK", 1 , 1);
+ # system("$iptables_cmd -t raw -A FW_CONNTRACK -j RETURN 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -A FW_CONNTRACK -j RETURN", 1, 1);
+ # system("$iptables_cmd -t raw -I PREROUTING 1 -j FW_CONNTRACK 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -I PREROUTING 1 -j FW_CONNTRACK", 1, 1);
+ # system("$iptables_cmd -t raw -I OUTPUT 1 -j FW_CONNTRACK 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t raw -I OUTPUT 1 -j FW_CONNTRACK", 1, 1);
return 0;
}
-sub add_default_drop_rule($$) {
- my ($table, $chain) = @_;
- system("iptables -t $table -A $chain -j DROP 2>&1 | $logger");
+sub add_default_drop_rule($$$) {
+ my ($table, $chain, $iptables_cmd) = @_;
+ # system("$iptables_cmd -t $table -A $chain -j DROP 2>&1 | $logger");
+ run_cmd("$iptables_cmd -t $table -A $chain -j DROP", 1, 1);
}
-sub setup_chain($$) {
- my ($table, $chain) = @_;
- my $configured = `iptables -t $table -n -L $chain 2>&1 | head -1`;
+sub setup_chain($$$) {
+ my ($table, $chain, $iptables_cmd) = @_;
+
+ my $configured = `$iptables_cmd -t $table -n -L $chain 2>&1 | head -1`;
$_ = $configured;
if (!/^Chain $chain/) {
- system("iptables -t $table --new-chain $chain");
+ # system("$iptables_cmd -t $table --new-chain $chain");
+ run_cmd("$iptables_cmd -t $table --new-chain $chain", 0, 0);
die "iptables error: $table $chain --new-chain: $!" if ($? >> 8);
- add_default_drop_rule($table, $chain);
+ add_default_drop_rule($table, $chain, $iptables_cmd);
}
}
-sub chain_referenced($$) {
- my ($table, $chain) = @_;
- my $line = `iptables -t $table -n -L $chain 2>/dev/null |head -n1`;
+sub chain_referenced($$$) {
+ my ($table, $chain, $iptables_cmd) = @_;
+
+ log_msg "chain_referenced executing: $iptables_cmd -t $table -n -L $chain \n";
+
+ my $line = `$iptables_cmd -t $table -n -L $chain 2>/dev/null |head -n1`;
if ($line =~ m/^Chain $chain \((\d+) references\)$/) {
if ($1 > 0) {
return 1;
@@ -465,20 +593,31 @@ sub chain_referenced($$) {
return 0;
}
-sub delete_chain($$) {
- my ($table, $chain) = @_;
- my $configured = `iptables -t $table -n -L $chain 2>&1 | head -1`;
+sub delete_chain($$$) {
+ my ($table, $chain, $iptables_cmd) = @_;
+
+ log_msg "delete_chain executing: $iptables_cmd -t $table -n -L $chain \n";
+
+ my $configured = `$iptables_cmd -t $table -n -L $chain 2>&1 | head -1`;
if ($configured =~ /^Chain $chain/) {
- system("iptables -t $table --flush $chain");
- die "iptables error: $table $chain --flush: $!" if ($? >> 8);
- if (!chain_referenced($table, $chain)) {
- system("iptables -t $table --delete-chain $chain");
- die "iptables error: $table $chain --delete-chain: $!" if ($? >> 8);
+ # system("$iptables_cmd -t $table --flush $chain");
+ run_cmd("$iptables_cmd -t $table --flush $chain", 0, 0);
+ die "$iptables_cmd error: $table $chain --flush: $!" if ($? >> 8);
+ if (!chain_referenced($table, $chain, $iptables_cmd)) {
+ # system("$iptables_cmd -t $table --delete-chain $chain");
+ run_cmd("$iptables_cmd -t $table --delete-chain $chain", 0, 0);
+ die "$iptables_cmd error: $table $chain --delete-chain: $!" if ($? >> 8);
} else {
- add_default_drop_rule($table, $chain);
+ add_default_drop_rule($table, $chain, $iptables_cmd);
}
}
}
sub numerically { $a <=> $b; }
+
+# Local Variables:
+# mode: perl
+# indent-tabs-mode: nil
+# perl-indent-level: 2
+# End: